Commit 1618fdd9602c689de2f820a88cb3e283a39c3d90

Authored by Jamie Iles
Committed by Russell King
1 parent 0f4f0672ac

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