1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17
18
19
20#define PM_PMC_SH 20
21#define PM_PMC_MSK 0xf
22#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
23#define PM_UNIT_SH 16
24#define PM_UNIT_MSK 0xf
25#define PM_BYTE_SH 12
26#define PM_BYTE_MSK 7
27#define PM_GRS_SH 8
28#define PM_GRS_MSK 7
29#define PM_BUSEVENT_MSK 0x80
30#define PM_PMCSEL_MSK 0x7f
31
32
33#define PM_FPU 0
34#define PM_ISU0 1
35#define PM_IFU 2
36#define PM_ISU1 3
37#define PM_IDU 4
38#define PM_ISU0_ALT 6
39#define PM_GRS 7
40#define PM_LSU0 8
41#define PM_LSU1 0xc
42#define PM_LASTUNIT 0xc
43
44
45
46
47#define MMCR1_TTM0SEL_SH 62
48#define MMCR1_TTM1SEL_SH 60
49#define MMCR1_TTM2SEL_SH 58
50#define MMCR1_TTM3SEL_SH 56
51#define MMCR1_TTMSEL_MSK 3
52#define MMCR1_TD_CP_DBG0SEL_SH 54
53#define MMCR1_TD_CP_DBG1SEL_SH 52
54#define MMCR1_TD_CP_DBG2SEL_SH 50
55#define MMCR1_TD_CP_DBG3SEL_SH 48
56#define MMCR1_GRS_L2SEL_SH 46
57#define MMCR1_GRS_L2SEL_MSK 3
58#define MMCR1_GRS_L3SEL_SH 44
59#define MMCR1_GRS_L3SEL_MSK 3
60#define MMCR1_GRS_MCSEL_SH 41
61#define MMCR1_GRS_MCSEL_MSK 7
62#define MMCR1_GRS_FABSEL_SH 39
63#define MMCR1_GRS_FABSEL_MSK 3
64#define MMCR1_PMC1_ADDER_SEL_SH 35
65#define MMCR1_PMC2_ADDER_SEL_SH 34
66#define MMCR1_PMC3_ADDER_SEL_SH 33
67#define MMCR1_PMC4_ADDER_SEL_SH 32
68#define MMCR1_PMC1SEL_SH 25
69#define MMCR1_PMC2SEL_SH 17
70#define MMCR1_PMC3SEL_SH 9
71#define MMCR1_PMC4SEL_SH 1
72#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
73#define MMCR1_PMCSEL_MSK 0x7f
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128static const int grsel_shift[8] = {
129 MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
130 MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
131 MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
132};
133
134
135static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
136 [PM_FPU] = { 0xc0002000000000ul, 0x00001000000000ul },
137 [PM_ISU0] = { 0x00002000000000ul, 0x00000800000000ul },
138 [PM_ISU1] = { 0xc0002000000000ul, 0xc0001000000000ul },
139 [PM_IFU] = { 0xc0002000000000ul, 0x80001000000000ul },
140 [PM_IDU] = { 0x30002000000000ul, 0x00000400000000ul },
141 [PM_GRS] = { 0x30002000000000ul, 0x30000400000000ul },
142};
143
144static int power5_get_constraint(u64 event, unsigned long *maskp,
145 unsigned long *valp)
146{
147 int pmc, byte, unit, sh;
148 int bit, fmask;
149 unsigned long mask = 0, value = 0;
150 int grp = -1;
151
152 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
153 if (pmc) {
154 if (pmc > 6)
155 return -1;
156 sh = (pmc - 1) * 2;
157 mask |= 2 << sh;
158 value |= 1 << sh;
159 if (pmc <= 4)
160 grp = (pmc - 1) >> 1;
161 else if (event != 0x500009 && event != 0x600005)
162 return -1;
163 }
164 if (event & PM_BUSEVENT_MSK) {
165 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
166 if (unit > PM_LASTUNIT)
167 return -1;
168 if (unit == PM_ISU0_ALT)
169 unit = PM_ISU0;
170 mask |= unit_cons[unit][0];
171 value |= unit_cons[unit][1];
172 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
173 if (byte >= 4) {
174 if (unit != PM_LSU1)
175 return -1;
176
177 ++unit;
178 byte &= 3;
179 }
180 if (unit == PM_GRS) {
181 bit = event & 7;
182 fmask = (bit == 6)? 7: 3;
183 sh = grsel_shift[bit];
184 mask |= (unsigned long)fmask << sh;
185 value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
186 << sh;
187 }
188
189
190
191
192 if (!pmc)
193 grp = byte & 1;
194
195 mask |= 0xfUL << (24 - 4 * byte);
196 value |= (unsigned long)unit << (24 - 4 * byte);
197 }
198 if (grp == 0) {
199
200 mask |= 0x200000000ul;
201 value |= 0x080000000ul;
202 } else if (grp == 1) {
203
204 mask |= 0x40000000ul;
205 value |= 0x10000000ul;
206 }
207 if (pmc < 5) {
208
209 mask |= 0x8000000000000ul;
210 value |= 0x1000000000000ul;
211 }
212 *maskp = mask;
213 *valp = value;
214 return 0;
215}
216
217#define MAX_ALT 3
218
219static const unsigned int event_alternatives[][MAX_ALT] = {
220 { 0x120e4, 0x400002 },
221 { 0x410c7, 0x441084 },
222 { 0x100005, 0x600005 },
223 { 0x100009, 0x200009, 0x500009 },
224 { 0x300009, 0x400009 },
225};
226
227
228
229
230
231static int find_alternative(u64 event)
232{
233 int i, j;
234
235 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
236 if (event < event_alternatives[i][0])
237 break;
238 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
239 if (event == event_alternatives[i][j])
240 return i;
241 }
242 return -1;
243}
244
245static const unsigned char bytedecode_alternatives[4][4] = {
246 { 0x21, 0x23, 0x25, 0x27 },
247 { 0x07, 0x17, 0x0e, 0x1e },
248 { 0x20, 0x22, 0x24, 0x26 },
249 { 0x07, 0x17, 0x0e, 0x1e }
250};
251
252
253
254
255
256
257static s64 find_alternative_bdecode(u64 event)
258{
259 int pmc, altpmc, pp, j;
260
261 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
262 if (pmc == 0 || pmc > 4)
263 return -1;
264 altpmc = 5 - pmc;
265 pp = event & PM_PMCSEL_MSK;
266 for (j = 0; j < 4; ++j) {
267 if (bytedecode_alternatives[pmc - 1][j] == pp) {
268 return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
269 (altpmc << PM_PMC_SH) |
270 bytedecode_alternatives[altpmc - 1][j];
271 }
272 }
273 return -1;
274}
275
276static int power5_get_alternatives(u64 event, unsigned int flags, u64 alt[])
277{
278 int i, j, nalt = 1;
279 s64 ae;
280
281 alt[0] = event;
282 nalt = 1;
283 i = find_alternative(event);
284 if (i >= 0) {
285 for (j = 0; j < MAX_ALT; ++j) {
286 ae = event_alternatives[i][j];
287 if (ae && ae != event)
288 alt[nalt++] = ae;
289 }
290 } else {
291 ae = find_alternative_bdecode(event);
292 if (ae > 0)
293 alt[nalt++] = ae;
294 }
295 return nalt;
296}
297
298
299
300
301
302
303
304static unsigned char direct_event_is_marked[0x28] = {
305 0,
306 0x1f,
307 0x2,
308 0xe,
309 0,
310 0x1c,
311 0x80,
312 0x80,
313 0, 0, 0,
314 0x18,
315 0,
316 0x80,
317 0x80,
318 0,
319 0,
320 0x14,
321 0,
322 0x10,
323 0x1f,
324 0x2,
325 0x80,
326 0x80,
327 0, 0, 0, 0, 0,
328 0x80,
329 0x80,
330 0,
331 0x80,
332 0x80,
333 0x80,
334 0x80,
335 0x80,
336 0x80,
337 0x80,
338 0x80,
339};
340
341
342
343
344
345static int power5_marked_instr_event(u64 event)
346{
347 int pmc, psel;
348 int bit, byte, unit;
349 u32 mask;
350
351 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
352 psel = event & PM_PMCSEL_MSK;
353 if (pmc >= 5)
354 return 0;
355
356 bit = -1;
357 if (psel < sizeof(direct_event_is_marked)) {
358 if (direct_event_is_marked[psel] & (1 << pmc))
359 return 1;
360 if (direct_event_is_marked[psel] & 0x80)
361 bit = 4;
362 else if (psel == 0x08)
363 bit = pmc - 1;
364 else if (psel == 0x10)
365 bit = 4 - pmc;
366 else if (psel == 0x1b && (pmc == 1 || pmc == 3))
367 bit = 4;
368 } else if ((psel & 0x58) == 0x40)
369 bit = psel & 7;
370
371 if (!(event & PM_BUSEVENT_MSK))
372 return 0;
373
374 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
375 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
376 if (unit == PM_LSU0) {
377
378 mask = 0x5dff00;
379 } else if (unit == PM_LSU1 && byte >= 4) {
380 byte -= 4;
381
382 mask = 0x5f00c0aa;
383 } else
384 return 0;
385
386 return (mask >> (byte * 8 + bit)) & 1;
387}
388
389static int power5_compute_mmcr(u64 event[], int n_ev,
390 unsigned int hwc[], unsigned long mmcr[])
391{
392 unsigned long mmcr1 = 0;
393 unsigned long mmcra = 0;
394 unsigned int pmc, unit, byte, psel;
395 unsigned int ttm, grp;
396 int i, isbus, bit, grsel;
397 unsigned int pmc_inuse = 0;
398 unsigned int pmc_grp_use[2];
399 unsigned char busbyte[4];
400 unsigned char unituse[16];
401 int ttmuse;
402
403 if (n_ev > 6)
404 return -1;
405
406
407 pmc_grp_use[0] = pmc_grp_use[1] = 0;
408 memset(busbyte, 0, sizeof(busbyte));
409 memset(unituse, 0, sizeof(unituse));
410 for (i = 0; i < n_ev; ++i) {
411 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
412 if (pmc) {
413 if (pmc > 6)
414 return -1;
415 if (pmc_inuse & (1 << (pmc - 1)))
416 return -1;
417 pmc_inuse |= 1 << (pmc - 1);
418
419 if (pmc <= 4)
420 ++pmc_grp_use[(pmc - 1) >> 1];
421 }
422 if (event[i] & PM_BUSEVENT_MSK) {
423 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
424 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
425 if (unit > PM_LASTUNIT)
426 return -1;
427 if (unit == PM_ISU0_ALT)
428 unit = PM_ISU0;
429 if (byte >= 4) {
430 if (unit != PM_LSU1)
431 return -1;
432 ++unit;
433 byte &= 3;
434 }
435 if (!pmc)
436 ++pmc_grp_use[byte & 1];
437 if (busbyte[byte] && busbyte[byte] != unit)
438 return -1;
439 busbyte[byte] = unit;
440 unituse[unit] = 1;
441 }
442 }
443 if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2)
444 return -1;
445
446
447
448
449
450
451
452 if (unituse[PM_ISU0] &
453 (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
454 unituse[PM_ISU0_ALT] = 1;
455 unituse[PM_ISU0] = 0;
456 }
457
458 ttmuse = 0;
459 for (i = PM_FPU; i <= PM_ISU1; ++i) {
460 if (!unituse[i])
461 continue;
462 if (ttmuse++)
463 return -1;
464 mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
465 }
466 ttmuse = 0;
467 for (; i <= PM_GRS; ++i) {
468 if (!unituse[i])
469 continue;
470 if (ttmuse++)
471 return -1;
472 mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
473 }
474 if (ttmuse > 1)
475 return -1;
476
477
478 for (byte = 0; byte < 4; ++byte) {
479 unit = busbyte[byte];
480 if (!unit)
481 continue;
482 if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
483
484 unit = PM_ISU0_ALT;
485 } else if (unit == PM_LSU1 + 1) {
486
487 mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
488 }
489 ttm = unit >> 2;
490 mmcr1 |= (unsigned long)ttm
491 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
492 }
493
494
495 for (i = 0; i < n_ev; ++i) {
496 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
497 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
498 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
499 psel = event[i] & PM_PMCSEL_MSK;
500 isbus = event[i] & PM_BUSEVENT_MSK;
501 if (!pmc) {
502
503 for (pmc = 0; pmc < 4; ++pmc) {
504 if (pmc_inuse & (1 << pmc))
505 continue;
506 grp = (pmc >> 1) & 1;
507 if (isbus) {
508 if (grp == (byte & 1))
509 break;
510 } else if (pmc_grp_use[grp] < 2) {
511 ++pmc_grp_use[grp];
512 break;
513 }
514 }
515 pmc_inuse |= 1 << pmc;
516 } else if (pmc <= 4) {
517
518 --pmc;
519 if ((psel == 8 || psel == 0x10) && isbus && (byte & 2))
520
521 mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
522 } else {
523
524 --pmc;
525 }
526 if (isbus && unit == PM_GRS) {
527 bit = psel & 7;
528 grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
529 mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
530 }
531 if (power5_marked_instr_event(event[i]))
532 mmcra |= MMCRA_SAMPLE_ENABLE;
533 if (pmc <= 3)
534 mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
535 hwc[i] = pmc;
536 }
537
538
539 mmcr[0] = 0;
540 if (pmc_inuse & 1)
541 mmcr[0] = MMCR0_PMC1CE;
542 if (pmc_inuse & 0x3e)
543 mmcr[0] |= MMCR0_PMCjCE;
544 mmcr[1] = mmcr1;
545 mmcr[2] = mmcra;
546 return 0;
547}
548
549static void power5_disable_pmc(unsigned int pmc, unsigned long mmcr[])
550{
551 if (pmc <= 3)
552 mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
553}
554
555static int power5_generic_events[] = {
556 [PERF_COUNT_HW_CPU_CYCLES] = 0xf,
557 [PERF_COUNT_HW_INSTRUCTIONS] = 0x100009,
558 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x4c1090,
559 [PERF_COUNT_HW_CACHE_MISSES] = 0x3c1088,
560 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x230e4,
561 [PERF_COUNT_HW_BRANCH_MISSES] = 0x230e5,
562};
563
564#define C(x) PERF_COUNT_HW_CACHE_##x
565
566
567
568
569
570
571static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
572 [C(L1D)] = {
573 [C(OP_READ)] = { 0x4c1090, 0x3c1088 },
574 [C(OP_WRITE)] = { 0x3c1090, 0xc10c3 },
575 [C(OP_PREFETCH)] = { 0xc70e7, 0 },
576 },
577 [C(L1I)] = {
578 [C(OP_READ)] = { 0, 0 },
579 [C(OP_WRITE)] = { -1, -1 },
580 [C(OP_PREFETCH)] = { 0, 0 },
581 },
582 [C(LL)] = {
583 [C(OP_READ)] = { 0, 0x3c309b },
584 [C(OP_WRITE)] = { 0, 0 },
585 [C(OP_PREFETCH)] = { 0xc50c3, 0 },
586 },
587 [C(DTLB)] = {
588 [C(OP_READ)] = { 0x2c4090, 0x800c4 },
589 [C(OP_WRITE)] = { -1, -1 },
590 [C(OP_PREFETCH)] = { -1, -1 },
591 },
592 [C(ITLB)] = {
593 [C(OP_READ)] = { 0, 0x800c0 },
594 [C(OP_WRITE)] = { -1, -1 },
595 [C(OP_PREFETCH)] = { -1, -1 },
596 },
597 [C(BPU)] = {
598 [C(OP_READ)] = { 0x230e4, 0x230e5 },
599 [C(OP_WRITE)] = { -1, -1 },
600 [C(OP_PREFETCH)] = { -1, -1 },
601 },
602};
603
604static struct power_pmu power5_pmu = {
605 .name = "POWER5",
606 .n_counter = 6,
607 .max_alternatives = MAX_ALT,
608 .add_fields = 0x7000090000555ul,
609 .test_adder = 0x3000490000000ul,
610 .compute_mmcr = power5_compute_mmcr,
611 .get_constraint = power5_get_constraint,
612 .get_alternatives = power5_get_alternatives,
613 .disable_pmc = power5_disable_pmc,
614 .n_generic = ARRAY_SIZE(power5_generic_events),
615 .generic_events = power5_generic_events,
616 .cache_events = &power5_cache_events,
617};
618
619static int init_power5_pmu(void)
620{
621 if (!cur_cpu_spec->oprofile_cpu_type ||
622 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
623 return -ENODEV;
624
625 return register_power_pmu(&power5_pmu);
626}
627
628arch_initcall(init_power5_pmu);
629