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