aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2009-06-17 07:53:51 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-18 05:11:46 -0400
commit7325927e5a20bfe0f006acf92801bf41c537d3d4 (patch)
tree53e3167588fa86d3fcb2e2dfac221706d71f2d07 /arch/powerpc
parent98fb1807b97e3e631b940f67544e265c64b984dc (diff)
perf_counter: powerpc: Add processor back-end for MPC7450 family
This adds support for the performance monitor hardware on the MPC7450 family of processors (7450, 7451, 7455, 7447/7457, 7447A, 7448), used in the later Apple G4 powermacs/powerbooks and other machines. These machines have 6 hardware counters with a unique set of events which can be counted on each counter, with some events being available on multiple counters. Raw event codes for these processors are (PMC << 8) + PMCSEL. If PMC is non-zero then the event is that selected by the given PMCSEL value for that PMC (hardware counter). If PMC is zero then the event selected is one of the low-numbered ones that are common to several PMCs. In this case PMCSEL must be <= 22 and the event is what that PMCSEL value would select on PMC1 (but it may be placed any other PMC that has the same event for that PMCSEL value). For events that count cycles or occurrences that exceed a threshold, the threshold requested can be specified in the 0x3f000 bits of the raw event codes. If the event uses the threshold multiplier bit and that bit should be set, that is indicated with the 0x40000 bit of the raw event code. This fills in some of the generic cache events. Unfortunately there are quite a few blank spaces in the table, partly because these processors tend to count cache hits rather than cache accesses. Signed-off-by: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: linuxppc-dev@ozlabs.org Cc: benh@kernel.crashing.org LKML-Reference: <19000.55631.802122.696927@cargo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/mpc7450-pmu.c417
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype1
3 files changed, 420 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index c5f93f061927..a9f882963379 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
98obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o 98obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o
99obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ 99obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \
100 power5+-pmu.o power6-pmu.o power7-pmu.o 100 power5+-pmu.o power6-pmu.o power7-pmu.o
101obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o
101 102
102obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o 103obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
103 104
@@ -106,6 +107,7 @@ obj-y += iomap.o
106endif 107endif
107 108
108obj-$(CONFIG_PPC64) += $(obj64-y) 109obj-$(CONFIG_PPC64) += $(obj64-y)
110obj-$(CONFIG_PPC32) += $(obj32-y)
109 111
110ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),) 112ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
111obj-y += ppc_save_regs.o 113obj-y += ppc_save_regs.o
diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/kernel/mpc7450-pmu.c
new file mode 100644
index 000000000000..75ff47fed7bf
--- /dev/null
+++ b/arch/powerpc/kernel/mpc7450-pmu.c
@@ -0,0 +1,417 @@
1/*
2 * Performance counter support for MPC7450-family processors.
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/string.h>
12#include <linux/perf_counter.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17#define N_COUNTER 6 /* Number of hardware counters */
18#define MAX_ALT 3 /* Maximum number of event alternative codes */
19
20/*
21 * Bits in event code for MPC7450 family
22 */
23#define PM_THRMULT_MSKS 0x40000
24#define PM_THRESH_SH 12
25#define PM_THRESH_MSK 0x3f
26#define PM_PMC_SH 8
27#define PM_PMC_MSK 7
28#define PM_PMCSEL_MSK 0x7f
29
30/*
31 * Classify events according to how specific their PMC requirements are.
32 * Result is:
33 * 0: can go on any PMC
34 * 1: can go on PMCs 1-4
35 * 2: can go on PMCs 1,2,4
36 * 3: can go on PMCs 1 or 2
37 * 4: can only go on one PMC
38 * -1: event code is invalid
39 */
40#define N_CLASSES 5
41
42static int mpc7450_classify_event(u32 event)
43{
44 int pmc;
45
46 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
47 if (pmc) {
48 if (pmc > N_COUNTER)
49 return -1;
50 return 4;
51 }
52 event &= PM_PMCSEL_MSK;
53 if (event <= 1)
54 return 0;
55 if (event <= 7)
56 return 1;
57 if (event <= 13)
58 return 2;
59 if (event <= 22)
60 return 3;
61 return -1;
62}
63
64/*
65 * Events using threshold and possible threshold scale:
66 * code scale? name
67 * 11e N PM_INSTQ_EXCEED_CYC
68 * 11f N PM_ALTV_IQ_EXCEED_CYC
69 * 128 Y PM_DTLB_SEARCH_EXCEED_CYC
70 * 12b Y PM_LD_MISS_EXCEED_L1_CYC
71 * 220 N PM_CQ_EXCEED_CYC
72 * 30c N PM_GPR_RB_EXCEED_CYC
73 * 30d ? PM_FPR_IQ_EXCEED_CYC ?
74 * 311 Y PM_ITLB_SEARCH_EXCEED
75 * 410 N PM_GPR_IQ_EXCEED_CYC
76 */
77
78/*
79 * Return use of threshold and threshold scale bits:
80 * 0 = uses neither, 1 = uses threshold, 2 = uses both
81 */
82static int mpc7450_threshold_use(u32 event)
83{
84 int pmc, sel;
85
86 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
87 sel = event & PM_PMCSEL_MSK;
88 switch (pmc) {
89 case 1:
90 if (sel == 0x1e || sel == 0x1f)
91 return 1;
92 if (sel == 0x28 || sel == 0x2b)
93 return 2;
94 break;
95 case 2:
96 if (sel == 0x20)
97 return 1;
98 break;
99 case 3:
100 if (sel == 0xc || sel == 0xd)
101 return 1;
102 if (sel == 0x11)
103 return 2;
104 break;
105 case 4:
106 if (sel == 0x10)
107 return 1;
108 break;
109 }
110 return 0;
111}
112
113/*
114 * Layout of constraint bits:
115 * 33222222222211111111110000000000
116 * 10987654321098765432109876543210
117 * |< >< > < > < ><><><><><><>
118 * TS TV G4 G3 G2P6P5P4P3P2P1
119 *
120 * P1 - P6
121 * 0 - 11: Count of events needing PMC1 .. PMC6
122 *
123 * G2
124 * 12 - 14: Count of events needing PMC1 or PMC2
125 *
126 * G3
127 * 16 - 18: Count of events needing PMC1, PMC2 or PMC4
128 *
129 * G4
130 * 20 - 23: Count of events needing PMC1, PMC2, PMC3 or PMC4
131 *
132 * TV
133 * 24 - 29: Threshold value requested
134 *
135 * TS
136 * 30: Threshold scale value requested
137 */
138
139static u32 pmcbits[N_COUNTER][2] = {
140 { 0x00844002, 0x00111001 }, /* PMC1 mask, value: P1,G2,G3,G4 */
141 { 0x00844008, 0x00111004 }, /* PMC2: P2,G2,G3,G4 */
142 { 0x00800020, 0x00100010 }, /* PMC3: P3,G4 */
143 { 0x00840080, 0x00110040 }, /* PMC4: P4,G3,G4 */
144 { 0x00000200, 0x00000100 }, /* PMC5: P5 */
145 { 0x00000800, 0x00000400 } /* PMC6: P6 */
146};
147
148static u32 classbits[N_CLASSES - 1][2] = {
149 { 0x00000000, 0x00000000 }, /* class 0: no constraint */
150 { 0x00800000, 0x00100000 }, /* class 1: G4 */
151 { 0x00040000, 0x00010000 }, /* class 2: G3 */
152 { 0x00004000, 0x00001000 }, /* class 3: G2 */
153};
154
155static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
156 unsigned long *valp)
157{
158 int pmc, class;
159 u32 mask, value;
160 int thresh, tuse;
161
162 class = mpc7450_classify_event(event);
163 if (class < 0)
164 return -1;
165 if (class == 4) {
166 pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
167 mask = pmcbits[pmc - 1][0];
168 value = pmcbits[pmc - 1][1];
169 } else {
170 mask = classbits[class][0];
171 value = classbits[class][1];
172 }
173
174 tuse = mpc7450_threshold_use(event);
175 if (tuse) {
176 thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
177 mask |= 0x3f << 24;
178 value |= thresh << 24;
179 if (tuse == 2) {
180 mask |= 0x40000000;
181 if ((unsigned int)event & PM_THRMULT_MSKS)
182 value |= 0x40000000;
183 }
184 }
185
186 *maskp = mask;
187 *valp = value;
188 return 0;
189}
190
191static const unsigned int event_alternatives[][MAX_ALT] = {
192 { 0x217, 0x317 }, /* PM_L1_DCACHE_MISS */
193 { 0x418, 0x50f, 0x60f }, /* PM_SNOOP_RETRY */
194 { 0x502, 0x602 }, /* PM_L2_HIT */
195 { 0x503, 0x603 }, /* PM_L3_HIT */
196 { 0x504, 0x604 }, /* PM_L2_ICACHE_MISS */
197 { 0x505, 0x605 }, /* PM_L3_ICACHE_MISS */
198 { 0x506, 0x606 }, /* PM_L2_DCACHE_MISS */
199 { 0x507, 0x607 }, /* PM_L3_DCACHE_MISS */
200 { 0x50a, 0x623 }, /* PM_LD_HIT_L3 */
201 { 0x50b, 0x624 }, /* PM_ST_HIT_L3 */
202 { 0x50d, 0x60d }, /* PM_L2_TOUCH_HIT */
203 { 0x50e, 0x60e }, /* PM_L3_TOUCH_HIT */
204 { 0x512, 0x612 }, /* PM_INT_LOCAL */
205 { 0x513, 0x61d }, /* PM_L2_MISS */
206 { 0x514, 0x61e }, /* PM_L3_MISS */
207};
208
209/*
210 * Scan the alternatives table for a match and return the
211 * index into the alternatives table if found, else -1.
212 */
213static int find_alternative(u32 event)
214{
215 int i, j;
216
217 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
218 if (event < event_alternatives[i][0])
219 break;
220 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
221 if (event == event_alternatives[i][j])
222 return i;
223 }
224 return -1;
225}
226
227static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
228{
229 int i, j, nalt = 1;
230 u32 ae;
231
232 alt[0] = event;
233 nalt = 1;
234 i = find_alternative((u32)event);
235 if (i >= 0) {
236 for (j = 0; j < MAX_ALT; ++j) {
237 ae = event_alternatives[i][j];
238 if (ae && ae != (u32)event)
239 alt[nalt++] = ae;
240 }
241 }
242 return nalt;
243}
244
245/*
246 * Bitmaps of which PMCs each class can use for classes 0 - 3.
247 * Bit i is set if PMC i+1 is usable.
248 */
249static const u8 classmap[N_CLASSES] = {
250 0x3f, 0x0f, 0x0b, 0x03, 0
251};
252
253/* Bit position and width of each PMCSEL field */
254static const int pmcsel_shift[N_COUNTER] = {
255 6, 0, 27, 22, 17, 11
256};
257static const u32 pmcsel_mask[N_COUNTER] = {
258 0x7f, 0x3f, 0x1f, 0x1f, 0x1f, 0x3f
259};
260
261/*
262 * Compute MMCR0/1/2 values for a set of events.
263 */
264static int mpc7450_compute_mmcr(u64 event[], int n_ev,
265 unsigned int hwc[], unsigned long mmcr[])
266{
267 u8 event_index[N_CLASSES][N_COUNTER];
268 int n_classevent[N_CLASSES];
269 int i, j, class, tuse;
270 u32 pmc_inuse = 0, pmc_avail;
271 u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
272 u32 ev, pmc, thresh;
273
274 if (n_ev > N_COUNTER)
275 return -1;
276
277 /* First pass: count usage in each class */
278 for (i = 0; i < N_CLASSES; ++i)
279 n_classevent[i] = 0;
280 for (i = 0; i < n_ev; ++i) {
281 class = mpc7450_classify_event(event[i]);
282 if (class < 0)
283 return -1;
284 j = n_classevent[class]++;
285 event_index[class][j] = i;
286 }
287
288 /* Second pass: allocate PMCs from most specific event to least */
289 for (class = N_CLASSES - 1; class >= 0; --class) {
290 for (i = 0; i < n_classevent[class]; ++i) {
291 ev = event[event_index[class][i]];
292 if (class == 4) {
293 pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
294 if (pmc_inuse & (1 << (pmc - 1)))
295 return -1;
296 } else {
297 /* Find a suitable PMC */
298 pmc_avail = classmap[class] & ~pmc_inuse;
299 if (!pmc_avail)
300 return -1;
301 pmc = ffs(pmc_avail);
302 }
303 pmc_inuse |= 1 << (pmc - 1);
304
305 tuse = mpc7450_threshold_use(ev);
306 if (tuse) {
307 thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
308 mmcr0 |= thresh << 16;
309 if (tuse == 2 && (ev & PM_THRMULT_MSKS))
310 mmcr2 = 0x80000000;
311 }
312 ev &= pmcsel_mask[pmc - 1];
313 ev <<= pmcsel_shift[pmc - 1];
314 if (pmc <= 2)
315 mmcr0 |= ev;
316 else
317 mmcr1 |= ev;
318 hwc[event_index[class][i]] = pmc - 1;
319 }
320 }
321
322 if (pmc_inuse & 1)
323 mmcr0 |= MMCR0_PMC1CE;
324 if (pmc_inuse & 0x3e)
325 mmcr0 |= MMCR0_PMCnCE;
326
327 /* Return MMCRx values */
328 mmcr[0] = mmcr0;
329 mmcr[1] = mmcr1;
330 mmcr[2] = mmcr2;
331 return 0;
332}
333
334/*
335 * Disable counting by a PMC.
336 * Note that the pmc argument is 0-based here, not 1-based.
337 */
338static void mpc7450_disable_pmc(unsigned int pmc, unsigned long mmcr[])
339{
340 if (pmc <= 1)
341 mmcr[0] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
342 else
343 mmcr[1] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
344}
345
346static int mpc7450_generic_events[] = {
347 [PERF_COUNT_HW_CPU_CYCLES] = 1,
348 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
349 [PERF_COUNT_HW_CACHE_MISSES] = 0x217, /* PM_L1_DCACHE_MISS */
350 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x122, /* PM_BR_CMPL */
351 [PERF_COUNT_HW_BRANCH_MISSES] = 0x41c, /* PM_BR_MPRED */
352};
353
354#define C(x) PERF_COUNT_HW_CACHE_##x
355
356/*
357 * Table of generalized cache-related events.
358 * 0 means not supported, -1 means nonsensical, other values
359 * are event codes.
360 */
361static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
362 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
363 [C(OP_READ)] = { 0, 0x225 },
364 [C(OP_WRITE)] = { 0, 0x227 },
365 [C(OP_PREFETCH)] = { 0, 0 },
366 },
367 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
368 [C(OP_READ)] = { 0x129, 0x115 },
369 [C(OP_WRITE)] = { -1, -1 },
370 [C(OP_PREFETCH)] = { 0x634, 0 },
371 },
372 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
373 [C(OP_READ)] = { 0, 0 },
374 [C(OP_WRITE)] = { 0, 0 },
375 [C(OP_PREFETCH)] = { 0, 0 },
376 },
377 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
378 [C(OP_READ)] = { 0, 0x312 },
379 [C(OP_WRITE)] = { -1, -1 },
380 [C(OP_PREFETCH)] = { -1, -1 },
381 },
382 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
383 [C(OP_READ)] = { 0, 0x223 },
384 [C(OP_WRITE)] = { -1, -1 },
385 [C(OP_PREFETCH)] = { -1, -1 },
386 },
387 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
388 [C(OP_READ)] = { 0x122, 0x41c },
389 [C(OP_WRITE)] = { -1, -1 },
390 [C(OP_PREFETCH)] = { -1, -1 },
391 },
392};
393
394struct power_pmu mpc7450_pmu = {
395 .name = "MPC7450 family",
396 .n_counter = N_COUNTER,
397 .max_alternatives = MAX_ALT,
398 .add_fields = 0x00111555ul,
399 .test_adder = 0x00301000ul,
400 .compute_mmcr = mpc7450_compute_mmcr,
401 .get_constraint = mpc7450_get_constraint,
402 .get_alternatives = mpc7450_get_alternatives,
403 .disable_pmc = mpc7450_disable_pmc,
404 .n_generic = ARRAY_SIZE(mpc7450_generic_events),
405 .generic_events = mpc7450_generic_events,
406 .cache_events = &mpc7450_cache_events,
407};
408
409static int init_mpc7450_pmu(void)
410{
411 if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
412 return -ENODEV;
413
414 return register_power_pmu(&mpc7450_pmu);
415}
416
417arch_initcall(init_mpc7450_pmu);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index dd9f3ec5ee30..8485c8ca7a06 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -75,6 +75,7 @@ config POWER4_ONLY
75config 6xx 75config 6xx
76 def_bool y 76 def_bool y
77 depends on PPC32 && PPC_BOOK3S 77 depends on PPC32 && PPC_BOOK3S
78 select PPC_HAVE_PMU_SUPPORT
78 79
79config POWER3 80config POWER3
80 bool 81 bool