root/arch/x86/events/msr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_aperfmperf
  2. test_ptsc
  3. test_irperf
  4. test_therm_status
  5. test_intel
  6. msr_event_init
  7. msr_read_counter
  8. msr_event_update
  9. msr_event_start
  10. msr_event_stop
  11. msr_event_del
  12. msr_event_add
  13. msr_init

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

/* [<][>][^][v][top][bottom][index][help] */