[PATCH v5 11/20] x86: perf: Intel PT and LBR/BTS are mutually exclusive

From: Alexander Shishkin
Date: Mon Oct 13 2014 - 09:47:40 EST


Intel PT cannot be used at the same time as LBR or BTS and will cause a
general protection fault if they are used together. In order to avoid
fixing up GPs in the fast path, instead we use flags to indicate that
that one of these is in use so that the other avoids MSR access altogether.

Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
---
arch/x86/kernel/cpu/perf_event.h | 6 ++++++
arch/x86/kernel/cpu/perf_event_intel_ds.c | 8 +++++++-
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 9 +++++----
3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index d98a34d435..8eee92be78 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -148,6 +148,7 @@ struct cpu_hw_events {
* Intel DebugStore bits
*/
struct debug_store *ds;
+ unsigned int bts_enabled;
u64 pebs_enabled;

/*
@@ -161,6 +162,11 @@ struct cpu_hw_events {
u64 br_sel;

/*
+ * Intel Processor Trace
+ */
+ unsigned int pt_enabled;
+
+ /*
* Intel host/guest exclude bits
*/
u64 intel_ctrl_guest_mask;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index b1553d05a5..865ee1268a 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -455,8 +455,13 @@ struct event_constraint bts_constraint =

void intel_pmu_enable_bts(u64 config)
{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
unsigned long debugctlmsr;

+ if (cpuc->pt_enabled)
+ return;
+
+ cpuc->bts_enabled = 1;
debugctlmsr = get_debugctlmsr();

debugctlmsr |= DEBUGCTLMSR_TR;
@@ -477,9 +482,10 @@ void intel_pmu_disable_bts(void)
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
unsigned long debugctlmsr;

- if (!cpuc->ds)
+ if (!cpuc->ds || cpuc->pt_enabled)
return;

+ cpuc->bts_enabled = 0;
debugctlmsr = get_debugctlmsr();

debugctlmsr &=
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 4af10617de..1b09c4b91a 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -172,7 +172,9 @@ static void intel_pmu_lbr_reset_64(void)

void intel_pmu_lbr_reset(void)
{
- if (!x86_pmu.lbr_nr)
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+ if (!x86_pmu.lbr_nr || cpuc->pt_enabled)
return;

if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
@@ -185,7 +187,7 @@ void intel_pmu_lbr_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);

- if (!x86_pmu.lbr_nr)
+ if (!x86_pmu.lbr_nr || cpuc->pt_enabled)
return;

/*
@@ -205,11 +207,10 @@ void intel_pmu_lbr_disable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);

- if (!x86_pmu.lbr_nr)
+ if (!x86_pmu.lbr_nr || !cpuc->lbr_users || cpuc->pt_enabled)
return;

cpuc->lbr_users--;
- WARN_ON_ONCE(cpuc->lbr_users < 0);

if (cpuc->enabled && !cpuc->lbr_users) {
__intel_pmu_lbr_disable();
--
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/