ARM: 7355/1: perf: clear overflow flag when disabling counter on ARMv7 PMU
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / kernel / perf_event_xscale.c
CommitLineData
43eab878
WD
1/*
2 * ARMv5 [xscale] Performance counter handling code.
3 *
4 * Copyright (C) 2010, ARM Ltd., Will Deacon <will.deacon@arm.com>
5 *
6 * Based on the previous xscale OProfile code.
7 *
8 * There are two variants of the xscale PMU that we support:
9 * - xscale1pmu: 2 event counters and a cycle counter
10 * - xscale2pmu: 4 event counters and a cycle counter
11 * The two variants share event definitions, but have different
12 * PMU structures.
13 */
14
15#ifdef CONFIG_CPU_XSCALE
16enum xscale_perf_types {
17 XSCALE_PERFCTR_ICACHE_MISS = 0x00,
18 XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01,
19 XSCALE_PERFCTR_DATA_STALL = 0x02,
20 XSCALE_PERFCTR_ITLB_MISS = 0x03,
21 XSCALE_PERFCTR_DTLB_MISS = 0x04,
22 XSCALE_PERFCTR_BRANCH = 0x05,
23 XSCALE_PERFCTR_BRANCH_MISS = 0x06,
24 XSCALE_PERFCTR_INSTRUCTION = 0x07,
25 XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08,
26 XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09,
27 XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A,
28 XSCALE_PERFCTR_DCACHE_MISS = 0x0B,
29 XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C,
30 XSCALE_PERFCTR_PC_CHANGED = 0x0D,
31 XSCALE_PERFCTR_BCU_REQUEST = 0x10,
32 XSCALE_PERFCTR_BCU_FULL = 0x11,
33 XSCALE_PERFCTR_BCU_DRAIN = 0x12,
34 XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14,
35 XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15,
36 XSCALE_PERFCTR_RMW = 0x16,
37 /* XSCALE_PERFCTR_CCNT is not hardware defined */
38 XSCALE_PERFCTR_CCNT = 0xFE,
39 XSCALE_PERFCTR_UNUSED = 0xFF,
40};
41
42enum xscale_counters {
d2b41f74 43 XSCALE_CYCLE_COUNTER = 0,
43eab878
WD
44 XSCALE_COUNTER0,
45 XSCALE_COUNTER1,
46 XSCALE_COUNTER2,
47 XSCALE_COUNTER3,
48};
49
50static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = {
0445e7a5
WD
51 [PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT,
52 [PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION,
53 [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
54 [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
55 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH,
56 [PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS,
57 [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
58 [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = XSCALE_PERFCTR_ICACHE_NO_DELIVER,
59 [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED,
43eab878
WD
60};
61
62static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
63 [PERF_COUNT_HW_CACHE_OP_MAX]
64 [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
65 [C(L1D)] = {
66 [C(OP_READ)] = {
67 [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
68 [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
69 },
70 [C(OP_WRITE)] = {
71 [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS,
72 [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS,
73 },
74 [C(OP_PREFETCH)] = {
75 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
76 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
77 },
78 },
79 [C(L1I)] = {
80 [C(OP_READ)] = {
81 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
82 [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
83 },
84 [C(OP_WRITE)] = {
85 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
86 [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
87 },
88 [C(OP_PREFETCH)] = {
89 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
90 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
91 },
92 },
93 [C(LL)] = {
94 [C(OP_READ)] = {
95 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
96 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
97 },
98 [C(OP_WRITE)] = {
99 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
100 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
101 },
102 [C(OP_PREFETCH)] = {
103 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
104 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
105 },
106 },
107 [C(DTLB)] = {
108 [C(OP_READ)] = {
109 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
110 [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
111 },
112 [C(OP_WRITE)] = {
113 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
114 [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS,
115 },
116 [C(OP_PREFETCH)] = {
117 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
118 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
119 },
120 },
121 [C(ITLB)] = {
122 [C(OP_READ)] = {
123 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
124 [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
125 },
126 [C(OP_WRITE)] = {
127 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
128 [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS,
129 },
130 [C(OP_PREFETCH)] = {
131 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
132 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
133 },
134 },
135 [C(BPU)] = {
136 [C(OP_READ)] = {
137 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
138 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
139 },
140 [C(OP_WRITE)] = {
141 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
142 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
143 },
144 [C(OP_PREFETCH)] = {
145 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
146 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
147 },
148 },
89d6c0b5
PZ
149 [C(NODE)] = {
150 [C(OP_READ)] = {
151 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
152 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
153 },
154 [C(OP_WRITE)] = {
155 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
156 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
157 },
158 [C(OP_PREFETCH)] = {
159 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
160 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
161 },
162 },
43eab878
WD
163};
164
165#define XSCALE_PMU_ENABLE 0x001
166#define XSCALE_PMN_RESET 0x002
167#define XSCALE_CCNT_RESET 0x004
168#define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET)
169#define XSCALE_PMU_CNT64 0x008
170
171#define XSCALE1_OVERFLOWED_MASK 0x700
172#define XSCALE1_CCOUNT_OVERFLOW 0x400
173#define XSCALE1_COUNT0_OVERFLOW 0x100
174#define XSCALE1_COUNT1_OVERFLOW 0x200
175#define XSCALE1_CCOUNT_INT_EN 0x040
176#define XSCALE1_COUNT0_INT_EN 0x010
177#define XSCALE1_COUNT1_INT_EN 0x020
178#define XSCALE1_COUNT0_EVT_SHFT 12
179#define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT)
180#define XSCALE1_COUNT1_EVT_SHFT 20
181#define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT)
182
183static inline u32
184xscale1pmu_read_pmnc(void)
185{
186 u32 val;
187 asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
188 return val;
189}
190
191static inline void
192xscale1pmu_write_pmnc(u32 val)
193{
194 /* upper 4bits and 7, 11 are write-as-0 */
195 val &= 0xffff77f;
196 asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
197}
198
199static inline int
200xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
201 enum xscale_counters counter)
202{
203 int ret = 0;
204
205 switch (counter) {
206 case XSCALE_CYCLE_COUNTER:
207 ret = pmnc & XSCALE1_CCOUNT_OVERFLOW;
208 break;
209 case XSCALE_COUNTER0:
210 ret = pmnc & XSCALE1_COUNT0_OVERFLOW;
211 break;
212 case XSCALE_COUNTER1:
213 ret = pmnc & XSCALE1_COUNT1_OVERFLOW;
214 break;
215 default:
216 WARN_ONCE(1, "invalid counter number (%d)\n", counter);
217 }
218
219 return ret;
220}
221
222static irqreturn_t
223xscale1pmu_handle_irq(int irq_num, void *dev)
224{
225 unsigned long pmnc;
226 struct perf_sample_data data;
8be3f9a2 227 struct pmu_hw_events *cpuc;
43eab878
WD
228 struct pt_regs *regs;
229 int idx;
230
231 /*
232 * NOTE: there's an A stepping erratum that states if an overflow
233 * bit already exists and another occurs, the previous
234 * Overflow bit gets cleared. There's no workaround.
235 * Fixed in B stepping or later.
236 */
237 pmnc = xscale1pmu_read_pmnc();
238
239 /*
240 * Write the value back to clear the overflow flags. Overflow
241 * flags remain in pmnc for use below. We also disable the PMU
242 * while we process the interrupt.
243 */
244 xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
245
246 if (!(pmnc & XSCALE1_OVERFLOWED_MASK))
247 return IRQ_NONE;
248
249 regs = get_irq_regs();
250
251 perf_sample_data_init(&data, 0);
252
253 cpuc = &__get_cpu_var(cpu_hw_events);
8be3f9a2 254 for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
43eab878
WD
255 struct perf_event *event = cpuc->events[idx];
256 struct hw_perf_event *hwc;
257
43eab878
WD
258 if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
259 continue;
260
261 hwc = &event->hw;
57273471 262 armpmu_event_update(event, hwc, idx);
43eab878
WD
263 data.period = event->hw.last_period;
264 if (!armpmu_event_set_period(event, hwc, idx))
265 continue;
266
a8b0ca17 267 if (perf_event_overflow(event, &data, regs))
8be3f9a2 268 cpu_pmu->disable(hwc, idx);
43eab878
WD
269 }
270
271 irq_work_run();
272
273 /*
274 * Re-enable the PMU.
275 */
276 pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE;
277 xscale1pmu_write_pmnc(pmnc);
278
279 return IRQ_HANDLED;
280}
281
282static void
283xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
284{
285 unsigned long val, mask, evt, flags;
8be3f9a2 286 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878
WD
287
288 switch (idx) {
289 case XSCALE_CYCLE_COUNTER:
290 mask = 0;
291 evt = XSCALE1_CCOUNT_INT_EN;
292 break;
293 case XSCALE_COUNTER0:
294 mask = XSCALE1_COUNT0_EVT_MASK;
295 evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) |
296 XSCALE1_COUNT0_INT_EN;
297 break;
298 case XSCALE_COUNTER1:
299 mask = XSCALE1_COUNT1_EVT_MASK;
300 evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) |
301 XSCALE1_COUNT1_INT_EN;
302 break;
303 default:
304 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
305 return;
306 }
307
0f78d2d5 308 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
309 val = xscale1pmu_read_pmnc();
310 val &= ~mask;
311 val |= evt;
312 xscale1pmu_write_pmnc(val);
0f78d2d5 313 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
314}
315
316static void
317xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
318{
319 unsigned long val, mask, evt, flags;
8be3f9a2 320 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878
WD
321
322 switch (idx) {
323 case XSCALE_CYCLE_COUNTER:
324 mask = XSCALE1_CCOUNT_INT_EN;
325 evt = 0;
326 break;
327 case XSCALE_COUNTER0:
328 mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK;
329 evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT;
330 break;
331 case XSCALE_COUNTER1:
332 mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK;
333 evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT;
334 break;
335 default:
336 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
337 return;
338 }
339
0f78d2d5 340 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
341 val = xscale1pmu_read_pmnc();
342 val &= ~mask;
343 val |= evt;
344 xscale1pmu_write_pmnc(val);
0f78d2d5 345 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
346}
347
348static int
8be3f9a2 349xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
43eab878
WD
350 struct hw_perf_event *event)
351{
352 if (XSCALE_PERFCTR_CCNT == event->config_base) {
353 if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))
354 return -EAGAIN;
355
356 return XSCALE_CYCLE_COUNTER;
357 } else {
358 if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask))
359 return XSCALE_COUNTER1;
360
361 if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask))
362 return XSCALE_COUNTER0;
363
364 return -EAGAIN;
365 }
366}
367
368static void
369xscale1pmu_start(void)
370{
371 unsigned long flags, val;
8be3f9a2 372 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878 373
0f78d2d5 374 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
375 val = xscale1pmu_read_pmnc();
376 val |= XSCALE_PMU_ENABLE;
377 xscale1pmu_write_pmnc(val);
0f78d2d5 378 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
379}
380
381static void
382xscale1pmu_stop(void)
383{
384 unsigned long flags, val;
8be3f9a2 385 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878 386
0f78d2d5 387 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
388 val = xscale1pmu_read_pmnc();
389 val &= ~XSCALE_PMU_ENABLE;
390 xscale1pmu_write_pmnc(val);
0f78d2d5 391 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
392}
393
394static inline u32
395xscale1pmu_read_counter(int counter)
396{
397 u32 val = 0;
398
399 switch (counter) {
400 case XSCALE_CYCLE_COUNTER:
401 asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
402 break;
403 case XSCALE_COUNTER0:
404 asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
405 break;
406 case XSCALE_COUNTER1:
407 asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
408 break;
409 }
410
411 return val;
412}
413
414static inline void
415xscale1pmu_write_counter(int counter, u32 val)
416{
417 switch (counter) {
418 case XSCALE_CYCLE_COUNTER:
419 asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
420 break;
421 case XSCALE_COUNTER0:
422 asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
423 break;
424 case XSCALE_COUNTER1:
425 asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
426 break;
427 }
428}
429
e1f431b5
MR
430static int xscale_map_event(struct perf_event *event)
431{
432 return map_cpu_event(event, &xscale_perf_map,
433 &xscale_perf_cache_map, 0xFF);
434}
435
a6c93afe 436static struct arm_pmu xscale1pmu = {
43eab878
WD
437 .id = ARM_PERF_PMU_ID_XSCALE1,
438 .name = "xscale1",
439 .handle_irq = xscale1pmu_handle_irq,
440 .enable = xscale1pmu_enable_event,
441 .disable = xscale1pmu_disable_event,
442 .read_counter = xscale1pmu_read_counter,
443 .write_counter = xscale1pmu_write_counter,
444 .get_event_idx = xscale1pmu_get_event_idx,
445 .start = xscale1pmu_start,
446 .stop = xscale1pmu_stop,
e1f431b5 447 .map_event = xscale_map_event,
43eab878
WD
448 .num_events = 3,
449 .max_period = (1LLU << 32) - 1,
450};
451
a6c93afe 452static struct arm_pmu *__init xscale1pmu_init(void)
43eab878
WD
453{
454 return &xscale1pmu;
455}
456
457#define XSCALE2_OVERFLOWED_MASK 0x01f
458#define XSCALE2_CCOUNT_OVERFLOW 0x001
459#define XSCALE2_COUNT0_OVERFLOW 0x002
460#define XSCALE2_COUNT1_OVERFLOW 0x004
461#define XSCALE2_COUNT2_OVERFLOW 0x008
462#define XSCALE2_COUNT3_OVERFLOW 0x010
463#define XSCALE2_CCOUNT_INT_EN 0x001
464#define XSCALE2_COUNT0_INT_EN 0x002
465#define XSCALE2_COUNT1_INT_EN 0x004
466#define XSCALE2_COUNT2_INT_EN 0x008
467#define XSCALE2_COUNT3_INT_EN 0x010
468#define XSCALE2_COUNT0_EVT_SHFT 0
469#define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT)
470#define XSCALE2_COUNT1_EVT_SHFT 8
471#define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT)
472#define XSCALE2_COUNT2_EVT_SHFT 16
473#define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT)
474#define XSCALE2_COUNT3_EVT_SHFT 24
475#define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT)
476
477static inline u32
478xscale2pmu_read_pmnc(void)
479{
480 u32 val;
481 asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
482 /* bits 1-2 and 4-23 are read-unpredictable */
483 return val & 0xff000009;
484}
485
486static inline void
487xscale2pmu_write_pmnc(u32 val)
488{
489 /* bits 4-23 are write-as-0, 24-31 are write ignored */
490 val &= 0xf;
491 asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
492}
493
494static inline u32
495xscale2pmu_read_overflow_flags(void)
496{
497 u32 val;
498 asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val));
499 return val;
500}
501
502static inline void
503xscale2pmu_write_overflow_flags(u32 val)
504{
505 asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val));
506}
507
508static inline u32
509xscale2pmu_read_event_select(void)
510{
511 u32 val;
512 asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val));
513 return val;
514}
515
516static inline void
517xscale2pmu_write_event_select(u32 val)
518{
519 asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));
520}
521
522static inline u32
523xscale2pmu_read_int_enable(void)
524{
525 u32 val;
526 asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val));
527 return val;
528}
529
530static void
531xscale2pmu_write_int_enable(u32 val)
532{
533 asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val));
534}
535
536static inline int
537xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
538 enum xscale_counters counter)
539{
540 int ret = 0;
541
542 switch (counter) {
543 case XSCALE_CYCLE_COUNTER:
544 ret = of_flags & XSCALE2_CCOUNT_OVERFLOW;
545 break;
546 case XSCALE_COUNTER0:
547 ret = of_flags & XSCALE2_COUNT0_OVERFLOW;
548 break;
549 case XSCALE_COUNTER1:
550 ret = of_flags & XSCALE2_COUNT1_OVERFLOW;
551 break;
552 case XSCALE_COUNTER2:
553 ret = of_flags & XSCALE2_COUNT2_OVERFLOW;
554 break;
555 case XSCALE_COUNTER3:
556 ret = of_flags & XSCALE2_COUNT3_OVERFLOW;
557 break;
558 default:
559 WARN_ONCE(1, "invalid counter number (%d)\n", counter);
560 }
561
562 return ret;
563}
564
565static irqreturn_t
566xscale2pmu_handle_irq(int irq_num, void *dev)
567{
568 unsigned long pmnc, of_flags;
569 struct perf_sample_data data;
8be3f9a2 570 struct pmu_hw_events *cpuc;
43eab878
WD
571 struct pt_regs *regs;
572 int idx;
573
574 /* Disable the PMU. */
575 pmnc = xscale2pmu_read_pmnc();
576 xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
577
578 /* Check the overflow flag register. */
579 of_flags = xscale2pmu_read_overflow_flags();
580 if (!(of_flags & XSCALE2_OVERFLOWED_MASK))
581 return IRQ_NONE;
582
583 /* Clear the overflow bits. */
584 xscale2pmu_write_overflow_flags(of_flags);
585
586 regs = get_irq_regs();
587
588 perf_sample_data_init(&data, 0);
589
590 cpuc = &__get_cpu_var(cpu_hw_events);
8be3f9a2 591 for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
43eab878
WD
592 struct perf_event *event = cpuc->events[idx];
593 struct hw_perf_event *hwc;
594
43eab878
WD
595 if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
596 continue;
597
598 hwc = &event->hw;
57273471 599 armpmu_event_update(event, hwc, idx);
43eab878
WD
600 data.period = event->hw.last_period;
601 if (!armpmu_event_set_period(event, hwc, idx))
602 continue;
603
a8b0ca17 604 if (perf_event_overflow(event, &data, regs))
8be3f9a2 605 cpu_pmu->disable(hwc, idx);
43eab878
WD
606 }
607
608 irq_work_run();
609
610 /*
611 * Re-enable the PMU.
612 */
613 pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE;
614 xscale2pmu_write_pmnc(pmnc);
615
616 return IRQ_HANDLED;
617}
618
619static void
620xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
621{
622 unsigned long flags, ien, evtsel;
8be3f9a2 623 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878
WD
624
625 ien = xscale2pmu_read_int_enable();
626 evtsel = xscale2pmu_read_event_select();
627
628 switch (idx) {
629 case XSCALE_CYCLE_COUNTER:
630 ien |= XSCALE2_CCOUNT_INT_EN;
631 break;
632 case XSCALE_COUNTER0:
633 ien |= XSCALE2_COUNT0_INT_EN;
634 evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
635 evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT;
636 break;
637 case XSCALE_COUNTER1:
638 ien |= XSCALE2_COUNT1_INT_EN;
639 evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
640 evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT;
641 break;
642 case XSCALE_COUNTER2:
643 ien |= XSCALE2_COUNT2_INT_EN;
644 evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
645 evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT;
646 break;
647 case XSCALE_COUNTER3:
648 ien |= XSCALE2_COUNT3_INT_EN;
649 evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
650 evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT;
651 break;
652 default:
653 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
654 return;
655 }
656
0f78d2d5 657 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
658 xscale2pmu_write_event_select(evtsel);
659 xscale2pmu_write_int_enable(ien);
0f78d2d5 660 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
661}
662
663static void
664xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
665{
666 unsigned long flags, ien, evtsel;
8be3f9a2 667 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878
WD
668
669 ien = xscale2pmu_read_int_enable();
670 evtsel = xscale2pmu_read_event_select();
671
672 switch (idx) {
673 case XSCALE_CYCLE_COUNTER:
674 ien &= ~XSCALE2_CCOUNT_INT_EN;
675 break;
676 case XSCALE_COUNTER0:
677 ien &= ~XSCALE2_COUNT0_INT_EN;
678 evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
679 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
680 break;
681 case XSCALE_COUNTER1:
682 ien &= ~XSCALE2_COUNT1_INT_EN;
683 evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
684 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
685 break;
686 case XSCALE_COUNTER2:
687 ien &= ~XSCALE2_COUNT2_INT_EN;
688 evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
689 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
690 break;
691 case XSCALE_COUNTER3:
692 ien &= ~XSCALE2_COUNT3_INT_EN;
693 evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
694 evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
695 break;
696 default:
697 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
698 return;
699 }
700
0f78d2d5 701 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
702 xscale2pmu_write_event_select(evtsel);
703 xscale2pmu_write_int_enable(ien);
0f78d2d5 704 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
705}
706
707static int
8be3f9a2 708xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc,
43eab878
WD
709 struct hw_perf_event *event)
710{
711 int idx = xscale1pmu_get_event_idx(cpuc, event);
712 if (idx >= 0)
713 goto out;
714
715 if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask))
716 idx = XSCALE_COUNTER3;
717 else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask))
718 idx = XSCALE_COUNTER2;
719out:
720 return idx;
721}
722
723static void
724xscale2pmu_start(void)
725{
726 unsigned long flags, val;
8be3f9a2 727 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878 728
0f78d2d5 729 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
730 val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
731 val |= XSCALE_PMU_ENABLE;
732 xscale2pmu_write_pmnc(val);
0f78d2d5 733 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
734}
735
736static void
737xscale2pmu_stop(void)
738{
739 unsigned long flags, val;
8be3f9a2 740 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
43eab878 741
0f78d2d5 742 raw_spin_lock_irqsave(&events->pmu_lock, flags);
43eab878
WD
743 val = xscale2pmu_read_pmnc();
744 val &= ~XSCALE_PMU_ENABLE;
745 xscale2pmu_write_pmnc(val);
0f78d2d5 746 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
43eab878
WD
747}
748
749static inline u32
750xscale2pmu_read_counter(int counter)
751{
752 u32 val = 0;
753
754 switch (counter) {
755 case XSCALE_CYCLE_COUNTER:
756 asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
757 break;
758 case XSCALE_COUNTER0:
759 asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
760 break;
761 case XSCALE_COUNTER1:
762 asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
763 break;
764 case XSCALE_COUNTER2:
765 asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
766 break;
767 case XSCALE_COUNTER3:
768 asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
769 break;
770 }
771
772 return val;
773}
774
775static inline void
776xscale2pmu_write_counter(int counter, u32 val)
777{
778 switch (counter) {
779 case XSCALE_CYCLE_COUNTER:
780 asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
781 break;
782 case XSCALE_COUNTER0:
783 asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
784 break;
785 case XSCALE_COUNTER1:
786 asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
787 break;
788 case XSCALE_COUNTER2:
789 asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
790 break;
791 case XSCALE_COUNTER3:
792 asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
793 break;
794 }
795}
796
a6c93afe 797static struct arm_pmu xscale2pmu = {
43eab878
WD
798 .id = ARM_PERF_PMU_ID_XSCALE2,
799 .name = "xscale2",
800 .handle_irq = xscale2pmu_handle_irq,
801 .enable = xscale2pmu_enable_event,
802 .disable = xscale2pmu_disable_event,
803 .read_counter = xscale2pmu_read_counter,
804 .write_counter = xscale2pmu_write_counter,
805 .get_event_idx = xscale2pmu_get_event_idx,
806 .start = xscale2pmu_start,
807 .stop = xscale2pmu_stop,
e1f431b5 808 .map_event = xscale_map_event,
43eab878
WD
809 .num_events = 5,
810 .max_period = (1LLU << 32) - 1,
811};
812
a6c93afe 813static struct arm_pmu *__init xscale2pmu_init(void)
43eab878
WD
814{
815 return &xscale2pmu;
816}
817#else
a6c93afe 818static struct arm_pmu *__init xscale1pmu_init(void)
43eab878
WD
819{
820 return NULL;
821}
822
a6c93afe 823static struct arm_pmu *__init xscale2pmu_init(void)
43eab878
WD
824{
825 return NULL;
826}
827#endif /* CONFIG_CPU_XSCALE */