diff options
| author | Yan, Zheng <zheng.z.yan@intel.com> | 2012-08-06 01:11:21 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2012-08-13 13:01:03 -0400 |
| commit | ebb6cc03596cc89c89670473282ea46573feb34f (patch) | |
| tree | 2e045ae53633e0777a1ba73d934cfc357d7e5e88 | |
| parent | cffa59baa5f1cf3e3e9e172697db48912471531c (diff) | |
perf/x86: Fixes for Nehalem-EX uncore driver
This patch includes following fixes and update:
- Only some events in the Sbox and Mbox can use the match/mask
registers, add code to check this.
- The format definitions for xbr_mm_cfg and xbr_match registers
in the Rbox are wrong, xbr_mm_cfg should use 32 bits, xbr_match
should use 64 bits.
- Cleanup the Rbox code. Compute the addresses extra registers in
the enable_event function instead of the hw_config function.
This simplifies the code in nhmex_rbox_alter_er().
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1344229882-3907-2-git-send-email-zheng.z.yan@intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore.c | 195 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore.h | 1 |
2 files changed, 87 insertions, 109 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index a7ccd68aa13a..84434e2a676f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |||
| @@ -796,7 +796,6 @@ static struct intel_uncore_type *nhm_msr_uncores[] = { | |||
| 796 | 796 | ||
| 797 | DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); | 797 | DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); |
| 798 | DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); | 798 | DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); |
| 799 | DEFINE_UNCORE_FORMAT_ATTR(mm_cfg, mm_cfg, "config:63"); | ||
| 800 | DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63"); | 799 | DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63"); |
| 801 | DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63"); | 800 | DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63"); |
| 802 | 801 | ||
| @@ -1032,24 +1031,22 @@ static struct intel_uncore_type nhmex_uncore_bbox = { | |||
| 1032 | 1031 | ||
| 1033 | static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) | 1032 | static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) |
| 1034 | { | 1033 | { |
| 1035 | struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; | 1034 | struct hw_perf_event *hwc = &event->hw; |
| 1036 | struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; | 1035 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; |
| 1036 | struct hw_perf_event_extra *reg2 = &hwc->branch_reg; | ||
| 1037 | 1037 | ||
| 1038 | if (event->attr.config & NHMEX_S_PMON_MM_CFG_EN) { | 1038 | /* only TO_R_PROG_EV event uses the match/mask register */ |
| 1039 | reg1->config = event->attr.config1; | 1039 | if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) != |
| 1040 | reg2->config = event->attr.config2; | 1040 | NHMEX_S_EVENT_TO_R_PROG_EV) |
| 1041 | } else { | 1041 | return 0; |
| 1042 | reg1->config = ~0ULL; | ||
| 1043 | reg2->config = ~0ULL; | ||
| 1044 | } | ||
| 1045 | 1042 | ||
| 1046 | if (box->pmu->pmu_idx == 0) | 1043 | if (box->pmu->pmu_idx == 0) |
| 1047 | reg1->reg = NHMEX_S0_MSR_MM_CFG; | 1044 | reg1->reg = NHMEX_S0_MSR_MM_CFG; |
| 1048 | else | 1045 | else |
| 1049 | reg1->reg = NHMEX_S1_MSR_MM_CFG; | 1046 | reg1->reg = NHMEX_S1_MSR_MM_CFG; |
| 1050 | |||
| 1051 | reg1->idx = 0; | 1047 | reg1->idx = 0; |
| 1052 | 1048 | reg1->config = event->attr.config1; | |
| 1049 | reg2->config = event->attr.config2; | ||
| 1053 | return 0; | 1050 | return 0; |
| 1054 | } | 1051 | } |
| 1055 | 1052 | ||
| @@ -1059,8 +1056,8 @@ static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct per | |||
| 1059 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; | 1056 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; |
| 1060 | struct hw_perf_event_extra *reg2 = &hwc->branch_reg; | 1057 | struct hw_perf_event_extra *reg2 = &hwc->branch_reg; |
| 1061 | 1058 | ||
| 1062 | wrmsrl(reg1->reg, 0); | 1059 | if (reg1->idx != EXTRA_REG_NONE) { |
| 1063 | if (reg1->config != ~0ULL || reg2->config != ~0ULL) { | 1060 | wrmsrl(reg1->reg, 0); |
| 1064 | wrmsrl(reg1->reg + 1, reg1->config); | 1061 | wrmsrl(reg1->reg + 1, reg1->config); |
| 1065 | wrmsrl(reg1->reg + 2, reg2->config); | 1062 | wrmsrl(reg1->reg + 2, reg2->config); |
| 1066 | wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN); | 1063 | wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN); |
| @@ -1074,7 +1071,6 @@ static struct attribute *nhmex_uncore_sbox_formats_attr[] = { | |||
| 1074 | &format_attr_edge.attr, | 1071 | &format_attr_edge.attr, |
| 1075 | &format_attr_inv.attr, | 1072 | &format_attr_inv.attr, |
| 1076 | &format_attr_thresh8.attr, | 1073 | &format_attr_thresh8.attr, |
| 1077 | &format_attr_mm_cfg.attr, | ||
| 1078 | &format_attr_match.attr, | 1074 | &format_attr_match.attr, |
| 1079 | &format_attr_mask.attr, | 1075 | &format_attr_mask.attr, |
| 1080 | NULL, | 1076 | NULL, |
| @@ -1264,7 +1260,8 @@ again: | |||
| 1264 | } | 1260 | } |
| 1265 | 1261 | ||
| 1266 | /* for the match/mask registers */ | 1262 | /* for the match/mask registers */ |
| 1267 | if ((uncore_box_is_fake(box) || !reg2->alloc) && | 1263 | if (reg2->idx != EXTRA_REG_NONE && |
| 1264 | (uncore_box_is_fake(box) || !reg2->alloc) && | ||
| 1268 | !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config)) | 1265 | !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config)) |
| 1269 | goto fail; | 1266 | goto fail; |
| 1270 | 1267 | ||
| @@ -1278,7 +1275,8 @@ again: | |||
| 1278 | if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) | 1275 | if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) |
| 1279 | nhmex_mbox_alter_er(event, idx[0], true); | 1276 | nhmex_mbox_alter_er(event, idx[0], true); |
| 1280 | reg1->alloc |= alloc; | 1277 | reg1->alloc |= alloc; |
| 1281 | reg2->alloc = 1; | 1278 | if (reg2->idx != EXTRA_REG_NONE) |
| 1279 | reg2->alloc = 1; | ||
| 1282 | } | 1280 | } |
| 1283 | return NULL; | 1281 | return NULL; |
| 1284 | fail: | 1282 | fail: |
| @@ -1342,9 +1340,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event | |||
| 1342 | struct extra_reg *er; | 1340 | struct extra_reg *er; |
| 1343 | unsigned msr; | 1341 | unsigned msr; |
| 1344 | int reg_idx = 0; | 1342 | int reg_idx = 0; |
| 1345 | |||
| 1346 | if (WARN_ON_ONCE(reg1->idx != -1)) | ||
| 1347 | return -EINVAL; | ||
| 1348 | /* | 1343 | /* |
| 1349 | * The mbox events may require 2 extra MSRs at the most. But only | 1344 | * The mbox events may require 2 extra MSRs at the most. But only |
| 1350 | * the lower 32 bits in these MSRs are significant, so we can use | 1345 | * the lower 32 bits in these MSRs are significant, so we can use |
| @@ -1355,11 +1350,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event | |||
| 1355 | continue; | 1350 | continue; |
| 1356 | if (event->attr.config1 & ~er->valid_mask) | 1351 | if (event->attr.config1 & ~er->valid_mask) |
| 1357 | return -EINVAL; | 1352 | return -EINVAL; |
| 1358 | if (er->idx == __BITS_VALUE(reg1->idx, 0, 8) || | ||
| 1359 | er->idx == __BITS_VALUE(reg1->idx, 1, 8)) | ||
| 1360 | continue; | ||
| 1361 | if (WARN_ON_ONCE(reg_idx >= 2)) | ||
| 1362 | return -EINVAL; | ||
| 1363 | 1353 | ||
| 1364 | msr = er->msr + type->msr_offset * box->pmu->pmu_idx; | 1354 | msr = er->msr + type->msr_offset * box->pmu->pmu_idx; |
| 1365 | if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff)) | 1355 | if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff)) |
| @@ -1368,6 +1358,8 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event | |||
| 1368 | /* always use the 32~63 bits to pass the PLD config */ | 1358 | /* always use the 32~63 bits to pass the PLD config */ |
| 1369 | if (er->idx == EXTRA_REG_NHMEX_M_PLD) | 1359 | if (er->idx == EXTRA_REG_NHMEX_M_PLD) |
| 1370 | reg_idx = 1; | 1360 | reg_idx = 1; |
| 1361 | else if (WARN_ON_ONCE(reg_idx > 0)) | ||
| 1362 | return -EINVAL; | ||
| 1371 | 1363 | ||
| 1372 | reg1->idx &= ~(0xff << (reg_idx * 8)); | 1364 | reg1->idx &= ~(0xff << (reg_idx * 8)); |
| 1373 | reg1->reg &= ~(0xffff << (reg_idx * 16)); | 1365 | reg1->reg &= ~(0xffff << (reg_idx * 16)); |
| @@ -1376,17 +1368,21 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event | |||
| 1376 | reg1->config = event->attr.config1; | 1368 | reg1->config = event->attr.config1; |
| 1377 | reg_idx++; | 1369 | reg_idx++; |
| 1378 | } | 1370 | } |
| 1379 | /* use config2 to pass the filter config */ | 1371 | /* |
| 1380 | reg2->idx = EXTRA_REG_NHMEX_M_FILTER; | 1372 | * The mbox only provides ability to perform address matching |
| 1381 | if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN) | 1373 | * for the PLD events. |
| 1382 | reg2->config = event->attr.config2; | 1374 | */ |
| 1383 | else | 1375 | if (reg_idx == 2) { |
| 1384 | reg2->config = ~0ULL; | 1376 | reg2->idx = EXTRA_REG_NHMEX_M_FILTER; |
| 1385 | if (box->pmu->pmu_idx == 0) | 1377 | if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN) |
| 1386 | reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG; | 1378 | reg2->config = event->attr.config2; |
| 1387 | else | 1379 | else |
| 1388 | reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG; | 1380 | reg2->config = ~0ULL; |
| 1389 | 1381 | if (box->pmu->pmu_idx == 0) | |
| 1382 | reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG; | ||
| 1383 | else | ||
| 1384 | reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG; | ||
| 1385 | } | ||
| 1390 | return 0; | 1386 | return 0; |
| 1391 | } | 1387 | } |
| 1392 | 1388 | ||
| @@ -1422,34 +1418,36 @@ static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct per | |||
