Commit 1618fdd9602c689de2f820a88cb3e283a39c3d90
Committed by
Russell King
1 parent
0f4f0672ac
Exists in
master
and in
7 other branches
ARM: 5901/2: arm/oprofile: reserve the PMU when starting
Make sure that we have access to the performance counters and that they aren't being used by perf events or anything else. Cc: Will Deacon <will.deacon@arm.com> Cc: Jean Pihet <jpihet@mvista.com> Signed-off-by: Jamie Iles <jamie.iles@picochip.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Showing 7 changed files with 85 additions and 64 deletions Side-by-side Diff
arch/arm/oprofile/op_model_arm11_core.c
... | ... | @@ -132,7 +132,7 @@ |
132 | 132 | return IRQ_HANDLED; |
133 | 133 | } |
134 | 134 | |
135 | -int arm11_request_interrupts(int *irqs, int nr) | |
135 | +int arm11_request_interrupts(const int *irqs, int nr) | |
136 | 136 | { |
137 | 137 | unsigned int i; |
138 | 138 | int ret = 0; |
... | ... | @@ -153,7 +153,7 @@ |
153 | 153 | return ret; |
154 | 154 | } |
155 | 155 | |
156 | -void arm11_release_interrupts(int *irqs, int nr) | |
156 | +void arm11_release_interrupts(const int *irqs, int nr) | |
157 | 157 | { |
158 | 158 | unsigned int i; |
159 | 159 |
arch/arm/oprofile/op_model_arm11_core.h
... | ... | @@ -39,8 +39,8 @@ |
39 | 39 | int arm11_setup_pmu(void); |
40 | 40 | int arm11_start_pmu(void); |
41 | 41 | int arm11_stop_pmu(void); |
42 | -int arm11_request_interrupts(int *, int); | |
43 | -void arm11_release_interrupts(int *, int); | |
42 | +int arm11_request_interrupts(const int *, int); | |
43 | +void arm11_release_interrupts(const int *, int); | |
44 | 44 | |
45 | 45 | #endif |
arch/arm/oprofile/op_model_mpcore.c
... | ... | @@ -32,6 +32,7 @@ |
32 | 32 | /* #define DEBUG */ |
33 | 33 | #include <linux/types.h> |
34 | 34 | #include <linux/errno.h> |
35 | +#include <linux/err.h> | |
35 | 36 | #include <linux/sched.h> |
36 | 37 | #include <linux/oprofile.h> |
37 | 38 | #include <linux/interrupt.h> |
... | ... | @@ -43,6 +44,7 @@ |
43 | 44 | #include <mach/hardware.h> |
44 | 45 | #include <mach/board-eb.h> |
45 | 46 | #include <asm/system.h> |
47 | +#include <asm/pmu.h> | |
46 | 48 | |
47 | 49 | #include "op_counter.h" |
48 | 50 | #include "op_arm_model.h" |
... | ... | @@ -58,6 +60,7 @@ |
58 | 60 | * Bitmask of used SCU counters |
59 | 61 | */ |
60 | 62 | static unsigned int scu_em_used; |
63 | +static const struct pmu_irqs *pmu_irqs; | |
61 | 64 | |
62 | 65 | /* |
63 | 66 | * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) |
64 | 67 | |
65 | 68 | |
66 | 69 | |
67 | 70 | |
68 | 71 | |
... | ... | @@ -225,33 +228,40 @@ |
225 | 228 | return 0; |
226 | 229 | } |
227 | 230 | |
228 | -static int arm11_irqs[] = { | |
229 | - [0] = IRQ_EB11MP_PMU_CPU0, | |
230 | - [1] = IRQ_EB11MP_PMU_CPU1, | |
231 | - [2] = IRQ_EB11MP_PMU_CPU2, | |
232 | - [3] = IRQ_EB11MP_PMU_CPU3 | |
233 | -}; | |
234 | - | |
235 | 231 | static int em_start(void) |
236 | 232 | { |
237 | 233 | int ret; |
238 | 234 | |
239 | - ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); | |
235 | + pmu_irqs = reserve_pmu(); | |
236 | + if (IS_ERR(pmu_irqs)) { | |
237 | + ret = PTR_ERR(pmu_irqs); | |
238 | + goto out; | |
239 | + } | |
240 | + | |
241 | + ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
240 | 242 | if (ret == 0) { |
241 | 243 | em_call_function(arm11_start_pmu); |
242 | 244 | |
243 | 245 | ret = scu_start(); |
244 | - if (ret) | |
245 | - arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); | |
246 | + if (ret) { | |
247 | + arm11_release_interrupts(pmu_irqs->irqs, | |
248 | + pmu_irqs->num_irqs); | |
249 | + } else { | |
250 | + release_pmu(pmu_irqs); | |
251 | + pmu_irqs = NULL; | |
252 | + } | |
246 | 253 | } |
254 | + | |
255 | +out: | |
247 | 256 | return ret; |
248 | 257 | } |
249 | 258 | |
250 | 259 | static void em_stop(void) |
251 | 260 | { |
252 | 261 | em_call_function(arm11_stop_pmu); |
253 | - arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); | |
262 | + arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
254 | 263 | scu_stop(); |
264 | + release_pmu(pmu_irqs); | |
255 | 265 | } |
256 | 266 | |
257 | 267 | /* |
... | ... | @@ -283,15 +293,7 @@ |
283 | 293 | em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); |
284 | 294 | em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); |
285 | 295 | |
286 | - /* | |
287 | - * Send CP15 PMU interrupts to the owner CPU. | |
288 | - */ | |
289 | - em_route_irq(IRQ_EB11MP_PMU_CPU0, 0); | |
290 | - em_route_irq(IRQ_EB11MP_PMU_CPU1, 1); | |
291 | - em_route_irq(IRQ_EB11MP_PMU_CPU2, 2); | |
292 | - em_route_irq(IRQ_EB11MP_PMU_CPU3, 3); | |
293 | - | |
294 | - return 0; | |
296 | + return init_pmu(); | |
295 | 297 | } |
296 | 298 | |
297 | 299 | struct op_arm_model_spec op_mpcore_spec = { |
arch/arm/oprofile/op_model_v6.c
... | ... | @@ -19,39 +19,47 @@ |
19 | 19 | /* #define DEBUG */ |
20 | 20 | #include <linux/types.h> |
21 | 21 | #include <linux/errno.h> |
22 | +#include <linux/err.h> | |
22 | 23 | #include <linux/sched.h> |
23 | 24 | #include <linux/oprofile.h> |
24 | 25 | #include <linux/interrupt.h> |
25 | 26 | #include <asm/irq.h> |
26 | 27 | #include <asm/system.h> |
28 | +#include <asm/pmu.h> | |
27 | 29 | |
28 | 30 | #include "op_counter.h" |
29 | 31 | #include "op_arm_model.h" |
30 | 32 | #include "op_model_arm11_core.h" |
31 | 33 | |
32 | -static int irqs[] = { | |
33 | -#ifdef CONFIG_ARCH_OMAP2 | |
34 | - 3, | |
35 | -#endif | |
36 | -#ifdef CONFIG_ARCH_BCMRING | |
37 | - IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */ | |
38 | -#endif | |
39 | -}; | |
34 | +static const struct pmu_irqs *pmu_irqs; | |
40 | 35 | |
41 | 36 | static void armv6_pmu_stop(void) |
42 | 37 | { |
43 | 38 | arm11_stop_pmu(); |
44 | - arm11_release_interrupts(irqs, ARRAY_SIZE(irqs)); | |
39 | + arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
40 | + release_pmu(pmu_irqs); | |
41 | + pmu_irqs = NULL; | |
45 | 42 | } |
46 | 43 | |
47 | 44 | static int armv6_pmu_start(void) |
48 | 45 | { |
49 | 46 | int ret; |
50 | 47 | |
51 | - ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs)); | |
52 | - if (ret >= 0) | |
48 | + pmu_irqs = reserve_pmu(); | |
49 | + if (IS_ERR(pmu_irqs)) { | |
50 | + ret = PTR_ERR(pmu_irqs); | |
51 | + goto out; | |
52 | + } | |
53 | + | |
54 | + ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
55 | + if (ret >= 0) { | |
53 | 56 | ret = arm11_start_pmu(); |
57 | + } else { | |
58 | + release_pmu(pmu_irqs); | |
59 | + pmu_irqs = NULL; | |
60 | + } | |
54 | 61 | |
62 | +out: | |
55 | 63 | return ret; |
56 | 64 | } |
57 | 65 |
arch/arm/oprofile/op_model_v7.c
... | ... | @@ -11,11 +11,14 @@ |
11 | 11 | */ |
12 | 12 | #include <linux/types.h> |
13 | 13 | #include <linux/errno.h> |
14 | +#include <linux/err.h> | |
14 | 15 | #include <linux/oprofile.h> |
15 | 16 | #include <linux/interrupt.h> |
16 | 17 | #include <linux/irq.h> |
17 | 18 | #include <linux/smp.h> |
18 | 19 | |
20 | +#include <asm/pmu.h> | |
21 | + | |
19 | 22 | #include "op_counter.h" |
20 | 23 | #include "op_arm_model.h" |
21 | 24 | #include "op_model_v7.h" |
... | ... | @@ -295,7 +298,7 @@ |
295 | 298 | return IRQ_HANDLED; |
296 | 299 | } |
297 | 300 | |
298 | -int armv7_request_interrupts(int *irqs, int nr) | |
301 | +int armv7_request_interrupts(const int *irqs, int nr) | |
299 | 302 | { |
300 | 303 | unsigned int i; |
301 | 304 | int ret = 0; |
... | ... | @@ -318,7 +321,7 @@ |
318 | 321 | return ret; |
319 | 322 | } |
320 | 323 | |
321 | -void armv7_release_interrupts(int *irqs, int nr) | |
324 | +void armv7_release_interrupts(const int *irqs, int nr) | |
322 | 325 | { |
323 | 326 | unsigned int i; |
324 | 327 | |
325 | 328 | |
326 | 329 | |
327 | 330 | |
328 | 331 | |
329 | 332 | |
... | ... | @@ -362,32 +365,37 @@ |
362 | 365 | } |
363 | 366 | #endif |
364 | 367 | |
368 | +static const struct pmu_irqs *pmu_irqs; | |
365 | 369 | |
366 | -static int irqs[] = { | |
367 | -#ifdef CONFIG_ARCH_OMAP3 | |
368 | - INT_34XX_BENCH_MPU_EMUL, | |
369 | -#endif | |
370 | -}; | |
371 | - | |
372 | 370 | static void armv7_pmnc_stop(void) |
373 | 371 | { |
374 | 372 | #ifdef DEBUG |
375 | 373 | armv7_pmnc_dump_regs(); |
376 | 374 | #endif |
377 | 375 | armv7_stop_pmnc(); |
378 | - armv7_release_interrupts(irqs, ARRAY_SIZE(irqs)); | |
376 | + armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
377 | + release_pmu(pmu_irqs); | |
378 | + pmu_irqs = NULL; | |
379 | 379 | } |
380 | 380 | |
381 | 381 | static int armv7_pmnc_start(void) |
382 | 382 | { |
383 | 383 | int ret; |
384 | 384 | |
385 | + pmu_irqs = reserve_pmu(); | |
386 | + if (IS_ERR(pmu_irqs)) | |
387 | + return PTR_ERR(pmu_irqs); | |
388 | + | |
385 | 389 | #ifdef DEBUG |
386 | 390 | armv7_pmnc_dump_regs(); |
387 | 391 | #endif |
388 | - ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs)); | |
389 | - if (ret >= 0) | |
392 | + ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); | |
393 | + if (ret >= 0) { | |
390 | 394 | armv7_start_pmnc(); |
395 | + } else { | |
396 | + release_pmu(pmu_irqs); | |
397 | + pmu_irqs = NULL; | |
398 | + } | |
391 | 399 | |
392 | 400 | return ret; |
393 | 401 | } |
arch/arm/oprofile/op_model_v7.h
... | ... | @@ -97,8 +97,8 @@ |
97 | 97 | int armv7_setup_pmu(void); |
98 | 98 | int armv7_start_pmu(void); |
99 | 99 | int armv7_stop_pmu(void); |
100 | -int armv7_request_interrupts(int *, int); | |
101 | -void armv7_release_interrupts(int *, int); | |
100 | +int armv7_request_interrupts(const int *, int); | |
101 | +void armv7_release_interrupts(const int *, int); | |
102 | 102 | |
103 | 103 | #endif |
arch/arm/oprofile/op_model_xscale.c
... | ... | @@ -17,12 +17,14 @@ |
17 | 17 | /* #define DEBUG */ |
18 | 18 | #include <linux/types.h> |
19 | 19 | #include <linux/errno.h> |
20 | +#include <linux/err.h> | |
20 | 21 | #include <linux/sched.h> |
21 | 22 | #include <linux/oprofile.h> |
22 | 23 | #include <linux/interrupt.h> |
23 | 24 | #include <linux/irq.h> |
24 | 25 | |
25 | 26 | #include <asm/cputype.h> |
27 | +#include <asm/pmu.h> | |
26 | 28 | |
27 | 29 | #include "op_counter.h" |
28 | 30 | #include "op_arm_model.h" |
... | ... | @@ -33,17 +35,6 @@ |
33 | 35 | #define PMU_RESET (CCNT_RESET | PMN_RESET) |
34 | 36 | #define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */ |
35 | 37 | |
36 | -/* TODO do runtime detection */ | |
37 | -#ifdef CONFIG_ARCH_IOP32X | |
38 | -#define XSCALE_PMU_IRQ IRQ_IOP32X_CORE_PMU | |
39 | -#endif | |
40 | -#ifdef CONFIG_ARCH_IOP33X | |
41 | -#define XSCALE_PMU_IRQ IRQ_IOP33X_CORE_PMU | |
42 | -#endif | |
43 | -#ifdef CONFIG_ARCH_PXA | |
44 | -#define XSCALE_PMU_IRQ IRQ_PMU | |
45 | -#endif | |
46 | - | |
47 | 38 | /* |
48 | 39 | * Different types of events that can be counted by the XScale PMU |
49 | 40 | * as used by Oprofile userspace. Here primarily for documentation |
... | ... | @@ -367,6 +358,8 @@ |
367 | 358 | return IRQ_HANDLED; |
368 | 359 | } |
369 | 360 | |
361 | +static const struct pmu_irqs *pmu_irqs; | |
362 | + | |
370 | 363 | static void xscale_pmu_stop(void) |
371 | 364 | { |
372 | 365 | u32 pmnc = read_pmnc(); |
373 | 366 | |
374 | 367 | |
375 | 368 | |
376 | 369 | |
... | ... | @@ -374,20 +367,30 @@ |
374 | 367 | pmnc &= ~PMU_ENABLE; |
375 | 368 | write_pmnc(pmnc); |
376 | 369 | |
377 | - free_irq(XSCALE_PMU_IRQ, results); | |
370 | + free_irq(pmu_irqs->irqs[0], results); | |
371 | + release_pmu(pmu_irqs); | |
372 | + pmu_irqs = NULL; | |
378 | 373 | } |
379 | 374 | |
380 | 375 | static int xscale_pmu_start(void) |
381 | 376 | { |
382 | 377 | int ret; |
383 | - u32 pmnc = read_pmnc(); | |
378 | + u32 pmnc; | |
384 | 379 | |
385 | - ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED, | |
386 | - "XScale PMU", (void *)results); | |
380 | + pmu_irqs = reserve_pmu(); | |
381 | + if (IS_ERR(pmu_irqs)) | |
382 | + return PTR_ERR(pmu_irqs); | |
387 | 383 | |
384 | + pmnc = read_pmnc(); | |
385 | + | |
386 | + ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt, | |
387 | + IRQF_DISABLED, "XScale PMU", (void *)results); | |
388 | + | |
388 | 389 | if (ret < 0) { |
389 | 390 | printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n", |
390 | - XSCALE_PMU_IRQ); | |
391 | + pmu_irqs->irqs[0]); | |
392 | + release_pmu(pmu_irqs); | |
393 | + pmu_irqs = NULL; | |
391 | 394 | return ret; |
392 | 395 | } |
393 | 396 |