aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/oprofile
diff options
context:
space:
mode:
authorJamie Iles <jamie.iles@picochip.com>2010-02-02 14:24:07 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-02-12 12:23:43 -0500
commit1618fdd9602c689de2f820a88cb3e283a39c3d90 (patch)
treebe2cec6548d61dc83b7fc538fa929533f9cb9112 /arch/arm/oprofile
parent0f4f0672ac950c96cffaf84a666d35e817d7c3ca (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>
Diffstat (limited to 'arch/arm/oprofile')
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.c4
-rw-r--r--arch/arm/oprofile/op_model_arm11_core.h4
-rw-r--r--arch/arm/oprofile/op_model_mpcore.c42
-rw-r--r--arch/arm/oprofile/op_model_v6.c30
-rw-r--r--arch/arm/oprofile/op_model_v7.c30
-rw-r--r--arch/arm/oprofile/op_model_v7.h4
-rw-r--r--arch/arm/oprofile/op_model_xscale.c35
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 ad80752cb9f..ef3e2653b90 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
135int arm11_request_interrupts(int *irqs, int nr) 135int 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
156void arm11_release_interrupts(int *irqs, int nr) 156void 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 6f8538e5a96..1902b99d9df 100644
--- a/arch/arm/oprofile/op_model_arm11_core.h
+++ b/arch/arm/oprofile/op_model_arm11_core.h
@@ -39,7 +39,7 @@
39int arm11_setup_pmu(void); 39int arm11_setup_pmu(void);
40int arm11_start_pmu(void); 40int arm11_start_pmu(void);
41int arm11_stop_pmu(void); 41int arm11_stop_pmu(void);
42int arm11_request_interrupts(int *, int); 42int arm11_request_interrupts(const int *, int);
43void arm11_release_interrupts(int *, int); 43void 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 4ce0f9801e2..f73ce875a39 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 */
60static unsigned int scu_em_used; 62static unsigned int scu_em_used;
63static 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
228static 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
235static int em_start(void) 231static 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
255out:
247 return ret; 256 return ret;
248} 257}
249 258
250static void em_stop(void) 259static 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
297struct op_arm_model_spec op_mpcore_spec = { 299struct 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 f7d2ec5ee9a..a22357a2fd0 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
32static int irqs[] = { 34static 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
41static void armv6_pmu_stop(void) 36static 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
47static int armv6_pmu_start(void) 44static 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
62out:
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 2088a6c0cc0..8642d0891ae 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
298int armv7_request_interrupts(int *irqs, int nr) 301int 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
321void armv7_release_interrupts(int *irqs, int nr) 324void 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 368static const struct pmu_irqs *pmu_irqs;
366static int irqs[] = {
367#ifdef CONFIG_ARCH_OMAP3
368 INT_34XX_BENCH_MPU_EMUL,
369#endif
370};
371 369
372static void armv7_pmnc_stop(void) 370static 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
381static int armv7_pmnc_start(void) 381static 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 0e19bcc2e10..9ca334b39c7 100644
--- a/arch/arm/oprofile/op_model_v7.h
+++ b/arch/arm/oprofile/op_model_v7.h
@@ -97,7 +97,7 @@
97int armv7_setup_pmu(void); 97int armv7_setup_pmu(void);
98int armv7_start_pmu(void); 98int armv7_start_pmu(void);
99int armv7_stop_pmu(void); 99int armv7_stop_pmu(void);
100int armv7_request_interrupts(int *, int); 100int armv7_request_interrupts(const int *, int);
101void armv7_release_interrupts(int *, int); 101void 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 724ab9ce252..1d34a02048b 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
361static const struct pmu_irqs *pmu_irqs;
362
370static void xscale_pmu_stop(void) 363static 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
380static int xscale_pmu_start(void) 375static 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