]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/x86/events/intel/core.c
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-artful-kernel.git] / arch / x86 / events / intel / core.c
index 110ce8238466f7e404d8312dd8d9297fa09355c9..31acf2a9839437979bc1e849a10dbdecbe270d13 100644 (file)
@@ -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: