Merge branch 'for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[sfrench/cifs-2.6.git] / arch / x86 / events / msr.c
index 14efaa0e8684144989adb75e1b4dda0ee06ba203..18e2628e2d8f7da6f2e124d0506733fc6e84c809 100644 (file)
@@ -10,7 +10,9 @@ enum perf_msr_id {
        PERF_MSR_SMI                    = 4,
        PERF_MSR_PTSC                   = 5,
        PERF_MSR_IRPERF                 = 6,
-
+       PERF_MSR_THERM                  = 7,
+       PERF_MSR_THERM_SNAP             = 8,
+       PERF_MSR_THERM_UNIT             = 9,
        PERF_MSR_EVENT_MAX,
 };
 
@@ -29,6 +31,11 @@ static bool test_irperf(int idx)
        return boot_cpu_has(X86_FEATURE_IRPERF);
 }
 
+static bool test_therm_status(int idx)
+{
+       return boot_cpu_has(X86_FEATURE_DTHERM);
+}
+
 static bool test_intel(int idx)
 {
        if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
@@ -95,22 +102,28 @@ struct perf_msr {
        bool    (*test)(int idx);
 };
 
-PMU_EVENT_ATTR_STRING(tsc,    evattr_tsc,    "event=0x00");
-PMU_EVENT_ATTR_STRING(aperf,  evattr_aperf,  "event=0x01");
-PMU_EVENT_ATTR_STRING(mperf,  evattr_mperf,  "event=0x02");
-PMU_EVENT_ATTR_STRING(pperf,  evattr_pperf,  "event=0x03");
-PMU_EVENT_ATTR_STRING(smi,    evattr_smi,    "event=0x04");
-PMU_EVENT_ATTR_STRING(ptsc,   evattr_ptsc,   "event=0x05");
-PMU_EVENT_ATTR_STRING(irperf, evattr_irperf, "event=0x06");
+PMU_EVENT_ATTR_STRING(tsc,                             evattr_tsc,             "event=0x00"    );
+PMU_EVENT_ATTR_STRING(aperf,                           evattr_aperf,           "event=0x01"    );
+PMU_EVENT_ATTR_STRING(mperf,                           evattr_mperf,           "event=0x02"    );
+PMU_EVENT_ATTR_STRING(pperf,                           evattr_pperf,           "event=0x03"    );
+PMU_EVENT_ATTR_STRING(smi,                             evattr_smi,             "event=0x04"    );
+PMU_EVENT_ATTR_STRING(ptsc,                            evattr_ptsc,            "event=0x05"    );
+PMU_EVENT_ATTR_STRING(irperf,                          evattr_irperf,          "event=0x06"    );
+PMU_EVENT_ATTR_STRING(cpu_thermal_margin,              evattr_therm,           "event=0x07"    );
+PMU_EVENT_ATTR_STRING(cpu_thermal_margin.snapshot,     evattr_therm_snap,      "1"             );
+PMU_EVENT_ATTR_STRING(cpu_thermal_margin.unit,         evattr_therm_unit,      "C"             );
 
 static struct perf_msr msr[] = {
-       [PERF_MSR_TSC]    = { 0,                &evattr_tsc,    NULL,            },
-       [PERF_MSR_APERF]  = { MSR_IA32_APERF,   &evattr_aperf,  test_aperfmperf, },
-       [PERF_MSR_MPERF]  = { MSR_IA32_MPERF,   &evattr_mperf,  test_aperfmperf, },
-       [PERF_MSR_PPERF]  = { MSR_PPERF,        &evattr_pperf,  test_intel,      },
-       [PERF_MSR_SMI]    = { MSR_SMI_COUNT,    &evattr_smi,    test_intel,      },
-       [PERF_MSR_PTSC]   = { MSR_F15H_PTSC,    &evattr_ptsc,   test_ptsc,       },
-       [PERF_MSR_IRPERF] = { MSR_F17H_IRPERF,  &evattr_irperf, test_irperf,     },
+       [PERF_MSR_TSC]          = { 0,                          &evattr_tsc,            NULL,                   },
+       [PERF_MSR_APERF]        = { MSR_IA32_APERF,             &evattr_aperf,          test_aperfmperf,        },
+       [PERF_MSR_MPERF]        = { MSR_IA32_MPERF,             &evattr_mperf,          test_aperfmperf,        },
+       [PERF_MSR_PPERF]        = { MSR_PPERF,                  &evattr_pperf,          test_intel,             },
+       [PERF_MSR_SMI]          = { MSR_SMI_COUNT,              &evattr_smi,            test_intel,             },
+       [PERF_MSR_PTSC]         = { MSR_F15H_PTSC,              &evattr_ptsc,           test_ptsc,              },
+       [PERF_MSR_IRPERF]       = { MSR_F17H_IRPERF,            &evattr_irperf,         test_irperf,            },
+       [PERF_MSR_THERM]        = { MSR_IA32_THERM_STATUS,      &evattr_therm,          test_therm_status,      },
+       [PERF_MSR_THERM_SNAP]   = { MSR_IA32_THERM_STATUS,      &evattr_therm_snap,     test_therm_status,      },
+       [PERF_MSR_THERM_UNIT]   = { MSR_IA32_THERM_STATUS,      &evattr_therm_unit,     test_therm_status,      },
 };
 
 static struct attribute *events_attrs[PERF_MSR_EVENT_MAX + 1] = {
@@ -161,9 +174,9 @@ static int msr_event_init(struct perf_event *event)
        if (!msr[cfg].attr)
                return -EINVAL;
 
-       event->hw.idx = -1;
-       event->hw.event_base = msr[cfg].msr;
-       event->hw.config = cfg;
+       event->hw.idx           = -1;
+       event->hw.event_base    = msr[cfg].msr;
+       event->hw.config        = cfg;
 
        return 0;
 }
@@ -184,7 +197,7 @@ static void msr_event_update(struct perf_event *event)
        u64 prev, now;
        s64 delta;
 
-       /* Careful, an NMI might modify the previous event value. */
+       /* Careful, an NMI might modify the previous event value: */
 again:
        prev = local64_read(&event->hw.prev_count);
        now = msr_read_counter(event);
@@ -193,17 +206,22 @@ again:
                goto again;
 
        delta = now - prev;
-       if (unlikely(event->hw.event_base == MSR_SMI_COUNT))
+       if (unlikely(event->hw.event_base == MSR_SMI_COUNT)) {
                delta = sign_extend64(delta, 31);
-
-       local64_add(delta, &event->count);
+               local64_add(delta, &event->count);
+       } else if (unlikely(event->hw.event_base == MSR_IA32_THERM_STATUS)) {
+               /* If valid, extract digital readout, otherwise set to -1: */
+               now = now & (1ULL << 31) ? (now >> 16) & 0x3f :  -1;
+               local64_set(&event->count, now);
+       } else {
+               local64_add(delta, &event->count);
+       }
 }
 
 static void msr_event_start(struct perf_event *event, int flags)
 {
-       u64 now;
+       u64 now = msr_read_counter(event);
 
-       now = msr_read_counter(event);
        local64_set(&event->hw.prev_count, now);
 }
 
@@ -250,9 +268,7 @@ static int __init msr_init(void)
        for (i = PERF_MSR_TSC + 1; i < PERF_MSR_EVENT_MAX; i++) {
                u64 val;
 
-               /*
-                * Virt sucks arse; you cannot tell if a R/O MSR is present :/
-                */
+               /* Virt sucks; you cannot tell if a R/O MSR is present :/ */
                if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val))
                        msr[i].attr = NULL;
        }