diff options
author | Jamie Iles <jamie.iles@picochip.com> | 2010-02-02 14:24:07 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-02-12 12:23:43 -0500 |
commit | 1618fdd9602c689de2f820a88cb3e283a39c3d90 (patch) | |
tree | be2cec6548d61dc83b7fc538fa929533f9cb9112 | |
parent | 0f4f0672ac950c96cffaf84a666d35e817d7c3ca (diff) |
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>
-rw-r--r-- | arch/arm/oprofile/op_model_arm11_core.c | 4 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_arm11_core.h | 4 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_mpcore.c | 42 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_v6.c | 30 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_v7.c | 30 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_v7.h | 4 | ||||
-rw-r--r-- | arch/arm/oprofile/op_model_xscale.c | 35 |
7 files changed, 85 insertions, 64 deletions
diff --git a/arch/arm/oprofile/op_model_arm11_core.c b/arch/arm/oprofile/op_model_arm11_core.c index ad80752cb9fb..ef3e2653b90c 100644 --- a/arch/arm/oprofile/op_model_arm11_core.c +++ b/arch/arm/oprofile/op_model_arm11_core.c | |||
@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg) | |||
132 | return IRQ_HANDLED; | 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 | unsigned int i; | 137 | unsigned int i; |
138 | int ret = 0; | 138 | int ret = 0; |
@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr) | |||
153 | return ret; | 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 | unsigned int i; | 158 | unsigned int i; |
159 | 159 | ||
diff --git a/arch/arm/oprofile/op_model_arm11_core.h b/arch/arm/oprofile/op_model_arm11_core.h index 6f8538e5a960..1902b99d9dfd 100644 --- a/arch/arm/oprofile/op_model_arm11_core.h +++ b/arch/arm/oprofile/op_model_arm11_core.h | |||
@@ -39,7 +39,7 @@ | |||
39 | int arm11_setup_pmu(void); | 39 | int arm11_setup_pmu(void); |
40 | int arm11_start_pmu(void); | 40 | int arm11_start_pmu(void); |
41 | int arm11_stop_pmu(void); | 41 | int arm11_stop_pmu(void); |
42 | int arm11_request_interrupts(int *, int); | 42 | int arm11_request_interrupts(const int *, int); |
43 | void arm11_release_interrupts(int *, int); | 43 | void arm11_release_interrupts(const int *, int); |
44 | 44 | ||
45 | #endif | 45 | #endif |
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c index 4ce0f9801e2e..f73ce875a395 100644 --- a/arch/arm/oprofile/op_model_mpcore.c +++ b/arch/arm/oprofile/op_model_mpcore.c | |||
@@ -32,6 +32,7 @@ | |||
32 | /* #define DEBUG */ | 32 | /* #define DEBUG */ |
33 | #include <linux/types.h> | 33 | #include <linux/types.h> |
34 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
35 | #include <linux/err.h> | ||
35 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
36 | #include <linux/oprofile.h> | 37 | #include <linux/oprofile.h> |
37 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -43,6 +44,7 @@ | |||
43 | #include <mach/hardware.h> | 44 | #include <mach/hardware.h> |
44 | #include <mach/board-eb.h> | 45 | #include <mach/board-eb.h> |
45 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | #include <asm/pmu.h> | ||
46 | 48 | ||
47 | #include "op_counter.h" | 49 | #include "op_counter.h" |
48 | #include "op_arm_model.h" | 50 | #include "op_arm_model.h" |
@@ -58,6 +60,7 @@ | |||
58 | * Bitmask of used SCU counters | 60 | * Bitmask of used SCU counters |
59 | */ | 61 | */ |
60 | static unsigned int scu_em_used; | 62 | static unsigned int scu_em_used; |
63 | static const struct pmu_irqs *pmu_irqs; | ||
61 | 64 | ||
62 | /* | 65 | /* |
63 | * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) | 66 | * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number) |
@@ -225,33 +228,40 @@ static int em_setup_ctrs(void) | |||
225 | return 0; | 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 | static int em_start(void) | 231 | static int em_start(void) |
236 | { | 232 | { |
237 | int ret; | 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 | if (ret == 0) { | 242 | if (ret == 0) { |
241 | em_call_function(arm11_start_pmu); | 243 | em_call_function(arm11_start_pmu); |
242 | 244 | ||
243 | ret = scu_start(); | 245 | ret = scu_start(); |
244 | if (ret) | 246 | if (ret) { |
245 | arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs)); | 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 | return ret; | 256 | return ret; |
248 | } | 257 | } |
249 | 258 | ||
250 | static void em_stop(void) | 259 | static void em_stop(void) |
251 | { | 260 | { |
252 | em_call_function(arm11_stop_pmu); | 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 | scu_stop(); | 263 | scu_stop(); |
264 | release_pmu(pmu_irqs); | ||
255 | } | 265 | } |
256 | 266 | ||
257 | /* | 267 | /* |
@@ -283,15 +293,7 @@ static int em_setup(void) | |||
283 | em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); | 293 | em_route_irq(IRQ_EB11MP_PMU_SCU6, 3); |
284 | em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); | 294 | em_route_irq(IRQ_EB11MP_PMU_SCU7, 3); |
285 | 295 | ||
286 | /* | 296 | return init_pmu(); |
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; | ||
295 | } | 297 | } |
296 | 298 | ||
297 | struct op_arm_model_spec op_mpcore_spec = { | 299 | struct op_arm_model_spec op_mpcore_spec = { |
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c index f7d2ec5ee9a1..a22357a2fd08 100644 --- a/arch/arm/oprofile/op_model_v6.c +++ b/arch/arm/oprofile/op_model_v6.c | |||
@@ -19,39 +19,47 @@ | |||
19 | /* #define DEBUG */ | 19 | /* #define DEBUG */ |
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
22 | #include <linux/err.h> | ||
22 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
23 | #include <linux/oprofile.h> | 24 | #include <linux/oprofile.h> |
24 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
25 | #include <asm/irq.h> | 26 | #include <asm/irq.h> |
26 | #include <asm/system.h> | 27 | #include <asm/system.h> |
28 | #include <asm/pmu.h> | ||
27 | 29 | ||
28 | #include "op_counter.h" | 30 | #include "op_counter.h" |
29 | #include "op_arm_model.h" | 31 | #include "op_arm_model.h" |
30 | #include "op_model_arm11_core.h" | 32 | #include "op_model_arm11_core.h" |
31 | 33 | ||
32 | static int irqs[] = { | 34 | static const struct pmu_irqs *pmu_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 | }; | ||
40 | 35 | ||
41 | static void armv6_pmu_stop(void) | 36 | static void armv6_pmu_stop(void) |
42 | { | 37 | { |
43 | arm11_stop_pmu(); | 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 | static int armv6_pmu_start(void) | 44 | static int armv6_pmu_start(void) |
48 | { | 45 | { |
49 | int ret; | 46 | int ret; |
50 | 47 | ||
51 | ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs)); | 48 | pmu_irqs = reserve_pmu(); |
52 | if (ret >= 0) | 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 | ret = arm11_start_pmu(); | 56 | ret = arm11_start_pmu(); |
57 | } else { | ||
58 | release_pmu(pmu_irqs); | ||
59 | pmu_irqs = NULL; | ||
60 | } | ||
54 | 61 | ||
62 | out: | ||
55 | return ret; | 63 | return ret; |
56 | } | 64 | } |
57 | 65 | ||
diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c index 2088a6c0cc0e..8642d0891ae1 100644 --- a/arch/arm/oprofile/op_model_v7.c +++ b/arch/arm/oprofile/op_model_v7.c | |||
@@ -11,11 +11,14 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/err.h> | ||
14 | #include <linux/oprofile.h> | 15 | #include <linux/oprofile.h> |
15 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
16 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
17 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
18 | 19 | ||
20 | #include <asm/pmu.h> | ||
21 | |||
19 | #include "op_counter.h" | 22 | #include "op_counter.h" |
20 | #include "op_arm_model.h" | 23 | #include "op_arm_model.h" |
21 | #include "op_model_v7.h" | 24 | #include "op_model_v7.h" |
@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg) | |||
295 | return IRQ_HANDLED; | 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 | unsigned int i; | 303 | unsigned int i; |
301 | int ret = 0; | 304 | int ret = 0; |
@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr) | |||
318 | return ret; | 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 | unsigned int i; | 326 | unsigned int i; |
324 | 327 | ||
@@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void) | |||
362 | } | 365 | } |
363 | #endif | 366 | #endif |
364 | 367 | ||
365 | 368 | static const struct pmu_irqs *pmu_irqs; | |
366 | static int irqs[] = { | ||
367 | #ifdef CONFIG_ARCH_OMAP3 | ||
368 | INT_34XX_BENCH_MPU_EMUL, | ||
369 | #endif | ||
370 | }; | ||
371 | 369 | ||
372 | static void armv7_pmnc_stop(void) | 370 | static void armv7_pmnc_stop(void) |
373 | { | 371 | { |
@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void) | |||
375 | armv7_pmnc_dump_regs(); | 373 | armv7_pmnc_dump_regs(); |
376 | #endif | 374 | #endif |
377 | armv7_stop_pmnc(); | 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 | static int armv7_pmnc_start(void) | 381 | static int armv7_pmnc_start(void) |
382 | { | 382 | { |
383 | int ret; | 383 | int ret; |
384 | 384 | ||
385 | pmu_irqs = reserve_pmu(); | ||
386 | if (IS_ERR(pmu_irqs)) | ||
387 | return PTR_ERR(pmu_irqs); | ||
388 | |||
385 | #ifdef DEBUG | 389 | #ifdef DEBUG |
386 | armv7_pmnc_dump_regs(); | 390 | armv7_pmnc_dump_regs(); |
387 | #endif | 391 | #endif |
388 | ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs)); | 392 | ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs); |
389 | if (ret >= 0) | 393 | if (ret >= 0) { |
390 | armv7_start_pmnc(); | 394 | armv7_start_pmnc(); |
395 | } else { | ||
396 | release_pmu(pmu_irqs); | ||
397 | pmu_irqs = NULL; | ||
398 | } | ||
391 | 399 | ||
392 | return ret; | 400 | return ret; |
393 | } | 401 | } |
diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h index 0e19bcc2e100..9ca334b39c75 100644 --- a/arch/arm/oprofile/op_model_v7.h +++ b/arch/arm/oprofile/op_model_v7.h | |||
@@ -97,7 +97,7 @@ | |||
97 | int armv7_setup_pmu(void); | 97 | int armv7_setup_pmu(void); |
98 | int armv7_start_pmu(void); | 98 | int armv7_start_pmu(void); |
99 | int armv7_stop_pmu(void); | 99 | int armv7_stop_pmu(void); |
100 | int armv7_request_interrupts(int *, int); | 100 | int armv7_request_interrupts(const int *, int); |
101 | void armv7_release_interrupts(int *, int); | 101 | void armv7_release_interrupts(const int *, int); |
102 | 102 | ||
103 | #endif | 103 | #endif |
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c index 724ab9ce2526..1d34a02048bd 100644 --- a/arch/arm/oprofile/op_model_xscale.c +++ b/arch/arm/oprofile/op_model_xscale.c | |||
@@ -17,12 +17,14 @@ | |||
17 | /* #define DEBUG */ | 17 | /* #define DEBUG */ |
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/err.h> | ||
20 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
21 | #include <linux/oprofile.h> | 22 | #include <linux/oprofile.h> |
22 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
23 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
24 | 25 | ||
25 | #include <asm/cputype.h> | 26 | #include <asm/cputype.h> |
27 | #include <asm/pmu.h> | ||
26 | 28 | ||
27 | #include "op_counter.h" | 29 | #include "op_counter.h" |
28 | #include "op_arm_model.h" | 30 | #include "op_arm_model.h" |
@@ -33,17 +35,6 @@ | |||
33 | #define PMU_RESET (CCNT_RESET | PMN_RESET) | 35 | #define PMU_RESET (CCNT_RESET | PMN_RESET) |
34 | #define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */ | 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 | * Different types of events that can be counted by the XScale PMU | 39 | * Different types of events that can be counted by the XScale PMU |
49 | * as used by Oprofile userspace. Here primarily for documentation | 40 | * as used by Oprofile userspace. Here primarily for documentation |
@@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg) | |||
367 | return IRQ_HANDLED; | 358 | return IRQ_HANDLED; |
368 | } | 359 | } |
369 | 360 | ||
361 | static const struct pmu_irqs *pmu_irqs; | ||
362 | |||
370 | static void xscale_pmu_stop(void) | 363 | static void xscale_pmu_stop(void) |
371 | { | 364 | { |
372 | u32 pmnc = read_pmnc(); | 365 | u32 pmnc = read_pmnc(); |
@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void) | |||
374 | pmnc &= ~PMU_ENABLE; | 367 | pmnc &= ~PMU_ENABLE; |
375 | write_pmnc(pmnc); | 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 | static int xscale_pmu_start(void) | 375 | static int xscale_pmu_start(void) |
381 | { | 376 | { |
382 | int ret; | 377 | int ret; |
383 | u32 pmnc = read_pmnc(); | 378 | u32 pmnc; |
379 | |||
380 | pmu_irqs = reserve_pmu(); | ||
381 | if (IS_ERR(pmu_irqs)) | ||
382 | return PTR_ERR(pmu_irqs); | ||
383 | |||
384 | pmnc = read_pmnc(); | ||
384 | 385 | ||
385 | ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED, | 386 | ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt, |
386 | "XScale PMU", (void *)results); | 387 | IRQF_DISABLED, "XScale PMU", (void *)results); |
387 | 388 | ||
388 | if (ret < 0) { | 389 | if (ret < 0) { |
389 | printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n", | 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 | return ret; | 394 | return ret; |
392 | } | 395 | } |
393 | 396 | ||