MIPS: Whitespace cleanup.
[linux-drm-fsl-dcu.git] / arch / mips / oprofile / op_model_mipsxx.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2004, 05, 06 by Ralf Baechle
7  * Copyright (C) 2005 by MIPS Technologies, Inc.
8  */
9 #include <linux/cpumask.h>
10 #include <linux/oprofile.h>
11 #include <linux/interrupt.h>
12 #include <linux/smp.h>
13 #include <asm/irq_regs.h>
14
15 #include "op_impl.h"
16
17 #define M_PERFCTL_EXL                   (1UL      <<  0)
18 #define M_PERFCTL_KERNEL                (1UL      <<  1)
19 #define M_PERFCTL_SUPERVISOR            (1UL      <<  2)
20 #define M_PERFCTL_USER                  (1UL      <<  3)
21 #define M_PERFCTL_INTERRUPT_ENABLE      (1UL      <<  4)
22 #define M_PERFCTL_EVENT(event)          (((event) & 0x3ff)  << 5)
23 #define M_PERFCTL_VPEID(vpe)            ((vpe)    << 16)
24 #define M_PERFCTL_MT_EN(filter)         ((filter) << 20)
25 #define    M_TC_EN_ALL                  M_PERFCTL_MT_EN(0)
26 #define    M_TC_EN_VPE                  M_PERFCTL_MT_EN(1)
27 #define    M_TC_EN_TC                   M_PERFCTL_MT_EN(2)
28 #define M_PERFCTL_TCID(tcid)            ((tcid)   << 22)
29 #define M_PERFCTL_WIDE                  (1UL      << 30)
30 #define M_PERFCTL_MORE                  (1UL      << 31)
31
32 #define M_COUNTER_OVERFLOW              (1UL      << 31)
33
34 /* Netlogic XLR specific, count events in all threads in a core */
35 #define M_PERFCTL_COUNT_ALL_THREADS     (1UL      << 13)
36
37 static int (*save_perf_irq)(void);
38
39 /*
40  * XLR has only one set of counters per core. Designate the
41  * first hardware thread in the core for setup and init.
42  * Skip CPUs with non-zero hardware thread id (4 hwt per core)
43  */
44 #ifdef CONFIG_CPU_XLR
45 #define oprofile_skip_cpu(c)    ((cpu_logical_map(c) & 0x3) != 0)
46 #else
47 #define oprofile_skip_cpu(c)    0
48 #endif
49
50 #ifdef CONFIG_MIPS_MT_SMP
51 static int cpu_has_mipsmt_pertccounters;
52 #define WHAT            (M_TC_EN_VPE | \
53                          M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id))
54 #define vpe_id()        (cpu_has_mipsmt_pertccounters ? \
55                         0 : cpu_data[smp_processor_id()].vpe_id)
56
57 /*
58  * The number of bits to shift to convert between counters per core and
59  * counters per VPE.  There is no reasonable interface atm to obtain the
60  * number of VPEs used by Linux and in the 34K this number is fixed to two
61  * anyways so we hardcore a few things here for the moment.  The way it's
62  * done here will ensure that oprofile VSMP kernel will run right on a lesser
63  * core like a 24K also or with maxcpus=1.
64  */
65 static inline unsigned int vpe_shift(void)
66 {
67         if (num_possible_cpus() > 1)
68                 return 1;
69
70         return 0;
71 }
72
73 #else
74
75 #define WHAT            0
76 #define vpe_id()        0
77
78 static inline unsigned int vpe_shift(void)
79 {
80         return 0;
81 }
82
83 #endif
84
85 static inline unsigned int counters_total_to_per_cpu(unsigned int counters)
86 {
87         return counters >> vpe_shift();
88 }
89
90 static inline unsigned int counters_per_cpu_to_total(unsigned int counters)
91 {
92         return counters << vpe_shift();
93 }
94
95 #define __define_perf_accessors(r, n, np)                               \
96                                                                         \
97 static inline unsigned int r_c0_ ## r ## n(void)                        \
98 {                                                                       \
99         unsigned int cpu = vpe_id();                                    \
100                                                                         \
101         switch (cpu) {                                                  \
102         case 0:                                                         \
103                 return read_c0_ ## r ## n();                            \
104         case 1:                                                         \
105                 return read_c0_ ## r ## np();                           \
106         default:                                                        \
107                 BUG();                                                  \
108         }                                                               \
109         return 0;                                                       \
110 }                                                                       \
111                                                                         \
112 static inline void w_c0_ ## r ## n(unsigned int value)                  \
113 {                                                                       \
114         unsigned int cpu = vpe_id();                                    \
115                                                                         \
116         switch (cpu) {                                                  \
117         case 0:                                                         \
118                 write_c0_ ## r ## n(value);                             \
119                 return;                                                 \
120         case 1:                                                         \
121                 write_c0_ ## r ## np(value);                            \
122                 return;                                                 \
123         default:                                                        \
124                 BUG();                                                  \
125         }                                                               \
126         return;                                                         \
127 }                                                                       \
128
129 __define_perf_accessors(perfcntr, 0, 2)
130 __define_perf_accessors(perfcntr, 1, 3)
131 __define_perf_accessors(perfcntr, 2, 0)
132 __define_perf_accessors(perfcntr, 3, 1)
133
134 __define_perf_accessors(perfctrl, 0, 2)
135 __define_perf_accessors(perfctrl, 1, 3)
136 __define_perf_accessors(perfctrl, 2, 0)
137 __define_perf_accessors(perfctrl, 3, 1)
138
139 struct op_mips_model op_model_mipsxx_ops;
140
141 static struct mipsxx_register_config {
142         unsigned int control[4];
143         unsigned int counter[4];
144 } reg;
145
146 /* Compute all of the registers in preparation for enabling profiling.  */
147
148 static void mipsxx_reg_setup(struct op_counter_config *ctr)
149 {
150         unsigned int counters = op_model_mipsxx_ops.num_counters;
151         int i;
152
153         /* Compute the performance counter control word.  */
154         for (i = 0; i < counters; i++) {
155                 reg.control[i] = 0;
156                 reg.counter[i] = 0;
157
158                 if (!ctr[i].enabled)
159                         continue;
160
161                 reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) |
162                                  M_PERFCTL_INTERRUPT_ENABLE;
163                 if (ctr[i].kernel)
164                         reg.control[i] |= M_PERFCTL_KERNEL;
165                 if (ctr[i].user)
166                         reg.control[i] |= M_PERFCTL_USER;
167                 if (ctr[i].exl)
168                         reg.control[i] |= M_PERFCTL_EXL;
169                 if (current_cpu_type() == CPU_XLR)
170                         reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS;
171                 reg.counter[i] = 0x80000000 - ctr[i].count;
172         }
173 }
174
175 /* Program all of the registers in preparation for enabling profiling.  */
176
177 static void mipsxx_cpu_setup(void *args)
178 {
179         unsigned int counters = op_model_mipsxx_ops.num_counters;
180
181         if (oprofile_skip_cpu(smp_processor_id()))
182                 return;
183
184         switch (counters) {
185         case 4:
186                 w_c0_perfctrl3(0);
187                 w_c0_perfcntr3(reg.counter[3]);
188         case 3:
189                 w_c0_perfctrl2(0);
190                 w_c0_perfcntr2(reg.counter[2]);
191         case 2:
192                 w_c0_perfctrl1(0);
193                 w_c0_perfcntr1(reg.counter[1]);
194         case 1:
195                 w_c0_perfctrl0(0);
196                 w_c0_perfcntr0(reg.counter[0]);
197         }
198 }
199
200 /* Start all counters on current CPU */
201 static void mipsxx_cpu_start(void *args)
202 {
203         unsigned int counters = op_model_mipsxx_ops.num_counters;
204
205         if (oprofile_skip_cpu(smp_processor_id()))
206                 return;
207
208         switch (counters) {
209         case 4:
210                 w_c0_perfctrl3(WHAT | reg.control[3]);
211         case 3:
212                 w_c0_perfctrl2(WHAT | reg.control[2]);
213         case 2:
214                 w_c0_perfctrl1(WHAT | reg.control[1]);
215         case 1:
216                 w_c0_perfctrl0(WHAT | reg.control[0]);
217         }
218 }
219
220 /* Stop all counters on current CPU */
221 static void mipsxx_cpu_stop(void *args)
222 {
223         unsigned int counters = op_model_mipsxx_ops.num_counters;
224
225         if (oprofile_skip_cpu(smp_processor_id()))
226                 return;
227
228         switch (counters) {
229         case 4:
230                 w_c0_perfctrl3(0);
231         case 3:
232                 w_c0_perfctrl2(0);
233         case 2:
234                 w_c0_perfctrl1(0);
235         case 1:
236                 w_c0_perfctrl0(0);
237         }
238 }
239
240 static int mipsxx_perfcount_handler(void)
241 {
242         unsigned int counters = op_model_mipsxx_ops.num_counters;
243         unsigned int control;
244         unsigned int counter;
245         int handled = IRQ_NONE;
246
247         if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26)))
248                 return handled;
249
250         switch (counters) {
251 #define HANDLE_COUNTER(n)                                               \
252         case n + 1:                                                     \
253                 control = r_c0_perfctrl ## n();                         \
254                 counter = r_c0_perfcntr ## n();                         \
255                 if ((control & M_PERFCTL_INTERRUPT_ENABLE) &&           \
256                     (counter & M_COUNTER_OVERFLOW)) {                   \
257                         oprofile_add_sample(get_irq_regs(), n);         \
258                         w_c0_perfcntr ## n(reg.counter[n]);             \
259                         handled = IRQ_HANDLED;                          \
260                 }
261         HANDLE_COUNTER(3)
262         HANDLE_COUNTER(2)
263         HANDLE_COUNTER(1)
264         HANDLE_COUNTER(0)
265         }
266
267         return handled;
268 }
269
270 #define M_CONFIG1_PC    (1 << 4)
271
272 static inline int __n_counters(void)
273 {
274         if (!(read_c0_config1() & M_CONFIG1_PC))
275                 return 0;
276         if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
277                 return 1;
278         if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
279                 return 2;
280         if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
281                 return 3;
282
283         return 4;
284 }
285
286 static inline int n_counters(void)
287 {
288         int counters;
289
290         switch (current_cpu_type()) {
291         case CPU_R10000:
292                 counters = 2;
293                 break;
294
295         case CPU_R12000:
296         case CPU_R14000:
297                 counters = 4;
298                 break;
299
300         default:
301                 counters = __n_counters();
302         }
303
304         return counters;
305 }
306
307 static void reset_counters(void *arg)
308 {
309         int counters = (int)(long)arg;
310         switch (counters) {
311         case 4:
312                 w_c0_perfctrl3(0);
313                 w_c0_perfcntr3(0);
314         case 3:
315                 w_c0_perfctrl2(0);
316                 w_c0_perfcntr2(0);
317         case 2:
318                 w_c0_perfctrl1(0);
319                 w_c0_perfcntr1(0);
320         case 1:
321                 w_c0_perfctrl0(0);
322                 w_c0_perfcntr0(0);
323         }
324 }
325
326 static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id)
327 {
328         return mipsxx_perfcount_handler();
329 }
330
331 static int __init mipsxx_init(void)
332 {
333         int counters;
334
335         counters = n_counters();
336         if (counters == 0) {
337                 printk(KERN_ERR "Oprofile: CPU has no performance counters\n");
338                 return -ENODEV;
339         }
340
341 #ifdef CONFIG_MIPS_MT_SMP
342         cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
343         if (!cpu_has_mipsmt_pertccounters)
344                 counters = counters_total_to_per_cpu(counters);
345 #endif
346         on_each_cpu(reset_counters, (void *)(long)counters, 1);
347
348         op_model_mipsxx_ops.num_counters = counters;
349         switch (current_cpu_type()) {
350         case CPU_M14KC:
351                 op_model_mipsxx_ops.cpu_type = "mips/M14Kc";
352                 break;
353
354         case CPU_20KC:
355                 op_model_mipsxx_ops.cpu_type = "mips/20K";
356                 break;
357
358         case CPU_24K:
359                 op_model_mipsxx_ops.cpu_type = "mips/24K";
360                 break;
361
362         case CPU_25KF:
363                 op_model_mipsxx_ops.cpu_type = "mips/25K";
364                 break;
365
366         case CPU_1004K:
367         case CPU_34K:
368                 op_model_mipsxx_ops.cpu_type = "mips/34K";
369                 break;
370
371         case CPU_74K:
372                 op_model_mipsxx_ops.cpu_type = "mips/74K";
373                 break;
374
375         case CPU_5KC:
376                 op_model_mipsxx_ops.cpu_type = "mips/5K";
377                 break;
378
379         case CPU_R10000:
380                 if ((current_cpu_data.processor_id & 0xff) == 0x20)
381                         op_model_mipsxx_ops.cpu_type = "mips/r10000-v2.x";
382                 else
383                         op_model_mipsxx_ops.cpu_type = "mips/r10000";
384                 break;
385
386         case CPU_R12000:
387         case CPU_R14000:
388                 op_model_mipsxx_ops.cpu_type = "mips/r12000";
389                 break;
390
391         case CPU_SB1:
392         case CPU_SB1A:
393                 op_model_mipsxx_ops.cpu_type = "mips/sb1";
394                 break;
395
396         case CPU_LOONGSON1:
397                 op_model_mipsxx_ops.cpu_type = "mips/loongson1";
398                 break;
399
400         case CPU_XLR:
401                 op_model_mipsxx_ops.cpu_type = "mips/xlr";
402                 break;
403
404         default:
405                 printk(KERN_ERR "Profiling unsupported for this CPU\n");
406
407                 return -ENODEV;
408         }
409
410         save_perf_irq = perf_irq;
411         perf_irq = mipsxx_perfcount_handler;
412
413         if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
414                 return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int,
415                         0, "Perfcounter", save_perf_irq);
416
417         return 0;
418 }
419
420 static void mipsxx_exit(void)
421 {
422         int counters = op_model_mipsxx_ops.num_counters;
423
424         if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq))
425                 free_irq(cp0_perfcount_irq, save_perf_irq);
426
427         counters = counters_per_cpu_to_total(counters);
428         on_each_cpu(reset_counters, (void *)(long)counters, 1);
429
430         perf_irq = save_perf_irq;
431 }
432
433 struct op_mips_model op_model_mipsxx_ops = {
434         .reg_setup      = mipsxx_reg_setup,
435         .cpu_setup      = mipsxx_cpu_setup,
436         .init           = mipsxx_init,
437         .exit           = mipsxx_exit,
438         .cpu_start      = mipsxx_cpu_start,
439         .cpu_stop       = mipsxx_cpu_stop,
440 };