aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event_intel.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2014-11-17 14:07:04 -0500
committerIngo Molnar <mingo@kernel.org>2015-04-02 11:33:15 -0400
commitb37609c30e41264c4df4acff78abfc894499a49b (patch)
tree4b7d2a6af573999133bfe9a9aecbc7d1df3d1dbe /arch/x86/kernel/cpu/perf_event_intel.c
parentb3738d29323344da3017a91010530cf3a58590fc (diff)
perf/x86/intel: Make the HT bug workaround conditional on HT enabled
This patch disables the PMU HT bug when Hyperthreading (HT) is disabled. We cannot do this test immediately when perf_events is initialized. We need to wait until the topology information is setup properly. As such, we register a later initcall, check the topology and potentially disable the workaround. To do this, we need to ensure there is no user of the PMU. At this point of the boot, the only user is the NMI watchdog, thus we disable it during the switch and re-enable it right after. Having the workaround disabled when it is not needed provides some benefits by limiting the overhead is time and space. The workaround still ensures correct scheduling of the corrupting memory events (0xd0, 0xd1, 0xd2) when HT is off. Those events can only be measured on counters 0-3. Something else the current kernel did not handle correctly. Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: bp@alien8.de Cc: jolsa@redhat.com Cc: kan.liang@intel.com Cc: maria.n.dimakopoulou@gmail.com Link: http://lkml.kernel.org/r/1416251225-17721-13-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_intel.c')
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c95
1 files changed, 74 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 4187d3f4ed12..6ea61a572fb0 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -12,6 +12,7 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/export.h> 14#include <linux/export.h>
15#include <linux/watchdog.h>
15 16
16#include <asm/cpufeature.h> 17#include <asm/cpufeature.h>
17#include <asm/hardirq.h> 18#include <asm/hardirq.h>
@@ -1885,8 +1886,9 @@ intel_start_scheduling(struct cpu_hw_events *cpuc)
1885 /* 1886 /*
1886 * nothing needed if in group validation mode 1887 * nothing needed if in group validation mode
1887 */ 1888 */
1888 if (cpuc->is_fake) 1889 if (cpuc->is_fake || !is_ht_workaround_enabled())
1889 return; 1890 return;
1891
1890 /* 1892 /*
1891 * no exclusion needed 1893 * no exclusion needed
1892 */ 1894 */
@@ -1923,7 +1925,7 @@ intel_stop_scheduling(struct cpu_hw_events *cpuc)
1923 /* 1925 /*
1924 * nothing needed if in group validation mode 1926 * nothing needed if in group validation mode
1925 */ 1927 */
1926 if (cpuc->is_fake) 1928 if (cpuc->is_fake || !is_ht_workaround_enabled())
1927 return; 1929 return;
1928 /* 1930 /*
1929 * no exclusion needed 1931 * no exclusion needed
@@ -1961,7 +1963,13 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
1961 * validating a group does not require 1963 * validating a group does not require
1962 * enforcing cross-thread exclusion 1964 * enforcing cross-thread exclusion
1963 */ 1965 */
1964 if (cpuc->is_fake) 1966 if (cpuc->is_fake || !is_ht_workaround_enabled())
1967 return c;
1968
1969 /*
1970 * no exclusion needed
1971 */
1972 if (!excl_cntrs)
1965 return c; 1973 return c;
1966 /* 1974 /*
1967 * event requires exclusive counter access 1975 * event requires exclusive counter access
@@ -2658,18 +2666,11 @@ static void intel_pmu_cpu_starting(int cpu)
2658 } 2666 }
2659} 2667}
2660 2668
2661static void intel_pmu_cpu_dying(int cpu) 2669static void free_excl_cntrs(int cpu)
2662{ 2670{
2663 struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); 2671 struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
2664 struct intel_shared_regs *pc;
2665 struct intel_excl_cntrs *c; 2672 struct intel_excl_cntrs *c;
2666 2673
2667 pc = cpuc->shared_regs;
2668 if (pc) {
2669 if (pc->core_id == -1 || --pc->refcnt == 0)
2670 kfree(pc);
2671 cpuc->shared_regs = NULL;
2672 }
2673 c = cpuc->excl_cntrs; 2674 c = cpuc->excl_cntrs;
2674 if (c) { 2675 if (c) {
2675 if (c->core_id == -1 || --c->refcnt == 0) 2676 if (c->core_id == -1 || --c->refcnt == 0)
@@ -2678,14 +2679,22 @@ static void intel_pmu_cpu_dying(int cpu)
2678 kfree(cpuc->constraint_list); 2679 kfree(cpuc->constraint_list);
2679 cpuc->constraint_list = NULL; 2680 cpuc->constraint_list = NULL;
2680 } 2681 }
2682}
2681 2683
2682 c = cpuc->excl_cntrs; 2684static void intel_pmu_cpu_dying(int cpu)
2683 if (c) { 2685{
2684 if (c->core_id == -1 || --c->refcnt == 0) 2686 struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
2685 kfree(c); 2687 struct intel_shared_regs *pc;
2686 cpuc->excl_cntrs = NULL; 2688
2689 pc = cpuc->shared_regs;
2690 if (pc) {
2691 if (pc->core_id == -1 || --pc->refcnt == 0)
2692 kfree(pc);
2693 cpuc->shared_regs = NULL;
2687 } 2694 }
2688 2695
2696 free_excl_cntrs(cpu);
2697
2689 fini_debug_store_on_cpu(cpu); 2698 fini_debug_store_on_cpu(cpu);
2690} 2699}
2691 2700
@@ -2904,18 +2913,18 @@ static __init void intel_nehalem_quirk(void)
2904 * HSW: HSD29 2913 * HSW: HSD29
2905 * 2914 *
2906 * Only needed when HT is enabled. However detecting 2915 * Only needed when HT is enabled. However detecting
2907 * this is too difficult and model specific so we enable 2916 * if HT is enabled is difficult (model specific). So instead,
2908 * it even with HT off for now. 2917 * we enable the workaround in the early boot, and verify if
2918 * it is needed in a later initcall phase once we have valid
2919 * topology information to check if HT is actually enabled
2909 */ 2920 */
2910static __init void intel_ht_bug(void) 2921static __init void intel_ht_bug(void)
2911{ 2922{
2912 x86_pmu.flags |= PMU_FL_EXCL_CNTRS; 2923 x86_pmu.flags |= PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED;
2913 2924
2914 x86_pmu.commit_scheduling = intel_commit_scheduling; 2925 x86_pmu.commit_scheduling = intel_commit_scheduling;
2915 x86_pmu.start_scheduling = intel_start_scheduling; 2926 x86_pmu.start_scheduling = intel_start_scheduling;
2916 x86_pmu.stop_scheduling = intel_stop_scheduling; 2927 x86_pmu.stop_scheduling = intel_stop_scheduling;
2917
2918 pr_info("CPU erratum BJ122, BV98, HSD29 worked around\n");
2919} 2928}
2920 2929
2921EVENT_ATTR_STR(mem-loads, mem_ld_hsw, "event=0xcd,umask=0x1,ldlat=3"); 2930EVENT_ATTR_STR(mem-loads, mem_ld_hsw, "event=0xcd,umask=0x1,ldlat=3");
@@ -3343,3 +3352,47 @@ __init int intel_pmu_init(void)
3343 3352
3344 return 0; 3353 return 0;
3345} 3354}
3355
3356/*
3357 * HT bug: phase 2 init
3358 * Called once we have valid topology information to check
3359 * whether or not HT is enabled
3360 * If HT is off, then we disable the workaround
3361 */
3362static __init int fixup_ht_bug(void)
3363{
3364 int cpu = smp_processor_id();
3365 int w, c;
3366 /*
3367 * problem not present on this CPU model, nothing to do
3368 */
3369 if (!(x86_pmu.flags & PMU_FL_EXCL_ENABLED))
3370 return 0;
3371
3372 w = cpumask_weight(topology_thread_cpumask(cpu));
3373 if (w > 1) {
3374 pr_info("PMU erratum BJ122, BV98, HSD29 worked around, HT is on\n");
3375 return 0;
3376 }
3377
3378 watchdog_nmi_disable_all();
3379
3380 x86_pmu.flags &= ~(PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED);
3381
3382 x86_pmu.commit_scheduling = NULL;
3383 x86_pmu.start_scheduling = NULL;
3384 x86_pmu.stop_scheduling = NULL;
3385
3386 watchdog_nmi_enable_all();
3387
3388 get_online_cpus();
3389
3390 for_each_online_cpu(c) {
3391 free_excl_cntrs(c);
3392 }
3393
3394 put_online_cpus();
3395 pr_info("PMU erratum BJ122, BV98, HSD29 workaround disabled, HT off\n");
3396 return 0;
3397}
3398subsys_initcall(fixup_ht_bug)