1
2
3
4
5
6
7#include <linux/string.h>
8#include <linux/perf_event.h>
9#include <asm/reg.h>
10#include <asm/cputable.h>
11
12
13
14
15#define PM_PMC_SH 12
16#define PM_PMC_MSK 0xf
17#define PM_UNIT_SH 8
18#define PM_UNIT_MSK 0xf
19#define PM_SPCSEL_SH 6
20#define PM_SPCSEL_MSK 3
21#define PM_BYTE_SH 4
22#define PM_BYTE_MSK 3
23#define PM_PMCSEL_MSK 0xf
24
25
26#define PM_NONE 0
27#define PM_FPU 1
28#define PM_VPU 2
29#define PM_ISU 3
30#define PM_IFU 4
31#define PM_IDU 5
32#define PM_STS 6
33#define PM_LSU0 7
34#define PM_LSU1U 8
35#define PM_LSU1L 9
36#define PM_LASTUNIT 9
37
38
39
40
41#define MMCR0_PMC1SEL_SH 8
42#define MMCR0_PMC2SEL_SH 1
43#define MMCR_PMCSEL_MSK 0x1f
44
45
46
47
48#define MMCR1_TTM0SEL_SH 62
49#define MMCR1_TTM1SEL_SH 59
50#define MMCR1_TTM3SEL_SH 53
51#define MMCR1_TTMSEL_MSK 3
52#define MMCR1_TD_CP_DBG0SEL_SH 50
53#define MMCR1_TD_CP_DBG1SEL_SH 48
54#define MMCR1_TD_CP_DBG2SEL_SH 46
55#define MMCR1_TD_CP_DBG3SEL_SH 44
56#define MMCR1_PMC1_ADDER_SEL_SH 39
57#define MMCR1_PMC2_ADDER_SEL_SH 38
58#define MMCR1_PMC6_ADDER_SEL_SH 37
59#define MMCR1_PMC5_ADDER_SEL_SH 36
60#define MMCR1_PMC8_ADDER_SEL_SH 35
61#define MMCR1_PMC7_ADDER_SEL_SH 34
62#define MMCR1_PMC3_ADDER_SEL_SH 33
63#define MMCR1_PMC4_ADDER_SEL_SH 32
64#define MMCR1_PMC3SEL_SH 27
65#define MMCR1_PMC4SEL_SH 22
66#define MMCR1_PMC5SEL_SH 17
67#define MMCR1_PMC6SEL_SH 12
68#define MMCR1_PMC7SEL_SH 7
69#define MMCR1_PMC8SEL_SH 2
70
71static short mmcr1_adder_bits[8] = {
72 MMCR1_PMC1_ADDER_SEL_SH,
73 MMCR1_PMC2_ADDER_SEL_SH,
74 MMCR1_PMC3_ADDER_SEL_SH,
75 MMCR1_PMC4_ADDER_SEL_SH,
76 MMCR1_PMC5_ADDER_SEL_SH,
77 MMCR1_PMC6_ADDER_SEL_SH,
78 MMCR1_PMC7_ADDER_SEL_SH,
79 MMCR1_PMC8_ADDER_SEL_SH
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
127static unsigned char direct_marked_event[8] = {
128 (1<<2) | (1<<3),
129 (1<<3) | (1<<5),
130 (1<<3) | (1<<5),
131 (1<<4) | (1<<5),
132 (1<<4) | (1<<5),
133 (1<<3) | (1<<4) | (1<<5),
134
135 (1<<4) | (1<<5),
136 (1<<4)
137};
138
139
140
141
142
143static int p970_marked_instr_event(u64 event)
144{
145 int pmc, psel, unit, byte, bit;
146 unsigned int mask;
147
148 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
149 psel = event & PM_PMCSEL_MSK;
150 if (pmc) {
151 if (direct_marked_event[pmc - 1] & (1 << psel))
152 return 1;
153 if (psel == 0)
154 bit = (pmc <= 4)? pmc - 1: 8 - pmc;
155 else if (psel == 7 || psel == 13)
156 bit = 4;
157 else
158 return 0;
159 } else
160 bit = psel;
161
162 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
163 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
164 mask = 0;
165 switch (unit) {
166 case PM_VPU:
167 mask = 0x4c;
168 break;
169 case PM_LSU0:
170
171 mask = 0x085dff00;
172 break;
173 case PM_LSU1L:
174 mask = 0x50 << 24;
175 break;
176 }
177 return (mask >> (byte * 8 + bit)) & 1;
178}
179
180
181static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
182 [PM_FPU] = { 0xc80000000000ull, 0x040000000000ull },
183 [PM_VPU] = { 0xc80000000000ull, 0xc40000000000ull },
184 [PM_ISU] = { 0x080000000000ull, 0x020000000000ull },
185 [PM_IFU] = { 0xc80000000000ull, 0x840000000000ull },
186 [PM_IDU] = { 0x380000000000ull, 0x010000000000ull },
187 [PM_STS] = { 0x380000000000ull, 0x310000000000ull },
188};
189
190static int p970_get_constraint(u64 event, unsigned long *maskp,
191 unsigned long *valp)
192{
193 int pmc, byte, unit, sh, spcsel;
194 unsigned long mask = 0, value = 0;
195 int grp = -1;
196
197 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
198 if (pmc) {
199 if (pmc > 8)
200 return -1;
201 sh = (pmc - 1) * 2;
202 mask |= 2 << sh;
203 value |= 1 << sh;
204 grp = ((pmc - 1) >> 1) & 1;
205 }
206 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
207 if (unit) {
208 if (unit > PM_LASTUNIT)
209 return -1;
210 mask |= unit_cons[unit][0];
211 value |= unit_cons[unit][1];
212 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
213
214
215
216
217 if (!pmc)
218 grp = byte & 1;
219
220 mask |= 0xfULL << (28 - 4 * byte);
221 value |= (unsigned long)unit << (28 - 4 * byte);
222 }
223 if (grp == 0) {
224
225 mask |= 0x8000000000ull;
226 value |= 0x1000000000ull;
227 } else if (grp == 1) {
228
229 mask |= 0x800000000ull;
230 value |= 0x100000000ull;
231 }
232 spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
233 if (spcsel) {
234 mask |= 3ull << 48;
235 value |= (unsigned long)spcsel << 48;
236 }
237 *maskp = mask;
238 *valp = value;
239 return 0;
240}
241
242static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
243{
244 alt[0] = event;
245
246
247 if (event == 0x2002 || event == 0x3002) {
248 alt[1] = event ^ 0x1000;
249 return 2;
250 }
251
252 return 1;
253}
254
255static int p970_compute_mmcr(u64 event[], int n_ev,
256 unsigned int hwc[], struct mmcr_regs *mmcr,
257 struct perf_event *pevents[])
258{
259 unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
260 unsigned int pmc, unit, byte, psel;
261 unsigned int ttm, grp;
262 unsigned int pmc_inuse = 0;
263 unsigned int pmc_grp_use[2];
264 unsigned char busbyte[4];
265 unsigned char unituse[16];
266 unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
267 unsigned char ttmuse[2];
268 unsigned char pmcsel[8];
269 int i;
270 int spcsel;
271
272 if (n_ev > 8)
273 return -1;
274
275
276 pmc_grp_use[0] = pmc_grp_use[1] = 0;
277 memset(busbyte, 0, sizeof(busbyte));
278 memset(unituse, 0, sizeof(unituse));
279 for (i = 0; i < n_ev; ++i) {
280 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
281 if (pmc) {
282 if (pmc_inuse & (1 << (pmc - 1)))
283 return -1;
284 pmc_inuse |= 1 << (pmc - 1);
285
286 ++pmc_grp_use[((pmc - 1) >> 1) & 1];
287 }
288 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
289 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
290 if (unit) {
291 if (unit > PM_LASTUNIT)
292 return -1;
293 if (!pmc)
294 ++pmc_grp_use[byte & 1];
295 if (busbyte[byte] && busbyte[byte] != unit)
296 return -1;
297 busbyte[byte] = unit;
298 unituse[unit] = 1;
299 }
300 }
301 if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
302 return -1;
303
304
305
306
307
308
309
310 if (unituse[PM_ISU] &
311 (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
312 unitmap[PM_ISU] = 2 | 4;
313
314 ttmuse[0] = ttmuse[1] = 0;
315 for (i = PM_FPU; i <= PM_STS; ++i) {
316 if (!unituse[i])
317 continue;
318 ttm = unitmap[i];
319 ++ttmuse[(ttm >> 2) & 1];
320 mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
321 }
322
323 if (ttmuse[0] > 1 || ttmuse[1] > 1)
324 return -1;
325
326
327 for (byte = 0; byte < 4; ++byte) {
328 unit = busbyte[byte];
329 if (!unit)
330 continue;
331 if (unit <= PM_STS)
332 ttm = (unitmap[unit] >> 2) & 1;
333 else if (unit == PM_LSU0)
334 ttm = 2;
335 else {
336 ttm = 3;
337 if (unit == PM_LSU1L && byte >= 2)
338 mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
339 }
340 mmcr1 |= (unsigned long)ttm
341 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
342 }
343
344
345 memset(pmcsel, 0x8, sizeof(pmcsel));
346 for (i = 0; i < n_ev; ++i) {
347 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
348 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
349 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
350 psel = event[i] & PM_PMCSEL_MSK;
351 if (!pmc) {
352
353 if (unit)
354 psel |= 0x10 | ((byte & 2) << 2);
355 else
356 psel |= 8;
357 for (pmc = 0; pmc < 8; ++pmc) {
358 if (pmc_inuse & (1 << pmc))
359 continue;
360 grp = (pmc >> 1) & 1;
361 if (unit) {
362 if (grp == (byte & 1))
363 break;
364 } else if (pmc_grp_use[grp] < 4) {
365 ++pmc_grp_use[grp];
366 break;
367 }
368 }
369 pmc_inuse |= 1 << pmc;
370 } else {
371
372 --pmc;
373 if (psel == 0 && (byte & 2))
374
375 mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
376 }
377 pmcsel[pmc] = psel;
378 hwc[i] = pmc;
379 spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
380 mmcr1 |= spcsel;
381 if (p970_marked_instr_event(event[i]))
382 mmcra |= MMCRA_SAMPLE_ENABLE;
383 }
384 for (pmc = 0; pmc < 2; ++pmc)
385 mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
386 for (; pmc < 8; ++pmc)
387 mmcr1 |= (unsigned long)pmcsel[pmc]
388 << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
389 if (pmc_inuse & 1)
390 mmcr0 |= MMCR0_PMC1CE;
391 if (pmc_inuse & 0xfe)
392 mmcr0 |= MMCR0_PMCjCE;
393
394 mmcra |= 0x2000;
395
396
397 mmcr->mmcr0 = mmcr0;
398 mmcr->mmcr1 = mmcr1;
399 mmcr->mmcra = mmcra;
400 return 0;
401}
402
403static void p970_disable_pmc(unsigned int pmc, struct mmcr_regs *mmcr)
404{
405 int shift;
406
407
408
409
410 if (pmc <= 1) {
411 shift = MMCR0_PMC1SEL_SH - 7 * pmc;
412 mmcr->mmcr0 = (mmcr->mmcr0 & ~(0x1fUL << shift)) | (0x08UL << shift);
413 } else {
414 shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
415 mmcr->mmcr1 = (mmcr->mmcr1 & ~(0x1fUL << shift)) | (0x08UL << shift);
416 }
417}
418
419static int ppc970_generic_events[] = {
420 [PERF_COUNT_HW_CPU_CYCLES] = 7,
421 [PERF_COUNT_HW_INSTRUCTIONS] = 1,
422 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x8810,
423 [PERF_COUNT_HW_CACHE_MISSES] = 0x3810,
424 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x431,
425 [PERF_COUNT_HW_BRANCH_MISSES] = 0x327,
426};
427
428#define C(x) PERF_COUNT_HW_CACHE_##x
429
430
431
432
433
434
435static u64 ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
436 [C(L1D)] = {
437 [C(OP_READ)] = { 0x8810, 0x3810 },
438 [C(OP_WRITE)] = { 0x7810, 0x813 },
439 [C(OP_PREFETCH)] = { 0x731, 0 },
440 },
441 [C(L1I)] = {
442 [C(OP_READ)] = { 0, 0 },
443 [C(OP_WRITE)] = { -1, -1 },
444 [C(OP_PREFETCH)] = { 0, 0 },
445 },
446 [C(LL)] = {
447 [C(OP_READ)] = { 0, 0 },
448 [C(OP_WRITE)] = { 0, 0 },
449 [C(OP_PREFETCH)] = { 0x733, 0 },
450 },
451 [C(DTLB)] = {
452 [C(OP_READ)] = { 0, 0x704 },
453 [C(OP_WRITE)] = { -1, -1 },
454 [C(OP_PREFETCH)] = { -1, -1 },
455 },
456 [C(ITLB)] = {
457 [C(OP_READ)] = { 0, 0x700 },
458 [C(OP_WRITE)] = { -1, -1 },
459 [C(OP_PREFETCH)] = { -1, -1 },
460 },
461 [C(BPU)] = {
462 [C(OP_READ)] = { 0x431, 0x327 },
463 [C(OP_WRITE)] = { -1, -1 },
464 [C(OP_PREFETCH)] = { -1, -1 },
465 },
466 [C(NODE)] = {
467 [C(OP_READ)] = { -1, -1 },
468 [C(OP_WRITE)] = { -1, -1 },
469 [C(OP_PREFETCH)] = { -1, -1 },
470 },
471};
472
473static struct power_pmu ppc970_pmu = {
474 .name = "PPC970/FX/MP",
475 .n_counter = 8,
476 .max_alternatives = 2,
477 .add_fields = 0x001100005555ull,
478 .test_adder = 0x013300000000ull,
479 .compute_mmcr = p970_compute_mmcr,
480 .get_constraint = p970_get_constraint,
481 .get_alternatives = p970_get_alternatives,
482 .disable_pmc = p970_disable_pmc,
483 .n_generic = ARRAY_SIZE(ppc970_generic_events),
484 .generic_events = ppc970_generic_events,
485 .cache_events = &ppc970_cache_events,
486 .flags = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
487};
488
489int init_ppc970_pmu(void)
490{
491 if (!cur_cpu_spec->oprofile_cpu_type ||
492 (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
493 && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
494 return -ENODEV;
495
496 return register_power_pmu(&ppc970_pmu);
497}
498