Commit b3b3a9b63f2deacfd59137e3781211d21a568ca9

Authored by Anand Gadiyar
Committed by Robert Richter
1 parent 277dd98417

oprofile: fix linker errors

Commit e9677b3ce (oprofile, ARM: Use oprofile_arch_exit() to
cleanup on failure) caused oprofile_perf_exit to be called
in the cleanup path of oprofile_perf_init. The __exit tag
for oprofile_perf_exit should therefore be dropped.

The same has to be done for exit_driverfs as well, as this
function is called from oprofile_perf_exit. Else, we get
the following two linker errors.

  LD      .tmp_vmlinux1
`oprofile_perf_exit' referenced in section `.init.text' of arch/arm/oprofile/built-in.o: defined in discarded section `.exit.text' of arch/arm/oprofile/built-in.o
make: *** [.tmp_vmlinux1] Error 1

  LD      .tmp_vmlinux1
`exit_driverfs' referenced in section `.text' of arch/arm/oprofile/built-in.o: defined in discarded section `.exit.text' of arch/arm/oprofile/built-in.o
make: *** [.tmp_vmlinux1] Error 1

Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Robert Richter <robert.richter@amd.com>

Showing 2 changed files with 2 additions and 2 deletions Inline Diff

drivers/oprofile/oprofile_perf.c
1 /* 1 /*
2 * Copyright 2010 ARM Ltd. 2 * Copyright 2010 ARM Ltd.
3 * 3 *
4 * Perf-events backend for OProfile. 4 * Perf-events backend for OProfile.
5 */ 5 */
6 #include <linux/perf_event.h> 6 #include <linux/perf_event.h>
7 #include <linux/platform_device.h> 7 #include <linux/platform_device.h>
8 #include <linux/oprofile.h> 8 #include <linux/oprofile.h>
9 #include <linux/slab.h> 9 #include <linux/slab.h>
10 10
11 /* 11 /*
12 * Per performance monitor configuration as set via oprofilefs. 12 * Per performance monitor configuration as set via oprofilefs.
13 */ 13 */
14 struct op_counter_config { 14 struct op_counter_config {
15 unsigned long count; 15 unsigned long count;
16 unsigned long enabled; 16 unsigned long enabled;
17 unsigned long event; 17 unsigned long event;
18 unsigned long unit_mask; 18 unsigned long unit_mask;
19 unsigned long kernel; 19 unsigned long kernel;
20 unsigned long user; 20 unsigned long user;
21 struct perf_event_attr attr; 21 struct perf_event_attr attr;
22 }; 22 };
23 23
24 static int oprofile_perf_enabled; 24 static int oprofile_perf_enabled;
25 static DEFINE_MUTEX(oprofile_perf_mutex); 25 static DEFINE_MUTEX(oprofile_perf_mutex);
26 26
27 static struct op_counter_config *counter_config; 27 static struct op_counter_config *counter_config;
28 static struct perf_event **perf_events[nr_cpumask_bits]; 28 static struct perf_event **perf_events[nr_cpumask_bits];
29 static int num_counters; 29 static int num_counters;
30 30
31 /* 31 /*
32 * Overflow callback for oprofile. 32 * Overflow callback for oprofile.
33 */ 33 */
34 static void op_overflow_handler(struct perf_event *event, int unused, 34 static void op_overflow_handler(struct perf_event *event, int unused,
35 struct perf_sample_data *data, struct pt_regs *regs) 35 struct perf_sample_data *data, struct pt_regs *regs)
36 { 36 {
37 int id; 37 int id;
38 u32 cpu = smp_processor_id(); 38 u32 cpu = smp_processor_id();
39 39
40 for (id = 0; id < num_counters; ++id) 40 for (id = 0; id < num_counters; ++id)
41 if (perf_events[cpu][id] == event) 41 if (perf_events[cpu][id] == event)
42 break; 42 break;
43 43
44 if (id != num_counters) 44 if (id != num_counters)
45 oprofile_add_sample(regs, id); 45 oprofile_add_sample(regs, id);
46 else 46 else
47 pr_warning("oprofile: ignoring spurious overflow " 47 pr_warning("oprofile: ignoring spurious overflow "
48 "on cpu %u\n", cpu); 48 "on cpu %u\n", cpu);
49 } 49 }
50 50
51 /* 51 /*
52 * Called by oprofile_perf_setup to create perf attributes to mirror the oprofile 52 * Called by oprofile_perf_setup to create perf attributes to mirror the oprofile
53 * settings in counter_config. Attributes are created as `pinned' events and 53 * settings in counter_config. Attributes are created as `pinned' events and
54 * so are permanently scheduled on the PMU. 54 * so are permanently scheduled on the PMU.
55 */ 55 */
56 static void op_perf_setup(void) 56 static void op_perf_setup(void)
57 { 57 {
58 int i; 58 int i;
59 u32 size = sizeof(struct perf_event_attr); 59 u32 size = sizeof(struct perf_event_attr);
60 struct perf_event_attr *attr; 60 struct perf_event_attr *attr;
61 61
62 for (i = 0; i < num_counters; ++i) { 62 for (i = 0; i < num_counters; ++i) {
63 attr = &counter_config[i].attr; 63 attr = &counter_config[i].attr;
64 memset(attr, 0, size); 64 memset(attr, 0, size);
65 attr->type = PERF_TYPE_RAW; 65 attr->type = PERF_TYPE_RAW;
66 attr->size = size; 66 attr->size = size;
67 attr->config = counter_config[i].event; 67 attr->config = counter_config[i].event;
68 attr->sample_period = counter_config[i].count; 68 attr->sample_period = counter_config[i].count;
69 attr->pinned = 1; 69 attr->pinned = 1;
70 } 70 }
71 } 71 }
72 72
73 static int op_create_counter(int cpu, int event) 73 static int op_create_counter(int cpu, int event)
74 { 74 {
75 struct perf_event *pevent; 75 struct perf_event *pevent;
76 76
77 if (!counter_config[event].enabled || perf_events[cpu][event]) 77 if (!counter_config[event].enabled || perf_events[cpu][event])
78 return 0; 78 return 0;
79 79
80 pevent = perf_event_create_kernel_counter(&counter_config[event].attr, 80 pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
81 cpu, NULL, 81 cpu, NULL,
82 op_overflow_handler); 82 op_overflow_handler);
83 83
84 if (IS_ERR(pevent)) 84 if (IS_ERR(pevent))
85 return PTR_ERR(pevent); 85 return PTR_ERR(pevent);
86 86
87 if (pevent->state != PERF_EVENT_STATE_ACTIVE) { 87 if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
88 perf_event_release_kernel(pevent); 88 perf_event_release_kernel(pevent);
89 pr_warning("oprofile: failed to enable event %d " 89 pr_warning("oprofile: failed to enable event %d "
90 "on CPU %d\n", event, cpu); 90 "on CPU %d\n", event, cpu);
91 return -EBUSY; 91 return -EBUSY;
92 } 92 }
93 93
94 perf_events[cpu][event] = pevent; 94 perf_events[cpu][event] = pevent;
95 95
96 return 0; 96 return 0;
97 } 97 }
98 98
99 static void op_destroy_counter(int cpu, int event) 99 static void op_destroy_counter(int cpu, int event)
100 { 100 {
101 struct perf_event *pevent = perf_events[cpu][event]; 101 struct perf_event *pevent = perf_events[cpu][event];
102 102
103 if (pevent) { 103 if (pevent) {
104 perf_event_release_kernel(pevent); 104 perf_event_release_kernel(pevent);
105 perf_events[cpu][event] = NULL; 105 perf_events[cpu][event] = NULL;
106 } 106 }
107 } 107 }
108 108
109 /* 109 /*
110 * Called by oprofile_perf_start to create active perf events based on the 110 * Called by oprofile_perf_start to create active perf events based on the
111 * perviously configured attributes. 111 * perviously configured attributes.
112 */ 112 */
113 static int op_perf_start(void) 113 static int op_perf_start(void)
114 { 114 {
115 int cpu, event, ret = 0; 115 int cpu, event, ret = 0;
116 116
117 for_each_online_cpu(cpu) { 117 for_each_online_cpu(cpu) {
118 for (event = 0; event < num_counters; ++event) { 118 for (event = 0; event < num_counters; ++event) {
119 ret = op_create_counter(cpu, event); 119 ret = op_create_counter(cpu, event);
120 if (ret) 120 if (ret)
121 return ret; 121 return ret;
122 } 122 }
123 } 123 }
124 124
125 return ret; 125 return ret;
126 } 126 }
127 127
128 /* 128 /*
129 * Called by oprofile_perf_stop at the end of a profiling run. 129 * Called by oprofile_perf_stop at the end of a profiling run.
130 */ 130 */
131 static void op_perf_stop(void) 131 static void op_perf_stop(void)
132 { 132 {
133 int cpu, event; 133 int cpu, event;
134 134
135 for_each_online_cpu(cpu) 135 for_each_online_cpu(cpu)
136 for (event = 0; event < num_counters; ++event) 136 for (event = 0; event < num_counters; ++event)
137 op_destroy_counter(cpu, event); 137 op_destroy_counter(cpu, event);
138 } 138 }
139 139
140 static int oprofile_perf_create_files(struct super_block *sb, struct dentry *root) 140 static int oprofile_perf_create_files(struct super_block *sb, struct dentry *root)
141 { 141 {
142 unsigned int i; 142 unsigned int i;
143 143
144 for (i = 0; i < num_counters; i++) { 144 for (i = 0; i < num_counters; i++) {
145 struct dentry *dir; 145 struct dentry *dir;
146 char buf[4]; 146 char buf[4];
147 147
148 snprintf(buf, sizeof buf, "%d", i); 148 snprintf(buf, sizeof buf, "%d", i);
149 dir = oprofilefs_mkdir(sb, root, buf); 149 dir = oprofilefs_mkdir(sb, root, buf);
150 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); 150 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
151 oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); 151 oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
152 oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); 152 oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
153 oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); 153 oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
154 oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); 154 oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
155 oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); 155 oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
156 } 156 }
157 157
158 return 0; 158 return 0;
159 } 159 }
160 160
161 static int oprofile_perf_setup(void) 161 static int oprofile_perf_setup(void)
162 { 162 {
163 spin_lock(&oprofilefs_lock); 163 spin_lock(&oprofilefs_lock);
164 op_perf_setup(); 164 op_perf_setup();
165 spin_unlock(&oprofilefs_lock); 165 spin_unlock(&oprofilefs_lock);
166 return 0; 166 return 0;
167 } 167 }
168 168
169 static int oprofile_perf_start(void) 169 static int oprofile_perf_start(void)
170 { 170 {
171 int ret = -EBUSY; 171 int ret = -EBUSY;
172 172
173 mutex_lock(&oprofile_perf_mutex); 173 mutex_lock(&oprofile_perf_mutex);
174 if (!oprofile_perf_enabled) { 174 if (!oprofile_perf_enabled) {
175 ret = 0; 175 ret = 0;
176 op_perf_start(); 176 op_perf_start();
177 oprofile_perf_enabled = 1; 177 oprofile_perf_enabled = 1;
178 } 178 }
179 mutex_unlock(&oprofile_perf_mutex); 179 mutex_unlock(&oprofile_perf_mutex);
180 return ret; 180 return ret;
181 } 181 }
182 182
183 static void oprofile_perf_stop(void) 183 static void oprofile_perf_stop(void)
184 { 184 {
185 mutex_lock(&oprofile_perf_mutex); 185 mutex_lock(&oprofile_perf_mutex);
186 if (oprofile_perf_enabled) 186 if (oprofile_perf_enabled)
187 op_perf_stop(); 187 op_perf_stop();
188 oprofile_perf_enabled = 0; 188 oprofile_perf_enabled = 0;
189 mutex_unlock(&oprofile_perf_mutex); 189 mutex_unlock(&oprofile_perf_mutex);
190 } 190 }
191 191
192 #ifdef CONFIG_PM 192 #ifdef CONFIG_PM
193 static int oprofile_perf_suspend(struct platform_device *dev, pm_message_t state) 193 static int oprofile_perf_suspend(struct platform_device *dev, pm_message_t state)
194 { 194 {
195 mutex_lock(&oprofile_perf_mutex); 195 mutex_lock(&oprofile_perf_mutex);
196 if (oprofile_perf_enabled) 196 if (oprofile_perf_enabled)
197 op_perf_stop(); 197 op_perf_stop();
198 mutex_unlock(&oprofile_perf_mutex); 198 mutex_unlock(&oprofile_perf_mutex);
199 return 0; 199 return 0;
200 } 200 }
201 201
202 static int oprofile_perf_resume(struct platform_device *dev) 202 static int oprofile_perf_resume(struct platform_device *dev)
203 { 203 {
204 mutex_lock(&oprofile_perf_mutex); 204 mutex_lock(&oprofile_perf_mutex);
205 if (oprofile_perf_enabled && op_perf_start()) 205 if (oprofile_perf_enabled && op_perf_start())
206 oprofile_perf_enabled = 0; 206 oprofile_perf_enabled = 0;
207 mutex_unlock(&oprofile_perf_mutex); 207 mutex_unlock(&oprofile_perf_mutex);
208 return 0; 208 return 0;
209 } 209 }
210 210
211 static struct platform_driver oprofile_driver = { 211 static struct platform_driver oprofile_driver = {
212 .driver = { 212 .driver = {
213 .name = "oprofile-perf", 213 .name = "oprofile-perf",
214 }, 214 },
215 .resume = oprofile_perf_resume, 215 .resume = oprofile_perf_resume,
216 .suspend = oprofile_perf_suspend, 216 .suspend = oprofile_perf_suspend,
217 }; 217 };
218 218
219 static struct platform_device *oprofile_pdev; 219 static struct platform_device *oprofile_pdev;
220 220
221 static int __init init_driverfs(void) 221 static int __init init_driverfs(void)
222 { 222 {
223 int ret; 223 int ret;
224 224
225 ret = platform_driver_register(&oprofile_driver); 225 ret = platform_driver_register(&oprofile_driver);
226 if (ret) 226 if (ret)
227 return ret; 227 return ret;
228 228
229 oprofile_pdev = platform_device_register_simple( 229 oprofile_pdev = platform_device_register_simple(
230 oprofile_driver.driver.name, 0, NULL, 0); 230 oprofile_driver.driver.name, 0, NULL, 0);
231 if (IS_ERR(oprofile_pdev)) { 231 if (IS_ERR(oprofile_pdev)) {
232 ret = PTR_ERR(oprofile_pdev); 232 ret = PTR_ERR(oprofile_pdev);
233 platform_driver_unregister(&oprofile_driver); 233 platform_driver_unregister(&oprofile_driver);
234 } 234 }
235 235
236 return ret; 236 return ret;
237 } 237 }
238 238
239 static void __exit exit_driverfs(void) 239 static void exit_driverfs(void)
240 { 240 {
241 platform_device_unregister(oprofile_pdev); 241 platform_device_unregister(oprofile_pdev);
242 platform_driver_unregister(&oprofile_driver); 242 platform_driver_unregister(&oprofile_driver);
243 } 243 }
244 #else 244 #else
245 static int __init init_driverfs(void) { return 0; } 245 static int __init init_driverfs(void) { return 0; }
246 #define exit_driverfs() do { } while (0) 246 #define exit_driverfs() do { } while (0)
247 #endif /* CONFIG_PM */ 247 #endif /* CONFIG_PM */
248 248
249 void oprofile_perf_exit(void) 249 void oprofile_perf_exit(void)
250 { 250 {
251 int cpu, id; 251 int cpu, id;
252 struct perf_event *event; 252 struct perf_event *event;
253 253
254 for_each_possible_cpu(cpu) { 254 for_each_possible_cpu(cpu) {
255 for (id = 0; id < num_counters; ++id) { 255 for (id = 0; id < num_counters; ++id) {
256 event = perf_events[cpu][id]; 256 event = perf_events[cpu][id];
257 if (event) 257 if (event)
258 perf_event_release_kernel(event); 258 perf_event_release_kernel(event);
259 } 259 }
260 260
261 kfree(perf_events[cpu]); 261 kfree(perf_events[cpu]);
262 } 262 }
263 263
264 kfree(counter_config); 264 kfree(counter_config);
265 exit_driverfs(); 265 exit_driverfs();
266 } 266 }
267 267
268 int __init oprofile_perf_init(struct oprofile_operations *ops) 268 int __init oprofile_perf_init(struct oprofile_operations *ops)
269 { 269 {
270 int cpu, ret = 0; 270 int cpu, ret = 0;
271 271
272 ret = init_driverfs(); 272 ret = init_driverfs();
273 if (ret) 273 if (ret)
274 return ret; 274 return ret;
275 275
276 memset(&perf_events, 0, sizeof(perf_events)); 276 memset(&perf_events, 0, sizeof(perf_events));
277 277
278 num_counters = perf_num_counters(); 278 num_counters = perf_num_counters();
279 if (num_counters <= 0) { 279 if (num_counters <= 0) {
280 pr_info("oprofile: no performance counters\n"); 280 pr_info("oprofile: no performance counters\n");
281 ret = -ENODEV; 281 ret = -ENODEV;
282 goto out; 282 goto out;
283 } 283 }
284 284
285 counter_config = kcalloc(num_counters, 285 counter_config = kcalloc(num_counters,
286 sizeof(struct op_counter_config), GFP_KERNEL); 286 sizeof(struct op_counter_config), GFP_KERNEL);
287 287
288 if (!counter_config) { 288 if (!counter_config) {
289 pr_info("oprofile: failed to allocate %d " 289 pr_info("oprofile: failed to allocate %d "
290 "counters\n", num_counters); 290 "counters\n", num_counters);
291 ret = -ENOMEM; 291 ret = -ENOMEM;
292 num_counters = 0; 292 num_counters = 0;
293 goto out; 293 goto out;
294 } 294 }
295 295
296 for_each_possible_cpu(cpu) { 296 for_each_possible_cpu(cpu) {
297 perf_events[cpu] = kcalloc(num_counters, 297 perf_events[cpu] = kcalloc(num_counters,
298 sizeof(struct perf_event *), GFP_KERNEL); 298 sizeof(struct perf_event *), GFP_KERNEL);
299 if (!perf_events[cpu]) { 299 if (!perf_events[cpu]) {
300 pr_info("oprofile: failed to allocate %d perf events " 300 pr_info("oprofile: failed to allocate %d perf events "
301 "for cpu %d\n", num_counters, cpu); 301 "for cpu %d\n", num_counters, cpu);
302 ret = -ENOMEM; 302 ret = -ENOMEM;
303 goto out; 303 goto out;
304 } 304 }
305 } 305 }
306 306
307 ops->create_files = oprofile_perf_create_files; 307 ops->create_files = oprofile_perf_create_files;
308 ops->setup = oprofile_perf_setup; 308 ops->setup = oprofile_perf_setup;
309 ops->start = oprofile_perf_start; 309 ops->start = oprofile_perf_start;
310 ops->stop = oprofile_perf_stop; 310 ops->stop = oprofile_perf_stop;
311 ops->shutdown = oprofile_perf_stop; 311 ops->shutdown = oprofile_perf_stop;
312 ops->cpu_type = op_name_from_perf_id(); 312 ops->cpu_type = op_name_from_perf_id();
313 313
314 if (!ops->cpu_type) 314 if (!ops->cpu_type)
315 ret = -ENODEV; 315 ret = -ENODEV;
316 else 316 else
317 pr_info("oprofile: using %s\n", ops->cpu_type); 317 pr_info("oprofile: using %s\n", ops->cpu_type);
318 318
319 out: 319 out:
320 if (ret) 320 if (ret)
321 oprofile_perf_exit(); 321 oprofile_perf_exit();
322 322
323 return ret; 323 return ret;
324 } 324 }
325 325
include/linux/oprofile.h
1 /** 1 /**
2 * @file oprofile.h 2 * @file oprofile.h
3 * 3 *
4 * API for machine-specific interrupts to interface 4 * API for machine-specific interrupts to interface
5 * to oprofile. 5 * to oprofile.
6 * 6 *
7 * @remark Copyright 2002 OProfile authors 7 * @remark Copyright 2002 OProfile authors
8 * @remark Read the file COPYING 8 * @remark Read the file COPYING
9 * 9 *
10 * @author John Levon <levon@movementarian.org> 10 * @author John Levon <levon@movementarian.org>
11 */ 11 */
12 12
13 #ifndef OPROFILE_H 13 #ifndef OPROFILE_H
14 #define OPROFILE_H 14 #define OPROFILE_H
15 15
16 #include <linux/types.h> 16 #include <linux/types.h>
17 #include <linux/spinlock.h> 17 #include <linux/spinlock.h>
18 #include <linux/init.h> 18 #include <linux/init.h>
19 #include <asm/atomic.h> 19 #include <asm/atomic.h>
20 20
21 /* Each escaped entry is prefixed by ESCAPE_CODE 21 /* Each escaped entry is prefixed by ESCAPE_CODE
22 * then one of the following codes, then the 22 * then one of the following codes, then the
23 * relevant data. 23 * relevant data.
24 * These #defines live in this file so that arch-specific 24 * These #defines live in this file so that arch-specific
25 * buffer sync'ing code can access them. 25 * buffer sync'ing code can access them.
26 */ 26 */
27 #define ESCAPE_CODE ~0UL 27 #define ESCAPE_CODE ~0UL
28 #define CTX_SWITCH_CODE 1 28 #define CTX_SWITCH_CODE 1
29 #define CPU_SWITCH_CODE 2 29 #define CPU_SWITCH_CODE 2
30 #define COOKIE_SWITCH_CODE 3 30 #define COOKIE_SWITCH_CODE 3
31 #define KERNEL_ENTER_SWITCH_CODE 4 31 #define KERNEL_ENTER_SWITCH_CODE 4
32 #define KERNEL_EXIT_SWITCH_CODE 5 32 #define KERNEL_EXIT_SWITCH_CODE 5
33 #define MODULE_LOADED_CODE 6 33 #define MODULE_LOADED_CODE 6
34 #define CTX_TGID_CODE 7 34 #define CTX_TGID_CODE 7
35 #define TRACE_BEGIN_CODE 8 35 #define TRACE_BEGIN_CODE 8
36 #define TRACE_END_CODE 9 36 #define TRACE_END_CODE 9
37 #define XEN_ENTER_SWITCH_CODE 10 37 #define XEN_ENTER_SWITCH_CODE 10
38 #define SPU_PROFILING_CODE 11 38 #define SPU_PROFILING_CODE 11
39 #define SPU_CTX_SWITCH_CODE 12 39 #define SPU_CTX_SWITCH_CODE 12
40 #define IBS_FETCH_CODE 13 40 #define IBS_FETCH_CODE 13
41 #define IBS_OP_CODE 14 41 #define IBS_OP_CODE 14
42 42
43 struct super_block; 43 struct super_block;
44 struct dentry; 44 struct dentry;
45 struct file_operations; 45 struct file_operations;
46 struct pt_regs; 46 struct pt_regs;
47 47
48 /* Operations structure to be filled in */ 48 /* Operations structure to be filled in */
49 struct oprofile_operations { 49 struct oprofile_operations {
50 /* create any necessary configuration files in the oprofile fs. 50 /* create any necessary configuration files in the oprofile fs.
51 * Optional. */ 51 * Optional. */
52 int (*create_files)(struct super_block * sb, struct dentry * root); 52 int (*create_files)(struct super_block * sb, struct dentry * root);
53 /* Do any necessary interrupt setup. Optional. */ 53 /* Do any necessary interrupt setup. Optional. */
54 int (*setup)(void); 54 int (*setup)(void);
55 /* Do any necessary interrupt shutdown. Optional. */ 55 /* Do any necessary interrupt shutdown. Optional. */
56 void (*shutdown)(void); 56 void (*shutdown)(void);
57 /* Start delivering interrupts. */ 57 /* Start delivering interrupts. */
58 int (*start)(void); 58 int (*start)(void);
59 /* Stop delivering interrupts. */ 59 /* Stop delivering interrupts. */
60 void (*stop)(void); 60 void (*stop)(void);
61 /* Arch-specific buffer sync functions. 61 /* Arch-specific buffer sync functions.
62 * Return value = 0: Success 62 * Return value = 0: Success
63 * Return value = -1: Failure 63 * Return value = -1: Failure
64 * Return value = 1: Run generic sync function 64 * Return value = 1: Run generic sync function
65 */ 65 */
66 int (*sync_start)(void); 66 int (*sync_start)(void);
67 int (*sync_stop)(void); 67 int (*sync_stop)(void);
68 68
69 /* Initiate a stack backtrace. Optional. */ 69 /* Initiate a stack backtrace. Optional. */
70 void (*backtrace)(struct pt_regs * const regs, unsigned int depth); 70 void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
71 71
72 /* Multiplex between different events. Optional. */ 72 /* Multiplex between different events. Optional. */
73 int (*switch_events)(void); 73 int (*switch_events)(void);
74 /* CPU identification string. */ 74 /* CPU identification string. */
75 char * cpu_type; 75 char * cpu_type;
76 }; 76 };
77 77
78 /** 78 /**
79 * One-time initialisation. *ops must be set to a filled-in 79 * One-time initialisation. *ops must be set to a filled-in
80 * operations structure. This is called even in timer interrupt 80 * operations structure. This is called even in timer interrupt
81 * mode so an arch can set a backtrace callback. 81 * mode so an arch can set a backtrace callback.
82 * 82 *
83 * If an error occurs, the fields should be left untouched. 83 * If an error occurs, the fields should be left untouched.
84 */ 84 */
85 int oprofile_arch_init(struct oprofile_operations * ops); 85 int oprofile_arch_init(struct oprofile_operations * ops);
86 86
87 /** 87 /**
88 * One-time exit/cleanup for the arch. 88 * One-time exit/cleanup for the arch.
89 */ 89 */
90 void oprofile_arch_exit(void); 90 void oprofile_arch_exit(void);
91 91
92 /** 92 /**
93 * Add a sample. This may be called from any context. 93 * Add a sample. This may be called from any context.
94 */ 94 */
95 void oprofile_add_sample(struct pt_regs * const regs, unsigned long event); 95 void oprofile_add_sample(struct pt_regs * const regs, unsigned long event);
96 96
97 /** 97 /**
98 * Add an extended sample. Use this when the PC is not from the regs, and 98 * Add an extended sample. Use this when the PC is not from the regs, and
99 * we cannot determine if we're in kernel mode from the regs. 99 * we cannot determine if we're in kernel mode from the regs.
100 * 100 *
101 * This function does perform a backtrace. 101 * This function does perform a backtrace.
102 * 102 *
103 */ 103 */
104 void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, 104 void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
105 unsigned long event, int is_kernel); 105 unsigned long event, int is_kernel);
106 106
107 /* Use this instead when the PC value is not from the regs. Doesn't 107 /* Use this instead when the PC value is not from the regs. Doesn't
108 * backtrace. */ 108 * backtrace. */
109 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event); 109 void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event);
110 110
111 /* add a backtrace entry, to be called from the ->backtrace callback */ 111 /* add a backtrace entry, to be called from the ->backtrace callback */
112 void oprofile_add_trace(unsigned long eip); 112 void oprofile_add_trace(unsigned long eip);
113 113
114 114
115 /** 115 /**
116 * Create a file of the given name as a child of the given root, with 116 * Create a file of the given name as a child of the given root, with
117 * the specified file operations. 117 * the specified file operations.
118 */ 118 */
119 int oprofilefs_create_file(struct super_block * sb, struct dentry * root, 119 int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
120 char const * name, const struct file_operations * fops); 120 char const * name, const struct file_operations * fops);
121 121
122 int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root, 122 int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
123 char const * name, const struct file_operations * fops, int perm); 123 char const * name, const struct file_operations * fops, int perm);
124 124
125 /** Create a file for read/write access to an unsigned long. */ 125 /** Create a file for read/write access to an unsigned long. */
126 int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, 126 int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
127 char const * name, ulong * val); 127 char const * name, ulong * val);
128 128
129 /** Create a file for read-only access to an unsigned long. */ 129 /** Create a file for read-only access to an unsigned long. */
130 int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, 130 int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
131 char const * name, ulong * val); 131 char const * name, ulong * val);
132 132
133 /** Create a file for read-only access to an atomic_t. */ 133 /** Create a file for read-only access to an atomic_t. */
134 int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, 134 int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
135 char const * name, atomic_t * val); 135 char const * name, atomic_t * val);
136 136
137 /** create a directory */ 137 /** create a directory */
138 struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root, 138 struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root,
139 char const * name); 139 char const * name);
140 140
141 /** 141 /**
142 * Write the given asciz string to the given user buffer @buf, updating *offset 142 * Write the given asciz string to the given user buffer @buf, updating *offset
143 * appropriately. Returns bytes written or -EFAULT. 143 * appropriately. Returns bytes written or -EFAULT.
144 */ 144 */
145 ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset); 145 ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset);
146 146
147 /** 147 /**
148 * Convert an unsigned long value into ASCII and copy it to the user buffer @buf, 148 * Convert an unsigned long value into ASCII and copy it to the user buffer @buf,
149 * updating *offset appropriately. Returns bytes written or -EFAULT. 149 * updating *offset appropriately. Returns bytes written or -EFAULT.
150 */ 150 */
151 ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset); 151 ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset);
152 152
153 /** 153 /**
154 * Read an ASCII string for a number from a userspace buffer and fill *val on success. 154 * Read an ASCII string for a number from a userspace buffer and fill *val on success.
155 * Returns 0 on success, < 0 on error. 155 * Returns 0 on success, < 0 on error.
156 */ 156 */
157 int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count); 157 int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count);
158 158
159 /** lock for read/write safety */ 159 /** lock for read/write safety */
160 extern spinlock_t oprofilefs_lock; 160 extern spinlock_t oprofilefs_lock;
161 161
162 /** 162 /**
163 * Add the contents of a circular buffer to the event buffer. 163 * Add the contents of a circular buffer to the event buffer.
164 */ 164 */
165 void oprofile_put_buff(unsigned long *buf, unsigned int start, 165 void oprofile_put_buff(unsigned long *buf, unsigned int start,
166 unsigned int stop, unsigned int max); 166 unsigned int stop, unsigned int max);
167 167
168 unsigned long oprofile_get_cpu_buffer_size(void); 168 unsigned long oprofile_get_cpu_buffer_size(void);
169 void oprofile_cpu_buffer_inc_smpl_lost(void); 169 void oprofile_cpu_buffer_inc_smpl_lost(void);
170 170
171 /* cpu buffer functions */ 171 /* cpu buffer functions */
172 172
173 struct op_sample; 173 struct op_sample;
174 174
175 struct op_entry { 175 struct op_entry {
176 struct ring_buffer_event *event; 176 struct ring_buffer_event *event;
177 struct op_sample *sample; 177 struct op_sample *sample;
178 unsigned long size; 178 unsigned long size;
179 unsigned long *data; 179 unsigned long *data;
180 }; 180 };
181 181
182 void oprofile_write_reserve(struct op_entry *entry, 182 void oprofile_write_reserve(struct op_entry *entry,
183 struct pt_regs * const regs, 183 struct pt_regs * const regs,
184 unsigned long pc, int code, int size); 184 unsigned long pc, int code, int size);
185 int oprofile_add_data(struct op_entry *entry, unsigned long val); 185 int oprofile_add_data(struct op_entry *entry, unsigned long val);
186 int oprofile_add_data64(struct op_entry *entry, u64 val); 186 int oprofile_add_data64(struct op_entry *entry, u64 val);
187 int oprofile_write_commit(struct op_entry *entry); 187 int oprofile_write_commit(struct op_entry *entry);
188 188
189 #ifdef CONFIG_PERF_EVENTS 189 #ifdef CONFIG_PERF_EVENTS
190 int __init oprofile_perf_init(struct oprofile_operations *ops); 190 int __init oprofile_perf_init(struct oprofile_operations *ops);
191 void __exit oprofile_perf_exit(void); 191 void oprofile_perf_exit(void);
192 char *op_name_from_perf_id(void); 192 char *op_name_from_perf_id(void);
193 #endif /* CONFIG_PERF_EVENTS */ 193 #endif /* CONFIG_PERF_EVENTS */
194 194
195 #endif /* OPROFILE_H */ 195 #endif /* OPROFILE_H */
196 196