diff options
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_p4.c')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_p4.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 3486e6660357..5d466b7d8609 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c | |||
@@ -1257,7 +1257,24 @@ again: | |||
1257 | pass++; | 1257 | pass++; |
1258 | goto again; | 1258 | goto again; |
1259 | } | 1259 | } |
1260 | 1260 | /* | |
1261 | * Perf does test runs to see if a whole group can be assigned | ||
1262 | * together succesfully. There can be multiple rounds of this. | ||
1263 | * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config | ||
1264 | * bits, such that the next round of group assignments will | ||
1265 | * cause the above p4_should_swap_ts to pass instead of fail. | ||
1266 | * This leads to counters exclusive to thread0 being used by | ||
1267 | * thread1. | ||
1268 | * | ||
1269 | * Solve this with a cheap hack, reset the idx back to -1 to | ||
1270 | * force a new lookup (p4_next_cntr) to get the right counter | ||
1271 | * for the right thread. | ||
1272 | * | ||
1273 | * This probably doesn't comply with the general spirit of how | ||
1274 | * perf wants to work, but P4 is special. :-( | ||
1275 | */ | ||
1276 | if (p4_should_swap_ts(hwc->config, cpu)) | ||
1277 | hwc->idx = -1; | ||
1261 | p4_pmu_swap_config_ts(hwc, cpu); | 1278 | p4_pmu_swap_config_ts(hwc, cpu); |
1262 | if (assign) | 1279 | if (assign) |
1263 | assign[i] = cntr_idx; | 1280 | assign[i] = cntr_idx; |
@@ -1322,6 +1339,7 @@ static __initconst const struct x86_pmu p4_pmu = { | |||
1322 | __init int p4_pmu_init(void) | 1339 | __init int p4_pmu_init(void) |
1323 | { | 1340 | { |
1324 | unsigned int low, high; | 1341 | unsigned int low, high; |
1342 | int i, reg; | ||
1325 | 1343 | ||
1326 | /* If we get stripped -- indexing fails */ | 1344 | /* If we get stripped -- indexing fails */ |
1327 | BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC); | 1345 | BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC); |
@@ -1340,5 +1358,19 @@ __init int p4_pmu_init(void) | |||
1340 | 1358 | ||
1341 | x86_pmu = p4_pmu; | 1359 | x86_pmu = p4_pmu; |
1342 | 1360 | ||
1361 | /* | ||
1362 | * Even though the counters are configured to interrupt a particular | ||
1363 | * logical processor when an overflow happens, testing has shown that | ||
1364 | * on kdump kernels (which uses a single cpu), thread1's counter | ||
1365 | * continues to run and will report an NMI on thread0. Due to the | ||
1366 | * overflow bug, this leads to a stream of unknown NMIs. | ||
1367 | * | ||
1368 | * Solve this by zero'ing out the registers to mimic a reset. | ||
1369 | */ | ||
1370 | for (i = 0; i < x86_pmu.num_counters; i++) { | ||
1371 | reg = x86_pmu_config_addr(i); | ||
1372 | wrmsrl_safe(reg, 0ULL); | ||
1373 | } | ||
1374 | |||
1343 | return 0; | 1375 | return 0; |
1344 | } | 1376 | } |