aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/perf
diff options
context:
space:
mode:
authorMichael Ellerman <mpe@ellerman.id.au>2014-07-23 07:12:38 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-07-28 00:30:58 -0400
commit9de5cb0f6df83243c58b2d1e3754a3c237d954ff (patch)
tree4bb6c4fd36e681ab5059bafc9ee6a4bf33b3b3bf /arch/powerpc/perf
parent8abd818fc76705065f3699a753ad2df594dafe86 (diff)
powerpc/perf: Add per-event excludes on Power8
Power8 has a new register (MMCR2), which contains individual freeze bits for each counter. This is an improvement on previous chips as it means we can have multiple events on the PMU at the same time with different exclude_{user,kernel,hv} settings. Previously we had to ensure all events on the PMU had the same exclude settings. The core of the patch is fairly simple. We use the 207S feature flag to indicate that the PMU backend supports per-event excludes, if it's set we skip the generic logic that enforces the equality of excludes between events. We also use that flag to skip setting the freeze bits in MMCR0, the PMU backend is expected to have handled setting them in MMCR2. The complication arises with EBB. The FCxP bits in MMCR2 are accessible R/W to a task using EBB. Which means a task using EBB will be able to see that we are using MMCR2 for freezing, whereas the old logic which used MMCR0 is not user visible. The task can not see or affect exclude_kernel & exclude_hv, so we only need to consider exclude_user. The table below summarises the behaviour both before and after this commit is applied: exclude_user true false ------------------------------------ | User visible | N N Before | Can freeze | Y Y | Can unfreeze | N Y ------------------------------------ | User visible | Y Y After | Can freeze | Y Y | Can unfreeze | Y/N Y ------------------------------------ So firstly I assert that the simple visibility of the exclude_user setting in MMCR2 is a non-issue. The event belongs to the task, and was most likely created by the task. So the exclude_user setting is not privileged information in any way. Secondly, the behaviour in the exclude_user = false case is unchanged. This is important as it is the case that is actually useful, ie. the event is created with no exclude setting and the task uses MMCR2 to implement exclusion manually. For exclude_user = true there is no meaningful change to freezing the event. Previously the task could use MMCR2 to freeze the event, though it was already frozen with MMCR0. With the new code the task can use MMCR2 to freeze the event, though it was already frozen with MMCR2. The only real change is when exclude_user = true and the task tries to use MMCR2 to unfreeze the event. Previously this had no effect, because the event was already frozen in MMCR0. With the new code the task can unfreeze the event in MMCR2, but at some indeterminate time in the future the kernel will overwrite its setting and refreeze the event. Therefore my final assertion is that any task using exclude_user = true and also fiddling with MMCR2 was deeply confused before this change, and remains so after it. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/perf')
-rw-r--r--arch/powerpc/perf/core-book3s.c67
-rw-r--r--arch/powerpc/perf/power8-pmu.c24
2 files changed, 67 insertions, 24 deletions
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 01b30238d7d1..b7cd00b0171e 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -36,7 +36,12 @@ struct cpu_hw_events {
36 struct perf_event *event[MAX_HWEVENTS]; 36 struct perf_event *event[MAX_HWEVENTS];
37 u64 events[MAX_HWEVENTS]; 37 u64 events[MAX_HWEVENTS];
38 unsigned int flags[MAX_HWEVENTS]; 38 unsigned int flags[MAX_HWEVENTS];
39 unsigned long mmcr[3]; 39 /*
40 * The order of the MMCR array is:
41 * - 64-bit, MMCR0, MMCR1, MMCRA, MMCR2
42 * - 32-bit, MMCR0, MMCR1, MMCR2
43 */
44 unsigned long mmcr[4];
40 struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS]; 45 struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
41 u8 limited_hwidx[MAX_LIMITED_HWCOUNTERS]; 46 u8 limited_hwidx[MAX_LIMITED_HWCOUNTERS];
42 u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; 47 u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
@@ -112,9 +117,9 @@ static bool is_ebb_event(struct perf_event *event) { return false; }
112static int ebb_event_check(struct perf_event *event) { return 0; } 117static int ebb_event_check(struct perf_event *event) { return 0; }
113static void ebb_event_add(struct perf_event *event) { } 118static void ebb_event_add(struct perf_event *event) { }
114static void ebb_switch_out(unsigned long mmcr0) { } 119static void ebb_switch_out(unsigned long mmcr0) { }
115static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0) 120static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw)
116{ 121{
117 return mmcr0; 122 return cpuhw->mmcr[0];
118} 123}
119 124
120static inline void power_pmu_bhrb_enable(struct perf_event *event) {} 125static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
@@ -542,8 +547,10 @@ static void ebb_switch_out(unsigned long mmcr0)
542 current->thread.mmcr2 = mfspr(SPRN_MMCR2) & MMCR2_USER_MASK; 547 current->thread.mmcr2 = mfspr(SPRN_MMCR2) & MMCR2_USER_MASK;
543} 548}
544 549
545static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0) 550static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw)
546{ 551{
552 unsigned long mmcr0 = cpuhw->mmcr[0];
553
547 if (!ebb) 554 if (!ebb)
548 goto out; 555 goto out;
549 556
@@ -568,7 +575,15 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
568 mtspr(SPRN_SIAR, current->thread.siar); 575 mtspr(SPRN_SIAR, current->thread.siar);
569 mtspr(SPRN_SIER, current->thread.sier); 576 mtspr(SPRN_SIER, current->thread.sier);
570 mtspr(SPRN_SDAR, current->thread.sdar); 577 mtspr(SPRN_SDAR, current->thread.sdar);
571 mtspr(SPRN_MMCR2, current->thread.mmcr2); 578
579 /*
580 * Merge the kernel & user values of MMCR2. The semantics we implement
581 * are that the user MMCR2 can set bits, ie. cause counters to freeze,
582 * but not clear bits. If a task wants to be able to clear bits, ie.
583 * unfreeze counters, it should not set exclude_xxx in its events and
584 * instead manage the MMCR2 entirely by itself.
585 */
586 mtspr(SPRN_MMCR2, cpuhw->mmcr[3] | current->thread.mmcr2);
572out: 587out:
573 return mmcr0; 588 return mmcr0;
574} 589}
@@ -915,6 +930,14 @@ static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
915 int i, n, first; 930 int i, n, first;
916 struct perf_event *event; 931 struct perf_event *event;
917 932
933 /*
934 * If the PMU we're on supports per event exclude settings then we
935 * don't need to do any of this logic. NB. This assumes no PMU has both
936 * per event exclude and limited PMCs.
937 */
938 if (ppmu->flags & PPMU_ARCH_207S)
939 return 0;
940
918 n = n_prev + n_new; 941 n = n_prev + n_new;
919 if (n <= 1) 942 if (n <= 1)
920 return 0; 943 return 0;
@@ -1230,19 +1253,20 @@ static void power_pmu_enable(struct pmu *pmu)
1230 goto out; 1253 goto out;
1231 } 1254 }
1232 1255
1233 /* 1256 if (!(ppmu->flags & PPMU_ARCH_207S)) {
1234 * Add in MMCR0 freeze bits corresponding to the 1257 /*
1235 * attr.exclude_* bits for the first event. 1258 * Add in MMCR0 freeze bits corresponding to the attr.exclude_*
1236 * We have already checked that all events have the 1259 * bits for the first event. We have already checked that all
1237 * same values for these bits as the first event. 1260 * events have the same value for these bits as the first event.
1238 */ 1261 */
1239 event = cpuhw->event[0]; 1262 event = cpuhw->event[0];
1240 if (event->attr.exclude_user) 1263 if (event->attr.exclude_user)
1241 cpuhw->mmcr[0] |= MMCR0_FCP; 1264 cpuhw->mmcr[0] |= MMCR0_FCP;
1242 if (event->attr.exclude_kernel) 1265 if (event->attr.exclude_kernel)
1243 cpuhw->mmcr[0] |= freeze_events_kernel; 1266 cpuhw->mmcr[0] |= freeze_events_kernel;
1244 if (event->attr.exclude_hv) 1267 if (event->attr.exclude_hv)
1245 cpuhw->mmcr[0] |= MMCR0_FCHV; 1268 cpuhw->mmcr[0] |= MMCR0_FCHV;
1269 }
1246 1270
1247 /* 1271 /*
1248 * Write the new configuration to MMCR* with the freeze 1272 * Write the new configuration to MMCR* with the freeze
@@ -1254,6 +1278,8 @@ static void power_pmu_enable(struct pmu *pmu)
1254 mtspr(SPRN_MMCR1, cpuhw->mmcr[1]); 1278 mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
1255 mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)) 1279 mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
1256 | MMCR0_FC); 1280 | MMCR0_FC);
1281 if (ppmu->flags & PPMU_ARCH_207S)
1282 mtspr(SPRN_MMCR2, cpuhw->mmcr[3]);
1257 1283
1258 /* 1284 /*
1259 * Read off any pre-existing events that need to move 1285 * Read off any pre-existing events that need to move
@@ -1309,10 +1335,7 @@ static void power_pmu_enable(struct pmu *pmu)
1309 out_enable: 1335 out_enable:
1310 pmao_restore_workaround(ebb); 1336 pmao_restore_workaround(ebb);
1311 1337
1312 if (ppmu->flags & PPMU_ARCH_207S) 1338 mmcr0 = ebb_switch_in(ebb, cpuhw);
1313 mtspr(SPRN_MMCR2, 0);
1314
1315 mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
1316 1339
1317 mb(); 1340 mb();
1318 if (cpuhw->bhrb_users) 1341 if (cpuhw->bhrb_users)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 19bbddf495dd..396351db601b 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/perf_event.h> 16#include <linux/perf_event.h>
17#include <asm/firmware.h> 17#include <asm/firmware.h>
18#include <asm/cputable.h>
18 19
19 20
20/* 21/*
@@ -266,6 +267,11 @@
266#define MMCRA_SDAR_MODE_TLB (1ull << 42) 267#define MMCRA_SDAR_MODE_TLB (1ull << 42)
267#define MMCRA_IFM_SHIFT 30 268#define MMCRA_IFM_SHIFT 30
268 269
270/* Bits in MMCR2 for POWER8 */
271#define MMCR2_FCS(pmc) (1ull << (63 - (((pmc) - 1) * 9)))
272#define MMCR2_FCP(pmc) (1ull << (62 - (((pmc) - 1) * 9)))
273#define MMCR2_FCH(pmc) (1ull << (57 - (((pmc) - 1) * 9)))
274
269 275
270static inline bool event_is_fab_match(u64 event) 276static inline bool event_is_fab_match(u64 event)
271{ 277{
@@ -396,7 +402,7 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
396 unsigned int hwc[], unsigned long mmcr[], 402 unsigned int hwc[], unsigned long mmcr[],
397 struct perf_event *pevents[]) 403 struct perf_event *pevents[])
398{ 404{
399 unsigned long mmcra, mmcr1, unit, combine, psel, cache, val; 405 unsigned long mmcra, mmcr1, mmcr2, unit, combine, psel, cache, val;
400 unsigned int pmc, pmc_inuse; 406 unsigned int pmc, pmc_inuse;
401 int i; 407 int i;
402 408
@@ -411,7 +417,7 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
411 417
412 /* In continous sampling mode, update SDAR on TLB miss */ 418 /* In continous sampling mode, update SDAR on TLB miss */
413 mmcra = MMCRA_SDAR_MODE_TLB; 419 mmcra = MMCRA_SDAR_MODE_TLB;
414 mmcr1 = 0; 420 mmcr1 = mmcr2 = 0;
415 421
416 /* Second pass: assign PMCs, set all MMCR1 fields */ 422 /* Second pass: assign PMCs, set all MMCR1 fields */
417 for (i = 0; i < n_ev; ++i) { 423 for (i = 0; i < n_ev; ++i) {
@@ -473,6 +479,19 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
473 mmcra |= val << MMCRA_IFM_SHIFT; 479 mmcra |= val << MMCRA_IFM_SHIFT;
474 } 480 }
475 481
482 if (pevents[i]->attr.exclude_user)
483 mmcr2 |= MMCR2_FCP(pmc);
484
485 if (pevents[i]->attr.exclude_hv)
486 mmcr2 |= MMCR2_FCH(pmc);
487
488 if (pevents[i]->attr.exclude_kernel) {
489 if (cpu_has_feature(CPU_FTR_HVMODE))
490 mmcr2 |= MMCR2_FCH(pmc);
491 else
492 mmcr2 |= MMCR2_FCS(pmc);
493 }
494
476 hwc[i] = pmc - 1; 495 hwc[i] = pmc - 1;
477 } 496 }
478 497
@@ -492,6 +511,7 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
492 511
493 mmcr[1] = mmcr1; 512 mmcr[1] = mmcr1;
494 mmcr[2] = mmcra; 513 mmcr[2] = mmcra;
514 mmcr[3] = mmcr2;
495 515
496 return 0; 516 return 0;
497} 517}