desktop-files: Changed a few categories for the scripts
[openpandora.oe.git] / recipes / linux / omap3-pandora-kernel / oprofile-0.9.3.armv7.diff
1 Hi,
2
3 This patch adds Oprofile support on ARMv7, using the PMNC unit.
4 Tested on OMAP3430 SDP.
5
6 Feedback and comments are welcome.
7
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).
11
12 Regards,
13 Jean.
14
15 ---
16
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
20
21 Add ARMv7 Oprofile support to kernel
22
23 Signed-off-by: Jean Pihet <jpihet@mvista.com>
24 ---
25
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
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
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
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)
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;
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  
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>
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 +};
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
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
599