This source file includes following definitions.
- mpc7450_classify_event
- mpc7450_threshold_use
- mpc7450_get_constraint
- find_alternative
- mpc7450_get_alternatives
- mpc7450_compute_mmcr
- mpc7450_disable_pmc
- init_mpc7450_pmu
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 #define N_COUNTER 6
13 #define MAX_ALT 3
14
15
16
17
18 #define PM_THRMULT_MSKS 0x40000
19 #define PM_THRESH_SH 12
20 #define PM_THRESH_MSK 0x3f
21 #define PM_PMC_SH 8
22 #define PM_PMC_MSK 7
23 #define PM_PMCSEL_MSK 0x7f
24
25
26
27
28
29
30
31
32
33
34
35 #define N_CLASSES 5
36
37 static int mpc7450_classify_event(u32 event)
38 {
39 int pmc;
40
41 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
42 if (pmc) {
43 if (pmc > N_COUNTER)
44 return -1;
45 return 4;
46 }
47 event &= PM_PMCSEL_MSK;
48 if (event <= 1)
49 return 0;
50 if (event <= 7)
51 return 1;
52 if (event <= 13)
53 return 2;
54 if (event <= 22)
55 return 3;
56 return -1;
57 }
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 static int mpc7450_threshold_use(u32 event)
78 {
79 int pmc, sel;
80
81 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
82 sel = event & PM_PMCSEL_MSK;
83 switch (pmc) {
84 case 1:
85 if (sel == 0x1e || sel == 0x1f)
86 return 1;
87 if (sel == 0x28 || sel == 0x2b)
88 return 2;
89 break;
90 case 2:
91 if (sel == 0x20)
92 return 1;
93 break;
94 case 3:
95 if (sel == 0xc || sel == 0xd)
96 return 1;
97 if (sel == 0x11)
98 return 2;
99 break;
100 case 4:
101 if (sel == 0x10)
102 return 1;
103 break;
104 }
105 return 0;
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 static u32 pmcbits[N_COUNTER][2] = {
135 { 0x00844002, 0x00111001 },
136 { 0x00844008, 0x00111004 },
137 { 0x00800020, 0x00100010 },
138 { 0x00840080, 0x00110040 },
139 { 0x00000200, 0x00000100 },
140 { 0x00000800, 0x00000400 }
141 };
142
143 static u32 classbits[N_CLASSES - 1][2] = {
144 { 0x00000000, 0x00000000 },
145 { 0x00800000, 0x00100000 },
146 { 0x00040000, 0x00010000 },
147 { 0x00004000, 0x00001000 },
148 };
149
150 static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
151 unsigned long *valp)
152 {
153 int pmc, class;
154 u32 mask, value;
155 int thresh, tuse;
156
157 class = mpc7450_classify_event(event);
158 if (class < 0)
159 return -1;
160 if (class == 4) {
161 pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
162 mask = pmcbits[pmc - 1][0];
163 value = pmcbits[pmc - 1][1];
164 } else {
165 mask = classbits[class][0];
166 value = classbits[class][1];
167 }
168
169 tuse = mpc7450_threshold_use(event);
170 if (tuse) {
171 thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
172 mask |= 0x3f << 24;
173 value |= thresh << 24;
174 if (tuse == 2) {
175 mask |= 0x40000000;
176 if ((unsigned int)event & PM_THRMULT_MSKS)
177 value |= 0x40000000;
178 }
179 }
180
181 *maskp = mask;
182 *valp = value;
183 return 0;
184 }
185
186 static const unsigned int event_alternatives[][MAX_ALT] = {
187 { 0x217, 0x317 },
188 { 0x418, 0x50f, 0x60f },
189 { 0x502, 0x602 },
190 { 0x503, 0x603 },
191 { 0x504, 0x604 },
192 { 0x505, 0x605 },
193 { 0x506, 0x606 },
194 { 0x507, 0x607 },
195 { 0x50a, 0x623 },
196 { 0x50b, 0x624 },
197 { 0x50d, 0x60d },
198 { 0x50e, 0x60e },
199 { 0x512, 0x612 },
200 { 0x513, 0x61d },
201 { 0x514, 0x61e },
202 };
203
204
205
206
207
208 static int find_alternative(u32 event)
209 {
210 int i, j;
211
212 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
213 if (event < event_alternatives[i][0])
214 break;
215 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
216 if (event == event_alternatives[i][j])
217 return i;
218 }
219 return -1;
220 }
221
222 static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
223 {
224 int i, j, nalt = 1;
225 u32 ae;
226
227 alt[0] = event;
228 nalt = 1;
229 i = find_alternative((u32)event);
230 if (i >= 0) {
231 for (j = 0; j < MAX_ALT; ++j) {
232 ae = event_alternatives[i][j];
233 if (ae && ae != (u32)event)
234 alt[nalt++] = ae;
235 }
236 }
237 return nalt;
238 }
239
240
241
242
243
244 static const u8 classmap[N_CLASSES] = {
245 0x3f, 0x0f, 0x0b, 0x03, 0
246 };
247
248
249 static const int pmcsel_shift[N_COUNTER] = {
250 6, 0, 27, 22, 17, 11
251 };
252 static const u32 pmcsel_mask[N_COUNTER] = {
253 0x7f, 0x3f, 0x1f, 0x1f, 0x1f, 0x3f
254 };
255
256
257
258
259 static int mpc7450_compute_mmcr(u64 event[], int n_ev, unsigned int hwc[],
260 unsigned long mmcr[],
261 struct perf_event *pevents[])
262 {
263 u8 event_index[N_CLASSES][N_COUNTER];
264 int n_classevent[N_CLASSES];
265 int i, j, class, tuse;
266 u32 pmc_inuse = 0, pmc_avail;
267 u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
268 u32 ev, pmc, thresh;
269
270 if (n_ev > N_COUNTER)
271 return -1;
272
273
274 for (i = 0; i < N_CLASSES; ++i)
275 n_classevent[i] = 0;
276 for (i = 0; i < n_ev; ++i) {
277 class = mpc7450_classify_event(event[i]);
278 if (class < 0)
279 return -1;
280 j = n_classevent[class]++;
281 event_index[class][j] = i;
282 }
283
284
285 for (class = N_CLASSES - 1; class >= 0; --class) {
286 for (i = 0; i < n_classevent[class]; ++i) {
287 ev = event[event_index[class][i]];
288 if (class == 4) {
289 pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
290 if (pmc_inuse & (1 << (pmc - 1)))
291 return -1;
292 } else {
293
294 pmc_avail = classmap[class] & ~pmc_inuse;
295 if (!pmc_avail)
296 return -1;
297 pmc = ffs(pmc_avail);
298 }
299 pmc_inuse |= 1 << (pmc - 1);
300
301 tuse = mpc7450_threshold_use(ev);
302 if (tuse) {
303 thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
304 mmcr0 |= thresh << 16;
305 if (tuse == 2 && (ev & PM_THRMULT_MSKS))
306 mmcr2 = 0x80000000;
307 }
308 ev &= pmcsel_mask[pmc - 1];
309 ev <<= pmcsel_shift[pmc - 1];
310 if (pmc <= 2)
311 mmcr0 |= ev;
312 else
313 mmcr1 |= ev;
314 hwc[event_index[class][i]] = pmc - 1;
315 }
316 }
317
318 if (pmc_inuse & 1)
319 mmcr0 |= MMCR0_PMC1CE;
320 if (pmc_inuse & 0x3e)
321 mmcr0 |= MMCR0_PMCnCE;
322
323
324 mmcr[0] = mmcr0;
325 mmcr[1] = mmcr1;
326 mmcr[2] = mmcr2;
327 return 0;
328 }
329
330
331
332
333
334 static void mpc7450_disable_pmc(unsigned int pmc, unsigned long mmcr[])
335 {
336 if (pmc <= 1)
337 mmcr[0] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
338 else
339 mmcr[1] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
340 }
341
342 static int mpc7450_generic_events[] = {
343 [PERF_COUNT_HW_CPU_CYCLES] = 1,
344 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
345 [PERF_COUNT_HW_CACHE_MISSES] = 0x217,
346 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x122,
347 [PERF_COUNT_HW_BRANCH_MISSES] = 0x41c,
348 };
349
350 #define C(x) PERF_COUNT_HW_CACHE_##x
351
352
353
354
355
356
357 static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
358 [C(L1D)] = {
359 [C(OP_READ)] = { 0, 0x225 },
360 [C(OP_WRITE)] = { 0, 0x227 },
361 [C(OP_PREFETCH)] = { 0, 0 },
362 },
363 [C(L1I)] = {
364 [C(OP_READ)] = { 0x129, 0x115 },
365 [C(OP_WRITE)] = { -1, -1 },
366 [C(OP_PREFETCH)] = { 0x634, 0 },
367 },
368 [C(LL)] = {
369 [C(OP_READ)] = { 0, 0 },
370 [C(OP_WRITE)] = { 0, 0 },
371 [C(OP_PREFETCH)] = { 0, 0 },
372 },
373 [C(DTLB)] = {
374 [C(OP_READ)] = { 0, 0x312 },
375 [C(OP_WRITE)] = { -1, -1 },
376 [C(OP_PREFETCH)] = { -1, -1 },
377 },
378 [C(ITLB)] = {
379 [C(OP_READ)] = { 0, 0x223 },
380 [C(OP_WRITE)] = { -1, -1 },
381 [C(OP_PREFETCH)] = { -1, -1 },
382 },
383 [C(BPU)] = {
384 [C(OP_READ)] = { 0x122, 0x41c },
385 [C(OP_WRITE)] = { -1, -1 },
386 [C(OP_PREFETCH)] = { -1, -1 },
387 },
388 [C(NODE)] = {
389 [C(OP_READ)] = { -1, -1 },
390 [C(OP_WRITE)] = { -1, -1 },
391 [C(OP_PREFETCH)] = { -1, -1 },
392 },
393 };
394
395 struct power_pmu mpc7450_pmu = {
396 .name = "MPC7450 family",
397 .n_counter = N_COUNTER,
398 .max_alternatives = MAX_ALT,
399 .add_fields = 0x00111555ul,
400 .test_adder = 0x00301000ul,
401 .compute_mmcr = mpc7450_compute_mmcr,
402 .get_constraint = mpc7450_get_constraint,
403 .get_alternatives = mpc7450_get_alternatives,
404 .disable_pmc = mpc7450_disable_pmc,
405 .n_generic = ARRAY_SIZE(mpc7450_generic_events),
406 .generic_events = mpc7450_generic_events,
407 .cache_events = &mpc7450_cache_events,
408 };
409
410 static int __init init_mpc7450_pmu(void)
411 {
412 if (!cur_cpu_spec->oprofile_cpu_type ||
413 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
414 return -ENODEV;
415
416 return register_power_pmu(&mpc7450_pmu);
417 }
418
419 early_initcall(init_mpc7450_pmu);