Commit d35869ba authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Ingo Molnar

perf/x86/intel/pt: Allow the disabling of branch tracing

Now that Intel PT supports more types of trace content than just branch
tracing, it may be useful to allow the user to disable branch tracing
when it is not needed.

The special case is BDW, where not setting BranchEn is not supported.

This is slightly trickier than necessary, because up to this moment
the driver has been setting BranchEn automatically and the userspace
assumes as much. Instead of reversing the semantics of BranchEn, we
introduce a 'passthrough' bit, which will forego the default and allow
the user to set BranchEn to their heart's content.
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: vince@deater.net
Link: http://lkml.kernel.org/r/20170206144140.14402-1-alexander.shishkin@linux.intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent c69f203d
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <asm/insn.h> #include <asm/insn.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/intel_pt.h> #include <asm/intel_pt.h>
#include <asm/intel-family.h>
#include "../perf_event.h" #include "../perf_event.h"
#include "pt.h" #include "pt.h"
...@@ -98,6 +99,7 @@ static struct attribute_group pt_cap_group = { ...@@ -98,6 +99,7 @@ static struct attribute_group pt_cap_group = {
.name = "caps", .name = "caps",
}; };
PMU_FORMAT_ATTR(pt, "config:0" );
PMU_FORMAT_ATTR(cyc, "config:1" ); PMU_FORMAT_ATTR(cyc, "config:1" );
PMU_FORMAT_ATTR(pwr_evt, "config:4" ); PMU_FORMAT_ATTR(pwr_evt, "config:4" );
PMU_FORMAT_ATTR(fup_on_ptw, "config:5" ); PMU_FORMAT_ATTR(fup_on_ptw, "config:5" );
...@@ -105,11 +107,13 @@ PMU_FORMAT_ATTR(mtc, "config:9" ); ...@@ -105,11 +107,13 @@ PMU_FORMAT_ATTR(mtc, "config:9" );
PMU_FORMAT_ATTR(tsc, "config:10" ); PMU_FORMAT_ATTR(tsc, "config:10" );
PMU_FORMAT_ATTR(noretcomp, "config:11" ); PMU_FORMAT_ATTR(noretcomp, "config:11" );
PMU_FORMAT_ATTR(ptw, "config:12" ); PMU_FORMAT_ATTR(ptw, "config:12" );
PMU_FORMAT_ATTR(branch, "config:13" );
PMU_FORMAT_ATTR(mtc_period, "config:14-17" ); PMU_FORMAT_ATTR(mtc_period, "config:14-17" );
PMU_FORMAT_ATTR(cyc_thresh, "config:19-22" ); PMU_FORMAT_ATTR(cyc_thresh, "config:19-22" );
PMU_FORMAT_ATTR(psb_period, "config:24-27" ); PMU_FORMAT_ATTR(psb_period, "config:24-27" );
static struct attribute *pt_formats_attr[] = { static struct attribute *pt_formats_attr[] = {
&format_attr_pt.attr,
&format_attr_cyc.attr, &format_attr_cyc.attr,
&format_attr_pwr_evt.attr, &format_attr_pwr_evt.attr,
&format_attr_fup_on_ptw.attr, &format_attr_fup_on_ptw.attr,
...@@ -117,6 +121,7 @@ static struct attribute *pt_formats_attr[] = { ...@@ -117,6 +121,7 @@ static struct attribute *pt_formats_attr[] = {
&format_attr_tsc.attr, &format_attr_tsc.attr,
&format_attr_noretcomp.attr, &format_attr_noretcomp.attr,
&format_attr_ptw.attr, &format_attr_ptw.attr,
&format_attr_branch.attr,
&format_attr_mtc_period.attr, &format_attr_mtc_period.attr,
&format_attr_cyc_thresh.attr, &format_attr_cyc_thresh.attr,
&format_attr_psb_period.attr, &format_attr_psb_period.attr,
...@@ -197,6 +202,19 @@ static int __init pt_pmu_hw_init(void) ...@@ -197,6 +202,19 @@ static int __init pt_pmu_hw_init(void)
pt_pmu.tsc_art_den = eax; pt_pmu.tsc_art_den = eax;
} }
/* model-specific quirks */
switch (boot_cpu_data.x86_model) {
case INTEL_FAM6_BROADWELL_CORE:
case INTEL_FAM6_BROADWELL_XEON_D:
case INTEL_FAM6_BROADWELL_GT3E:
case INTEL_FAM6_BROADWELL_X:
/* not setting BRANCH_EN will #GP, erratum BDM106 */
pt_pmu.branch_en_always_on = true;
break;
default:
break;
}
if (boot_cpu_has(X86_FEATURE_VMX)) { if (boot_cpu_has(X86_FEATURE_VMX)) {
/* /*
* Intel SDM, 36.5 "Tracing post-VMXON" says that * Intel SDM, 36.5 "Tracing post-VMXON" says that
...@@ -263,8 +281,20 @@ static int __init pt_pmu_hw_init(void) ...@@ -263,8 +281,20 @@ static int __init pt_pmu_hw_init(void)
#define RTIT_CTL_PTW (RTIT_CTL_PTW_EN | \ #define RTIT_CTL_PTW (RTIT_CTL_PTW_EN | \
RTIT_CTL_FUP_ON_PTW) RTIT_CTL_FUP_ON_PTW)
#define PT_CONFIG_MASK (RTIT_CTL_TSC_EN | \ /*
* Bit 0 (TraceEn) in the attr.config is meaningless as the
* corresponding bit in the RTIT_CTL can only be controlled
* by the driver; therefore, repurpose it to mean: pass
* through the bit that was previously assumed to be always
* on for PT, thereby allowing the user to *not* set it if
* they so wish. See also pt_event_valid() and pt_config().
*/
#define RTIT_CTL_PASSTHROUGH RTIT_CTL_TRACEEN
#define PT_CONFIG_MASK (RTIT_CTL_TRACEEN | \
RTIT_CTL_TSC_EN | \
RTIT_CTL_DISRETC | \ RTIT_CTL_DISRETC | \
RTIT_CTL_BRANCH_EN | \
RTIT_CTL_CYC_PSB | \ RTIT_CTL_CYC_PSB | \
RTIT_CTL_MTC | \ RTIT_CTL_MTC | \
RTIT_CTL_PWR_EVT_EN | \ RTIT_CTL_PWR_EVT_EN | \
...@@ -332,6 +362,33 @@ static bool pt_event_valid(struct perf_event *event) ...@@ -332,6 +362,33 @@ static bool pt_event_valid(struct perf_event *event)
return false; return false;
} }
/*
* Setting bit 0 (TraceEn in RTIT_CTL MSR) in the attr.config
* clears the assomption that BranchEn must always be enabled,
* as was the case with the first implementation of PT.
* If this bit is not set, the legacy behavior is preserved
* for compatibility with the older userspace.
*
* Re-using bit 0 for this purpose is fine because it is never
* directly set by the user; previous attempts at setting it in
* the attr.config resulted in -EINVAL.
*/
if (config & RTIT_CTL_PASSTHROUGH) {
/*
* Disallow not setting BRANCH_EN where BRANCH_EN is
* always required.
*/
if (pt_pmu.branch_en_always_on &&
!(config & RTIT_CTL_BRANCH_EN))
return false;
} else {
/*
* Disallow BRANCH_EN without the PASSTHROUGH.
*/
if (config & RTIT_CTL_BRANCH_EN)
return false;
}
return true; return true;
} }
...@@ -420,7 +477,20 @@ static void pt_config(struct perf_event *event) ...@@ -420,7 +477,20 @@ static void pt_config(struct perf_event *event)
} }
reg = pt_config_filters(event); reg = pt_config_filters(event);
reg |= RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_TRACEEN; reg |= RTIT_CTL_TOPA | RTIT_CTL_TRACEEN;
/*
* Previously, we had BRANCH_EN on by default, but now that PT has
* grown features outside of branch tracing, it is useful to allow
* the user to disable it. Setting bit 0 in the event's attr.config
* allows BRANCH_EN to pass through instead of being always on. See
* also the comment in pt_event_valid().
*/
if (event->attr.config & BIT(0)) {
reg |= event->attr.config & RTIT_CTL_BRANCH_EN;
} else {
reg |= RTIT_CTL_BRANCH_EN;
}
if (!event->attr.exclude_kernel) if (!event->attr.exclude_kernel)
reg |= RTIT_CTL_OS; reg |= RTIT_CTL_OS;
......
...@@ -110,6 +110,7 @@ struct pt_pmu { ...@@ -110,6 +110,7 @@ struct pt_pmu {
struct pmu pmu; struct pmu pmu;
u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES]; u32 caps[PT_CPUID_REGS_NUM * PT_CPUID_LEAVES];
bool vmx; bool vmx;
bool branch_en_always_on;
unsigned long max_nonturbo_ratio; unsigned long max_nonturbo_ratio;
unsigned int tsc_art_num; unsigned int tsc_art_num;
unsigned int tsc_art_den; unsigned int tsc_art_den;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment