xref: /linux/drivers/gpu/drm/xe/xe_pmu.c (revision dcdd6b84d9acaa0794c29de7024cfdb20cfd7b92)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2025 Intel Corporation
4  */
5 
6 #include <drm/drm_drv.h>
7 #include <linux/device.h>
8 
9 #include "xe_device.h"
10 #include "xe_gt_idle.h"
11 #include "xe_pm.h"
12 #include "xe_pmu.h"
13 
14 /**
15  * DOC: Xe PMU (Performance Monitoring Unit)
16  *
17  * Expose events/counters like GT-C6 residency and GT frequency to user land via
18  * the perf interface. Events are per device. The GT can be selected with an
19  * extra config sub-field (bits 60-63).
20  *
21  * All events are listed in sysfs:
22  *
23  *     $ ls -ld /sys/bus/event_source/devices/xe_*
24  *     $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/
25  *     $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/
26  *
27  * The format directory has info regarding the configs that can be used.
28  * The standard perf tool can be used to grep for a certain event as well.
29  * Example:
30  *
31  *     $ perf list | grep gt-c6
32  *
33  * To sample a specific event for a GT at regular intervals:
34  *
35  *     $ perf stat -e <event_name,gt=> -I <interval>
36  */
37 
38 #define XE_PMU_EVENT_GT_MASK		GENMASK_ULL(63, 60)
39 #define XE_PMU_EVENT_ID_MASK		GENMASK_ULL(11, 0)
40 
41 static unsigned int config_to_event_id(u64 config)
42 {
43 	return FIELD_GET(XE_PMU_EVENT_ID_MASK, config);
44 }
45 
46 static unsigned int config_to_gt_id(u64 config)
47 {
48 	return FIELD_GET(XE_PMU_EVENT_GT_MASK, config);
49 }
50 
51 #define XE_PMU_EVENT_GT_C6_RESIDENCY	0x01
52 
53 static struct xe_gt *event_to_gt(struct perf_event *event)
54 {
55 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
56 	u64 gt = config_to_gt_id(event->attr.config);
57 
58 	return xe_device_get_gt(xe, gt);
59 }
60 
61 static bool event_supported(struct xe_pmu *pmu, unsigned int gt,
62 			    unsigned int id)
63 {
64 	if (gt >= XE_MAX_GT_PER_TILE)
65 		return false;
66 
67 	return id < sizeof(pmu->supported_events) * BITS_PER_BYTE &&
68 		pmu->supported_events & BIT_ULL(id);
69 }
70 
71 static void xe_pmu_event_destroy(struct perf_event *event)
72 {
73 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
74 
75 	drm_WARN_ON(&xe->drm, event->parent);
76 	xe_pm_runtime_put(xe);
77 	drm_dev_put(&xe->drm);
78 }
79 
80 static int xe_pmu_event_init(struct perf_event *event)
81 {
82 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
83 	struct xe_pmu *pmu = &xe->pmu;
84 	unsigned int id, gt;
85 
86 	if (!pmu->registered)
87 		return -ENODEV;
88 
89 	if (event->attr.type != event->pmu->type)
90 		return -ENOENT;
91 
92 	/* unsupported modes and filters */
93 	if (event->attr.sample_period) /* no sampling */
94 		return -EINVAL;
95 
96 	if (event->cpu < 0)
97 		return -EINVAL;
98 
99 	gt = config_to_gt_id(event->attr.config);
100 	id = config_to_event_id(event->attr.config);
101 	if (!event_supported(pmu, gt, id))
102 		return -ENOENT;
103 
104 	if (has_branch_stack(event))
105 		return -EOPNOTSUPP;
106 
107 	if (!event->parent) {
108 		drm_dev_get(&xe->drm);
109 		xe_pm_runtime_get(xe);
110 		event->destroy = xe_pmu_event_destroy;
111 	}
112 
113 	return 0;
114 }
115 
116 static u64 __xe_pmu_event_read(struct perf_event *event)
117 {
118 	struct xe_gt *gt = event_to_gt(event);
119 
120 	if (!gt)
121 		return 0;
122 
123 	switch (config_to_event_id(event->attr.config)) {
124 	case XE_PMU_EVENT_GT_C6_RESIDENCY:
125 		return xe_gt_idle_residency_msec(&gt->gtidle);
126 	}
127 
128 	return 0;
129 }
130 
131 static void xe_pmu_event_update(struct perf_event *event)
132 {
133 	struct hw_perf_event *hwc = &event->hw;
134 	u64 prev, new;
135 
136 	prev = local64_read(&hwc->prev_count);
137 	do {
138 		new = __xe_pmu_event_read(event);
139 	} while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new));
140 
141 	local64_add(new - prev, &event->count);
142 }
143 
144 static void xe_pmu_event_read(struct perf_event *event)
145 {
146 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
147 	struct xe_pmu *pmu = &xe->pmu;
148 
149 	if (!pmu->registered) {
150 		event->hw.state = PERF_HES_STOPPED;
151 		return;
152 	}
153 
154 	xe_pmu_event_update(event);
155 }
156 
157 static void xe_pmu_enable(struct perf_event *event)
158 {
159 	/*
160 	 * Store the current counter value so we can report the correct delta
161 	 * for all listeners. Even when the event was already enabled and has
162 	 * an existing non-zero value.
163 	 */
164 	local64_set(&event->hw.prev_count, __xe_pmu_event_read(event));
165 }
166 
167 static void xe_pmu_event_start(struct perf_event *event, int flags)
168 {
169 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
170 	struct xe_pmu *pmu = &xe->pmu;
171 
172 	if (!pmu->registered)
173 		return;
174 
175 	xe_pmu_enable(event);
176 	event->hw.state = 0;
177 }
178 
179 static void xe_pmu_event_stop(struct perf_event *event, int flags)
180 {
181 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
182 	struct xe_pmu *pmu = &xe->pmu;
183 
184 	if (pmu->registered)
185 		if (flags & PERF_EF_UPDATE)
186 			xe_pmu_event_update(event);
187 
188 	event->hw.state = PERF_HES_STOPPED;
189 }
190 
191 static int xe_pmu_event_add(struct perf_event *event, int flags)
192 {
193 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
194 	struct xe_pmu *pmu = &xe->pmu;
195 
196 	if (!pmu->registered)
197 		return -ENODEV;
198 
199 	if (flags & PERF_EF_START)
200 		xe_pmu_event_start(event, flags);
201 
202 	return 0;
203 }
204 
205 static void xe_pmu_event_del(struct perf_event *event, int flags)
206 {
207 	xe_pmu_event_stop(event, PERF_EF_UPDATE);
208 }
209 
210 PMU_FORMAT_ATTR(gt,	"config:60-63");
211 PMU_FORMAT_ATTR(event,	"config:0-11");
212 
213 static struct attribute *pmu_format_attrs[] = {
214 	&format_attr_event.attr,
215 	&format_attr_gt.attr,
216 	NULL,
217 };
218 
219 static const struct attribute_group pmu_format_attr_group = {
220 	.name = "format",
221 	.attrs = pmu_format_attrs,
222 };
223 
224 static ssize_t event_attr_show(struct device *dev,
225 			       struct device_attribute *attr, char *buf)
226 {
227 	struct perf_pmu_events_attr *pmu_attr =
228 		container_of(attr, struct perf_pmu_events_attr, attr);
229 
230 	return sprintf(buf, "event=%#04llx\n", pmu_attr->id);
231 }
232 
233 #define XE_EVENT_ATTR(name_, v_, id_)					\
234 	PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show)
235 
236 #define XE_EVENT_ATTR_UNIT(name_, v_, unit_)				\
237 	PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_)
238 
239 #define XE_EVENT_ATTR_GROUP(v_, id_, ...)				\
240 	static struct attribute *pmu_attr_ ##v_[] = {			\
241 		__VA_ARGS__,						\
242 		NULL							\
243 	};								\
244 	static umode_t is_visible_##v_(struct kobject *kobj,		\
245 				       struct attribute *attr, int idx) \
246 	{								\
247 		struct perf_pmu_events_attr *pmu_attr;			\
248 		struct xe_pmu *pmu;					\
249 									\
250 		pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \
251 		pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)),	\
252 				   typeof(*pmu), base);			\
253 									\
254 		return event_supported(pmu, 0, id_) ? attr->mode : 0;	\
255 	}								\
256 	static const struct attribute_group pmu_group_ ##v_ = {		\
257 		.name = "events",					\
258 		.attrs = pmu_attr_ ## v_,				\
259 		.is_visible = is_visible_ ## v_,			\
260 	}
261 
262 #define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_)			\
263 	XE_EVENT_ATTR(name_, v_, id_)					\
264 	XE_EVENT_ATTR_UNIT(name_, v_, unit_)				\
265 	XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr,	\
266 			    &pmu_event_unit_ ##v_.attr.attr)
267 
268 #define XE_EVENT_ATTR_NOUNIT(name_, v_, id_)				\
269 	XE_EVENT_ATTR(name_, v_, id_)					\
270 	XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr)
271 
272 XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms");
273 
274 static struct attribute *pmu_empty_event_attrs[] = {
275 	/* Empty - all events are added as groups with .attr_update() */
276 	NULL,
277 };
278 
279 static const struct attribute_group pmu_events_attr_group = {
280 	.name = "events",
281 	.attrs = pmu_empty_event_attrs,
282 };
283 
284 static const struct attribute_group *pmu_events_attr_update[] = {
285 	&pmu_group_gt_c6_residency,
286 	NULL,
287 };
288 
289 static void set_supported_events(struct xe_pmu *pmu)
290 {
291 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
292 
293 	if (!xe->info.skip_guc_pc)
294 		pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY);
295 }
296 
297 /**
298  * xe_pmu_unregister() - Remove/cleanup PMU registration
299  * @arg: Ptr to pmu
300  */
301 static void xe_pmu_unregister(void *arg)
302 {
303 	struct xe_pmu *pmu = arg;
304 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
305 
306 	if (!pmu->registered)
307 		return;
308 
309 	pmu->registered = false;
310 
311 	perf_pmu_unregister(&pmu->base);
312 	kfree(pmu->name);
313 }
314 
315 /**
316  * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks.
317  * @pmu: the PMU object
318  *
319  * Returns 0 on success and an appropriate error code otherwise
320  */
321 int xe_pmu_register(struct xe_pmu *pmu)
322 {
323 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
324 	static const struct attribute_group *attr_groups[] = {
325 		&pmu_format_attr_group,
326 		&pmu_events_attr_group,
327 		NULL
328 	};
329 	int ret = -ENOMEM;
330 	char *name;
331 
332 	BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT);
333 
334 	if (IS_SRIOV_VF(xe))
335 		return 0;
336 
337 	name = kasprintf(GFP_KERNEL, "xe_%s",
338 			 dev_name(xe->drm.dev));
339 	if (!name)
340 		goto err;
341 
342 	/* tools/perf reserves colons as special. */
343 	strreplace(name, ':', '_');
344 
345 	pmu->name		= name;
346 	pmu->base.attr_groups	= attr_groups;
347 	pmu->base.attr_update	= pmu_events_attr_update;
348 	pmu->base.scope		= PERF_PMU_SCOPE_SYS_WIDE;
349 	pmu->base.module	= THIS_MODULE;
350 	pmu->base.task_ctx_nr	= perf_invalid_context;
351 	pmu->base.event_init	= xe_pmu_event_init;
352 	pmu->base.add		= xe_pmu_event_add;
353 	pmu->base.del		= xe_pmu_event_del;
354 	pmu->base.start		= xe_pmu_event_start;
355 	pmu->base.stop		= xe_pmu_event_stop;
356 	pmu->base.read		= xe_pmu_event_read;
357 
358 	set_supported_events(pmu);
359 
360 	ret = perf_pmu_register(&pmu->base, pmu->name, -1);
361 	if (ret)
362 		goto err_name;
363 
364 	pmu->registered = true;
365 
366 	return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu);
367 
368 err_name:
369 	kfree(name);
370 err:
371 	drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret);
372 
373 	return ret;
374 }
375