ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / arm / oprofile / op_model_xscale.c
1 /**
2  * @file op_model_xscale.c
3  * XScale Performance Monitor Driver
4  *
5  * @remark Copyright 2000-2004 Deepak Saxena <dsaxena@mvista.com>
6  * @remark Copyright 2000-2004 MontaVista Software Inc
7  * @remark Copyright 2004 Dave Jiang <dave.jiang@intel.com>
8  * @remark Copyright 2004 Intel Corporation
9  * @remark Copyright 2004 Zwane Mwaikambo <zwane@arm.linux.org.uk>
10  * @remark Copyright 2004 Oprofile Authors
11  *
12  * @remark Read the file COPYING
13  *
14  * @author Zwane Mwaikambo
15  */
16
17 /* #define DEBUG */
18 #include <linux/types.h>
19 #include <linux/errno.h>
20 #include <linux/sched.h>
21 #include <linux/oprofile.h>
22 #include <linux/interrupt.h>
23 #include <asm/irq.h>
24 #include <asm/system.h>
25
26 #include "op_counter.h"
27 #include "op_arm_model.h"
28
29 #define PMU_ENABLE      0x001   /* Enable counters */
30 #define PMN_RESET       0x002   /* Reset event counters */
31 #define CCNT_RESET      0x004   /* Reset clock counter */
32 #define PMU_RESET       (CCNT_RESET | PMN_RESET)
33
34 /* TODO do runtime detection */
35 #ifdef CONFIG_ARCH_IOP310
36 #define XSCALE_PMU_IRQ  IRQ_XS80200_PMU
37 #endif
38 #ifdef CONFIG_ARCH_IOP321
39 #define XSCALE_PMU_IRQ  IRQ_IOP321_CORE_PMU
40 #endif
41 #ifdef CONFIG_ARCH_IOP331
42 #define XSCALE_PMU_IRQ  IRQ_IOP331_CORE_PMU
43 #endif
44
45 /*
46  * Different types of events that can be counted by the XScale PMU
47  * as used by Oprofile userspace. Here primarily for documentation
48  * purposes.
49  */
50
51 #define EVT_ICACHE_MISS                 0x00
52 #define EVT_ICACHE_NO_DELIVER           0x01
53 #define EVT_DATA_STALL                  0x02
54 #define EVT_ITLB_MISS                   0x03
55 #define EVT_DTLB_MISS                   0x04
56 #define EVT_BRANCH                      0x05
57 #define EVT_BRANCH_MISS                 0x06
58 #define EVT_INSTRUCTION                 0x07
59 #define EVT_DCACHE_FULL_STALL           0x08
60 #define EVT_DCACHE_FULL_STALL_CONTIG    0x09
61 #define EVT_DCACHE_ACCESS               0x0A
62 #define EVT_DCACHE_MISS                 0x0B
63 #define EVT_DCACE_WRITE_BACK            0x0C
64 #define EVT_PC_CHANGED                  0x0D
65 #define EVT_BCU_REQUEST                 0x10
66 #define EVT_BCU_FULL                    0x11
67 #define EVT_BCU_DRAIN                   0x12
68 #define EVT_BCU_ECC_NO_ELOG             0x14
69 #define EVT_BCU_1_BIT_ERR               0x15
70 #define EVT_RMW                         0x16
71 /* EVT_CCNT is not hardware defined */
72 #define EVT_CCNT                        0xFE
73 #define EVT_UNUSED                      0xFF
74
75 struct pmu_counter {
76         volatile unsigned long ovf;
77         unsigned long reset_counter;
78 };
79
80 enum { CCNT, PMN0, PMN1, PMN2, PMN3, MAX_COUNTERS };
81
82 static struct pmu_counter results[MAX_COUNTERS];
83
84 /*
85  * There are two versions of the PMU in current XScale processors
86  * with differing register layouts and number of performance counters.
87  * e.g. IOP321 is xsc1 whilst IOP331 is xsc2.
88  * We detect which register layout to use in xscale_detect_pmu()
89  */
90 enum { PMU_XSC1, PMU_XSC2 };
91
92 struct pmu_type {
93         int id;
94         char *name;
95         int num_counters;
96         unsigned int int_enable;
97         unsigned int cnt_ovf[MAX_COUNTERS];
98         unsigned int int_mask[MAX_COUNTERS];
99 };
100
101 static struct pmu_type pmu_parms[] = {
102         {
103                 .id             = PMU_XSC1,
104                 .name           = "arm/xscale1",
105                 .num_counters   = 3,
106                 .int_mask       = { [PMN0] = 0x10, [PMN1] = 0x20,
107                                     [CCNT] = 0x40 },
108                 .cnt_ovf        = { [CCNT] = 0x400, [PMN0] = 0x100,
109                                     [PMN1] = 0x200},
110         },
111         {
112                 .id             = PMU_XSC2,
113                 .name           = "arm/xscale2",
114                 .num_counters   = 5,
115                 .int_mask       = { [CCNT] = 0x01, [PMN0] = 0x02,
116                                     [PMN1] = 0x04, [PMN2] = 0x08,
117                                     [PMN3] = 0x10 },
118                 .cnt_ovf        = { [CCNT] = 0x01, [PMN0] = 0x02,
119                                     [PMN1] = 0x04, [PMN2] = 0x08,
120                                     [PMN3] = 0x10 },
121         },
122 };
123
124 static struct pmu_type *pmu;
125
126 static void write_pmnc(u32 val)
127 {
128         /* upper 4bits and 7, 11 are write-as-0 */
129         val &= 0xffff77f;
130         if (pmu->id == PMU_XSC1)
131                 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
132         else
133                 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
134 }
135
136 static u32 read_pmnc(void)
137 {
138         u32 val;
139
140         if (pmu->id == PMU_XSC1)
141                 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
142         else
143                 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
144
145         return val;
146 }
147
148 static u32 __xsc1_read_counter(int counter)
149 {
150         u32 val = 0;
151
152         switch (counter) {
153         case CCNT:
154                 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
155                 break;
156         case PMN0:
157                 __asm__ __volatile__ ("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
158                 break;
159         case PMN1:
160                 __asm__ __volatile__ ("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
161                 break;
162         }
163         return val;
164 }
165
166 static u32 __xsc2_read_counter(int counter)
167 {
168         u32 val = 0;
169
170         switch (counter) {
171         case CCNT:
172                 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
173                 break;
174         case PMN0:
175                 __asm__ __volatile__ ("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
176                 break;
177         case PMN1:
178                 __asm__ __volatile__ ("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
179                 break;
180         case PMN2:
181                 __asm__ __volatile__ ("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
182                 break;
183         case PMN3:
184                 __asm__ __volatile__ ("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
185                 break;
186         }
187         return val;
188 }
189
190 static u32 read_counter(int counter)
191 {
192         u32 val;
193
194         if (pmu->id == PMU_XSC1)
195                 val = __xsc1_read_counter(counter);
196         else
197                 val = __xsc2_read_counter(counter);
198
199         return val;
200 }
201
202 static void __xsc1_write_counter(int counter, u32 val)
203 {
204         switch (counter) {
205         case CCNT:
206                 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
207                 break;
208         case PMN0:
209                 __asm__ __volatile__ ("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
210                 break;
211         case PMN1:
212                 __asm__ __volatile__ ("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
213                 break;
214         }
215 }
216
217 static void __xsc2_write_counter(int counter, u32 val)
218 {
219         switch (counter) {
220         case CCNT:
221                 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
222                 break;
223         case PMN0:
224                 __asm__ __volatile__ ("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
225                 break;
226         case PMN1:
227                 __asm__ __volatile__ ("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
228                 break;
229         case PMN2:
230                 __asm__ __volatile__ ("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
231                 break;
232         case PMN3:
233                 __asm__ __volatile__ ("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
234                 break;
235         }
236 }
237
238 static void write_counter(int counter, u32 val)
239 {
240         if (pmu->id == PMU_XSC1)
241                 __xsc1_write_counter(counter, val);
242         else
243                 __xsc2_write_counter(counter, val);
244 }
245
246 static int xscale_setup_ctrs(void)
247 {
248         u32 evtsel, pmnc;
249         int i;
250
251         for (i = CCNT; i < MAX_COUNTERS; i++) {
252                 if (counter_config[i].event)
253                         continue;
254
255                 counter_config[i].event = EVT_UNUSED;
256         }
257
258         switch (pmu->id) {
259         case PMU_XSC1:
260                 pmnc = (counter_config[PMN1].event << 20) | (counter_config[PMN0].event << 12);
261                 pr_debug("xscale_setup_ctrs: pmnc: %#08x\n", pmnc);
262                 write_pmnc(pmnc);
263                 break;
264
265         case PMU_XSC2:
266                 evtsel = counter_config[PMN0].event | (counter_config[PMN1].event << 8) |
267                         (counter_config[PMN2].event << 16) | (counter_config[PMN3].event << 24);
268
269                 pr_debug("xscale_setup_ctrs: evtsel %#08x\n", evtsel);
270                 __asm__ __volatile__ ("mcr p14, 0, %0, c8, c1, 0" : : "r" (evtsel));
271                 break;
272         }
273
274         for (i = CCNT; i < MAX_COUNTERS; i++) {
275                 if (counter_config[i].event == EVT_UNUSED) {
276                         counter_config[i].event = 0;
277                         pmu->int_enable &= ~pmu->int_mask[i];
278                         continue;
279                 }
280
281                 results[i].reset_counter = counter_config[i].count;
282                 write_counter(i, -(u32)counter_config[i].count);
283                 pmu->int_enable |= pmu->int_mask[i];
284                 pr_debug("xscale_setup_ctrs: counter%d %#08x from %#08lx\n", i,
285                         read_counter(i), counter_config[i].count);
286         }
287
288         return 0;
289 }
290
291 static void inline __xsc1_check_ctrs(void)
292 {
293         int i;
294         u32 pmnc = read_pmnc();
295
296         /* NOTE: there's an A stepping errata that states if an overflow */
297         /*       bit already exists and another occurs, the previous     */
298         /*       Overflow bit gets cleared. There's no workaround.       */
299         /*       Fixed in B stepping or later                            */
300
301         pmnc &= ~(PMU_ENABLE | pmu->cnt_ovf[PMN0] | pmu->cnt_ovf[PMN1] |
302                 pmu->cnt_ovf[CCNT]);
303         write_pmnc(pmnc);
304
305         for (i = CCNT; i <= PMN1; i++) {
306                 if (!(pmu->int_mask[i] & pmu->int_enable))
307                         continue;
308
309                 if (pmnc & pmu->cnt_ovf[i])
310                         results[i].ovf++;
311         }
312 }
313
314 static void inline __xsc2_check_ctrs(void)
315 {
316         int i;
317         u32 flag = 0, pmnc = read_pmnc();
318
319         pmnc &= ~PMU_ENABLE;
320         write_pmnc(pmnc);
321
322         /* read overflow flag register */
323         __asm__ __volatile__ ("mrc p14, 0, %0, c5, c1, 0" : "=r" (flag));
324
325         for (i = CCNT; i <= PMN3; i++) {
326                 if (!(pmu->int_mask[i] & pmu->int_enable))
327                         continue;
328
329                 if (flag & pmu->cnt_ovf[i])
330                         results[i].ovf++;
331         }
332
333         /* writeback clears overflow bits */
334         __asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag));
335 }
336
337 static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
338 {
339         unsigned long eip = instruction_pointer(regs);
340         int i, is_kernel = !user_mode(regs);
341         u32 pmnc;
342
343         if (pmu->id == PMU_XSC1)
344                 __xsc1_check_ctrs();
345         else
346                 __xsc2_check_ctrs();
347
348         for (i = CCNT; i < MAX_COUNTERS; i++) {
349                 if (!results[i].ovf)
350                         continue;
351
352                 write_counter(i, -(u32)results[i].reset_counter);
353                 oprofile_add_sample(eip, is_kernel, i, smp_processor_id());
354                 results[i].ovf--;
355         }
356
357         pmnc = read_pmnc() | PMU_ENABLE;
358         write_pmnc(pmnc);
359
360         return IRQ_HANDLED;
361 }
362
363 static void xscale_pmu_stop(void)
364 {
365         u32 pmnc = read_pmnc();
366
367         pmnc &= ~PMU_ENABLE;
368         write_pmnc(pmnc);
369
370         free_irq(XSCALE_PMU_IRQ, results);
371 }
372
373 static int xscale_pmu_start(void)
374 {
375         int ret;
376         u32 pmnc = read_pmnc();
377
378         ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, SA_INTERRUPT,
379                         "XScale PMU", (void *)results);
380
381         if (ret < 0) {
382                 printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n",
383                         XSCALE_PMU_IRQ);
384                 return ret;
385         }
386
387         if (pmu->id == PMU_XSC1)
388                 pmnc |= pmu->int_enable;
389         else
390                 __asm__ __volatile__ ("mcr p14, 0, %0, c4, c1, 0" : : "r" (pmu->int_enable));
391
392         pmnc |= PMU_ENABLE;
393         write_pmnc(pmnc);
394         pr_debug("xscale_pmu_start: pmnc: %#08x mask: %08x\n", pmnc, pmu->int_enable);
395         return 0;
396 }
397
398 static int xscale_detect_pmu(void)
399 {
400         int ret = 0;
401         u32 id;
402
403         id = (read_cpuid(CPUID_ID) >> 13) & 0x7;
404
405         switch (id) {
406         case 1:
407                 pmu = &pmu_parms[PMU_XSC1];
408                 break;
409         case 2:
410                 pmu = &pmu_parms[PMU_XSC2];
411                 break;
412         default:
413                 ret = -ENODEV;
414                 break;
415         }
416
417         if (!ret) {
418                 op_xscale_spec.name = pmu->name;
419                 op_xscale_spec.num_counters = pmu->num_counters;
420                 pr_debug("xscale_detect_pmu: detected %s PMU\n", pmu->name);
421         }
422
423         return ret;
424 }
425
426 struct op_arm_model_spec op_xscale_spec = {
427         .init           = xscale_detect_pmu,
428         .setup_ctrs     = xscale_setup_ctrs,
429         .start          = xscale_pmu_start,
430         .stop           = xscale_pmu_stop,
431 };
432