^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/perf_event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/nospec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <asm/intel-family.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "probe.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) enum perf_msr_id {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) PERF_MSR_TSC = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) PERF_MSR_APERF = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) PERF_MSR_MPERF = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) PERF_MSR_PPERF = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) PERF_MSR_SMI = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) PERF_MSR_PTSC = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) PERF_MSR_IRPERF = 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) PERF_MSR_THERM = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) PERF_MSR_EVENT_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static bool test_aperfmperf(int idx, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return boot_cpu_has(X86_FEATURE_APERFMPERF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static bool test_ptsc(int idx, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return boot_cpu_has(X86_FEATURE_PTSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static bool test_irperf(int idx, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return boot_cpu_has(X86_FEATURE_IRPERF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static bool test_therm_status(int idx, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return boot_cpu_has(X86_FEATURE_DTHERM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static bool test_intel(int idx, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) boot_cpu_data.x86 != 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) switch (boot_cpu_data.x86_model) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) case INTEL_FAM6_NEHALEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) case INTEL_FAM6_NEHALEM_G:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) case INTEL_FAM6_NEHALEM_EP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) case INTEL_FAM6_NEHALEM_EX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) case INTEL_FAM6_WESTMERE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) case INTEL_FAM6_WESTMERE_EP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) case INTEL_FAM6_WESTMERE_EX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) case INTEL_FAM6_SANDYBRIDGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) case INTEL_FAM6_SANDYBRIDGE_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) case INTEL_FAM6_IVYBRIDGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) case INTEL_FAM6_IVYBRIDGE_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) case INTEL_FAM6_HASWELL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) case INTEL_FAM6_HASWELL_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) case INTEL_FAM6_HASWELL_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) case INTEL_FAM6_HASWELL_G:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) case INTEL_FAM6_BROADWELL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) case INTEL_FAM6_BROADWELL_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) case INTEL_FAM6_BROADWELL_G:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) case INTEL_FAM6_BROADWELL_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) case INTEL_FAM6_SAPPHIRERAPIDS_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case INTEL_FAM6_ATOM_SILVERMONT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) case INTEL_FAM6_ATOM_SILVERMONT_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) case INTEL_FAM6_ATOM_AIRMONT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) case INTEL_FAM6_ATOM_GOLDMONT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) case INTEL_FAM6_ATOM_GOLDMONT_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) case INTEL_FAM6_ATOM_TREMONT_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) case INTEL_FAM6_ATOM_TREMONT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case INTEL_FAM6_ATOM_TREMONT_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) case INTEL_FAM6_XEON_PHI_KNL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) case INTEL_FAM6_XEON_PHI_KNM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (idx == PERF_MSR_SMI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case INTEL_FAM6_SKYLAKE_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case INTEL_FAM6_SKYLAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case INTEL_FAM6_SKYLAKE_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case INTEL_FAM6_KABYLAKE_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case INTEL_FAM6_KABYLAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case INTEL_FAM6_COMETLAKE_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case INTEL_FAM6_COMETLAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case INTEL_FAM6_ICELAKE_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case INTEL_FAM6_ICELAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case INTEL_FAM6_ICELAKE_X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case INTEL_FAM6_ICELAKE_D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case INTEL_FAM6_TIGERLAKE_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case INTEL_FAM6_TIGERLAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) PMU_EVENT_ATTR_STRING(tsc, attr_tsc, "event=0x00" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) PMU_EVENT_ATTR_STRING(aperf, attr_aperf, "event=0x01" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) PMU_EVENT_ATTR_STRING(mperf, attr_mperf, "event=0x02" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) PMU_EVENT_ATTR_STRING(pperf, attr_pperf, "event=0x03" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) PMU_EVENT_ATTR_STRING(smi, attr_smi, "event=0x04" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) PMU_EVENT_ATTR_STRING(ptsc, attr_ptsc, "event=0x05" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) PMU_EVENT_ATTR_STRING(irperf, attr_irperf, "event=0x06" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) PMU_EVENT_ATTR_STRING(cpu_thermal_margin, attr_therm, "event=0x07" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) PMU_EVENT_ATTR_STRING(cpu_thermal_margin.snapshot, attr_therm_snap, "1" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) PMU_EVENT_ATTR_STRING(cpu_thermal_margin.unit, attr_therm_unit, "C" );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static unsigned long msr_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) PMU_EVENT_GROUP(events, aperf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) PMU_EVENT_GROUP(events, mperf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) PMU_EVENT_GROUP(events, pperf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) PMU_EVENT_GROUP(events, smi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) PMU_EVENT_GROUP(events, ptsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) PMU_EVENT_GROUP(events, irperf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static struct attribute *attrs_therm[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) &attr_therm.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) &attr_therm_snap.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) &attr_therm_unit.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static struct attribute_group group_therm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .name = "events",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .attrs = attrs_therm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static struct perf_msr msr[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) [PERF_MSR_TSC] = { .no_check = true, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) [PERF_MSR_APERF] = { MSR_IA32_APERF, &group_aperf, test_aperfmperf, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) [PERF_MSR_MPERF] = { MSR_IA32_MPERF, &group_mperf, test_aperfmperf, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) [PERF_MSR_PPERF] = { MSR_PPERF, &group_pperf, test_intel, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) [PERF_MSR_SMI] = { MSR_SMI_COUNT, &group_smi, test_intel, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) [PERF_MSR_PTSC] = { MSR_F15H_PTSC, &group_ptsc, test_ptsc, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) [PERF_MSR_IRPERF] = { MSR_F17H_IRPERF, &group_irperf, test_irperf, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) [PERF_MSR_THERM] = { MSR_IA32_THERM_STATUS, &group_therm, test_therm_status, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static struct attribute *events_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) &attr_tsc.attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static struct attribute_group events_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .name = "events",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .attrs = events_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) PMU_FORMAT_ATTR(event, "config:0-63");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static struct attribute *format_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) &format_attr_event.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static struct attribute_group format_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .name = "format",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .attrs = format_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static const struct attribute_group *attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) &events_attr_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) &format_attr_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static const struct attribute_group *attr_update[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) &group_aperf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) &group_mperf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) &group_pperf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) &group_smi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) &group_ptsc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) &group_irperf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) &group_therm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static int msr_event_init(struct perf_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) u64 cfg = event->attr.config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (event->attr.type != event->pmu->type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* unsupported modes and filters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (event->attr.sample_period) /* no sampling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (cfg >= PERF_MSR_EVENT_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!(msr_mask & (1 << cfg)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) event->hw.idx = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) event->hw.event_base = msr[cfg].msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) event->hw.config = cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static inline u64 msr_read_counter(struct perf_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u64 now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (event->hw.event_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) rdmsrl(event->hw.event_base, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) now = rdtsc_ordered();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static void msr_event_update(struct perf_event *event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u64 prev, now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) s64 delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Careful, an NMI might modify the previous event value: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) prev = local64_read(&event->hw.prev_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) now = msr_read_counter(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (local64_cmpxchg(&event->hw.prev_count, prev, now) != prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) delta = now - prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (unlikely(event->hw.event_base == MSR_SMI_COUNT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) delta = sign_extend64(delta, 31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) local64_add(delta, &event->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) } else if (unlikely(event->hw.event_base == MSR_IA32_THERM_STATUS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* If valid, extract digital readout, otherwise set to -1: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) now = now & (1ULL << 31) ? (now >> 16) & 0x3f : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) local64_set(&event->count, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) local64_add(delta, &event->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static void msr_event_start(struct perf_event *event, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) u64 now = msr_read_counter(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) local64_set(&event->hw.prev_count, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static void msr_event_stop(struct perf_event *event, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) msr_event_update(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static void msr_event_del(struct perf_event *event, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) msr_event_stop(event, PERF_EF_UPDATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static int msr_event_add(struct perf_event *event, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (flags & PERF_EF_START)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) msr_event_start(event, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static struct pmu pmu_msr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .task_ctx_nr = perf_sw_context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .attr_groups = attr_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .event_init = msr_event_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .add = msr_event_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .del = msr_event_del,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .start = msr_event_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .stop = msr_event_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .read = msr_event_update,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .attr_update = attr_update,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int __init msr_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (!boot_cpu_has(X86_FEATURE_TSC)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) pr_cont("no MSR PMU driver.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) msr_mask = perf_msr_probe(msr, PERF_MSR_EVENT_MAX, true, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) perf_pmu_register(&pmu_msr, "msr", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) device_initcall(msr_init);