1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/kernel.h>
14#include <linux/perf_event.h>
15#include <asm/firmware.h>
16
17
18
19
20
21#define PM_CYC 0x0001e
22#define PM_GCT_NOSLOT_CYC 0x100f8
23#define PM_CMPLU_STALL 0x4000a
24#define PM_INST_CMPL 0x00002
25#define PM_BRU_FIN 0x10068
26#define PM_BR_MPRED_CMPL 0x400f6
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88#define EVENT_THR_CMP_SHIFT 40
89#define EVENT_THR_CMP_MASK 0x3ff
90#define EVENT_THR_CTL_SHIFT 32
91#define EVENT_THR_CTL_MASK 0xffull
92#define EVENT_THR_SEL_SHIFT 29
93#define EVENT_THR_SEL_MASK 0x7
94#define EVENT_THRESH_SHIFT 29
95#define EVENT_THRESH_MASK 0x1fffffull
96#define EVENT_SAMPLE_SHIFT 24
97#define EVENT_SAMPLE_MASK 0x1f
98#define EVENT_CACHE_SEL_SHIFT 20
99#define EVENT_CACHE_SEL_MASK 0xf
100#define EVENT_IS_L1 (4 << EVENT_CACHE_SEL_SHIFT)
101#define EVENT_PMC_SHIFT 16
102#define EVENT_PMC_MASK 0xf
103#define EVENT_UNIT_SHIFT 12
104#define EVENT_UNIT_MASK 0xf
105#define EVENT_COMBINE_SHIFT 11
106#define EVENT_COMBINE_MASK 0x1
107#define EVENT_MARKED_SHIFT 8
108#define EVENT_MARKED_MASK 0x1
109#define EVENT_IS_MARKED (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
110#define EVENT_PSEL_MASK 0xff
111
112
113#define POWER8_MMCRA_IFM1 0x0000000040000000UL
114#define POWER8_MMCRA_IFM2 0x0000000080000000UL
115#define POWER8_MMCRA_IFM3 0x00000000C0000000UL
116
117#define ONLY_PLM \
118 (PERF_SAMPLE_BRANCH_USER |\
119 PERF_SAMPLE_BRANCH_KERNEL |\
120 PERF_SAMPLE_BRANCH_HV)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145#define CNST_FAB_MATCH_VAL(v) (((v) & EVENT_THR_CTL_MASK) << 56)
146#define CNST_FAB_MATCH_MASK CNST_FAB_MATCH_VAL(EVENT_THR_CTL_MASK)
147
148
149#define CNST_THRESH_VAL(v) (((v) & EVENT_THRESH_MASK) << 32)
150#define CNST_THRESH_MASK CNST_THRESH_VAL(EVENT_THRESH_MASK)
151
152#define CNST_L1_QUAL_VAL(v) (((v) & 3) << 22)
153#define CNST_L1_QUAL_MASK CNST_L1_QUAL_VAL(3)
154
155#define CNST_SAMPLE_VAL(v) (((v) & EVENT_SAMPLE_MASK) << 16)
156#define CNST_SAMPLE_MASK CNST_SAMPLE_VAL(EVENT_SAMPLE_MASK)
157
158
159
160
161
162
163#define CNST_NC_SHIFT 12
164#define CNST_NC_VAL (1 << CNST_NC_SHIFT)
165#define CNST_NC_MASK (8 << CNST_NC_SHIFT)
166#define POWER8_TEST_ADDER (3 << CNST_NC_SHIFT)
167
168
169
170
171
172
173#define CNST_PMC_SHIFT(pmc) ((pmc - 1) * 2)
174#define CNST_PMC_VAL(pmc) (1 << CNST_PMC_SHIFT(pmc))
175#define CNST_PMC_MASK(pmc) (2 << CNST_PMC_SHIFT(pmc))
176
177
178#define POWER8_ADD_FIELDS \
179 CNST_PMC_VAL(1) | CNST_PMC_VAL(2) | CNST_PMC_VAL(3) | \
180 CNST_PMC_VAL(4) | CNST_PMC_VAL(5) | CNST_PMC_VAL(6) | CNST_NC_VAL
181
182
183
184#define MMCR1_UNIT_SHIFT(pmc) (60 - (4 * ((pmc) - 1)))
185#define MMCR1_COMBINE_SHIFT(pmc) (35 - ((pmc) - 1))
186#define MMCR1_PMCSEL_SHIFT(pmc) (24 - (((pmc) - 1)) * 8)
187#define MMCR1_DC_QUAL_SHIFT 47
188#define MMCR1_IC_QUAL_SHIFT 46
189
190
191#define MMCRA_SAMP_MODE_SHIFT 1
192#define MMCRA_SAMP_ELIG_SHIFT 4
193#define MMCRA_THR_CTL_SHIFT 8
194#define MMCRA_THR_SEL_SHIFT 16
195#define MMCRA_THR_CMP_SHIFT 32
196#define MMCRA_SDAR_MODE_TLB (1ull << 42)
197
198
199static inline bool event_is_fab_match(u64 event)
200{
201
202 event &= 0xff0fe;
203
204
205 return (event == 0x30056 || event == 0x4f052);
206}
207
208static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
209{
210 unsigned int unit, pmc, cache;
211 unsigned long mask, value;
212
213 mask = value = 0;
214
215 pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
216 unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
217 cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK;
218
219 if (pmc) {
220 if (pmc > 6)
221 return -1;
222
223 mask |= CNST_PMC_MASK(pmc);
224 value |= CNST_PMC_VAL(pmc);
225
226 if (pmc >= 5 && event != 0x500fa && event != 0x600f4)
227 return -1;
228 }
229
230 if (pmc <= 4) {
231
232
233
234
235
236
237 mask |= CNST_NC_MASK;
238 value |= CNST_NC_VAL;
239 }
240
241 if (unit >= 6 && unit <= 9) {
242
243
244
245
246
247
248
249
250 if (cache)
251 return -1;
252
253 } else if (event & EVENT_IS_L1) {
254 mask |= CNST_L1_QUAL_MASK;
255 value |= CNST_L1_QUAL_VAL(cache);
256 }
257
258 if (event & EVENT_IS_MARKED) {
259 mask |= CNST_SAMPLE_MASK;
260 value |= CNST_SAMPLE_VAL(event >> EVENT_SAMPLE_SHIFT);
261 }
262
263
264
265
266
267 if (event_is_fab_match(event)) {
268 mask |= CNST_FAB_MATCH_MASK;
269 value |= CNST_FAB_MATCH_VAL(event >> EVENT_THR_CTL_SHIFT);
270 } else {
271
272
273
274
275 unsigned int cmp, exp;
276
277 cmp = (event >> EVENT_THR_CMP_SHIFT) & EVENT_THR_CMP_MASK;
278 exp = cmp >> 7;
279
280 if (exp && (cmp & 0x60) == 0)
281 return -1;
282
283 mask |= CNST_THRESH_MASK;
284 value |= CNST_THRESH_VAL(event >> EVENT_THRESH_SHIFT);
285 }
286
287 *maskp = mask;
288 *valp = value;
289
290 return 0;
291}
292
293static int power8_compute_mmcr(u64 event[], int n_ev,
294 unsigned int hwc[], unsigned long mmcr[])
295{
296 unsigned long mmcra, mmcr1, unit, combine, psel, cache, val;
297 unsigned int pmc, pmc_inuse;
298 int i;
299
300 pmc_inuse = 0;
301
302
303 for (i = 0; i < n_ev; ++i) {
304 pmc = (event[i] >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
305 if (pmc)
306 pmc_inuse |= 1 << pmc;
307 }
308
309
310 mmcra = MMCRA_SDAR_MODE_TLB;
311 mmcr1 = 0;
312
313
314 for (i = 0; i < n_ev; ++i) {
315 pmc = (event[i] >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
316 unit = (event[i] >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
317 combine = (event[i] >> EVENT_COMBINE_SHIFT) & EVENT_COMBINE_MASK;
318 psel = event[i] & EVENT_PSEL_MASK;
319
320 if (!pmc) {
321 for (pmc = 1; pmc <= 4; ++pmc) {
322 if (!(pmc_inuse & (1 << pmc)))
323 break;
324 }
325
326 pmc_inuse |= 1 << pmc;
327 }
328
329 if (pmc <= 4) {
330 mmcr1 |= unit << MMCR1_UNIT_SHIFT(pmc);
331 mmcr1 |= combine << MMCR1_COMBINE_SHIFT(pmc);
332 mmcr1 |= psel << MMCR1_PMCSEL_SHIFT(pmc);
333 }
334
335 if (event[i] & EVENT_IS_L1) {
336 cache = event[i] >> EVENT_CACHE_SEL_SHIFT;
337 mmcr1 |= (cache & 1) << MMCR1_IC_QUAL_SHIFT;
338 cache >>= 1;
339 mmcr1 |= (cache & 1) << MMCR1_DC_QUAL_SHIFT;
340 }
341
342 if (event[i] & EVENT_IS_MARKED) {
343 mmcra |= MMCRA_SAMPLE_ENABLE;
344
345 val = (event[i] >> EVENT_SAMPLE_SHIFT) & EVENT_SAMPLE_MASK;
346 if (val) {
347 mmcra |= (val & 3) << MMCRA_SAMP_MODE_SHIFT;
348 mmcra |= (val >> 2) << MMCRA_SAMP_ELIG_SHIFT;
349 }
350 }
351
352
353
354
355
356 if (event_is_fab_match(event[i])) {
357 mmcr1 |= (event[i] >> EVENT_THR_CTL_SHIFT) &
358 EVENT_THR_CTL_MASK;
359 } else {
360 val = (event[i] >> EVENT_THR_CTL_SHIFT) & EVENT_THR_CTL_MASK;
361 mmcra |= val << MMCRA_THR_CTL_SHIFT;
362 val = (event[i] >> EVENT_THR_SEL_SHIFT) & EVENT_THR_SEL_MASK;
363 mmcra |= val << MMCRA_THR_SEL_SHIFT;
364 val = (event[i] >> EVENT_THR_CMP_SHIFT) & EVENT_THR_CMP_MASK;
365 mmcra |= val << MMCRA_THR_CMP_SHIFT;
366 }
367
368 hwc[i] = pmc - 1;
369 }
370
371
372 mmcr[0] = 0;
373
374
375 if (pmc_inuse & 2)
376 mmcr[0] = MMCR0_PMC1CE;
377
378 if (pmc_inuse & 0x7c)
379 mmcr[0] |= MMCR0_PMCjCE;
380
381 mmcr[1] = mmcr1;
382 mmcr[2] = mmcra;
383
384 return 0;
385}
386
387#define MAX_ALT 2
388
389
390static const unsigned int event_alternatives[][MAX_ALT] = {
391 { 0x10134, 0x301e2 },
392 { 0x10138, 0x40138 },
393 { 0x18082, 0x3e05e },
394 { 0x1d14e, 0x401e8 },
395 { 0x1e054, 0x4000a },
396 { 0x20036, 0x40036 },
397 { 0x200f2, 0x300f2 },
398 { 0x200f4, 0x600f4 },
399 { 0x2013c, 0x3012e },
400 { 0x3e054, 0x400f0 },
401 { 0x400fa, 0x500fa },
402};
403
404
405
406
407
408static int find_alternative(u64 event)
409{
410 int i, j;
411
412 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
413 if (event < event_alternatives[i][0])
414 break;
415
416 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
417 if (event == event_alternatives[i][j])
418 return i;
419 }
420
421 return -1;
422}
423
424static int power8_get_alternatives(u64 event, unsigned int flags, u64 alt[])
425{
426 int i, j, num_alt = 0;
427 u64 alt_event;
428
429 alt[num_alt++] = event;
430
431 i = find_alternative(event);
432 if (i >= 0) {
433
434 for (j = 0; j < MAX_ALT; ++j) {
435 alt_event = event_alternatives[i][j];
436 if (alt_event && alt_event != event)
437 alt[num_alt++] = alt_event;
438 }
439 }
440
441 if (flags & PPMU_ONLY_COUNT_RUN) {
442
443
444
445
446 j = num_alt;
447 for (i = 0; i < num_alt; ++i) {
448 switch (alt[i]) {
449 case 0x1e:
450 alt[j++] = 0x600f4;
451 break;
452 case 0x600f4:
453 alt[j++] = 0x1e;
454 break;
455 case 0x2:
456 alt[j++] = 0x500fa;
457 break;
458 case 0x500fa:
459 alt[j++] = 0x2;
460 break;
461 }
462 }
463 num_alt = j;
464 }
465
466 return num_alt;
467}
468
469static void power8_disable_pmc(unsigned int pmc, unsigned long mmcr[])
470{
471 if (pmc <= 3)
472 mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SHIFT(pmc + 1));
473}
474
475PMU_FORMAT_ATTR(event, "config:0-49");
476PMU_FORMAT_ATTR(pmcxsel, "config:0-7");
477PMU_FORMAT_ATTR(mark, "config:8");
478PMU_FORMAT_ATTR(combine, "config:11");
479PMU_FORMAT_ATTR(unit, "config:12-15");
480PMU_FORMAT_ATTR(pmc, "config:16-19");
481PMU_FORMAT_ATTR(cache_sel, "config:20-23");
482PMU_FORMAT_ATTR(sample_mode, "config:24-28");
483PMU_FORMAT_ATTR(thresh_sel, "config:29-31");
484PMU_FORMAT_ATTR(thresh_stop, "config:32-35");
485PMU_FORMAT_ATTR(thresh_start, "config:36-39");
486PMU_FORMAT_ATTR(thresh_cmp, "config:40-49");
487
488static struct attribute *power8_pmu_format_attr[] = {
489 &format_attr_event.attr,
490 &format_attr_pmcxsel.attr,
491 &format_attr_mark.attr,
492 &format_attr_combine.attr,
493 &format_attr_unit.attr,
494 &format_attr_pmc.attr,
495 &format_attr_cache_sel.attr,
496 &format_attr_sample_mode.attr,
497 &format_attr_thresh_sel.attr,
498 &format_attr_thresh_stop.attr,
499 &format_attr_thresh_start.attr,
500 &format_attr_thresh_cmp.attr,
501 NULL,
502};
503
504struct attribute_group power8_pmu_format_group = {
505 .name = "format",
506 .attrs = power8_pmu_format_attr,
507};
508
509static const struct attribute_group *power8_pmu_attr_groups[] = {
510 &power8_pmu_format_group,
511 NULL,
512};
513
514static int power8_generic_events[] = {
515 [PERF_COUNT_HW_CPU_CYCLES] = PM_CYC,
516 [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = PM_GCT_NOSLOT_CYC,
517 [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = PM_CMPLU_STALL,
518 [PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL,
519 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BRU_FIN,
520 [PERF_COUNT_HW_BRANCH_MISSES] = PM_BR_MPRED_CMPL,
521};
522
523static u64 power8_bhrb_filter_map(u64 branch_sample_type)
524{
525 u64 pmu_bhrb_filter = 0;
526 u64 br_privilege = branch_sample_type & ONLY_PLM;
527
528
529
530
531
532
533
534
535
536 if ((br_privilege != 7) && (br_privilege != 0))
537 return -1;
538
539
540 if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
541 return pmu_bhrb_filter;
542
543
544 if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
545 return -1;
546
547 if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL)
548 return -1;
549
550 if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
551 pmu_bhrb_filter |= POWER8_MMCRA_IFM1;
552 return pmu_bhrb_filter;
553 }
554
555
556 return -1;
557}
558
559static void power8_config_bhrb(u64 pmu_bhrb_filter)
560{
561
562 mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
563}
564
565static struct power_pmu power8_pmu = {
566 .name = "POWER8",
567 .n_counter = 6,
568 .max_alternatives = MAX_ALT + 1,
569 .add_fields = POWER8_ADD_FIELDS,
570 .test_adder = POWER8_TEST_ADDER,
571 .compute_mmcr = power8_compute_mmcr,
572 .config_bhrb = power8_config_bhrb,
573 .bhrb_filter_map = power8_bhrb_filter_map,
574 .get_constraint = power8_get_constraint,
575 .get_alternatives = power8_get_alternatives,
576 .disable_pmc = power8_disable_pmc,
577 .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB,
578 .n_generic = ARRAY_SIZE(power8_generic_events),
579 .generic_events = power8_generic_events,
580 .attr_groups = power8_pmu_attr_groups,
581 .bhrb_nr = 32,
582};
583
584static int __init init_power8_pmu(void)
585{
586 if (!cur_cpu_spec->oprofile_cpu_type ||
587 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power8"))
588 return -ENODEV;
589
590 return register_power_pmu(&power8_pmu);
591}
592early_initcall(init_power8_pmu);
593