File Index
Files and directories
Sign in
FILE

msr.c

File preview with syntax highlighting.

linux-6.19.14/arch/x86/events/msr.c C
  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/cpu_device_id.h>
  6#include <asm/msr.h>
  7
  8#include "probe.h"
  9
 10enum perf_msr_id {
 11	PERF_MSR_TSC			= 0,
 12	PERF_MSR_APERF			= 1,
 13	PERF_MSR_MPERF			= 2,
 14	PERF_MSR_PPERF			= 3,
 15	PERF_MSR_SMI			= 4,
 16	PERF_MSR_PTSC			= 5,
 17	PERF_MSR_IRPERF			= 6,
 18	PERF_MSR_THERM			= 7,
 19	PERF_MSR_EVENT_MAX,
 20};
 21
 22static bool test_aperfmperf(int idx, void *data)
 23{
 24	return boot_cpu_has(X86_FEATURE_APERFMPERF);
 25}
 26
 27static bool test_ptsc(int idx, void *data)
 28{
 29	return boot_cpu_has(X86_FEATURE_PTSC);
 30}
 31
 32static bool test_irperf(int idx, void *data)
 33{
 34	return boot_cpu_has(X86_FEATURE_IRPERF);
 35}
 36
 37static bool test_therm_status(int idx, void *data)
 38{
 39	return boot_cpu_has(X86_FEATURE_DTHERM);
 40}
 41
 42static bool test_intel(int idx, void *data)
 43{
 44	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
 45	    boot_cpu_data.x86 != 6)
 46		return false;
 47
 48	switch (boot_cpu_data.x86_vfm) {
 49	case INTEL_NEHALEM:
 50	case INTEL_NEHALEM_G:
 51	case INTEL_NEHALEM_EP:
 52	case INTEL_NEHALEM_EX:
 53
 54	case INTEL_WESTMERE:
 55	case INTEL_WESTMERE_EP:
 56	case INTEL_WESTMERE_EX:
 57
 58	case INTEL_SANDYBRIDGE:
 59	case INTEL_SANDYBRIDGE_X:
 60
 61	case INTEL_IVYBRIDGE:
 62	case INTEL_IVYBRIDGE_X:
 63
 64	case INTEL_HASWELL:
 65	case INTEL_HASWELL_X:
 66	case INTEL_HASWELL_L:
 67	case INTEL_HASWELL_G:
 68
 69	case INTEL_BROADWELL:
 70	case INTEL_BROADWELL_D:
 71	case INTEL_BROADWELL_G:
 72	case INTEL_BROADWELL_X:
 73	case INTEL_SAPPHIRERAPIDS_X:
 74	case INTEL_EMERALDRAPIDS_X:
 75	case INTEL_GRANITERAPIDS_X:
 76	case INTEL_GRANITERAPIDS_D:
 77
 78	case INTEL_ATOM_SILVERMONT:
 79	case INTEL_ATOM_SILVERMONT_D:
 80	case INTEL_ATOM_AIRMONT:
 81	case INTEL_ATOM_AIRMONT_NP:
 82
 83	case INTEL_ATOM_GOLDMONT:
 84	case INTEL_ATOM_GOLDMONT_D:
 85	case INTEL_ATOM_GOLDMONT_PLUS:
 86	case INTEL_ATOM_TREMONT_D:
 87	case INTEL_ATOM_TREMONT:
 88	case INTEL_ATOM_TREMONT_L:
 89
 90	case INTEL_XEON_PHI_KNL:
 91	case INTEL_XEON_PHI_KNM:
 92		if (idx == PERF_MSR_SMI)
 93			return true;
 94		break;
 95
 96	case INTEL_SKYLAKE_L:
 97	case INTEL_SKYLAKE:
 98	case INTEL_SKYLAKE_X:
 99	case INTEL_KABYLAKE_L:
100	case INTEL_KABYLAKE:
101	case INTEL_COMETLAKE_L:
102	case INTEL_COMETLAKE:
103	case INTEL_ICELAKE_L:
104	case INTEL_ICELAKE:
105	case INTEL_ICELAKE_X:
106	case INTEL_ICELAKE_D:
107	case INTEL_TIGERLAKE_L:
108	case INTEL_TIGERLAKE:
109	case INTEL_ROCKETLAKE:
110	case INTEL_ALDERLAKE:
111	case INTEL_ALDERLAKE_L:
112	case INTEL_ATOM_GRACEMONT:
113	case INTEL_RAPTORLAKE:
114	case INTEL_RAPTORLAKE_P:
115	case INTEL_RAPTORLAKE_S:
116	case INTEL_METEORLAKE:
117	case INTEL_METEORLAKE_L:
118		if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
119			return true;
120		break;
121	}
122
123	return false;
124}
125
126PMU_EVENT_ATTR_STRING(tsc,				attr_tsc,		"event=0x00"	);
127PMU_EVENT_ATTR_STRING(aperf,				attr_aperf,		"event=0x01"	);
128PMU_EVENT_ATTR_STRING(mperf,				attr_mperf,		"event=0x02"	);
129PMU_EVENT_ATTR_STRING(pperf,				attr_pperf,		"event=0x03"	);
130PMU_EVENT_ATTR_STRING(smi,				attr_smi,		"event=0x04"	);
131PMU_EVENT_ATTR_STRING(ptsc,				attr_ptsc,		"event=0x05"	);
132PMU_EVENT_ATTR_STRING(irperf,				attr_irperf,		"event=0x06"	);
133PMU_EVENT_ATTR_STRING(cpu_thermal_margin,		attr_therm,		"event=0x07"	);
134PMU_EVENT_ATTR_STRING(cpu_thermal_margin.snapshot,	attr_therm_snap,	"1"		);
135PMU_EVENT_ATTR_STRING(cpu_thermal_margin.unit,		attr_therm_unit,	"C"		);
136
137static unsigned long msr_mask;
138
139PMU_EVENT_GROUP(events, aperf);
140PMU_EVENT_GROUP(events, mperf);
141PMU_EVENT_GROUP(events, pperf);
142PMU_EVENT_GROUP(events, smi);
143PMU_EVENT_GROUP(events, ptsc);
144PMU_EVENT_GROUP(events, irperf);
145
146static struct attribute *attrs_therm[] = {
147	&attr_therm.attr.attr,
148	&attr_therm_snap.attr.attr,
149	&attr_therm_unit.attr.attr,
150	NULL,
151};
152
153static struct attribute_group group_therm = {
154	.name  = "events",
155	.attrs = attrs_therm,
156};
157
158static struct perf_msr msr[] = {
159	[PERF_MSR_TSC]		= { .no_check = true,								},
160	[PERF_MSR_APERF]	= { MSR_IA32_APERF,		&group_aperf,		test_aperfmperf,	},
161	[PERF_MSR_MPERF]	= { MSR_IA32_MPERF,		&group_mperf,		test_aperfmperf,	},
162	[PERF_MSR_PPERF]	= { MSR_PPERF,			&group_pperf,		test_intel,		},
163	[PERF_MSR_SMI]		= { MSR_SMI_COUNT,		&group_smi,		test_intel,		},
164	[PERF_MSR_PTSC]		= { MSR_F15H_PTSC,		&group_ptsc,		test_ptsc,		},
165	[PERF_MSR_IRPERF]	= { MSR_F17H_IRPERF,		&group_irperf,		test_irperf,		},
166	[PERF_MSR_THERM]	= { MSR_IA32_THERM_STATUS,	&group_therm,		test_therm_status,	},
167};
168
169static struct attribute *events_attrs[] = {
170	&attr_tsc.attr.attr,
171	NULL,
172};
173
174static struct attribute_group events_attr_group = {
175	.name = "events",
176	.attrs = events_attrs,
177};
178
179PMU_FORMAT_ATTR(event, "config:0-63");
180static struct attribute *format_attrs[] = {
181	&format_attr_event.attr,
182	NULL,
183};
184static struct attribute_group format_attr_group = {
185	.name = "format",
186	.attrs = format_attrs,
187};
188
189static const struct attribute_group *attr_groups[] = {
190	&events_attr_group,
191	&format_attr_group,
192	NULL,
193};
194
195static const struct attribute_group *attr_update[] = {
196	&group_aperf,
197	&group_mperf,
198	&group_pperf,
199	&group_smi,
200	&group_ptsc,
201	&group_irperf,
202	&group_therm,
203	NULL,
204};
205
206static int msr_event_init(struct perf_event *event)
207{
208	u64 cfg = event->attr.config;
209
210	if (event->attr.type != event->pmu->type)
211		return -ENOENT;
212
213	/* unsupported modes and filters */
214	if (event->attr.sample_period) /* no sampling */
215		return -EINVAL;
216
217	if (cfg >= PERF_MSR_EVENT_MAX)
218		return -EINVAL;
219
220	cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
221
222	if (!(msr_mask & (1 << cfg)))
223		return -EINVAL;
224
225	event->hw.idx		= -1;
226	event->hw.event_base	= msr[cfg].msr;
227	event->hw.config	= cfg;
228
229	return 0;
230}
231
232static inline u64 msr_read_counter(struct perf_event *event)
233{
234	u64 now;
235
236	if (event->hw.event_base)
237		rdmsrq(event->hw.event_base, now);
238	else
239		now = rdtsc_ordered();
240
241	return now;
242}
243
244static void msr_event_update(struct perf_event *event)
245{
246	u64 prev, now;
247	s64 delta;
248
249	/* Careful, an NMI might modify the previous event value: */
250	prev = local64_read(&event->hw.prev_count);
251	do {
252		now = msr_read_counter(event);
253	} while (!local64_try_cmpxchg(&event->hw.prev_count, &prev, now));
254
255	delta = now - prev;
256	if (unlikely(event->hw.event_base == MSR_SMI_COUNT)) {
257		delta = sign_extend64(delta, 31);
258		local64_add(delta, &event->count);
259	} else if (unlikely(event->hw.event_base == MSR_IA32_THERM_STATUS)) {
260		/* If valid, extract digital readout, otherwise set to -1: */
261		now = now & (1ULL << 31) ? (now >> 16) & 0x3f :  -1;
262		local64_set(&event->count, now);
263	} else {
264		local64_add(delta, &event->count);
265	}
266}
267
268static void msr_event_start(struct perf_event *event, int flags)
269{
270	u64 now = msr_read_counter(event);
271
272	local64_set(&event->hw.prev_count, now);
273}
274
275static void msr_event_stop(struct perf_event *event, int flags)
276{
277	msr_event_update(event);
278}
279
280static void msr_event_del(struct perf_event *event, int flags)
281{
282	msr_event_stop(event, PERF_EF_UPDATE);
283}
284
285static int msr_event_add(struct perf_event *event, int flags)
286{
287	if (flags & PERF_EF_START)
288		msr_event_start(event, flags);
289
290	return 0;
291}
292
293static struct pmu pmu_msr = {
294	.task_ctx_nr	= perf_sw_context,
295	.attr_groups	= attr_groups,
296	.event_init	= msr_event_init,
297	.add		= msr_event_add,
298	.del		= msr_event_del,
299	.start		= msr_event_start,
300	.stop		= msr_event_stop,
301	.read		= msr_event_update,
302	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
303	.attr_update	= attr_update,
304};
305
306static int __init msr_init(void)
307{
308	if (!boot_cpu_has(X86_FEATURE_TSC)) {
309		pr_cont("no MSR PMU driver.\n");
310		return 0;
311	}
312
313	msr_mask = perf_msr_probe(msr, PERF_MSR_EVENT_MAX, true, NULL);
314
315	perf_pmu_register(&pmu_msr, "msr", -1);
316
317	return 0;
318}
319device_initcall(msr_init);
~/ Read-only file preview.