diff options
Diffstat (limited to 'arch/powerpc/kernel/power5+-pmu.c')
-rw-r--r-- | arch/powerpc/kernel/power5+-pmu.c | 117 |
1 files changed, 98 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/kernel/power5+-pmu.c index 1222c8ea3c26..8154eaa2404f 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/kernel/power5+-pmu.c | |||
@@ -78,8 +78,8 @@ | |||
78 | * Layout of constraint bits: | 78 | * Layout of constraint bits: |
79 | * 6666555555555544444444443333333333222222222211111111110000000000 | 79 | * 6666555555555544444444443333333333222222222211111111110000000000 |
80 | * 3210987654321098765432109876543210987654321098765432109876543210 | 80 | * 3210987654321098765432109876543210987654321098765432109876543210 |
81 | * [ ><><>< ><> <><>[ > < >< >< >< ><><><><> | 81 | * [ ><><>< ><> <><>[ > < >< >< >< ><><><><><><> |
82 | * NC G0G1G2 G3 T0T1 UC B0 B1 B2 B3 P4P3P2P1 | 82 | * NC G0G1G2 G3 T0T1 UC B0 B1 B2 B3 P6P5P4P3P2P1 |
83 | * | 83 | * |
84 | * NC - number of counters | 84 | * NC - number of counters |
85 | * 51: NC error 0x0008_0000_0000_0000 | 85 | * 51: NC error 0x0008_0000_0000_0000 |
@@ -105,18 +105,18 @@ | |||
105 | * 30: IDU|GRS events needed 0x00_4000_0000 | 105 | * 30: IDU|GRS events needed 0x00_4000_0000 |
106 | * | 106 | * |
107 | * B0 | 107 | * B0 |
108 | * 20-23: Byte 0 event source 0x00f0_0000 | 108 | * 24-27: Byte 0 event source 0x0f00_0000 |
109 | * Encoding as for the event code | 109 | * Encoding as for the event code |
110 | * | 110 | * |
111 | * B1, B2, B3 | 111 | * B1, B2, B3 |
112 | * 16-19, 12-15, 8-11: Byte 1, 2, 3 event sources | 112 | * 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources |
113 | * | 113 | * |
114 | * P4 | 114 | * P6 |
115 | * 7: P1 error 0x80 | 115 | * 11: P6 error 0x800 |
116 | * 6-7: Count of events needing PMC4 | 116 | * 10-11: Count of events needing PMC6 |
117 | * | 117 | * |
118 | * P1..P3 | 118 | * P1..P5 |
119 | * 0-6: Count of events needing PMC1..PMC3 | 119 | * 0-9: Count of events needing PMC1..PMC5 |
120 | */ | 120 | */ |
121 | 121 | ||
122 | static const int grsel_shift[8] = { | 122 | static const int grsel_shift[8] = { |
@@ -143,11 +143,13 @@ static int power5p_get_constraint(unsigned int event, u64 *maskp, u64 *valp) | |||
143 | 143 | ||
144 | pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; | 144 | pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; |
145 | if (pmc) { | 145 | if (pmc) { |
146 | if (pmc > 4) | 146 | if (pmc > 6) |
147 | return -1; | 147 | return -1; |
148 | sh = (pmc - 1) * 2; | 148 | sh = (pmc - 1) * 2; |
149 | mask |= 2 << sh; | 149 | mask |= 2 << sh; |
150 | value |= 1 << sh; | 150 | value |= 1 << sh; |
151 | if (pmc >= 5 && !(event == 0x500009 || event == 0x600005)) | ||
152 | return -1; | ||
151 | } | 153 | } |
152 | if (event & PM_BUSEVENT_MSK) { | 154 | if (event & PM_BUSEVENT_MSK) { |
153 | unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK; | 155 | unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK; |
@@ -173,16 +175,26 @@ static int power5p_get_constraint(unsigned int event, u64 *maskp, u64 *valp) | |||
173 | value |= (u64)((event >> PM_GRS_SH) & fmask) << sh; | 175 | value |= (u64)((event >> PM_GRS_SH) & fmask) << sh; |
174 | } | 176 | } |
175 | /* Set byte lane select field */ | 177 | /* Set byte lane select field */ |
176 | mask |= 0xfULL << (20 - 4 * byte); | 178 | mask |= 0xfULL << (24 - 4 * byte); |
177 | value |= (u64)unit << (20 - 4 * byte); | 179 | value |= (u64)unit << (24 - 4 * byte); |
180 | } | ||
181 | if (pmc < 5) { | ||
182 | /* need a counter from PMC1-4 set */ | ||
183 | mask |= 0x8000000000000ull; | ||
184 | value |= 0x1000000000000ull; | ||
178 | } | 185 | } |
179 | mask |= 0x8000000000000ull; | ||
180 | value |= 0x1000000000000ull; | ||
181 | *maskp = mask; | 186 | *maskp = mask; |
182 | *valp = value; | 187 | *valp = value; |
183 | return 0; | 188 | return 0; |
184 | } | 189 | } |
185 | 190 | ||
191 | static int power5p_limited_pmc_event(unsigned int event) | ||
192 | { | ||
193 | int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; | ||
194 | |||
195 | return pmc == 5 || pmc == 6; | ||
196 | } | ||
197 | |||
186 | #define MAX_ALT 3 /* at most 3 alternatives for any event */ | 198 | #define MAX_ALT 3 /* at most 3 alternatives for any event */ |
187 | 199 | ||
188 | static const unsigned int event_alternatives[][MAX_ALT] = { | 200 | static const unsigned int event_alternatives[][MAX_ALT] = { |
@@ -193,6 +205,7 @@ static const unsigned int event_alternatives[][MAX_ALT] = { | |||
193 | { 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */ | 205 | { 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */ |
194 | { 0x800c4, 0xc20e0 }, /* PM_DTLB_MISS */ | 206 | { 0x800c4, 0xc20e0 }, /* PM_DTLB_MISS */ |
195 | { 0xc50c6, 0xc60e0 }, /* PM_MRK_DTLB_MISS */ | 207 | { 0xc50c6, 0xc60e0 }, /* PM_MRK_DTLB_MISS */ |
208 | { 0x100005, 0x600005 }, /* PM_RUN_CYC */ | ||
196 | { 0x100009, 0x200009 }, /* PM_INST_CMPL */ | 209 | { 0x100009, 0x200009 }, /* PM_INST_CMPL */ |
197 | { 0x200015, 0x300015 }, /* PM_LSU_LMQ_SRQ_EMPTY_CYC */ | 210 | { 0x200015, 0x300015 }, /* PM_LSU_LMQ_SRQ_EMPTY_CYC */ |
198 | { 0x300009, 0x400009 }, /* PM_INST_DISP */ | 211 | { 0x300009, 0x400009 }, /* PM_INST_DISP */ |
@@ -260,24 +273,85 @@ static int find_alternative_bdecode(unsigned int event) | |||
260 | return -1; | 273 | return -1; |
261 | } | 274 | } |
262 | 275 | ||
263 | static int power5p_get_alternatives(unsigned int event, unsigned int alt[]) | 276 | static int power5p_get_alternatives(unsigned int event, unsigned int flags, |
277 | unsigned int alt[]) | ||
264 | { | 278 | { |
265 | int i, j, ae, nalt = 1; | 279 | int i, j, ae, nalt = 1; |
280 | int nlim; | ||
266 | 281 | ||
267 | alt[0] = event; | 282 | alt[0] = event; |
268 | nalt = 1; | 283 | nalt = 1; |
284 | nlim = power5p_limited_pmc_event(event); | ||
269 | i = find_alternative(event); | 285 | i = find_alternative(event); |
270 | if (i >= 0) { | 286 | if (i >= 0) { |
271 | for (j = 0; j < MAX_ALT; ++j) { | 287 | for (j = 0; j < MAX_ALT; ++j) { |
272 | ae = event_alternatives[i][j]; | 288 | ae = event_alternatives[i][j]; |
273 | if (ae && ae != event) | 289 | if (ae && ae != event) |
274 | alt[nalt++] = ae; | 290 | alt[nalt++] = ae; |
291 | nlim += power5p_limited_pmc_event(ae); | ||
275 | } | 292 | } |
276 | } else { | 293 | } else { |
277 | ae = find_alternative_bdecode(event); | 294 | ae = find_alternative_bdecode(event); |
278 | if (ae > 0) | 295 | if (ae > 0) |
279 | alt[nalt++] = ae; | 296 | alt[nalt++] = ae; |
280 | } | 297 | } |
298 | |||
299 | if (flags & PPMU_ONLY_COUNT_RUN) { | ||
300 | /* | ||
301 | * We're only counting in RUN state, | ||
302 | * so PM_CYC is equivalent to PM_RUN_CYC | ||
303 | * and PM_INST_CMPL === PM_RUN_INST_CMPL. | ||
304 | * This doesn't include alternatives that don't provide | ||
305 | * any extra flexibility in assigning PMCs (e.g. | ||
306 | * 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC). | ||
307 | * Note that even with these additional alternatives | ||
308 | * we never end up with more than 3 alternatives for any event. | ||
309 | */ | ||
310 | j = nalt; | ||
311 | for (i = 0; i < nalt; ++i) { | ||
312 | switch (alt[i]) { | ||
313 | case 0xf: /* PM_CYC */ | ||
314 | alt[j++] = 0x600005; /* PM_RUN_CYC */ | ||
315 | ++nlim; | ||
316 | break; | ||
317 | case 0x600005: /* PM_RUN_CYC */ | ||
318 | alt[j++] = 0xf; | ||
319 | break; | ||
320 | case 0x100009: /* PM_INST_CMPL */ | ||
321 | alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */ | ||
322 | ++nlim; | ||
323 | break; | ||
324 | case 0x500009: /* PM_RUN_INST_CMPL */ | ||
325 | alt[j++] = 0x100009; /* PM_INST_CMPL */ | ||
326 | alt[j++] = 0x200009; | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | nalt = j; | ||
331 | } | ||
332 | |||
333 | if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) { | ||
334 | /* remove the limited PMC events */ | ||
335 | j = 0; | ||
336 | for (i = 0; i < nalt; ++i) { | ||
337 | if (!power5p_limited_pmc_event(alt[i])) { | ||
338 | alt[j] = alt[i]; | ||
339 | ++j; | ||
340 | } | ||
341 | } | ||
342 | nalt = j; | ||
343 | } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) { | ||
344 | /* remove all but the limited PMC events */ | ||
345 | j = 0; | ||
346 | for (i = 0; i < nalt; ++i) { | ||
347 | if (power5p_limited_pmc_event(alt[i])) { | ||
348 | alt[j] = alt[i]; | ||
349 | ++j; | ||
350 | } | ||
351 | } | ||
352 | nalt = j; | ||
353 | } | ||
354 | |||
281 | return nalt; | 355 | return nalt; |
282 | } | 356 | } |
283 | 357 | ||
@@ -390,7 +464,7 @@ static int power5p_compute_mmcr(unsigned int event[], int n_ev, | |||
390 | unsigned char unituse[16]; | 464 | unsigned char unituse[16]; |
391 | int ttmuse; | 465 | int ttmuse; |
392 | 466 | ||
393 | if (n_ev > 4) | 467 | if (n_ev > 6) |
394 | return -1; | 468 | return -1; |
395 | 469 | ||
396 | /* First pass to count resource use */ | 470 | /* First pass to count resource use */ |
@@ -399,7 +473,7 @@ static int power5p_compute_mmcr(unsigned int event[], int n_ev, | |||
399 | for (i = 0; i < n_ev; ++i) { | 473 | for (i = 0; i < n_ev; ++i) { |
400 | pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK; | 474 | pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK; |
401 | if (pmc) { | 475 | if (pmc) { |
402 | if (pmc > 4) | 476 | if (pmc > 6) |
403 | return -1; | 477 | return -1; |
404 | if (pmc_inuse & (1 << (pmc - 1))) | 478 | if (pmc_inuse & (1 << (pmc - 1))) |
405 | return -1; | 479 | return -1; |
@@ -488,13 +562,16 @@ static int power5p_compute_mmcr(unsigned int event[], int n_ev, | |||
488 | if (pmc >= 4) | 562 | if (pmc >= 4) |
489 | return -1; | 563 | return -1; |
490 | pmc_inuse |= 1 << pmc; | 564 | pmc_inuse |= 1 << pmc; |
491 | } else { | 565 | } else if (pmc <= 4) { |
492 | /* Direct event */ | 566 | /* Direct event */ |
493 | --pmc; | 567 | --pmc; |
494 | if (isbus && (byte & 2) && | 568 | if (isbus && (byte & 2) && |
495 | (psel == 8 || psel == 0x10 || psel == 0x28)) | 569 | (psel == 8 || psel == 0x10 || psel == 0x28)) |
496 | /* add events on higher-numbered bus */ | 570 | /* add events on higher-numbered bus */ |
497 | mmcr1 |= 1ull << (MMCR1_PMC1_ADDER_SEL_SH - pmc); | 571 | mmcr1 |= 1ull << (MMCR1_PMC1_ADDER_SEL_SH - pmc); |
572 | } else { | ||
573 | /* Instructions or run cycles on PMC5/6 */ | ||
574 | --pmc; | ||
498 | } | 575 | } |
499 | if (isbus && unit == PM_GRS) { | 576 | if (isbus && unit == PM_GRS) { |
500 | bit = psel & 7; | 577 | bit = psel & 7; |
@@ -538,7 +615,7 @@ static int power5p_generic_events[] = { | |||
538 | }; | 615 | }; |
539 | 616 | ||
540 | struct power_pmu power5p_pmu = { | 617 | struct power_pmu power5p_pmu = { |
541 | .n_counter = 4, | 618 | .n_counter = 6, |
542 | .max_alternatives = MAX_ALT, | 619 | .max_alternatives = MAX_ALT, |
543 | .add_fields = 0x7000000000055ull, | 620 | .add_fields = 0x7000000000055ull, |
544 | .test_adder = 0x3000040000000ull, | 621 | .test_adder = 0x3000040000000ull, |
@@ -548,4 +625,6 @@ struct power_pmu power5p_pmu = { | |||
548 | .disable_pmc = power5p_disable_pmc, | 625 | .disable_pmc = power5p_disable_pmc, |
549 | .n_generic = ARRAY_SIZE(power5p_generic_events), | 626 | .n_generic = ARRAY_SIZE(power5p_generic_events), |
550 | .generic_events = power5p_generic_events, | 627 | .generic_events = power5p_generic_events, |
628 | .limited_pmc5_6 = 1, | ||
629 | .limited_pmc_event = power5p_limited_pmc_event, | ||
551 | }; | 630 | }; |