diff options
author | Peter Zijlstra <peterz@infradead.org> | 2014-02-05 14:48:51 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-02-09 07:08:24 -0500 |
commit | e97df76377b8b3b1f7dfd5d6f8a1d5a31438b140 (patch) | |
tree | cd326431ed849d6778b31990970b8fcafac71a2c /arch | |
parent | 2737fce8bc8dea2852289df29b4f92e6a7fb7c91 (diff) |
perf/x86/intel/p6: Add userspace RDPMC quirk for PPro
PPro machines can die hard when PCE gets enabled due to a CPU erratum.
The safe way it so disable it by default and keep it disabled.
See erratum 26 in:
http://download.intel.com/design/archives/processors/pro/docs/24268935.pdf
Reported-and-Tested-by: Mark Davies <junk@eslaf.co.uk>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Stephane Eranian <eranian@google.com>
Cc: Vince Weaver <vince@deater.net>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140206170815.GW2936@laptop.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_p6.c | 48 |
3 files changed, 39 insertions, 16 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index b88645191fe5..1246b853c4e0 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1521,6 +1521,8 @@ static int __init init_hw_perf_events(void) | |||
1521 | 1521 | ||
1522 | pr_cont("%s PMU driver.\n", x86_pmu.name); | 1522 | pr_cont("%s PMU driver.\n", x86_pmu.name); |
1523 | 1523 | ||
1524 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | ||
1525 | |||
1524 | for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) | 1526 | for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) |
1525 | quirk->func(); | 1527 | quirk->func(); |
1526 | 1528 | ||
@@ -1534,7 +1536,6 @@ static int __init init_hw_perf_events(void) | |||
1534 | __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, | 1536 | __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, |
1535 | 0, x86_pmu.num_counters, 0, 0); | 1537 | 0, x86_pmu.num_counters, 0, 0); |
1536 | 1538 | ||
1537 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | ||
1538 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; | 1539 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; |
1539 | 1540 | ||
1540 | if (x86_pmu.event_attrs) | 1541 | if (x86_pmu.event_attrs) |
@@ -1820,6 +1821,9 @@ static ssize_t set_attr_rdpmc(struct device *cdev, | |||
1820 | if (ret) | 1821 | if (ret) |
1821 | return ret; | 1822 | return ret; |
1822 | 1823 | ||
1824 | if (x86_pmu.attr_rdpmc_broken) | ||
1825 | return -ENOTSUPP; | ||
1826 | |||
1823 | if (!!val != !!x86_pmu.attr_rdpmc) { | 1827 | if (!!val != !!x86_pmu.attr_rdpmc) { |
1824 | x86_pmu.attr_rdpmc = !!val; | 1828 | x86_pmu.attr_rdpmc = !!val; |
1825 | smp_call_function(change_rdpmc, (void *)val, 1); | 1829 | smp_call_function(change_rdpmc, (void *)val, 1); |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index c1a861829d81..4972c244d0bc 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -409,6 +409,7 @@ struct x86_pmu { | |||
409 | /* | 409 | /* |
410 | * sysfs attrs | 410 | * sysfs attrs |
411 | */ | 411 | */ |
412 | int attr_rdpmc_broken; | ||
412 | int attr_rdpmc; | 413 | int attr_rdpmc; |
413 | struct attribute **format_attrs; | 414 | struct attribute **format_attrs; |
414 | struct attribute **event_attrs; | 415 | struct attribute **event_attrs; |
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c index b1e2fe115323..7c1a0c07b607 100644 --- a/arch/x86/kernel/cpu/perf_event_p6.c +++ b/arch/x86/kernel/cpu/perf_event_p6.c | |||
@@ -231,31 +231,49 @@ static __initconst const struct x86_pmu p6_pmu = { | |||
231 | 231 | ||
232 | }; | 232 | }; |
233 | 233 | ||
234 | static __init void p6_pmu_rdpmc_quirk(void) | ||
235 | { | ||
236 | if (boot_cpu_data.x86_mask < 9) { | ||
237 | /* | ||
238 | * PPro erratum 26; fixed in stepping 9 and above. | ||
239 | */ | ||
240 | pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n"); | ||
241 | x86_pmu.attr_rdpmc_broken = 1; | ||
242 | x86_pmu.attr_rdpmc = 0; | ||
243 | } | ||
244 | } | ||
245 | |||
234 | __init int p6_pmu_init(void) | 246 | __init int p6_pmu_init(void) |
235 | { | 247 | { |
248 | x86_pmu = p6_pmu; | ||
249 | |||
236 | switch (boot_cpu_data.x86_model) { | 250 | switch (boot_cpu_data.x86_model) { |
237 | case 1: | 251 | case 1: /* Pentium Pro */ |
238 | case 3: /* Pentium Pro */ | 252 | x86_add_quirk(p6_pmu_rdpmc_quirk); |
239 | case 5: | 253 | break; |
240 | case 6: /* Pentium II */ | 254 | |
241 | case 7: | 255 | case 3: /* Pentium II - Klamath */ |
242 | case 8: | 256 | case 5: /* Pentium II - Deschutes */ |
243 | case 11: /* Pentium III */ | 257 | case 6: /* Pentium II - Mendocino */ |
244 | case 9: | ||
245 | case 13: | ||
246 | /* Pentium M */ | ||
247 | break; | 258 | break; |
259 | |||
260 | case 7: /* Pentium III - Katmai */ | ||
261 | case 8: /* Pentium III - Coppermine */ | ||
262 | case 10: /* Pentium III Xeon */ | ||
263 | case 11: /* Pentium III - Tualatin */ | ||
264 | break; | ||
265 | |||
266 | case 9: /* Pentium M - Banias */ | ||
267 | case 13: /* Pentium M - Dothan */ | ||
268 | break; | ||
269 | |||
248 | default: | 270 | default: |
249 | pr_cont("unsupported p6 CPU model %d ", | 271 | pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model); |
250 | boot_cpu_data.x86_model); | ||
251 | return -ENODEV; | 272 | return -ENODEV; |
252 | } | 273 | } |
253 | 274 | ||
254 | x86_pmu = p6_pmu; | ||
255 | |||
256 | memcpy(hw_cache_event_ids, p6_hw_cache_event_ids, | 275 | memcpy(hw_cache_event_ids, p6_hw_cache_event_ids, |
257 | sizeof(hw_cache_event_ids)); | 276 | sizeof(hw_cache_event_ids)); |
258 | 277 | ||
259 | |||
260 | return 0; | 278 | return 0; |
261 | } | 279 | } |