|
@@ -3160,6 +3160,19 @@ err:
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+static void flip_smm_bit(void *data)
|
|
|
+{
|
|
|
+ unsigned long set = *(unsigned long *)data;
|
|
|
+
|
|
|
+ if (set > 0) {
|
|
|
+ msr_set_bit(MSR_IA32_DEBUGCTLMSR,
|
|
|
+ DEBUGCTLMSR_FREEZE_IN_SMM_BIT);
|
|
|
+ } else {
|
|
|
+ msr_clear_bit(MSR_IA32_DEBUGCTLMSR,
|
|
|
+ DEBUGCTLMSR_FREEZE_IN_SMM_BIT);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void intel_pmu_cpu_starting(int cpu)
|
|
|
{
|
|
|
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
|
|
@@ -3174,6 +3187,8 @@ static void intel_pmu_cpu_starting(int cpu)
|
|
|
|
|
|
cpuc->lbr_sel = NULL;
|
|
|
|
|
|
+ flip_smm_bit(&x86_pmu.attr_freeze_on_smi);
|
|
|
+
|
|
|
if (!cpuc->shared_regs)
|
|
|
return;
|
|
|
|
|
@@ -3595,6 +3610,52 @@ static struct attribute *hsw_events_attrs[] = {
|
|
|
NULL
|
|
|
};
|
|
|
|
|
|
+static ssize_t freeze_on_smi_show(struct device *cdev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%lu\n", x86_pmu.attr_freeze_on_smi);
|
|
|
+}
|
|
|
+
|
|
|
+static DEFINE_MUTEX(freeze_on_smi_mutex);
|
|
|
+
|
|
|
+static ssize_t freeze_on_smi_store(struct device *cdev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buf, size_t count)
|
|
|
+{
|
|
|
+ unsigned long val;
|
|
|
+ ssize_t ret;
|
|
|
+
|
|
|
+ ret = kstrtoul(buf, 0, &val);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (val > 1)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mutex_lock(&freeze_on_smi_mutex);
|
|
|
+
|
|
|
+ if (x86_pmu.attr_freeze_on_smi == val)
|
|
|
+ goto done;
|
|
|
+
|
|
|
+ x86_pmu.attr_freeze_on_smi = val;
|
|
|
+
|
|
|
+ get_online_cpus();
|
|
|
+ on_each_cpu(flip_smm_bit, &val, 1);
|
|
|
+ put_online_cpus();
|
|
|
+done:
|
|
|
+ mutex_unlock(&freeze_on_smi_mutex);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR_RW(freeze_on_smi);
|
|
|
+
|
|
|
+static struct attribute *intel_pmu_attrs[] = {
|
|
|
+ &dev_attr_freeze_on_smi.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
__init int intel_pmu_init(void)
|
|
|
{
|
|
|
union cpuid10_edx edx;
|
|
@@ -3641,6 +3702,8 @@ __init int intel_pmu_init(void)
|
|
|
|
|
|
x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);
|
|
|
|
|
|
+
|
|
|
+ x86_pmu.attrs = intel_pmu_attrs;
|
|
|
/*
|
|
|
* Quirk: v2 perfmon does not report fixed-purpose events, so
|
|
|
* assume at least 3 events, when not running in a hypervisor:
|