xref: /linux/drivers/gpu/drm/xe/xe_pmu.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1011c1e24SVinay Belgaumkar // SPDX-License-Identifier: MIT
2011c1e24SVinay Belgaumkar /*
3011c1e24SVinay Belgaumkar  * Copyright © 2025 Intel Corporation
4011c1e24SVinay Belgaumkar  */
5011c1e24SVinay Belgaumkar 
6011c1e24SVinay Belgaumkar #include <drm/drm_drv.h>
7011c1e24SVinay Belgaumkar #include <linux/device.h>
8011c1e24SVinay Belgaumkar 
9011c1e24SVinay Belgaumkar #include "xe_device.h"
10*c7f2b8bfSRiana Tauro #include "xe_force_wake.h"
11897286f2SVinay Belgaumkar #include "xe_gt_idle.h"
126978c5f5SRiana Tauro #include "xe_guc_engine_activity.h"
136978c5f5SRiana Tauro #include "xe_hw_engine.h"
144ee64041SLucas De Marchi #include "xe_pm.h"
15011c1e24SVinay Belgaumkar #include "xe_pmu.h"
16011c1e24SVinay Belgaumkar 
17011c1e24SVinay Belgaumkar /**
18011c1e24SVinay Belgaumkar  * DOC: Xe PMU (Performance Monitoring Unit)
19011c1e24SVinay Belgaumkar  *
206978c5f5SRiana Tauro  * Expose events/counters like GT-C6 residency, GT frequency and per-class-engine
216978c5f5SRiana Tauro  * activity to user land via the perf interface. Events are per device.
22011c1e24SVinay Belgaumkar  *
23011c1e24SVinay Belgaumkar  * All events are listed in sysfs:
24011c1e24SVinay Belgaumkar  *
25011c1e24SVinay Belgaumkar  *     $ ls -ld /sys/bus/event_source/devices/xe_*
26011c1e24SVinay Belgaumkar  *     $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/
27011c1e24SVinay Belgaumkar  *     $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/
28011c1e24SVinay Belgaumkar  *
296978c5f5SRiana Tauro  * The following format parameters are available to read events,
306978c5f5SRiana Tauro  * but only few are valid with each event:
316978c5f5SRiana Tauro  *
326978c5f5SRiana Tauro  *	gt[60:63]		Selects gt for the event
336978c5f5SRiana Tauro  *	engine_class[20:27]	Selects engine-class for event
346978c5f5SRiana Tauro  *	engine_instance[12:19]	Selects the engine-instance for the event
356978c5f5SRiana Tauro  *
366978c5f5SRiana Tauro  * For engine specific events (engine-*), gt, engine_class and engine_instance parameters must be
376978c5f5SRiana Tauro  * set as populated by DRM_XE_DEVICE_QUERY_ENGINES.
386978c5f5SRiana Tauro  *
396978c5f5SRiana Tauro  * For gt specific events (gt-*) gt parameter must be passed. All other parameters will be 0.
406978c5f5SRiana Tauro  *
41011c1e24SVinay Belgaumkar  * The standard perf tool can be used to grep for a certain event as well.
42011c1e24SVinay Belgaumkar  * Example:
43011c1e24SVinay Belgaumkar  *
44011c1e24SVinay Belgaumkar  *     $ perf list | grep gt-c6
45011c1e24SVinay Belgaumkar  *
46011c1e24SVinay Belgaumkar  * To sample a specific event for a GT at regular intervals:
47011c1e24SVinay Belgaumkar  *
48011c1e24SVinay Belgaumkar  *     $ perf stat -e <event_name,gt=> -I <interval>
49011c1e24SVinay Belgaumkar  */
50011c1e24SVinay Belgaumkar 
51011c1e24SVinay Belgaumkar #define XE_PMU_EVENT_GT_MASK			GENMASK_ULL(63, 60)
526978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_CLASS_MASK		GENMASK_ULL(27, 20)
536978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_INSTANCE_MASK	GENMASK_ULL(19, 12)
54011c1e24SVinay Belgaumkar #define XE_PMU_EVENT_ID_MASK			GENMASK_ULL(11, 0)
55011c1e24SVinay Belgaumkar 
56011c1e24SVinay Belgaumkar static unsigned int config_to_event_id(u64 config)
57011c1e24SVinay Belgaumkar {
58011c1e24SVinay Belgaumkar 	return FIELD_GET(XE_PMU_EVENT_ID_MASK, config);
59011c1e24SVinay Belgaumkar }
60011c1e24SVinay Belgaumkar 
616978c5f5SRiana Tauro static unsigned int config_to_engine_class(u64 config)
626978c5f5SRiana Tauro {
636978c5f5SRiana Tauro 	return FIELD_GET(XE_PMU_EVENT_ENGINE_CLASS_MASK, config);
646978c5f5SRiana Tauro }
656978c5f5SRiana Tauro 
666978c5f5SRiana Tauro static unsigned int config_to_engine_instance(u64 config)
676978c5f5SRiana Tauro {
686978c5f5SRiana Tauro 	return FIELD_GET(XE_PMU_EVENT_ENGINE_INSTANCE_MASK, config);
696978c5f5SRiana Tauro }
706978c5f5SRiana Tauro 
71011c1e24SVinay Belgaumkar static unsigned int config_to_gt_id(u64 config)
72011c1e24SVinay Belgaumkar {
73011c1e24SVinay Belgaumkar 	return FIELD_GET(XE_PMU_EVENT_GT_MASK, config);
74011c1e24SVinay Belgaumkar }
75011c1e24SVinay Belgaumkar 
76897286f2SVinay Belgaumkar #define XE_PMU_EVENT_GT_C6_RESIDENCY		0x01
776978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_ACTIVE_TICKS	0x02
786978c5f5SRiana Tauro #define XE_PMU_EVENT_ENGINE_TOTAL_TICKS		0x03
79897286f2SVinay Belgaumkar 
80011c1e24SVinay Belgaumkar static struct xe_gt *event_to_gt(struct perf_event *event)
81011c1e24SVinay Belgaumkar {
82011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
83011c1e24SVinay Belgaumkar 	u64 gt = config_to_gt_id(event->attr.config);
84011c1e24SVinay Belgaumkar 
85011c1e24SVinay Belgaumkar 	return xe_device_get_gt(xe, gt);
86011c1e24SVinay Belgaumkar }
87011c1e24SVinay Belgaumkar 
886978c5f5SRiana Tauro static struct xe_hw_engine *event_to_hwe(struct perf_event *event)
896978c5f5SRiana Tauro {
906978c5f5SRiana Tauro 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
916978c5f5SRiana Tauro 	struct drm_xe_engine_class_instance eci;
926978c5f5SRiana Tauro 	u64 config = event->attr.config;
936978c5f5SRiana Tauro 	struct xe_hw_engine *hwe;
946978c5f5SRiana Tauro 
956978c5f5SRiana Tauro 	eci.engine_class = config_to_engine_class(config);
966978c5f5SRiana Tauro 	eci.engine_instance = config_to_engine_instance(config);
976978c5f5SRiana Tauro 	eci.gt_id = config_to_gt_id(config);
986978c5f5SRiana Tauro 
996978c5f5SRiana Tauro 	hwe = xe_hw_engine_lookup(xe, eci);
1006978c5f5SRiana Tauro 	if (!hwe || xe_hw_engine_is_reserved(hwe))
1016978c5f5SRiana Tauro 		return NULL;
1026978c5f5SRiana Tauro 
1036978c5f5SRiana Tauro 	return hwe;
1046978c5f5SRiana Tauro }
1056978c5f5SRiana Tauro 
106*c7f2b8bfSRiana Tauro static bool is_engine_event(u64 config)
107*c7f2b8bfSRiana Tauro {
108*c7f2b8bfSRiana Tauro 	unsigned int event_id = config_to_event_id(config);
109*c7f2b8bfSRiana Tauro 
110*c7f2b8bfSRiana Tauro 	return (event_id == XE_PMU_EVENT_ENGINE_TOTAL_TICKS ||
111*c7f2b8bfSRiana Tauro 		event_id == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS);
112*c7f2b8bfSRiana Tauro }
113*c7f2b8bfSRiana Tauro 
114*c7f2b8bfSRiana Tauro static bool event_gt_forcewake(struct perf_event *event)
115*c7f2b8bfSRiana Tauro {
116*c7f2b8bfSRiana Tauro 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
117*c7f2b8bfSRiana Tauro 	u64 config = event->attr.config;
118*c7f2b8bfSRiana Tauro 	struct xe_gt *gt;
119*c7f2b8bfSRiana Tauro 	unsigned int *fw_ref;
120*c7f2b8bfSRiana Tauro 
121*c7f2b8bfSRiana Tauro 	if (!is_engine_event(config))
122*c7f2b8bfSRiana Tauro 		return true;
123*c7f2b8bfSRiana Tauro 
124*c7f2b8bfSRiana Tauro 	gt = xe_device_get_gt(xe, config_to_gt_id(config));
125*c7f2b8bfSRiana Tauro 
126*c7f2b8bfSRiana Tauro 	fw_ref = kzalloc(sizeof(*fw_ref), GFP_KERNEL);
127*c7f2b8bfSRiana Tauro 	if (!fw_ref)
128*c7f2b8bfSRiana Tauro 		return false;
129*c7f2b8bfSRiana Tauro 
130*c7f2b8bfSRiana Tauro 	*fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
131*c7f2b8bfSRiana Tauro 	if (!*fw_ref) {
132*c7f2b8bfSRiana Tauro 		kfree(fw_ref);
133*c7f2b8bfSRiana Tauro 		return false;
134*c7f2b8bfSRiana Tauro 	}
135*c7f2b8bfSRiana Tauro 
136*c7f2b8bfSRiana Tauro 	event->pmu_private = fw_ref;
137*c7f2b8bfSRiana Tauro 
138*c7f2b8bfSRiana Tauro 	return true;
139*c7f2b8bfSRiana Tauro }
140*c7f2b8bfSRiana Tauro 
141011c1e24SVinay Belgaumkar static bool event_supported(struct xe_pmu *pmu, unsigned int gt,
142011c1e24SVinay Belgaumkar 			    unsigned int id)
143011c1e24SVinay Belgaumkar {
144011c1e24SVinay Belgaumkar 	if (gt >= XE_MAX_GT_PER_TILE)
145011c1e24SVinay Belgaumkar 		return false;
146011c1e24SVinay Belgaumkar 
1476ea5bf16SLucas De Marchi 	return id < sizeof(pmu->supported_events) * BITS_PER_BYTE &&
1486ea5bf16SLucas De Marchi 		pmu->supported_events & BIT_ULL(id);
149011c1e24SVinay Belgaumkar }
150011c1e24SVinay Belgaumkar 
1516978c5f5SRiana Tauro static bool event_param_valid(struct perf_event *event)
1526978c5f5SRiana Tauro {
1536978c5f5SRiana Tauro 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
1546978c5f5SRiana Tauro 	unsigned int engine_class, engine_instance;
1556978c5f5SRiana Tauro 	u64 config = event->attr.config;
1566978c5f5SRiana Tauro 	struct xe_gt *gt;
1576978c5f5SRiana Tauro 
1586978c5f5SRiana Tauro 	gt = xe_device_get_gt(xe, config_to_gt_id(config));
1596978c5f5SRiana Tauro 	if (!gt)
1606978c5f5SRiana Tauro 		return false;
1616978c5f5SRiana Tauro 
1626978c5f5SRiana Tauro 	engine_class = config_to_engine_class(config);
1636978c5f5SRiana Tauro 	engine_instance = config_to_engine_instance(config);
1646978c5f5SRiana Tauro 
1656978c5f5SRiana Tauro 	switch (config_to_event_id(config)) {
1666978c5f5SRiana Tauro 	case XE_PMU_EVENT_GT_C6_RESIDENCY:
1676978c5f5SRiana Tauro 		if (engine_class || engine_instance)
1686978c5f5SRiana Tauro 			return false;
1696978c5f5SRiana Tauro 		break;
1706978c5f5SRiana Tauro 	case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS:
1716978c5f5SRiana Tauro 	case XE_PMU_EVENT_ENGINE_TOTAL_TICKS:
1726978c5f5SRiana Tauro 		if (!event_to_hwe(event))
1736978c5f5SRiana Tauro 			return false;
1746978c5f5SRiana Tauro 		break;
1756978c5f5SRiana Tauro 	}
1766978c5f5SRiana Tauro 
1776978c5f5SRiana Tauro 	return true;
1786978c5f5SRiana Tauro }
1796978c5f5SRiana Tauro 
180011c1e24SVinay Belgaumkar static void xe_pmu_event_destroy(struct perf_event *event)
181011c1e24SVinay Belgaumkar {
182011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
183*c7f2b8bfSRiana Tauro 	struct xe_gt *gt;
184*c7f2b8bfSRiana Tauro 	unsigned int *fw_ref = event->pmu_private;
185*c7f2b8bfSRiana Tauro 
186*c7f2b8bfSRiana Tauro 	if (fw_ref) {
187*c7f2b8bfSRiana Tauro 		gt = xe_device_get_gt(xe, config_to_gt_id(event->attr.config));
188*c7f2b8bfSRiana Tauro 		xe_force_wake_put(gt_to_fw(gt), *fw_ref);
189*c7f2b8bfSRiana Tauro 		kfree(fw_ref);
190*c7f2b8bfSRiana Tauro 		event->pmu_private = NULL;
191*c7f2b8bfSRiana Tauro 	}
192011c1e24SVinay Belgaumkar 
193011c1e24SVinay Belgaumkar 	drm_WARN_ON(&xe->drm, event->parent);
1944ee64041SLucas De Marchi 	xe_pm_runtime_put(xe);
195011c1e24SVinay Belgaumkar 	drm_dev_put(&xe->drm);
196011c1e24SVinay Belgaumkar }
197011c1e24SVinay Belgaumkar 
198011c1e24SVinay Belgaumkar static int xe_pmu_event_init(struct perf_event *event)
199011c1e24SVinay Belgaumkar {
200011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
201011c1e24SVinay Belgaumkar 	struct xe_pmu *pmu = &xe->pmu;
202011c1e24SVinay Belgaumkar 	unsigned int id, gt;
203011c1e24SVinay Belgaumkar 
204011c1e24SVinay Belgaumkar 	if (!pmu->registered)
205011c1e24SVinay Belgaumkar 		return -ENODEV;
206011c1e24SVinay Belgaumkar 
207011c1e24SVinay Belgaumkar 	if (event->attr.type != event->pmu->type)
208011c1e24SVinay Belgaumkar 		return -ENOENT;
209011c1e24SVinay Belgaumkar 
210011c1e24SVinay Belgaumkar 	/* unsupported modes and filters */
211011c1e24SVinay Belgaumkar 	if (event->attr.sample_period) /* no sampling */
212011c1e24SVinay Belgaumkar 		return -EINVAL;
213011c1e24SVinay Belgaumkar 
214011c1e24SVinay Belgaumkar 	if (event->cpu < 0)
215011c1e24SVinay Belgaumkar 		return -EINVAL;
216011c1e24SVinay Belgaumkar 
217011c1e24SVinay Belgaumkar 	gt = config_to_gt_id(event->attr.config);
218011c1e24SVinay Belgaumkar 	id = config_to_event_id(event->attr.config);
219011c1e24SVinay Belgaumkar 	if (!event_supported(pmu, gt, id))
220011c1e24SVinay Belgaumkar 		return -ENOENT;
221011c1e24SVinay Belgaumkar 
222011c1e24SVinay Belgaumkar 	if (has_branch_stack(event))
223011c1e24SVinay Belgaumkar 		return -EOPNOTSUPP;
224011c1e24SVinay Belgaumkar 
2256978c5f5SRiana Tauro 	if (!event_param_valid(event))
2266978c5f5SRiana Tauro 		return -ENOENT;
2276978c5f5SRiana Tauro 
228011c1e24SVinay Belgaumkar 	if (!event->parent) {
229011c1e24SVinay Belgaumkar 		drm_dev_get(&xe->drm);
2304ee64041SLucas De Marchi 		xe_pm_runtime_get(xe);
231*c7f2b8bfSRiana Tauro 		if (!event_gt_forcewake(event)) {
232*c7f2b8bfSRiana Tauro 			xe_pm_runtime_put(xe);
233*c7f2b8bfSRiana Tauro 			drm_dev_put(&xe->drm);
234*c7f2b8bfSRiana Tauro 			return -EINVAL;
235*c7f2b8bfSRiana Tauro 		}
236011c1e24SVinay Belgaumkar 		event->destroy = xe_pmu_event_destroy;
237011c1e24SVinay Belgaumkar 	}
238011c1e24SVinay Belgaumkar 
239011c1e24SVinay Belgaumkar 	return 0;
240011c1e24SVinay Belgaumkar }
241011c1e24SVinay Belgaumkar 
2426978c5f5SRiana Tauro static u64 read_engine_events(struct xe_gt *gt, struct perf_event *event)
2436978c5f5SRiana Tauro {
2446978c5f5SRiana Tauro 	struct xe_hw_engine *hwe;
2456978c5f5SRiana Tauro 	u64 val = 0;
2466978c5f5SRiana Tauro 
2476978c5f5SRiana Tauro 	hwe = event_to_hwe(event);
2486978c5f5SRiana Tauro 	if (config_to_event_id(event->attr.config) == XE_PMU_EVENT_ENGINE_ACTIVE_TICKS)
2496978c5f5SRiana Tauro 		val = xe_guc_engine_activity_active_ticks(&gt->uc.guc, hwe);
2506978c5f5SRiana Tauro 	else
2516978c5f5SRiana Tauro 		val = xe_guc_engine_activity_total_ticks(&gt->uc.guc, hwe);
2526978c5f5SRiana Tauro 
2536978c5f5SRiana Tauro 	return val;
2546978c5f5SRiana Tauro }
2556978c5f5SRiana Tauro 
256011c1e24SVinay Belgaumkar static u64 __xe_pmu_event_read(struct perf_event *event)
257011c1e24SVinay Belgaumkar {
258011c1e24SVinay Belgaumkar 	struct xe_gt *gt = event_to_gt(event);
259011c1e24SVinay Belgaumkar 
260011c1e24SVinay Belgaumkar 	if (!gt)
261011c1e24SVinay Belgaumkar 		return 0;
262011c1e24SVinay Belgaumkar 
263897286f2SVinay Belgaumkar 	switch (config_to_event_id(event->attr.config)) {
264897286f2SVinay Belgaumkar 	case XE_PMU_EVENT_GT_C6_RESIDENCY:
265897286f2SVinay Belgaumkar 		return xe_gt_idle_residency_msec(&gt->gtidle);
2666978c5f5SRiana Tauro 	case XE_PMU_EVENT_ENGINE_ACTIVE_TICKS:
2676978c5f5SRiana Tauro 	case XE_PMU_EVENT_ENGINE_TOTAL_TICKS:
2686978c5f5SRiana Tauro 		return read_engine_events(gt, event);
269897286f2SVinay Belgaumkar 	}
270897286f2SVinay Belgaumkar 
271897286f2SVinay Belgaumkar 	return 0;
272011c1e24SVinay Belgaumkar }
273011c1e24SVinay Belgaumkar 
274ef7ce393SLucas De Marchi static void xe_pmu_event_update(struct perf_event *event)
275011c1e24SVinay Belgaumkar {
276011c1e24SVinay Belgaumkar 	struct hw_perf_event *hwc = &event->hw;
277011c1e24SVinay Belgaumkar 	u64 prev, new;
278011c1e24SVinay Belgaumkar 
279011c1e24SVinay Belgaumkar 	prev = local64_read(&hwc->prev_count);
280011c1e24SVinay Belgaumkar 	do {
281011c1e24SVinay Belgaumkar 		new = __xe_pmu_event_read(event);
282011c1e24SVinay Belgaumkar 	} while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new));
283011c1e24SVinay Belgaumkar 
284011c1e24SVinay Belgaumkar 	local64_add(new - prev, &event->count);
285011c1e24SVinay Belgaumkar }
286011c1e24SVinay Belgaumkar 
287ef7ce393SLucas De Marchi static void xe_pmu_event_read(struct perf_event *event)
288ef7ce393SLucas De Marchi {
289ef7ce393SLucas De Marchi 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
290ef7ce393SLucas De Marchi 	struct xe_pmu *pmu = &xe->pmu;
291ef7ce393SLucas De Marchi 
292ef7ce393SLucas De Marchi 	if (!pmu->registered) {
293ef7ce393SLucas De Marchi 		event->hw.state = PERF_HES_STOPPED;
294ef7ce393SLucas De Marchi 		return;
295ef7ce393SLucas De Marchi 	}
296ef7ce393SLucas De Marchi 
297ef7ce393SLucas De Marchi 	xe_pmu_event_update(event);
298ef7ce393SLucas De Marchi }
299ef7ce393SLucas De Marchi 
300011c1e24SVinay Belgaumkar static void xe_pmu_enable(struct perf_event *event)
301011c1e24SVinay Belgaumkar {
302011c1e24SVinay Belgaumkar 	/*
303011c1e24SVinay Belgaumkar 	 * Store the current counter value so we can report the correct delta
304011c1e24SVinay Belgaumkar 	 * for all listeners. Even when the event was already enabled and has
305011c1e24SVinay Belgaumkar 	 * an existing non-zero value.
306011c1e24SVinay Belgaumkar 	 */
307011c1e24SVinay Belgaumkar 	local64_set(&event->hw.prev_count, __xe_pmu_event_read(event));
308011c1e24SVinay Belgaumkar }
309011c1e24SVinay Belgaumkar 
310011c1e24SVinay Belgaumkar static void xe_pmu_event_start(struct perf_event *event, int flags)
311011c1e24SVinay Belgaumkar {
312011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
313011c1e24SVinay Belgaumkar 	struct xe_pmu *pmu = &xe->pmu;
314011c1e24SVinay Belgaumkar 
315011c1e24SVinay Belgaumkar 	if (!pmu->registered)
316011c1e24SVinay Belgaumkar 		return;
317011c1e24SVinay Belgaumkar 
318011c1e24SVinay Belgaumkar 	xe_pmu_enable(event);
319011c1e24SVinay Belgaumkar 	event->hw.state = 0;
320011c1e24SVinay Belgaumkar }
321011c1e24SVinay Belgaumkar 
322011c1e24SVinay Belgaumkar static void xe_pmu_event_stop(struct perf_event *event, int flags)
323011c1e24SVinay Belgaumkar {
324011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
325011c1e24SVinay Belgaumkar 	struct xe_pmu *pmu = &xe->pmu;
326011c1e24SVinay Belgaumkar 
327011c1e24SVinay Belgaumkar 	if (pmu->registered)
328011c1e24SVinay Belgaumkar 		if (flags & PERF_EF_UPDATE)
329ef7ce393SLucas De Marchi 			xe_pmu_event_update(event);
330011c1e24SVinay Belgaumkar 
331011c1e24SVinay Belgaumkar 	event->hw.state = PERF_HES_STOPPED;
332011c1e24SVinay Belgaumkar }
333011c1e24SVinay Belgaumkar 
334011c1e24SVinay Belgaumkar static int xe_pmu_event_add(struct perf_event *event, int flags)
335011c1e24SVinay Belgaumkar {
336011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base);
337011c1e24SVinay Belgaumkar 	struct xe_pmu *pmu = &xe->pmu;
338011c1e24SVinay Belgaumkar 
339011c1e24SVinay Belgaumkar 	if (!pmu->registered)
340011c1e24SVinay Belgaumkar 		return -ENODEV;
341011c1e24SVinay Belgaumkar 
342011c1e24SVinay Belgaumkar 	if (flags & PERF_EF_START)
343011c1e24SVinay Belgaumkar 		xe_pmu_event_start(event, flags);
344011c1e24SVinay Belgaumkar 
345011c1e24SVinay Belgaumkar 	return 0;
346011c1e24SVinay Belgaumkar }
347011c1e24SVinay Belgaumkar 
348011c1e24SVinay Belgaumkar static void xe_pmu_event_del(struct perf_event *event, int flags)
349011c1e24SVinay Belgaumkar {
350011c1e24SVinay Belgaumkar 	xe_pmu_event_stop(event, PERF_EF_UPDATE);
351011c1e24SVinay Belgaumkar }
352011c1e24SVinay Belgaumkar 
353011c1e24SVinay Belgaumkar PMU_FORMAT_ATTR(gt,			"config:60-63");
3546978c5f5SRiana Tauro PMU_FORMAT_ATTR(engine_class,		"config:20-27");
3556978c5f5SRiana Tauro PMU_FORMAT_ATTR(engine_instance,	"config:12-19");
356011c1e24SVinay Belgaumkar PMU_FORMAT_ATTR(event,			"config:0-11");
357011c1e24SVinay Belgaumkar 
358011c1e24SVinay Belgaumkar static struct attribute *pmu_format_attrs[] = {
359011c1e24SVinay Belgaumkar 	&format_attr_event.attr,
3606978c5f5SRiana Tauro 	&format_attr_engine_class.attr,
3616978c5f5SRiana Tauro 	&format_attr_engine_instance.attr,
362011c1e24SVinay Belgaumkar 	&format_attr_gt.attr,
363011c1e24SVinay Belgaumkar 	NULL,
364011c1e24SVinay Belgaumkar };
365011c1e24SVinay Belgaumkar 
366011c1e24SVinay Belgaumkar static const struct attribute_group pmu_format_attr_group = {
367011c1e24SVinay Belgaumkar 	.name = "format",
368011c1e24SVinay Belgaumkar 	.attrs = pmu_format_attrs,
369011c1e24SVinay Belgaumkar };
370011c1e24SVinay Belgaumkar 
371897286f2SVinay Belgaumkar static ssize_t event_attr_show(struct device *dev,
3726ea5bf16SLucas De Marchi 			       struct device_attribute *attr, char *buf)
3736ea5bf16SLucas De Marchi {
3746ea5bf16SLucas De Marchi 	struct perf_pmu_events_attr *pmu_attr =
3756ea5bf16SLucas De Marchi 		container_of(attr, struct perf_pmu_events_attr, attr);
3766ea5bf16SLucas De Marchi 
3776ea5bf16SLucas De Marchi 	return sprintf(buf, "event=%#04llx\n", pmu_attr->id);
3786ea5bf16SLucas De Marchi }
3796ea5bf16SLucas De Marchi 
3806ea5bf16SLucas De Marchi #define XE_EVENT_ATTR(name_, v_, id_)					\
3816ea5bf16SLucas De Marchi 	PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show)
3826ea5bf16SLucas De Marchi 
3836ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_UNIT(name_, v_, unit_)				\
3846ea5bf16SLucas De Marchi 	PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_)
3856ea5bf16SLucas De Marchi 
3866ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_GROUP(v_, id_, ...)				\
3876ea5bf16SLucas De Marchi 	static struct attribute *pmu_attr_ ##v_[] = {			\
3886ea5bf16SLucas De Marchi 		__VA_ARGS__,						\
3896ea5bf16SLucas De Marchi 		NULL							\
3906ea5bf16SLucas De Marchi 	};								\
3916ea5bf16SLucas De Marchi 	static umode_t is_visible_##v_(struct kobject *kobj,		\
3926ea5bf16SLucas De Marchi 				       struct attribute *attr, int idx) \
3936ea5bf16SLucas De Marchi 	{								\
3946ea5bf16SLucas De Marchi 		struct perf_pmu_events_attr *pmu_attr;			\
3956ea5bf16SLucas De Marchi 		struct xe_pmu *pmu;					\
3966ea5bf16SLucas De Marchi 									\
3976ea5bf16SLucas De Marchi 		pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \
3986ea5bf16SLucas De Marchi 		pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)),	\
3996ea5bf16SLucas De Marchi 				   typeof(*pmu), base);			\
4006ea5bf16SLucas De Marchi 									\
4016ea5bf16SLucas De Marchi 		return event_supported(pmu, 0, id_) ? attr->mode : 0;	\
4026ea5bf16SLucas De Marchi 	}								\
4036ea5bf16SLucas De Marchi 	static const struct attribute_group pmu_group_ ##v_ = {		\
4046ea5bf16SLucas De Marchi 		.name = "events",					\
4056ea5bf16SLucas De Marchi 		.attrs = pmu_attr_ ## v_,				\
4066ea5bf16SLucas De Marchi 		.is_visible = is_visible_ ## v_,			\
4076ea5bf16SLucas De Marchi 	}
4086ea5bf16SLucas De Marchi 
4096ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_)			\
4106ea5bf16SLucas De Marchi 	XE_EVENT_ATTR(name_, v_, id_)					\
4116ea5bf16SLucas De Marchi 	XE_EVENT_ATTR_UNIT(name_, v_, unit_)				\
4126ea5bf16SLucas De Marchi 	XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr,	\
4136ea5bf16SLucas De Marchi 			    &pmu_event_unit_ ##v_.attr.attr)
4146ea5bf16SLucas De Marchi 
4156ea5bf16SLucas De Marchi #define XE_EVENT_ATTR_NOUNIT(name_, v_, id_)				\
4166ea5bf16SLucas De Marchi 	XE_EVENT_ATTR(name_, v_, id_)					\
4176ea5bf16SLucas De Marchi 	XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr)
4186ea5bf16SLucas De Marchi 
419897286f2SVinay Belgaumkar XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms");
4206978c5f5SRiana Tauro XE_EVENT_ATTR_NOUNIT(engine-active-ticks, engine_active_ticks, XE_PMU_EVENT_ENGINE_ACTIVE_TICKS);
4216978c5f5SRiana Tauro XE_EVENT_ATTR_NOUNIT(engine-total-ticks, engine_total_ticks, XE_PMU_EVENT_ENGINE_TOTAL_TICKS);
422897286f2SVinay Belgaumkar 
4236ea5bf16SLucas De Marchi static struct attribute *pmu_empty_event_attrs[] = {
4246ea5bf16SLucas De Marchi 	/* Empty - all events are added as groups with .attr_update() */
425011c1e24SVinay Belgaumkar 	NULL,
426011c1e24SVinay Belgaumkar };
427011c1e24SVinay Belgaumkar 
428011c1e24SVinay Belgaumkar static const struct attribute_group pmu_events_attr_group = {
429011c1e24SVinay Belgaumkar 	.name = "events",
4306ea5bf16SLucas De Marchi 	.attrs = pmu_empty_event_attrs,
431011c1e24SVinay Belgaumkar };
432011c1e24SVinay Belgaumkar 
4336ea5bf16SLucas De Marchi static const struct attribute_group *pmu_events_attr_update[] = {
434897286f2SVinay Belgaumkar 	&pmu_group_gt_c6_residency,
4356978c5f5SRiana Tauro 	&pmu_group_engine_active_ticks,
4366978c5f5SRiana Tauro 	&pmu_group_engine_total_ticks,
4376ea5bf16SLucas De Marchi 	NULL,
4386ea5bf16SLucas De Marchi };
4396ea5bf16SLucas De Marchi 
4406ea5bf16SLucas De Marchi static void set_supported_events(struct xe_pmu *pmu)
4416ea5bf16SLucas De Marchi {
442897286f2SVinay Belgaumkar 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
4436978c5f5SRiana Tauro 	struct xe_gt *gt = xe_device_get_gt(xe, 0);
444897286f2SVinay Belgaumkar 
445897286f2SVinay Belgaumkar 	if (!xe->info.skip_guc_pc)
446897286f2SVinay Belgaumkar 		pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY);
4476978c5f5SRiana Tauro 
4486978c5f5SRiana Tauro 	if (xe_guc_engine_activity_supported(&gt->uc.guc)) {
4496978c5f5SRiana Tauro 		pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_ACTIVE_TICKS);
4506978c5f5SRiana Tauro 		pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_ENGINE_TOTAL_TICKS);
4516978c5f5SRiana Tauro 	}
4526ea5bf16SLucas De Marchi }
4536ea5bf16SLucas De Marchi 
454011c1e24SVinay Belgaumkar /**
455011c1e24SVinay Belgaumkar  * xe_pmu_unregister() - Remove/cleanup PMU registration
456011c1e24SVinay Belgaumkar  * @arg: Ptr to pmu
457011c1e24SVinay Belgaumkar  */
458011c1e24SVinay Belgaumkar static void xe_pmu_unregister(void *arg)
459011c1e24SVinay Belgaumkar {
460011c1e24SVinay Belgaumkar 	struct xe_pmu *pmu = arg;
461011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
462011c1e24SVinay Belgaumkar 
463011c1e24SVinay Belgaumkar 	if (!pmu->registered)
464011c1e24SVinay Belgaumkar 		return;
465011c1e24SVinay Belgaumkar 
466011c1e24SVinay Belgaumkar 	pmu->registered = false;
467011c1e24SVinay Belgaumkar 
468011c1e24SVinay Belgaumkar 	perf_pmu_unregister(&pmu->base);
469011c1e24SVinay Belgaumkar 	kfree(pmu->name);
470011c1e24SVinay Belgaumkar }
471011c1e24SVinay Belgaumkar 
472011c1e24SVinay Belgaumkar /**
473011c1e24SVinay Belgaumkar  * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks.
474011c1e24SVinay Belgaumkar  * @pmu: the PMU object
475011c1e24SVinay Belgaumkar  *
476011c1e24SVinay Belgaumkar  * Returns 0 on success and an appropriate error code otherwise
477011c1e24SVinay Belgaumkar  */
478011c1e24SVinay Belgaumkar int xe_pmu_register(struct xe_pmu *pmu)
479011c1e24SVinay Belgaumkar {
480011c1e24SVinay Belgaumkar 	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
481011c1e24SVinay Belgaumkar 	static const struct attribute_group *attr_groups[] = {
482011c1e24SVinay Belgaumkar 		&pmu_format_attr_group,
483011c1e24SVinay Belgaumkar 		&pmu_events_attr_group,
484011c1e24SVinay Belgaumkar 		NULL
485011c1e24SVinay Belgaumkar 	};
486011c1e24SVinay Belgaumkar 	int ret = -ENOMEM;
487011c1e24SVinay Belgaumkar 	char *name;
488011c1e24SVinay Belgaumkar 
489257a10c1SLucas De Marchi 	BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT);
490257a10c1SLucas De Marchi 
491011c1e24SVinay Belgaumkar 	if (IS_SRIOV_VF(xe))
492011c1e24SVinay Belgaumkar 		return 0;
493011c1e24SVinay Belgaumkar 
494011c1e24SVinay Belgaumkar 	name = kasprintf(GFP_KERNEL, "xe_%s",
495011c1e24SVinay Belgaumkar 			 dev_name(xe->drm.dev));
496011c1e24SVinay Belgaumkar 	if (!name)
497011c1e24SVinay Belgaumkar 		goto err;
498011c1e24SVinay Belgaumkar 
499011c1e24SVinay Belgaumkar 	/* tools/perf reserves colons as special. */
500011c1e24SVinay Belgaumkar 	strreplace(name, ':', '_');
501011c1e24SVinay Belgaumkar 
502011c1e24SVinay Belgaumkar 	pmu->name		= name;
503011c1e24SVinay Belgaumkar 	pmu->base.attr_groups	= attr_groups;
5046ea5bf16SLucas De Marchi 	pmu->base.attr_update	= pmu_events_attr_update;
505011c1e24SVinay Belgaumkar 	pmu->base.scope		= PERF_PMU_SCOPE_SYS_WIDE;
506011c1e24SVinay Belgaumkar 	pmu->base.module	= THIS_MODULE;
507011c1e24SVinay Belgaumkar 	pmu->base.task_ctx_nr	= perf_invalid_context;
508011c1e24SVinay Belgaumkar 	pmu->base.event_init	= xe_pmu_event_init;
509011c1e24SVinay Belgaumkar 	pmu->base.add		= xe_pmu_event_add;
510011c1e24SVinay Belgaumkar 	pmu->base.del		= xe_pmu_event_del;
511011c1e24SVinay Belgaumkar 	pmu->base.start		= xe_pmu_event_start;
512011c1e24SVinay Belgaumkar 	pmu->base.stop		= xe_pmu_event_stop;
513011c1e24SVinay Belgaumkar 	pmu->base.read		= xe_pmu_event_read;
514011c1e24SVinay Belgaumkar 
5156ea5bf16SLucas De Marchi 	set_supported_events(pmu);
5166ea5bf16SLucas De Marchi 
517011c1e24SVinay Belgaumkar 	ret = perf_pmu_register(&pmu->base, pmu->name, -1);
518011c1e24SVinay Belgaumkar 	if (ret)
519011c1e24SVinay Belgaumkar 		goto err_name;
520011c1e24SVinay Belgaumkar 
521011c1e24SVinay Belgaumkar 	pmu->registered = true;
522011c1e24SVinay Belgaumkar 
523011c1e24SVinay Belgaumkar 	return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu);
524011c1e24SVinay Belgaumkar 
525011c1e24SVinay Belgaumkar err_name:
526011c1e24SVinay Belgaumkar 	kfree(name);
527011c1e24SVinay Belgaumkar err:
528011c1e24SVinay Belgaumkar 	drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret);
529011c1e24SVinay Belgaumkar 
530011c1e24SVinay Belgaumkar 	return ret;
531011c1e24SVinay Belgaumkar }
532