libdmx: Add fso-specs to DEPENDS
[openembedded.git] / recipes / linux / linux-omap-2.6.27 / oprofile-0.9.3.armv7.diff
blob1eedbb50ff6314ac142c2b555bb030c1e06201e6
1 Hi,
3 This patch adds Oprofile support on ARMv7, using the PMNC unit.
4 Tested on OMAP3430 SDP.
6 Feedback and comments are welcome.
8 The patch to user space components is attached for reference. It i applies
9 against version 0.9.3 of oprofile source
10 (http://prdownloads.sourceforge.net/oprofile/oprofile-0.9.3.tar.gz).
12 Regards,
13 Jean.
15 ---
17 From: Jean Pihet <jpihet@mvista.com>
18 Date: Tue, 6 May 2008 17:21:44 +0200
19 Subject: [PATCH] ARM: Add ARMv7 oprofile support
21 Add ARMv7 Oprofile support to kernel
23 Signed-off-by: Jean Pihet <jpihet@mvista.com>
24 ---
26 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
27 index c60a27d..60b50a0 100644
28 --- a/arch/arm/Kconfig
29 +++ b/arch/arm/Kconfig
30 @@ -161,6 +161,11 @@ config OPROFILE_MPCORE
31 config OPROFILE_ARM11_CORE
32 bool
34 +config OPROFILE_ARMV7
35 + def_bool y
36 + depends on CPU_V7 && !SMP
37 + bool
39 endif
41 config VECTORS_BASE
42 diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
43 index e61d0cc..88e31f5 100644
44 --- a/arch/arm/oprofile/Makefile
45 +++ b/arch/arm/oprofile/Makefile
46 @@ -11,3 +11,4 @@ oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o
47 oprofile-$(CONFIG_OPROFILE_ARM11_CORE) += op_model_arm11_core.o
48 oprofile-$(CONFIG_OPROFILE_ARMV6) += op_model_v6.o
49 oprofile-$(CONFIG_OPROFILE_MPCORE) += op_model_mpcore.o
50 +oprofile-$(CONFIG_OPROFILE_ARMV7) += op_model_v7.o
51 diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
52 index 0a5cf3a..3fcd752 100644
53 --- a/arch/arm/oprofile/common.c
54 +++ b/arch/arm/oprofile/common.c
55 @@ -145,6 +145,10 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
56 spec = &op_mpcore_spec;
57 #endif
59 +#ifdef CONFIG_OPROFILE_ARMV7
60 + spec = &op_armv7_spec;
61 +#endif
63 if (spec) {
64 ret = spec->init();
65 if (ret < 0)
66 diff --git a/arch/arm/oprofile/op_arm_model.h
67 b/arch/arm/oprofile/op_arm_model.h
68 index 4899c62..8c4e4f6 100644
69 --- a/arch/arm/oprofile/op_arm_model.h
70 +++ b/arch/arm/oprofile/op_arm_model.h
71 @@ -26,6 +26,7 @@ extern struct op_arm_model_spec op_xscale_spec;
73 extern struct op_arm_model_spec op_armv6_spec;
74 extern struct op_arm_model_spec op_mpcore_spec;
75 +extern struct op_arm_model_spec op_armv7_spec;
77 extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
79 diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
80 new file mode 100644
81 index 0000000..a159bc1
82 --- /dev/null
83 +++ b/arch/arm/oprofile/op_model_v7.c
84 @@ -0,0 +1,407 @@
85 +/**
86 + * @file op_model_v7.c
87 + * ARM V7 (Cortex A8) Event Monitor Driver
88 + *
89 + * @remark Copyright 2008 Jean Pihet <jpihet@mvista.com>
90 + * @remark Copyright 2004 ARM SMP Development Team
91 + */
92 +#include <linux/types.h>
93 +#include <linux/errno.h>
94 +#include <linux/oprofile.h>
95 +#include <linux/interrupt.h>
96 +#include <linux/irq.h>
97 +#include <linux/smp.h>
99 +#include "op_counter.h"
100 +#include "op_arm_model.h"
101 +#include "op_model_v7.h"
103 +/* #define DEBUG */
107 + * ARM V7 PMNC support
108 + */
110 +static u32 cnt_en[CNTMAX];
112 +static inline void armv7_pmnc_write(u32 val)
114 + val &= PMNC_MASK;
115 + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
118 +static inline u32 armv7_pmnc_read(void)
120 + u32 val;
122 + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
123 + return val;
126 +static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
128 + u32 val;
130 + if (cnt >= CNTMAX) {
131 + printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
132 + " %d\n", smp_processor_id(), cnt);
133 + return -1;
136 + if (cnt == CCNT)
137 + val = CNTENS_C;
138 + else
139 + val = (1 << (cnt - CNT0));
141 + val &= CNTENS_MASK;
142 + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
144 + return cnt;
147 +static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
149 + u32 val;
151 + if (cnt >= CNTMAX) {
152 + printk(KERN_ERR "oprofile: CPU%u disabling wrong PMNC counter"
153 + " %d\n", smp_processor_id(), cnt);
154 + return -1;
157 + if (cnt == CCNT)
158 + val = CNTENC_C;
159 + else
160 + val = (1 << (cnt - CNT0));
162 + val &= CNTENC_MASK;
163 + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
165 + return cnt;
168 +static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
170 + u32 val;
172 + if (cnt >= CNTMAX) {
173 + printk(KERN_ERR "oprofile: CPU%u enabling wrong PMNC counter"
174 + " interrupt enable %d\n", smp_processor_id(), cnt);
175 + return -1;
178 + if (cnt == CCNT)
179 + val = INTENS_C;
180 + else
181 + val = (1 << (cnt - CNT0));
183 + val &= INTENS_MASK;
184 + asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
186 + return cnt;
189 +static inline u32 armv7_pmnc_getreset_flags(void)
191 + u32 val;
193 + /* Read */
194 + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
196 + /* Write to clear flags */
197 + val &= FLAG_MASK;
198 + asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
200 + return val;
203 +static inline int armv7_pmnc_select_counter(unsigned int cnt)
205 + u32 val;
207 + if ((cnt == CCNT) || (cnt >= CNTMAX)) {
208 + printk(KERN_ERR "oprofile: CPU%u selecting wrong PMNC counteri"
209 + " %d\n", smp_processor_id(), cnt);
210 + return -1;
213 + val = (cnt - CNT0) & SELECT_MASK;
214 + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
216 + return cnt;
219 +static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
221 + if (armv7_pmnc_select_counter(cnt) == cnt) {
222 + val &= EVTSEL_MASK;
223 + asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
227 +static void armv7_pmnc_reset_counter(unsigned int cnt)
229 + u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
230 + u32 val = -(u32)counter_config[cpu_cnt].count;
232 + switch (cnt) {
233 + case CCNT:
234 + armv7_pmnc_disable_counter(cnt);
236 + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
238 + if (cnt_en[cnt] != 0)
239 + armv7_pmnc_enable_counter(cnt);
241 + break;
243 + case CNT0:
244 + case CNT1:
245 + case CNT2:
246 + case CNT3:
247 + armv7_pmnc_disable_counter(cnt);
249 + if (armv7_pmnc_select_counter(cnt) == cnt)
250 + asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
252 + if (cnt_en[cnt] != 0)
253 + armv7_pmnc_enable_counter(cnt);
255 + break;
257 + default:
258 + printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter"
259 + " %d\n", smp_processor_id(), cnt);
260 + break;
264 +int armv7_setup_pmnc(void)
266 + unsigned int cnt;
268 + if (armv7_pmnc_read() & PMNC_E) {
269 + printk(KERN_ERR "oprofile: CPU%u PMNC still enabled when setup"
270 + " new event counter.\n", smp_processor_id());
271 + return -EBUSY;
274 + /*
275 + * Initialize & Reset PMNC: C bit, D bit and P bit.
276 + * Note: Using a slower count for CCNT (D bit: divide by 64) results
277 + * in a more stable system
278 + */
279 + armv7_pmnc_write(PMNC_P | PMNC_C | PMNC_D);
282 + for (cnt = CCNT; cnt < CNTMAX; cnt++) {
283 + unsigned long event;
284 + u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
286 + /*
287 + * Disable counter
288 + */
289 + armv7_pmnc_disable_counter(cnt);
290 + cnt_en[cnt] = 0;
292 + if (!counter_config[cpu_cnt].enabled)
293 + continue;
295 + event = counter_config[cpu_cnt].event & 255;
297 + /*
298 + * Set event (if destined for PMNx counters)
299 + * We don't need to set the event if it's a cycle count
300 + */
301 + if (cnt != CCNT)
302 + armv7_pmnc_write_evtsel(cnt, event);
304 + /*
305 + * Enable interrupt for this counter
306 + */
307 + armv7_pmnc_enable_intens(cnt);
309 + /*
310 + * Reset counter
311 + */
312 + armv7_pmnc_reset_counter(cnt);
314 + /*
315 + * Enable counter
316 + */
317 + armv7_pmnc_enable_counter(cnt);
318 + cnt_en[cnt] = 1;
321 + return 0;
324 +static inline void armv7_start_pmnc(void)
326 + armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
329 +static inline void armv7_stop_pmnc(void)
331 + armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
335 + * CPU counters' IRQ handler (one IRQ per CPU)
336 + */
337 +static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
339 + struct pt_regs *regs = get_irq_regs();
340 + unsigned int cnt;
341 + u32 flags;
344 + /*
345 + * Stop IRQ generation
346 + */
347 + armv7_stop_pmnc();
349 + /*
350 + * Get and reset overflow status flags
351 + */
352 + flags = armv7_pmnc_getreset_flags();
354 + /*
355 + * Cycle counter
356 + */
357 + if (flags & FLAG_C) {
358 + u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), CCNT);
359 + armv7_pmnc_reset_counter(CCNT);
360 + oprofile_add_sample(regs, cpu_cnt);
363 + /*
364 + * PMNC counters 0:3
365 + */
366 + for (cnt = CNT0; cnt < CNTMAX; cnt++) {
367 + if (flags & (1 << (cnt - CNT0))) {
368 + u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
369 + armv7_pmnc_reset_counter(cnt);
370 + oprofile_add_sample(regs, cpu_cnt);
374 + /*
375 + * Allow IRQ generation
376 + */
377 + armv7_start_pmnc();
379 + return IRQ_HANDLED;
382 +int armv7_request_interrupts(int *irqs, int nr)
384 + unsigned int i;
385 + int ret = 0;
387 + for (i = 0; i < nr; i++) {
388 + ret = request_irq(irqs[i], armv7_pmnc_interrupt,
389 + IRQF_DISABLED, "CP15 PMNC", NULL);
390 + if (ret != 0) {
391 + printk(KERN_ERR "oprofile: unable to request IRQ%u"
392 + " for ARMv7\n",
393 + irqs[i]);
394 + break;
398 + if (i != nr)
399 + while (i-- != 0)
400 + free_irq(irqs[i], NULL);
402 + return ret;
405 +void armv7_release_interrupts(int *irqs, int nr)
407 + unsigned int i;
409 + for (i = 0; i < nr; i++)
410 + free_irq(irqs[i], NULL);
413 +#ifdef DEBUG
414 +static void armv7_pmnc_dump_regs(void)
416 + u32 val;
417 + unsigned int cnt;
419 + printk(KERN_INFO "PMNC registers dump:\n");
421 + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
422 + printk(KERN_INFO "PMNC =0x%08x\n", val);
424 + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
425 + printk(KERN_INFO "CNTENS=0x%08x\n", val);
427 + asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
428 + printk(KERN_INFO "INTENS=0x%08x\n", val);
430 + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
431 + printk(KERN_INFO "FLAGS =0x%08x\n", val);
433 + asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
434 + printk(KERN_INFO "SELECT=0x%08x\n", val);
436 + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
437 + printk(KERN_INFO "CCNT =0x%08x\n", val);
439 + for (cnt = CNT0; cnt < CNTMAX; cnt++) {
440 + armv7_pmnc_select_counter(cnt);
441 + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
442 + printk(KERN_INFO "CNT[%d] count =0x%08x\n", cnt-CNT0, val);
443 + asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
444 + printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", cnt-CNT0, val);
447 +#endif
450 +static int irqs[] = {
451 +#ifdef CONFIG_ARCH_OMAP3
452 + INT_34XX_BENCH_MPU_EMUL,
453 +#endif
456 +static void armv7_pmnc_stop(void)
458 +#ifdef DEBUG
459 + armv7_pmnc_dump_regs();
460 +#endif
461 + armv7_stop_pmnc();
462 + armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
465 +static int armv7_pmnc_start(void)
467 + int ret;
469 +#ifdef DEBUG
470 + armv7_pmnc_dump_regs();
471 +#endif
472 + ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
473 + if (ret >= 0)
474 + armv7_start_pmnc();
476 + return ret;
479 +static int armv7_detect_pmnc(void)
481 + return 0;
484 +struct op_arm_model_spec op_armv7_spec = {
485 + .init = armv7_detect_pmnc,
486 + .num_counters = 5,
487 + .setup_ctrs = armv7_setup_pmnc,
488 + .start = armv7_pmnc_start,
489 + .stop = armv7_pmnc_stop,
490 + .name = "arm/armv7",
492 diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
493 new file mode 100644
494 index 0000000..08f40ea
495 --- /dev/null
496 +++ b/arch/arm/oprofile/op_model_v7.h
497 @@ -0,0 +1,101 @@
498 +/**
499 + * @file op_model_v7.h
500 + * ARM v7 (Cortex A8) Event Monitor Driver
502 + * @remark Copyright 2008 Jean Pihet <jpihet@mvista.com>
503 + * @remark Copyright 2004 ARM SMP Development Team
504 + * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
505 + * @remark Copyright 2000-2004 MontaVista Software Inc
506 + * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
507 + * @remark Copyright 2004 Intel Corporation
508 + * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
509 + * @remark Copyright 2004 Oprofile Authors
511 + * @remark Read the file COPYING
513 + * @author Zwane Mwaikambo
514 + */
515 +#ifndef OP_MODEL_V7_H
516 +#define OP_MODEL_V7_H
519 + * Per-CPU PMNC: config reg
520 + */
521 +#define PMNC_E (1 << 0) /* Enable all counters */
522 +#define PMNC_P (1 << 1) /* Reset all counters */
523 +#define PMNC_C (1 << 2) /* Cycle counter reset */
524 +#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
525 +#define PMNC_X (1 << 4) /* Export to ETM */
526 +#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
527 +#define PMNC_MASK 0x3f /* Mask for writable bits */
530 + * Available counters
531 + */
532 +#define CCNT 0
533 +#define CNT0 1
534 +#define CNT1 2
535 +#define CNT2 3
536 +#define CNT3 4
537 +#define CNTMAX 5
539 +#define CPU_COUNTER(cpu, counter) ((cpu) * CNTMAX + (counter))
542 + * CNTENS: counters enable reg
543 + */
544 +#define CNTENS_P0 (1 << 0)
545 +#define CNTENS_P1 (1 << 1)
546 +#define CNTENS_P2 (1 << 2)
547 +#define CNTENS_P3 (1 << 3)
548 +#define CNTENS_C (1 << 31)
549 +#define CNTENS_MASK 0x8000000f /* Mask for writable bits */
552 + * CNTENC: counters disable reg
553 + */
554 +#define CNTENC_P0 (1 << 0)
555 +#define CNTENC_P1 (1 << 1)
556 +#define CNTENC_P2 (1 << 2)
557 +#define CNTENC_P3 (1 << 3)
558 +#define CNTENC_C (1 << 31)
559 +#define CNTENC_MASK 0x8000000f /* Mask for writable bits */
562 + * INTENS: counters overflow interrupt enable reg
563 + */
564 +#define INTENS_P0 (1 << 0)
565 +#define INTENS_P1 (1 << 1)
566 +#define INTENS_P2 (1 << 2)
567 +#define INTENS_P3 (1 << 3)
568 +#define INTENS_C (1 << 31)
569 +#define INTENS_MASK 0x8000000f /* Mask for writable bits */
572 + * EVTSEL: Event selection reg
573 + */
574 +#define EVTSEL_MASK 0x7f /* Mask for writable bits */
577 + * SELECT: Counter selection reg
578 + */
579 +#define SELECT_MASK 0x1f /* Mask for writable bits */
582 + * FLAG: counters overflow flag status reg
583 + */
584 +#define FLAG_P0 (1 << 0)
585 +#define FLAG_P1 (1 << 1)
586 +#define FLAG_P2 (1 << 2)
587 +#define FLAG_P3 (1 << 3)
588 +#define FLAG_C (1 << 31)
589 +#define FLAG_MASK 0x8000000f /* Mask for writable bits */
592 +int armv7_setup_pmu(void);
593 +int armv7_start_pmu(void);
594 +int armv7_stop_pmu(void);
595 +int armv7_request_interrupts(int *, int);
596 +void armv7_release_interrupts(int *, int);
598 +#endif