summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff')
-rw-r--r--meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff611
1 files changed, 611 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff
new file mode 100644
index 0000000000..dbc11fbe7d
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/oprofile-0.9.3.armv7.diff
@@ -0,0 +1,611 @@
1Hi,
2
3This patch adds Oprofile support on ARMv7, using the PMNC unit.
4Tested on OMAP3430 SDP.
5
6Feedback and comments are welcome.
7
8The patch to user space components is attached for reference. It i applies
9against version 0.9.3 of oprofile source
10(http://prdownloads.sourceforge.net/oprofile/oprofile-0.9.3.tar.gz).
11
12Regards,
13Jean.
14
15---
16
17From: Jean Pihet <jpihet@mvista.com>
18Date: Tue, 6 May 2008 17:21:44 +0200
19Subject: [PATCH] ARM: Add ARMv7 oprofile support
20
21Add ARMv7 Oprofile support to kernel
22
23Signed-off-by: Jean Pihet <jpihet@mvista.com>
24---
25
26diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
27index 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
33
34+config OPROFILE_ARMV7
35+ def_bool y
36+ depends on CPU_V7 && !SMP
37+ bool
38+
39 endif
40
41 config VECTORS_BASE
42diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
43index 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
51diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
52index 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
58
59+#ifdef CONFIG_OPROFILE_ARMV7
60+ spec = &op_armv7_spec;
61+#endif
62+
63 if (spec) {
64 ret = spec->init();
65 if (ret < 0)
66diff --git a/arch/arm/oprofile/op_arm_model.h
67b/arch/arm/oprofile/op_arm_model.h
68index 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;
72
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;
76
77 extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
78
79diff --git a/arch/arm/oprofile/op_model_v7.c b/arch/arm/oprofile/op_model_v7.c
80new file mode 100644
81index 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>
98+
99+#include "op_counter.h"
100+#include "op_arm_model.h"
101+#include "op_model_v7.h"
102+
103+/* #define DEBUG */
104+
105+
106+/*
107+ * ARM V7 PMNC support
108+ */
109+
110+static u32 cnt_en[CNTMAX];
111+
112+static inline void armv7_pmnc_write(u32 val)
113+{
114+ val &= PMNC_MASK;
115+ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
116+}
117+
118+static inline u32 armv7_pmnc_read(void)
119+{
120+ u32 val;
121+
122+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
123+ return val;
124+}
125+
126+static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
127+{
128+ u32 val;
129+
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;
134+ }
135+
136+ if (cnt == CCNT)
137+ val = CNTENS_C;
138+ else
139+ val = (1 << (cnt - CNT0));
140+
141+ val &= CNTENS_MASK;
142+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
143+
144+ return cnt;
145+}
146+
147+static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
148+{
149+ u32 val;
150+
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;
155+ }
156+
157+ if (cnt == CCNT)
158+ val = CNTENC_C;
159+ else
160+ val = (1 << (cnt - CNT0));
161+
162+ val &= CNTENC_MASK;
163+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
164+
165+ return cnt;
166+}
167+
168+static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
169+{
170+ u32 val;
171+
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;
176+ }
177+
178+ if (cnt == CCNT)
179+ val = INTENS_C;
180+ else
181+ val = (1 << (cnt - CNT0));
182+
183+ val &= INTENS_MASK;
184+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
185+
186+ return cnt;
187+}
188+
189+static inline u32 armv7_pmnc_getreset_flags(void)
190+{
191+ u32 val;
192+
193+ /* Read */
194+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
195+
196+ /* Write to clear flags */
197+ val &= FLAG_MASK;
198+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
199+
200+ return val;
201+}
202+
203+static inline int armv7_pmnc_select_counter(unsigned int cnt)
204+{
205+ u32 val;
206+
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;
211+ }
212+
213+ val = (cnt - CNT0) & SELECT_MASK;
214+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
215+
216+ return cnt;
217+}
218+
219+static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
220+{
221+ if (armv7_pmnc_select_counter(cnt) == cnt) {
222+ val &= EVTSEL_MASK;
223+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
224+ }
225+}
226+
227+static void armv7_pmnc_reset_counter(unsigned int cnt)
228+{
229+ u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
230+ u32 val = -(u32)counter_config[cpu_cnt].count;
231+
232+ switch (cnt) {
233+ case CCNT:
234+ armv7_pmnc_disable_counter(cnt);
235+
236+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
237+
238+ if (cnt_en[cnt] != 0)
239+ armv7_pmnc_enable_counter(cnt);
240+
241+ break;
242+
243+ case CNT0:
244+ case CNT1:
245+ case CNT2:
246+ case CNT3:
247+ armv7_pmnc_disable_counter(cnt);
248+
249+ if (armv7_pmnc_select_counter(cnt) == cnt)
250+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
251+
252+ if (cnt_en[cnt] != 0)
253+ armv7_pmnc_enable_counter(cnt);
254+
255+ break;
256+
257+ default:
258+ printk(KERN_ERR "oprofile: CPU%u resetting wrong PMNC counter"
259+ " %d\n", smp_processor_id(), cnt);
260+ break;
261+ }
262+}
263+
264+int armv7_setup_pmnc(void)
265+{
266+ unsigned int cnt;
267+
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;
272+ }
273+
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);
280+
281+
282+ for (cnt = CCNT; cnt < CNTMAX; cnt++) {
283+ unsigned long event;
284+ u32 cpu_cnt = CPU_COUNTER(smp_processor_id(), cnt);
285+
286+ /*
287+ * Disable counter
288+ */
289+ armv7_pmnc_disable_counter(cnt);
290+ cnt_en[cnt] = 0;
291+
292+ if (!counter_config[cpu_cnt].enabled)
293+ continue;
294+
295+ event = counter_config[cpu_cnt].event & 255;
296+
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);
303+
304+ /*
305+ * Enable interrupt for this counter
306+ */
307+ armv7_pmnc_enable_intens(cnt);
308+
309+ /*
310+ * Reset counter
311+ */
312+ armv7_pmnc_reset_counter(cnt);
313+
314+ /*
315+ * Enable counter
316+ */
317+ armv7_pmnc_enable_counter(cnt);
318+ cnt_en[cnt] = 1;
319+ }
320+
321+ return 0;
322+}
323+
324+static inline void armv7_start_pmnc(void)
325+{
326+ armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
327+}
328+
329+static inline void armv7_stop_pmnc(void)
330+{
331+ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
332+}
333+
334+/*
335+ * CPU counters' IRQ handler (one IRQ per CPU)
336+ */
337+static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
338+{
339+ struct pt_regs *regs = get_irq_regs();
340+ unsigned int cnt;
341+ u32 flags;
342+
343+
344+ /*
345+ * Stop IRQ generation
346+ */
347+ armv7_stop_pmnc();
348+
349+ /*
350+ * Get and reset overflow status flags
351+ */
352+ flags = armv7_pmnc_getreset_flags();
353+
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);
361+ }
362+
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);
371+ }
372+ }
373+
374+ /*
375+ * Allow IRQ generation
376+ */
377+ armv7_start_pmnc();
378+
379+ return IRQ_HANDLED;
380+}
381+
382+int armv7_request_interrupts(int *irqs, int nr)
383+{
384+ unsigned int i;
385+ int ret = 0;
386+
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;
395+ }
396+ }
397+
398+ if (i != nr)
399+ while (i-- != 0)
400+ free_irq(irqs[i], NULL);
401+
402+ return ret;
403+}
404+
405+void armv7_release_interrupts(int *irqs, int nr)
406+{
407+ unsigned int i;
408+
409+ for (i = 0; i < nr; i++)
410+ free_irq(irqs[i], NULL);
411+}
412+
413+#ifdef DEBUG
414+static void armv7_pmnc_dump_regs(void)
415+{
416+ u32 val;
417+ unsigned int cnt;
418+
419+ printk(KERN_INFO "PMNC registers dump:\n");
420+
421+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
422+ printk(KERN_INFO "PMNC =0x%08x\n", val);
423+
424+ asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
425+ printk(KERN_INFO "CNTENS=0x%08x\n", val);
426+
427+ asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
428+ printk(KERN_INFO "INTENS=0x%08x\n", val);
429+
430+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
431+ printk(KERN_INFO "FLAGS =0x%08x\n", val);
432+
433+ asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
434+ printk(KERN_INFO "SELECT=0x%08x\n", val);
435+
436+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
437+ printk(KERN_INFO "CCNT =0x%08x\n", val);
438+
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);
445+ }
446+}
447+#endif
448+
449+
450+static int irqs[] = {
451+#ifdef CONFIG_ARCH_OMAP3
452+ INT_34XX_BENCH_MPU_EMUL,
453+#endif
454+};
455+
456+static void armv7_pmnc_stop(void)
457+{
458+#ifdef DEBUG
459+ armv7_pmnc_dump_regs();
460+#endif
461+ armv7_stop_pmnc();
462+ armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
463+}
464+
465+static int armv7_pmnc_start(void)
466+{
467+ int ret;
468+
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();
475+
476+ return ret;
477+}
478+
479+static int armv7_detect_pmnc(void)
480+{
481+ return 0;
482+}
483+
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",
491+};
492diff --git a/arch/arm/oprofile/op_model_v7.h b/arch/arm/oprofile/op_model_v7.h
493new file mode 100644
494index 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
501+ *
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
510+ *
511+ * @remark Read the file COPYING
512+ *
513+ * @author Zwane Mwaikambo
514+ */
515+#ifndef OP_MODEL_V7_H
516+#define OP_MODEL_V7_H
517+
518+/*
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 */
528+
529+/*
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
538+
539+#define CPU_COUNTER(cpu, counter) ((cpu) * CNTMAX + (counter))
540+
541+/*
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 */
550+
551+/*
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 */
560+
561+/*
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 */
570+
571+/*
572+ * EVTSEL: Event selection reg
573+ */
574+#define EVTSEL_MASK 0x7f /* Mask for writable bits */
575+
576+/*
577+ * SELECT: Counter selection reg
578+ */
579+#define SELECT_MASK 0x1f /* Mask for writable bits */
580+
581+/*
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 */
590+
591+
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);
597+
598+#endif
599diff --git a/include/asm-arm/arch-omap/irqs.h
600b/include/asm-arm/arch-omap/irqs.h
601index c80e160..89ca90e 100644
602--- a/include/asm-arm/arch-omap/irqs.h
603+++ b/include/asm-arm/arch-omap/irqs.h
604@@ -297,6 +297,7 @@
605 #define INT_243X_HS_USB_DMA 93
606 #define INT_243X_CARKIT_IRQ 94
607
608+#define INT_34XX_BENCH_MPU_EMUL 3
609 #define INT_34XX_ST_MCBSP2_IRQ 4
610 #define INT_34XX_ST_MCBSP3_IRQ 5
611 #define INT_34XX_SYS_NIRQ 7