xref: /linux/drivers/gpu/drm/xe/xe_eu_stall.c (revision 85502b2214d50ba0ddf2a5fb454e4d28a160d175)
11537ec85SHarish Chegondi // SPDX-License-Identifier: MIT
21537ec85SHarish Chegondi /*
31537ec85SHarish Chegondi  * Copyright © 2025 Intel Corporation
41537ec85SHarish Chegondi  */
51537ec85SHarish Chegondi 
61537ec85SHarish Chegondi #include <linux/anon_inodes.h>
71537ec85SHarish Chegondi #include <linux/fs.h>
81537ec85SHarish Chegondi #include <linux/poll.h>
91537ec85SHarish Chegondi #include <linux/types.h>
101537ec85SHarish Chegondi 
119a0b11d4SHarish Chegondi #include <drm/drm_drv.h>
12e67a35bcSHarish Chegondi #include <generated/xe_wa_oob.h>
131537ec85SHarish Chegondi #include <uapi/drm/xe_drm.h>
141537ec85SHarish Chegondi 
159a0b11d4SHarish Chegondi #include "xe_bo.h"
161537ec85SHarish Chegondi #include "xe_device.h"
171537ec85SHarish Chegondi #include "xe_eu_stall.h"
189a0b11d4SHarish Chegondi #include "xe_force_wake.h"
199a0b11d4SHarish Chegondi #include "xe_gt_mcr.h"
201537ec85SHarish Chegondi #include "xe_gt_printk.h"
211537ec85SHarish Chegondi #include "xe_gt_topology.h"
221537ec85SHarish Chegondi #include "xe_macros.h"
231537ec85SHarish Chegondi #include "xe_observation.h"
249a0b11d4SHarish Chegondi #include "xe_pm.h"
25760edec9SHarish Chegondi #include "xe_trace.h"
26e67a35bcSHarish Chegondi #include "xe_wa.h"
279a0b11d4SHarish Chegondi 
289a0b11d4SHarish Chegondi #include "regs/xe_eu_stall_regs.h"
299a0b11d4SHarish Chegondi #include "regs/xe_gt_regs.h"
309a0b11d4SHarish Chegondi 
31760edec9SHarish Chegondi #define POLL_PERIOD_MS	5
32760edec9SHarish Chegondi 
339a0b11d4SHarish Chegondi static size_t per_xecore_buf_size = SZ_512K;
349a0b11d4SHarish Chegondi 
359a0b11d4SHarish Chegondi struct per_xecore_buf {
369a0b11d4SHarish Chegondi 	/* Buffer vaddr */
379a0b11d4SHarish Chegondi 	u8 *vaddr;
389a0b11d4SHarish Chegondi 	/* Write pointer */
399a0b11d4SHarish Chegondi 	u32 write;
409a0b11d4SHarish Chegondi 	/* Read pointer */
419a0b11d4SHarish Chegondi 	u32 read;
429a0b11d4SHarish Chegondi };
439a0b11d4SHarish Chegondi 
449a0b11d4SHarish Chegondi struct xe_eu_stall_data_stream {
45760edec9SHarish Chegondi 	bool pollin;
469a0b11d4SHarish Chegondi 	bool enabled;
479a0b11d4SHarish Chegondi 	int wait_num_reports;
489a0b11d4SHarish Chegondi 	int sampling_rate_mult;
49760edec9SHarish Chegondi 	wait_queue_head_t poll_wq;
509a0b11d4SHarish Chegondi 	size_t data_record_size;
519a0b11d4SHarish Chegondi 	size_t per_xecore_buf_size;
529a0b11d4SHarish Chegondi 
539a0b11d4SHarish Chegondi 	struct xe_gt *gt;
549a0b11d4SHarish Chegondi 	struct xe_bo *bo;
555a295badSHarish Chegondi 	/* Lock to protect data buffer pointers */
565a295badSHarish Chegondi 	struct mutex xecore_buf_lock;
579a0b11d4SHarish Chegondi 	struct per_xecore_buf *xecore_buf;
589e0590eeSHarish Chegondi 	struct {
599e0590eeSHarish Chegondi 		bool reported_to_user;
609e0590eeSHarish Chegondi 		xe_dss_mask_t mask;
619e0590eeSHarish Chegondi 	} data_drop;
62760edec9SHarish Chegondi 	struct delayed_work buf_poll_work;
639a0b11d4SHarish Chegondi };
649a0b11d4SHarish Chegondi 
659a0b11d4SHarish Chegondi struct xe_eu_stall_gt {
669a0b11d4SHarish Chegondi 	/* Lock to protect stream */
679a0b11d4SHarish Chegondi 	struct mutex stream_lock;
689a0b11d4SHarish Chegondi 	/* EU stall data stream */
699a0b11d4SHarish Chegondi 	struct xe_eu_stall_data_stream *stream;
70760edec9SHarish Chegondi 	/* Workqueue to schedule buffer pointers polling work */
71760edec9SHarish Chegondi 	struct workqueue_struct *buf_ptr_poll_wq;
729a0b11d4SHarish Chegondi };
731537ec85SHarish Chegondi 
741537ec85SHarish Chegondi /**
751537ec85SHarish Chegondi  * struct eu_stall_open_properties - EU stall sampling properties received
761537ec85SHarish Chegondi  *				     from user space at open.
771537ec85SHarish Chegondi  * @sampling_rate_mult: EU stall sampling rate multiplier.
781537ec85SHarish Chegondi  *			HW will sample every (sampling_rate_mult x 251) cycles.
791537ec85SHarish Chegondi  * @wait_num_reports: Minimum number of EU stall data reports to unblock poll().
801537ec85SHarish Chegondi  * @gt: GT on which EU stall data will be captured.
811537ec85SHarish Chegondi  */
821537ec85SHarish Chegondi struct eu_stall_open_properties {
831537ec85SHarish Chegondi 	int sampling_rate_mult;
841537ec85SHarish Chegondi 	int wait_num_reports;
851537ec85SHarish Chegondi 	struct xe_gt *gt;
861537ec85SHarish Chegondi };
871537ec85SHarish Chegondi 
889a0b11d4SHarish Chegondi /*
899a0b11d4SHarish Chegondi  * EU stall data format for PVC
909a0b11d4SHarish Chegondi  */
919a0b11d4SHarish Chegondi struct xe_eu_stall_data_pvc {
929a0b11d4SHarish Chegondi 	__u64 ip_addr:29;	  /* Bits 0  to 28  */
939a0b11d4SHarish Chegondi 	__u64 active_count:8;	  /* Bits 29 to 36  */
949a0b11d4SHarish Chegondi 	__u64 other_count:8;	  /* Bits 37 to 44  */
959a0b11d4SHarish Chegondi 	__u64 control_count:8;	  /* Bits 45 to 52  */
969a0b11d4SHarish Chegondi 	__u64 pipestall_count:8;  /* Bits 53 to 60  */
979a0b11d4SHarish Chegondi 	__u64 send_count:8;	  /* Bits 61 to 68  */
989a0b11d4SHarish Chegondi 	__u64 dist_acc_count:8;	  /* Bits 69 to 76  */
999a0b11d4SHarish Chegondi 	__u64 sbid_count:8;	  /* Bits 77 to 84  */
1009a0b11d4SHarish Chegondi 	__u64 sync_count:8;	  /* Bits 85 to 92  */
1019a0b11d4SHarish Chegondi 	__u64 inst_fetch_count:8; /* Bits 93 to 100 */
1029a0b11d4SHarish Chegondi 	__u64 unused_bits:27;
1039a0b11d4SHarish Chegondi 	__u64 unused[6];
1049a0b11d4SHarish Chegondi } __packed;
1059a0b11d4SHarish Chegondi 
106e827cf32SHarish Chegondi /*
107e827cf32SHarish Chegondi  * EU stall data format for Xe2 arch GPUs (LNL, BMG).
108e827cf32SHarish Chegondi  */
109e827cf32SHarish Chegondi struct xe_eu_stall_data_xe2 {
110e827cf32SHarish Chegondi 	__u64 ip_addr:29;	  /* Bits 0  to 28  */
111e827cf32SHarish Chegondi 	__u64 tdr_count:8;	  /* Bits 29 to 36  */
112e827cf32SHarish Chegondi 	__u64 other_count:8;	  /* Bits 37 to 44  */
113e827cf32SHarish Chegondi 	__u64 control_count:8;	  /* Bits 45 to 52  */
114e827cf32SHarish Chegondi 	__u64 pipestall_count:8;  /* Bits 53 to 60  */
115e827cf32SHarish Chegondi 	__u64 send_count:8;	  /* Bits 61 to 68  */
116e827cf32SHarish Chegondi 	__u64 dist_acc_count:8;   /* Bits 69 to 76  */
117e827cf32SHarish Chegondi 	__u64 sbid_count:8;	  /* Bits 77 to 84  */
118e827cf32SHarish Chegondi 	__u64 sync_count:8;	  /* Bits 85 to 92  */
119e827cf32SHarish Chegondi 	__u64 inst_fetch_count:8; /* Bits 93 to 100 */
120e827cf32SHarish Chegondi 	__u64 active_count:8;	  /* Bits 101 to 108 */
121e827cf32SHarish Chegondi 	__u64 ex_id:3;		  /* Bits 109 to 111 */
122e827cf32SHarish Chegondi 	__u64 end_flag:1;	  /* Bit  112 */
123e827cf32SHarish Chegondi 	__u64 unused_bits:15;
124e827cf32SHarish Chegondi 	__u64 unused[6];
125e827cf32SHarish Chegondi } __packed;
126e827cf32SHarish Chegondi 
127cd5bbb25SHarish Chegondi const u64 eu_stall_sampling_rates[] = {251, 251 * 2, 251 * 3, 251 * 4, 251 * 5, 251 * 6, 251 * 7};
128cd5bbb25SHarish Chegondi 
129cd5bbb25SHarish Chegondi /**
130cd5bbb25SHarish Chegondi  * xe_eu_stall_get_sampling_rates - get EU stall sampling rates information.
131cd5bbb25SHarish Chegondi  *
132cd5bbb25SHarish Chegondi  * @num_rates: Pointer to a u32 to return the number of sampling rates.
133cd5bbb25SHarish Chegondi  * @rates: double u64 pointer to point to an array of sampling rates.
134cd5bbb25SHarish Chegondi  *
135cd5bbb25SHarish Chegondi  * Stores the number of sampling rates and pointer to the array of
136cd5bbb25SHarish Chegondi  * sampling rates in the input pointers.
137cd5bbb25SHarish Chegondi  *
138cd5bbb25SHarish Chegondi  * Returns: Size of the EU stall sampling rates array.
139cd5bbb25SHarish Chegondi  */
xe_eu_stall_get_sampling_rates(u32 * num_rates,const u64 ** rates)140cd5bbb25SHarish Chegondi size_t xe_eu_stall_get_sampling_rates(u32 *num_rates, const u64 **rates)
141cd5bbb25SHarish Chegondi {
142cd5bbb25SHarish Chegondi 	*num_rates = ARRAY_SIZE(eu_stall_sampling_rates);
143cd5bbb25SHarish Chegondi 	*rates = eu_stall_sampling_rates;
144cd5bbb25SHarish Chegondi 
145cd5bbb25SHarish Chegondi 	return sizeof(eu_stall_sampling_rates);
146cd5bbb25SHarish Chegondi }
147cd5bbb25SHarish Chegondi 
148cd5bbb25SHarish Chegondi /**
149cd5bbb25SHarish Chegondi  * xe_eu_stall_get_per_xecore_buf_size - get per XeCore buffer size.
150cd5bbb25SHarish Chegondi  *
151cd5bbb25SHarish Chegondi  * Returns: The per XeCore buffer size used to allocate the per GT
152cd5bbb25SHarish Chegondi  *	    EU stall data buffer.
153cd5bbb25SHarish Chegondi  */
xe_eu_stall_get_per_xecore_buf_size(void)154cd5bbb25SHarish Chegondi size_t xe_eu_stall_get_per_xecore_buf_size(void)
155cd5bbb25SHarish Chegondi {
156cd5bbb25SHarish Chegondi 	return per_xecore_buf_size;
157cd5bbb25SHarish Chegondi }
158cd5bbb25SHarish Chegondi 
159cd5bbb25SHarish Chegondi /**
160cd5bbb25SHarish Chegondi  * xe_eu_stall_data_record_size - get EU stall data record size.
161cd5bbb25SHarish Chegondi  *
162cd5bbb25SHarish Chegondi  * @xe: Pointer to a Xe device.
163cd5bbb25SHarish Chegondi  *
164cd5bbb25SHarish Chegondi  * Returns: EU stall data record size.
165cd5bbb25SHarish Chegondi  */
xe_eu_stall_data_record_size(struct xe_device * xe)166cd5bbb25SHarish Chegondi size_t xe_eu_stall_data_record_size(struct xe_device *xe)
1679a0b11d4SHarish Chegondi {
1689a0b11d4SHarish Chegondi 	size_t record_size = 0;
1699a0b11d4SHarish Chegondi 
1709a0b11d4SHarish Chegondi 	if (xe->info.platform == XE_PVC)
1719a0b11d4SHarish Chegondi 		record_size = sizeof(struct xe_eu_stall_data_pvc);
172e827cf32SHarish Chegondi 	else if (GRAPHICS_VER(xe) >= 20)
173e827cf32SHarish Chegondi 		record_size = sizeof(struct xe_eu_stall_data_xe2);
1749a0b11d4SHarish Chegondi 
1759a0b11d4SHarish Chegondi 	xe_assert(xe, is_power_of_2(record_size));
1769a0b11d4SHarish Chegondi 
1779a0b11d4SHarish Chegondi 	return record_size;
1789a0b11d4SHarish Chegondi }
1799a0b11d4SHarish Chegondi 
1809a0b11d4SHarish Chegondi /**
1819a0b11d4SHarish Chegondi  * num_data_rows - Return the number of EU stall data rows of 64B each
1829a0b11d4SHarish Chegondi  *		   for a given data size.
1839a0b11d4SHarish Chegondi  *
1849a0b11d4SHarish Chegondi  * @data_size: EU stall data size
1859a0b11d4SHarish Chegondi  */
num_data_rows(u32 data_size)1869a0b11d4SHarish Chegondi static u32 num_data_rows(u32 data_size)
1879a0b11d4SHarish Chegondi {
1889a0b11d4SHarish Chegondi 	return data_size >> 6;
1899a0b11d4SHarish Chegondi }
1909a0b11d4SHarish Chegondi 
xe_eu_stall_fini(void * arg)1919a0b11d4SHarish Chegondi static void xe_eu_stall_fini(void *arg)
1929a0b11d4SHarish Chegondi {
1939a0b11d4SHarish Chegondi 	struct xe_gt *gt = arg;
1949a0b11d4SHarish Chegondi 
195760edec9SHarish Chegondi 	destroy_workqueue(gt->eu_stall->buf_ptr_poll_wq);
1969a0b11d4SHarish Chegondi 	mutex_destroy(&gt->eu_stall->stream_lock);
1979a0b11d4SHarish Chegondi 	kfree(gt->eu_stall);
1989a0b11d4SHarish Chegondi }
1999a0b11d4SHarish Chegondi 
2009a0b11d4SHarish Chegondi /**
2019a0b11d4SHarish Chegondi  * xe_eu_stall_init() - Allocate and initialize GT level EU stall data
2029a0b11d4SHarish Chegondi  *			structure xe_eu_stall_gt within struct xe_gt.
2039a0b11d4SHarish Chegondi  *
2049a0b11d4SHarish Chegondi  * @gt: GT being initialized.
2059a0b11d4SHarish Chegondi  *
2069a0b11d4SHarish Chegondi  * Returns: zero on success or a negative error code.
2079a0b11d4SHarish Chegondi  */
xe_eu_stall_init(struct xe_gt * gt)2089a0b11d4SHarish Chegondi int xe_eu_stall_init(struct xe_gt *gt)
2099a0b11d4SHarish Chegondi {
2109a0b11d4SHarish Chegondi 	struct xe_device *xe = gt_to_xe(gt);
2119a0b11d4SHarish Chegondi 	int ret;
2129a0b11d4SHarish Chegondi 
213*1d622a4fSHarish Chegondi 	if (!xe_eu_stall_supported_on_platform(xe))
214*1d622a4fSHarish Chegondi 		return 0;
215*1d622a4fSHarish Chegondi 
2169a0b11d4SHarish Chegondi 	gt->eu_stall = kzalloc(sizeof(*gt->eu_stall), GFP_KERNEL);
2179a0b11d4SHarish Chegondi 	if (!gt->eu_stall) {
2189a0b11d4SHarish Chegondi 		ret = -ENOMEM;
2199a0b11d4SHarish Chegondi 		goto exit;
2209a0b11d4SHarish Chegondi 	}
2219a0b11d4SHarish Chegondi 
2229a0b11d4SHarish Chegondi 	mutex_init(&gt->eu_stall->stream_lock);
2239a0b11d4SHarish Chegondi 
224760edec9SHarish Chegondi 	gt->eu_stall->buf_ptr_poll_wq = alloc_ordered_workqueue("xe_eu_stall", 0);
225760edec9SHarish Chegondi 	if (!gt->eu_stall->buf_ptr_poll_wq) {
226760edec9SHarish Chegondi 		ret = -ENOMEM;
227760edec9SHarish Chegondi 		goto exit_free;
228760edec9SHarish Chegondi 	}
229760edec9SHarish Chegondi 
230488975c2SHarish Chegondi 	return devm_add_action_or_reset(xe->drm.dev, xe_eu_stall_fini, gt);
2319a0b11d4SHarish Chegondi exit_free:
2329a0b11d4SHarish Chegondi 	mutex_destroy(&gt->eu_stall->stream_lock);
2339a0b11d4SHarish Chegondi 	kfree(gt->eu_stall);
2349a0b11d4SHarish Chegondi exit:
2359a0b11d4SHarish Chegondi 	return ret;
2369a0b11d4SHarish Chegondi }
2379a0b11d4SHarish Chegondi 
set_prop_eu_stall_sampling_rate(struct xe_device * xe,u64 value,struct eu_stall_open_properties * props)2381537ec85SHarish Chegondi static int set_prop_eu_stall_sampling_rate(struct xe_device *xe, u64 value,
2391537ec85SHarish Chegondi 					   struct eu_stall_open_properties *props)
2401537ec85SHarish Chegondi {
2411537ec85SHarish Chegondi 	value = div_u64(value, 251);
2421537ec85SHarish Chegondi 	if (value == 0 || value > 7) {
2431537ec85SHarish Chegondi 		drm_dbg(&xe->drm, "Invalid EU stall sampling rate %llu\n", value);
2441537ec85SHarish Chegondi 		return -EINVAL;
2451537ec85SHarish Chegondi 	}
2461537ec85SHarish Chegondi 	props->sampling_rate_mult = value;
2471537ec85SHarish Chegondi 	return 0;
2481537ec85SHarish Chegondi }
2491537ec85SHarish Chegondi 
set_prop_eu_stall_wait_num_reports(struct xe_device * xe,u64 value,struct eu_stall_open_properties * props)2501537ec85SHarish Chegondi static int set_prop_eu_stall_wait_num_reports(struct xe_device *xe, u64 value,
2511537ec85SHarish Chegondi 					      struct eu_stall_open_properties *props)
2521537ec85SHarish Chegondi {
2531537ec85SHarish Chegondi 	props->wait_num_reports = value;
2541537ec85SHarish Chegondi 
2551537ec85SHarish Chegondi 	return 0;
2561537ec85SHarish Chegondi }
2571537ec85SHarish Chegondi 
set_prop_eu_stall_gt_id(struct xe_device * xe,u64 value,struct eu_stall_open_properties * props)2581537ec85SHarish Chegondi static int set_prop_eu_stall_gt_id(struct xe_device *xe, u64 value,
2591537ec85SHarish Chegondi 				   struct eu_stall_open_properties *props)
2601537ec85SHarish Chegondi {
2611537ec85SHarish Chegondi 	if (value >= xe->info.gt_count) {
2621537ec85SHarish Chegondi 		drm_dbg(&xe->drm, "Invalid GT ID %llu for EU stall sampling\n", value);
2631537ec85SHarish Chegondi 		return -EINVAL;
2641537ec85SHarish Chegondi 	}
2651537ec85SHarish Chegondi 	props->gt = xe_device_get_gt(xe, value);
2661537ec85SHarish Chegondi 	return 0;
2671537ec85SHarish Chegondi }
2681537ec85SHarish Chegondi 
2691537ec85SHarish Chegondi typedef int (*set_eu_stall_property_fn)(struct xe_device *xe, u64 value,
2701537ec85SHarish Chegondi 					struct eu_stall_open_properties *props);
2711537ec85SHarish Chegondi 
2721537ec85SHarish Chegondi static const set_eu_stall_property_fn xe_set_eu_stall_property_funcs[] = {
2731537ec85SHarish Chegondi 	[DRM_XE_EU_STALL_PROP_SAMPLE_RATE] = set_prop_eu_stall_sampling_rate,
2741537ec85SHarish Chegondi 	[DRM_XE_EU_STALL_PROP_WAIT_NUM_REPORTS] = set_prop_eu_stall_wait_num_reports,
2751537ec85SHarish Chegondi 	[DRM_XE_EU_STALL_PROP_GT_ID] = set_prop_eu_stall_gt_id,
2761537ec85SHarish Chegondi };
2771537ec85SHarish Chegondi 
xe_eu_stall_user_ext_set_property(struct xe_device * xe,u64 extension,struct eu_stall_open_properties * props)2781537ec85SHarish Chegondi static int xe_eu_stall_user_ext_set_property(struct xe_device *xe, u64 extension,
2791537ec85SHarish Chegondi 					     struct eu_stall_open_properties *props)
2801537ec85SHarish Chegondi {
2811537ec85SHarish Chegondi 	u64 __user *address = u64_to_user_ptr(extension);
2821537ec85SHarish Chegondi 	struct drm_xe_ext_set_property ext;
2831537ec85SHarish Chegondi 	int err;
2841537ec85SHarish Chegondi 	u32 idx;
2851537ec85SHarish Chegondi 
2861537ec85SHarish Chegondi 	err = copy_from_user(&ext, address, sizeof(ext));
2871537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, err))
2881537ec85SHarish Chegondi 		return -EFAULT;
2891537ec85SHarish Chegondi 
2901537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, ext.property >= ARRAY_SIZE(xe_set_eu_stall_property_funcs)) ||
2911537ec85SHarish Chegondi 	    XE_IOCTL_DBG(xe, ext.pad))
2921537ec85SHarish Chegondi 		return -EINVAL;
2931537ec85SHarish Chegondi 
2941537ec85SHarish Chegondi 	idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_set_eu_stall_property_funcs));
2951537ec85SHarish Chegondi 	return xe_set_eu_stall_property_funcs[idx](xe, ext.value, props);
2961537ec85SHarish Chegondi }
2971537ec85SHarish Chegondi 
2981537ec85SHarish Chegondi typedef int (*xe_eu_stall_user_extension_fn)(struct xe_device *xe, u64 extension,
2991537ec85SHarish Chegondi 					     struct eu_stall_open_properties *props);
3001537ec85SHarish Chegondi static const xe_eu_stall_user_extension_fn xe_eu_stall_user_extension_funcs[] = {
3011537ec85SHarish Chegondi 	[DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY] = xe_eu_stall_user_ext_set_property,
3021537ec85SHarish Chegondi };
3031537ec85SHarish Chegondi 
3041537ec85SHarish Chegondi #define MAX_USER_EXTENSIONS	5
xe_eu_stall_user_extensions(struct xe_device * xe,u64 extension,int ext_number,struct eu_stall_open_properties * props)3051537ec85SHarish Chegondi static int xe_eu_stall_user_extensions(struct xe_device *xe, u64 extension,
3061537ec85SHarish Chegondi 				       int ext_number, struct eu_stall_open_properties *props)
3071537ec85SHarish Chegondi {
3081537ec85SHarish Chegondi 	u64 __user *address = u64_to_user_ptr(extension);
3091537ec85SHarish Chegondi 	struct drm_xe_user_extension ext;
3101537ec85SHarish Chegondi 	int err;
3111537ec85SHarish Chegondi 	u32 idx;
3121537ec85SHarish Chegondi 
3131537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS))
3141537ec85SHarish Chegondi 		return -E2BIG;
3151537ec85SHarish Chegondi 
3161537ec85SHarish Chegondi 	err = copy_from_user(&ext, address, sizeof(ext));
3171537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, err))
3181537ec85SHarish Chegondi 		return -EFAULT;
3191537ec85SHarish Chegondi 
3201537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, ext.pad) ||
3211537ec85SHarish Chegondi 	    XE_IOCTL_DBG(xe, ext.name >= ARRAY_SIZE(xe_eu_stall_user_extension_funcs)))
3221537ec85SHarish Chegondi 		return -EINVAL;
3231537ec85SHarish Chegondi 
3241537ec85SHarish Chegondi 	idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_eu_stall_user_extension_funcs));
3251537ec85SHarish Chegondi 	err = xe_eu_stall_user_extension_funcs[idx](xe, extension, props);
3261537ec85SHarish Chegondi 	if (XE_IOCTL_DBG(xe, err))
3271537ec85SHarish Chegondi 		return err;
3281537ec85SHarish Chegondi 
3291537ec85SHarish Chegondi 	if (ext.next_extension)
3301537ec85SHarish Chegondi 		return xe_eu_stall_user_extensions(xe, ext.next_extension, ++ext_number, props);
3311537ec85SHarish Chegondi 
3321537ec85SHarish Chegondi 	return 0;
3331537ec85SHarish Chegondi }
3341537ec85SHarish Chegondi 
335760edec9SHarish Chegondi /**
336760edec9SHarish Chegondi  * buf_data_size - Calculate the number of bytes in a circular buffer
337760edec9SHarish Chegondi  *		   given the read and write pointers and the size of
338760edec9SHarish Chegondi  *		   the buffer.
339760edec9SHarish Chegondi  *
340760edec9SHarish Chegondi  * @buf_size: Size of the circular buffer
341760edec9SHarish Chegondi  * @read_ptr: Read pointer with an additional overflow bit
342760edec9SHarish Chegondi  * @write_ptr: Write pointer with an additional overflow bit
343760edec9SHarish Chegondi  *
344760edec9SHarish Chegondi  * Since the read and write pointers have an additional overflow bit,
345760edec9SHarish Chegondi  * this function calculates the offsets from the pointers and use the
346760edec9SHarish Chegondi  * offsets to calculate the data size in the buffer.
347760edec9SHarish Chegondi  *
348760edec9SHarish Chegondi  * Returns: number of bytes of data in the buffer
349760edec9SHarish Chegondi  */
buf_data_size(size_t buf_size,u32 read_ptr,u32 write_ptr)350760edec9SHarish Chegondi static u32 buf_data_size(size_t buf_size, u32 read_ptr, u32 write_ptr)
351760edec9SHarish Chegondi {
352760edec9SHarish Chegondi 	u32 read_offset, write_offset, size = 0;
353760edec9SHarish Chegondi 
354760edec9SHarish Chegondi 	if (read_ptr == write_ptr)
355760edec9SHarish Chegondi 		goto exit;
356760edec9SHarish Chegondi 
357760edec9SHarish Chegondi 	read_offset = read_ptr & (buf_size - 1);
358760edec9SHarish Chegondi 	write_offset = write_ptr & (buf_size - 1);
359760edec9SHarish Chegondi 
360760edec9SHarish Chegondi 	if (write_offset > read_offset)
361760edec9SHarish Chegondi 		size = write_offset - read_offset;
362760edec9SHarish Chegondi 	else
363760edec9SHarish Chegondi 		size = buf_size - read_offset + write_offset;
364760edec9SHarish Chegondi exit:
365760edec9SHarish Chegondi 	return size;
366760edec9SHarish Chegondi }
367760edec9SHarish Chegondi 
368760edec9SHarish Chegondi /**
369760edec9SHarish Chegondi  * eu_stall_data_buf_poll - Poll for EU stall data in the buffer.
370760edec9SHarish Chegondi  *
371760edec9SHarish Chegondi  * @stream: xe EU stall data stream instance
372760edec9SHarish Chegondi  *
373760edec9SHarish Chegondi  * Returns: true if the EU stall buffer contains minimum stall data as
374760edec9SHarish Chegondi  *	    specified by the event report count, else false.
375760edec9SHarish Chegondi  */
eu_stall_data_buf_poll(struct xe_eu_stall_data_stream * stream)376760edec9SHarish Chegondi static bool eu_stall_data_buf_poll(struct xe_eu_stall_data_stream *stream)
377760edec9SHarish Chegondi {
378760edec9SHarish Chegondi 	u32 read_ptr, write_ptr_reg, write_ptr, total_data = 0;
379760edec9SHarish Chegondi 	u32 buf_size = stream->per_xecore_buf_size;
380760edec9SHarish Chegondi 	struct per_xecore_buf *xecore_buf;
381760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
382760edec9SHarish Chegondi 	bool min_data_present = false;
383760edec9SHarish Chegondi 	u16 group, instance;
384760edec9SHarish Chegondi 	unsigned int xecore;
385760edec9SHarish Chegondi 
3865a295badSHarish Chegondi 	mutex_lock(&stream->xecore_buf_lock);
387760edec9SHarish Chegondi 	for_each_dss_steering(xecore, gt, group, instance) {
388760edec9SHarish Chegondi 		xecore_buf = &stream->xecore_buf[xecore];
389760edec9SHarish Chegondi 		read_ptr = xecore_buf->read;
390760edec9SHarish Chegondi 		write_ptr_reg = xe_gt_mcr_unicast_read(gt, XEHPC_EUSTALL_REPORT,
391760edec9SHarish Chegondi 						       group, instance);
392760edec9SHarish Chegondi 		write_ptr = REG_FIELD_GET(XEHPC_EUSTALL_REPORT_WRITE_PTR_MASK, write_ptr_reg);
393760edec9SHarish Chegondi 		write_ptr <<= 6;
394760edec9SHarish Chegondi 		write_ptr &= ((buf_size << 1) - 1);
395760edec9SHarish Chegondi 		if (!min_data_present) {
396760edec9SHarish Chegondi 			total_data += buf_data_size(buf_size, read_ptr, write_ptr);
397760edec9SHarish Chegondi 			if (num_data_rows(total_data) >= stream->wait_num_reports)
398760edec9SHarish Chegondi 				min_data_present = true;
399760edec9SHarish Chegondi 		}
4009e0590eeSHarish Chegondi 		if (write_ptr_reg & XEHPC_EUSTALL_REPORT_OVERFLOW_DROP)
4019e0590eeSHarish Chegondi 			set_bit(xecore, stream->data_drop.mask);
402760edec9SHarish Chegondi 		xecore_buf->write = write_ptr;
403760edec9SHarish Chegondi 	}
4045a295badSHarish Chegondi 	mutex_unlock(&stream->xecore_buf_lock);
405760edec9SHarish Chegondi 
406760edec9SHarish Chegondi 	return min_data_present;
407760edec9SHarish Chegondi }
408760edec9SHarish Chegondi 
clear_dropped_eviction_line_bit(struct xe_gt * gt,u16 group,u16 instance)4099e0590eeSHarish Chegondi static void clear_dropped_eviction_line_bit(struct xe_gt *gt, u16 group, u16 instance)
4109e0590eeSHarish Chegondi {
411e827cf32SHarish Chegondi 	struct xe_device *xe = gt_to_xe(gt);
4129e0590eeSHarish Chegondi 	u32 write_ptr_reg;
4139e0590eeSHarish Chegondi 
414e827cf32SHarish Chegondi 	/* On PVC, the overflow bit has to be cleared by writing 1 to it.
415e827cf32SHarish Chegondi 	 * On Xe2 and later GPUs, the bit has to be cleared by writing 0 to it.
416e827cf32SHarish Chegondi 	 */
417e827cf32SHarish Chegondi 	if (GRAPHICS_VER(xe) >= 20)
418e827cf32SHarish Chegondi 		write_ptr_reg = _MASKED_BIT_DISABLE(XEHPC_EUSTALL_REPORT_OVERFLOW_DROP);
419e827cf32SHarish Chegondi 	else
4209e0590eeSHarish Chegondi 		write_ptr_reg = _MASKED_BIT_ENABLE(XEHPC_EUSTALL_REPORT_OVERFLOW_DROP);
4219e0590eeSHarish Chegondi 
4229e0590eeSHarish Chegondi 	xe_gt_mcr_unicast_write(gt, XEHPC_EUSTALL_REPORT, write_ptr_reg, group, instance);
4239e0590eeSHarish Chegondi }
4249e0590eeSHarish Chegondi 
xe_eu_stall_data_buf_read(struct xe_eu_stall_data_stream * stream,char __user * buf,size_t count,size_t * total_data_size,struct xe_gt * gt,u16 group,u16 instance,unsigned int xecore)425760edec9SHarish Chegondi static int xe_eu_stall_data_buf_read(struct xe_eu_stall_data_stream *stream,
426760edec9SHarish Chegondi 				     char __user *buf, size_t count,
427760edec9SHarish Chegondi 				     size_t *total_data_size, struct xe_gt *gt,
428760edec9SHarish Chegondi 				     u16 group, u16 instance, unsigned int xecore)
429760edec9SHarish Chegondi {
430760edec9SHarish Chegondi 	size_t read_data_size, copy_size, buf_size;
431760edec9SHarish Chegondi 	u32 read_ptr_reg, read_ptr, write_ptr;
432760edec9SHarish Chegondi 	u8 *xecore_start_vaddr, *read_vaddr;
433760edec9SHarish Chegondi 	struct per_xecore_buf *xecore_buf;
434760edec9SHarish Chegondi 	u32 read_offset, write_offset;
435760edec9SHarish Chegondi 
436760edec9SHarish Chegondi 	/* Hardware increments the read and write pointers such that they can
437760edec9SHarish Chegondi 	 * overflow into one additional bit. For example, a 256KB size buffer
438760edec9SHarish Chegondi 	 * offset pointer needs 18 bits. But HW uses 19 bits for the read and
439760edec9SHarish Chegondi 	 * write pointers. This technique avoids wasting a slot in the buffer.
440760edec9SHarish Chegondi 	 * Read and write offsets are calculated from the pointers in order to
441760edec9SHarish Chegondi 	 * check if the write pointer has wrapped around the array.
442760edec9SHarish Chegondi 	 */
443760edec9SHarish Chegondi 	xecore_buf = &stream->xecore_buf[xecore];
444760edec9SHarish Chegondi 	xecore_start_vaddr = xecore_buf->vaddr;
445760edec9SHarish Chegondi 	read_ptr = xecore_buf->read;
446760edec9SHarish Chegondi 	write_ptr = xecore_buf->write;
447760edec9SHarish Chegondi 	buf_size = stream->per_xecore_buf_size;
448760edec9SHarish Chegondi 
449760edec9SHarish Chegondi 	read_data_size = buf_data_size(buf_size, read_ptr, write_ptr);
450760edec9SHarish Chegondi 	/* Read only the data that the user space buffer can accommodate */
451760edec9SHarish Chegondi 	read_data_size = min_t(size_t, count - *total_data_size, read_data_size);
452760edec9SHarish Chegondi 	if (read_data_size == 0)
4539e0590eeSHarish Chegondi 		goto exit_drop;
454760edec9SHarish Chegondi 
455760edec9SHarish Chegondi 	read_offset = read_ptr & (buf_size - 1);
456760edec9SHarish Chegondi 	write_offset = write_ptr & (buf_size - 1);
457760edec9SHarish Chegondi 	read_vaddr = xecore_start_vaddr + read_offset;
458760edec9SHarish Chegondi 
459760edec9SHarish Chegondi 	if (write_offset > read_offset) {
460760edec9SHarish Chegondi 		if (copy_to_user(buf + *total_data_size, read_vaddr, read_data_size))
461760edec9SHarish Chegondi 			return -EFAULT;
462760edec9SHarish Chegondi 	} else {
463760edec9SHarish Chegondi 		if (read_data_size >= buf_size - read_offset)
464760edec9SHarish Chegondi 			copy_size = buf_size - read_offset;
465760edec9SHarish Chegondi 		else
466760edec9SHarish Chegondi 			copy_size = read_data_size;
467760edec9SHarish Chegondi 		if (copy_to_user(buf + *total_data_size, read_vaddr, copy_size))
468760edec9SHarish Chegondi 			return -EFAULT;
469760edec9SHarish Chegondi 		if (copy_to_user(buf + *total_data_size + copy_size,
470760edec9SHarish Chegondi 				 xecore_start_vaddr, read_data_size - copy_size))
471760edec9SHarish Chegondi 			return -EFAULT;
472760edec9SHarish Chegondi 	}
473760edec9SHarish Chegondi 
474760edec9SHarish Chegondi 	*total_data_size += read_data_size;
475760edec9SHarish Chegondi 	read_ptr += read_data_size;
476760edec9SHarish Chegondi 
477760edec9SHarish Chegondi 	/* Read pointer can overflow into one additional bit */
478760edec9SHarish Chegondi 	read_ptr &= (buf_size << 1) - 1;
479760edec9SHarish Chegondi 	read_ptr_reg = REG_FIELD_PREP(XEHPC_EUSTALL_REPORT1_READ_PTR_MASK, (read_ptr >> 6));
480760edec9SHarish Chegondi 	read_ptr_reg = _MASKED_FIELD(XEHPC_EUSTALL_REPORT1_READ_PTR_MASK, read_ptr_reg);
481760edec9SHarish Chegondi 	xe_gt_mcr_unicast_write(gt, XEHPC_EUSTALL_REPORT1, read_ptr_reg, group, instance);
482760edec9SHarish Chegondi 	xecore_buf->read = read_ptr;
483760edec9SHarish Chegondi 	trace_xe_eu_stall_data_read(group, instance, read_ptr, write_ptr,
484760edec9SHarish Chegondi 				    read_data_size, *total_data_size);
4859e0590eeSHarish Chegondi exit_drop:
4869e0590eeSHarish Chegondi 	/* Clear drop bit (if set) after any data was read or if the buffer was empty.
4879e0590eeSHarish Chegondi 	 * Drop bit can be set even if the buffer is empty as the buffer may have been emptied
4889e0590eeSHarish Chegondi 	 * in the previous read() and the data drop bit was set during the previous read().
4899e0590eeSHarish Chegondi 	 */
4909e0590eeSHarish Chegondi 	if (test_bit(xecore, stream->data_drop.mask)) {
4919e0590eeSHarish Chegondi 		clear_dropped_eviction_line_bit(gt, group, instance);
4929e0590eeSHarish Chegondi 		clear_bit(xecore, stream->data_drop.mask);
4939e0590eeSHarish Chegondi 	}
494760edec9SHarish Chegondi 	return 0;
495760edec9SHarish Chegondi }
496760edec9SHarish Chegondi 
497760edec9SHarish Chegondi /**
498760edec9SHarish Chegondi  * xe_eu_stall_stream_read_locked - copy EU stall counters data from the
499760edec9SHarish Chegondi  *				    per xecore buffers to the userspace buffer
500760edec9SHarish Chegondi  * @stream: A stream opened for EU stall count metrics
501760edec9SHarish Chegondi  * @file: An xe EU stall data stream file
502760edec9SHarish Chegondi  * @buf: destination buffer given by userspace
503760edec9SHarish Chegondi  * @count: the number of bytes userspace wants to read
504760edec9SHarish Chegondi  *
505760edec9SHarish Chegondi  * Returns: Number of bytes copied or a negative error code
506760edec9SHarish Chegondi  * If we've successfully copied any data then reporting that takes
507760edec9SHarish Chegondi  * precedence over any internal error status, so the data isn't lost.
508760edec9SHarish Chegondi  */
xe_eu_stall_stream_read_locked(struct xe_eu_stall_data_stream * stream,struct file * file,char __user * buf,size_t count)509760edec9SHarish Chegondi static ssize_t xe_eu_stall_stream_read_locked(struct xe_eu_stall_data_stream *stream,
510760edec9SHarish Chegondi 					      struct file *file, char __user *buf,
511760edec9SHarish Chegondi 					      size_t count)
512760edec9SHarish Chegondi {
513760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
514760edec9SHarish Chegondi 	size_t total_size = 0;
515760edec9SHarish Chegondi 	u16 group, instance;
516760edec9SHarish Chegondi 	unsigned int xecore;
517760edec9SHarish Chegondi 	int ret = 0;
518760edec9SHarish Chegondi 
5195a295badSHarish Chegondi 	mutex_lock(&stream->xecore_buf_lock);
5209e0590eeSHarish Chegondi 	if (bitmap_weight(stream->data_drop.mask, XE_MAX_DSS_FUSE_BITS)) {
5219e0590eeSHarish Chegondi 		if (!stream->data_drop.reported_to_user) {
5229e0590eeSHarish Chegondi 			stream->data_drop.reported_to_user = true;
5239e0590eeSHarish Chegondi 			xe_gt_dbg(gt, "EU stall data dropped in XeCores: %*pb\n",
5249e0590eeSHarish Chegondi 				  XE_MAX_DSS_FUSE_BITS, stream->data_drop.mask);
5255a295badSHarish Chegondi 			mutex_unlock(&stream->xecore_buf_lock);
5269e0590eeSHarish Chegondi 			return -EIO;
5279e0590eeSHarish Chegondi 		}
5289e0590eeSHarish Chegondi 		stream->data_drop.reported_to_user = false;
5299e0590eeSHarish Chegondi 	}
5309e0590eeSHarish Chegondi 
531760edec9SHarish Chegondi 	for_each_dss_steering(xecore, gt, group, instance) {
532760edec9SHarish Chegondi 		ret = xe_eu_stall_data_buf_read(stream, buf, count, &total_size,
533760edec9SHarish Chegondi 						gt, group, instance, xecore);
534760edec9SHarish Chegondi 		if (ret || count == total_size)
535760edec9SHarish Chegondi 			break;
536760edec9SHarish Chegondi 	}
5375a295badSHarish Chegondi 	mutex_unlock(&stream->xecore_buf_lock);
538760edec9SHarish Chegondi 	return total_size ?: (ret ?: -EAGAIN);
539760edec9SHarish Chegondi }
540760edec9SHarish Chegondi 
5411537ec85SHarish Chegondi /*
5421537ec85SHarish Chegondi  * Userspace must enable the EU stall stream with DRM_XE_OBSERVATION_IOCTL_ENABLE
5431537ec85SHarish Chegondi  * before calling read().
5449e0590eeSHarish Chegondi  *
5459e0590eeSHarish Chegondi  * Returns: The number of bytes copied or a negative error code on failure.
5469e0590eeSHarish Chegondi  *	    -EIO if HW drops any EU stall data when the buffer is full.
5471537ec85SHarish Chegondi  */
xe_eu_stall_stream_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)5481537ec85SHarish Chegondi static ssize_t xe_eu_stall_stream_read(struct file *file, char __user *buf,
5491537ec85SHarish Chegondi 				       size_t count, loff_t *ppos)
5501537ec85SHarish Chegondi {
551760edec9SHarish Chegondi 	struct xe_eu_stall_data_stream *stream = file->private_data;
552760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
553760edec9SHarish Chegondi 	ssize_t ret, aligned_count;
554760edec9SHarish Chegondi 
555760edec9SHarish Chegondi 	aligned_count = ALIGN_DOWN(count, stream->data_record_size);
556760edec9SHarish Chegondi 	if (aligned_count == 0)
557760edec9SHarish Chegondi 		return -EINVAL;
558760edec9SHarish Chegondi 
559760edec9SHarish Chegondi 	if (!stream->enabled) {
560760edec9SHarish Chegondi 		xe_gt_dbg(gt, "EU stall data stream not enabled to read\n");
561760edec9SHarish Chegondi 		return -EINVAL;
562760edec9SHarish Chegondi 	}
563760edec9SHarish Chegondi 
564760edec9SHarish Chegondi 	if (!(file->f_flags & O_NONBLOCK)) {
565760edec9SHarish Chegondi 		do {
566760edec9SHarish Chegondi 			ret = wait_event_interruptible(stream->poll_wq, stream->pollin);
567760edec9SHarish Chegondi 			if (ret)
568760edec9SHarish Chegondi 				return -EINTR;
569760edec9SHarish Chegondi 
570760edec9SHarish Chegondi 			mutex_lock(&gt->eu_stall->stream_lock);
571760edec9SHarish Chegondi 			ret = xe_eu_stall_stream_read_locked(stream, file, buf, aligned_count);
572760edec9SHarish Chegondi 			mutex_unlock(&gt->eu_stall->stream_lock);
573760edec9SHarish Chegondi 		} while (ret == -EAGAIN);
574760edec9SHarish Chegondi 	} else {
575760edec9SHarish Chegondi 		mutex_lock(&gt->eu_stall->stream_lock);
576760edec9SHarish Chegondi 		ret = xe_eu_stall_stream_read_locked(stream, file, buf, aligned_count);
577760edec9SHarish Chegondi 		mutex_unlock(&gt->eu_stall->stream_lock);
578760edec9SHarish Chegondi 	}
579760edec9SHarish Chegondi 
580760edec9SHarish Chegondi 	/*
581760edec9SHarish Chegondi 	 * This may not work correctly if the user buffer is very small.
582760edec9SHarish Chegondi 	 * We don't want to block the next read() when there is data in the buffer
583760edec9SHarish Chegondi 	 * now, but couldn't be accommodated in the small user buffer.
584760edec9SHarish Chegondi 	 */
585760edec9SHarish Chegondi 	stream->pollin = false;
5861537ec85SHarish Chegondi 
5871537ec85SHarish Chegondi 	return ret;
5881537ec85SHarish Chegondi }
5891537ec85SHarish Chegondi 
xe_eu_stall_stream_free(struct xe_eu_stall_data_stream * stream)5909a0b11d4SHarish Chegondi static void xe_eu_stall_stream_free(struct xe_eu_stall_data_stream *stream)
5919a0b11d4SHarish Chegondi {
5929a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
5939a0b11d4SHarish Chegondi 
5945a295badSHarish Chegondi 	mutex_destroy(&stream->xecore_buf_lock);
5959a0b11d4SHarish Chegondi 	gt->eu_stall->stream = NULL;
5969a0b11d4SHarish Chegondi 	kfree(stream);
5979a0b11d4SHarish Chegondi }
5989a0b11d4SHarish Chegondi 
xe_eu_stall_data_buf_destroy(struct xe_eu_stall_data_stream * stream)5999a0b11d4SHarish Chegondi static void xe_eu_stall_data_buf_destroy(struct xe_eu_stall_data_stream *stream)
6009a0b11d4SHarish Chegondi {
6019a0b11d4SHarish Chegondi 	xe_bo_unpin_map_no_vm(stream->bo);
6029a0b11d4SHarish Chegondi 	kfree(stream->xecore_buf);
6039a0b11d4SHarish Chegondi }
6049a0b11d4SHarish Chegondi 
xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream * stream,u16 last_xecore)6059a0b11d4SHarish Chegondi static int xe_eu_stall_data_buf_alloc(struct xe_eu_stall_data_stream *stream,
6069a0b11d4SHarish Chegondi 				      u16 last_xecore)
6079a0b11d4SHarish Chegondi {
6089a0b11d4SHarish Chegondi 	struct xe_tile *tile = stream->gt->tile;
6099a0b11d4SHarish Chegondi 	struct xe_bo *bo;
6109a0b11d4SHarish Chegondi 	u32 size;
6119a0b11d4SHarish Chegondi 
6129a0b11d4SHarish Chegondi 	stream->xecore_buf = kcalloc(last_xecore, sizeof(*stream->xecore_buf), GFP_KERNEL);
6139a0b11d4SHarish Chegondi 	if (!stream->xecore_buf)
6149a0b11d4SHarish Chegondi 		return -ENOMEM;
6159a0b11d4SHarish Chegondi 
6169a0b11d4SHarish Chegondi 	size = stream->per_xecore_buf_size * last_xecore;
6179a0b11d4SHarish Chegondi 
6189a0b11d4SHarish Chegondi 	bo = xe_bo_create_pin_map_at_aligned(tile->xe, tile, NULL,
6199a0b11d4SHarish Chegondi 					     size, ~0ull, ttm_bo_type_kernel,
6209a0b11d4SHarish Chegondi 					     XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT, SZ_64);
6219a0b11d4SHarish Chegondi 	if (IS_ERR(bo)) {
6229a0b11d4SHarish Chegondi 		kfree(stream->xecore_buf);
6239a0b11d4SHarish Chegondi 		return PTR_ERR(bo);
6249a0b11d4SHarish Chegondi 	}
6259a0b11d4SHarish Chegondi 
6269a0b11d4SHarish Chegondi 	XE_WARN_ON(!IS_ALIGNED(xe_bo_ggtt_addr(bo), SZ_64));
6279a0b11d4SHarish Chegondi 	stream->bo = bo;
6289a0b11d4SHarish Chegondi 
6299a0b11d4SHarish Chegondi 	return 0;
6309a0b11d4SHarish Chegondi }
6319a0b11d4SHarish Chegondi 
xe_eu_stall_stream_enable(struct xe_eu_stall_data_stream * stream)6329a0b11d4SHarish Chegondi static int xe_eu_stall_stream_enable(struct xe_eu_stall_data_stream *stream)
6339a0b11d4SHarish Chegondi {
6349a0b11d4SHarish Chegondi 	u32 write_ptr_reg, write_ptr, read_ptr_reg, reg_value;
6359a0b11d4SHarish Chegondi 	struct per_xecore_buf *xecore_buf;
6369a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
6379a0b11d4SHarish Chegondi 	u16 group, instance;
6389a0b11d4SHarish Chegondi 	unsigned int fw_ref;
6399a0b11d4SHarish Chegondi 	int xecore;
6409a0b11d4SHarish Chegondi 
6419a0b11d4SHarish Chegondi 	/* Take runtime pm ref and forcewake to disable RC6 */
6429a0b11d4SHarish Chegondi 	xe_pm_runtime_get(gt_to_xe(gt));
6439a0b11d4SHarish Chegondi 	fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_RENDER);
6449a0b11d4SHarish Chegondi 	if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_RENDER)) {
6459a0b11d4SHarish Chegondi 		xe_gt_err(gt, "Failed to get RENDER forcewake\n");
6469a0b11d4SHarish Chegondi 		xe_pm_runtime_put(gt_to_xe(gt));
6479a0b11d4SHarish Chegondi 		return -ETIMEDOUT;
6489a0b11d4SHarish Chegondi 	}
6499a0b11d4SHarish Chegondi 
650e67a35bcSHarish Chegondi 	if (XE_WA(gt, 22016596838))
651e67a35bcSHarish Chegondi 		xe_gt_mcr_multicast_write(gt, ROW_CHICKEN2,
652e67a35bcSHarish Chegondi 					  _MASKED_BIT_ENABLE(DISABLE_DOP_GATING));
653e67a35bcSHarish Chegondi 
6549a0b11d4SHarish Chegondi 	for_each_dss_steering(xecore, gt, group, instance) {
6559a0b11d4SHarish Chegondi 		write_ptr_reg = xe_gt_mcr_unicast_read(gt, XEHPC_EUSTALL_REPORT, group, instance);
6569e0590eeSHarish Chegondi 		/* Clear any drop bits set and not cleared in the previous session. */
6579e0590eeSHarish Chegondi 		if (write_ptr_reg & XEHPC_EUSTALL_REPORT_OVERFLOW_DROP)
6589e0590eeSHarish Chegondi 			clear_dropped_eviction_line_bit(gt, group, instance);
6599a0b11d4SHarish Chegondi 		write_ptr = REG_FIELD_GET(XEHPC_EUSTALL_REPORT_WRITE_PTR_MASK, write_ptr_reg);
6609a0b11d4SHarish Chegondi 		read_ptr_reg = REG_FIELD_PREP(XEHPC_EUSTALL_REPORT1_READ_PTR_MASK, write_ptr);
6619a0b11d4SHarish Chegondi 		read_ptr_reg = _MASKED_FIELD(XEHPC_EUSTALL_REPORT1_READ_PTR_MASK, read_ptr_reg);
6629a0b11d4SHarish Chegondi 		/* Initialize the read pointer to the write pointer */
6639a0b11d4SHarish Chegondi 		xe_gt_mcr_unicast_write(gt, XEHPC_EUSTALL_REPORT1, read_ptr_reg, group, instance);
6649a0b11d4SHarish Chegondi 		write_ptr <<= 6;
6659a0b11d4SHarish Chegondi 		write_ptr &= (stream->per_xecore_buf_size << 1) - 1;
6669a0b11d4SHarish Chegondi 		xecore_buf = &stream->xecore_buf[xecore];
6679a0b11d4SHarish Chegondi 		xecore_buf->write = write_ptr;
6689a0b11d4SHarish Chegondi 		xecore_buf->read = write_ptr;
6699a0b11d4SHarish Chegondi 	}
6709e0590eeSHarish Chegondi 	stream->data_drop.reported_to_user = false;
6719e0590eeSHarish Chegondi 	bitmap_zero(stream->data_drop.mask, XE_MAX_DSS_FUSE_BITS);
6729e0590eeSHarish Chegondi 
6739a0b11d4SHarish Chegondi 	reg_value = _MASKED_FIELD(EUSTALL_MOCS | EUSTALL_SAMPLE_RATE,
6749a0b11d4SHarish Chegondi 				  REG_FIELD_PREP(EUSTALL_MOCS, gt->mocs.uc_index << 1) |
6759a0b11d4SHarish Chegondi 				  REG_FIELD_PREP(EUSTALL_SAMPLE_RATE,
6769a0b11d4SHarish Chegondi 						 stream->sampling_rate_mult));
6779a0b11d4SHarish Chegondi 	xe_gt_mcr_multicast_write(gt, XEHPC_EUSTALL_CTRL, reg_value);
6789a0b11d4SHarish Chegondi 	/* GGTT addresses can never be > 32 bits */
6799a0b11d4SHarish Chegondi 	xe_gt_mcr_multicast_write(gt, XEHPC_EUSTALL_BASE_UPPER, 0);
6809a0b11d4SHarish Chegondi 	reg_value = xe_bo_ggtt_addr(stream->bo);
6819a0b11d4SHarish Chegondi 	reg_value |= REG_FIELD_PREP(XEHPC_EUSTALL_BASE_XECORE_BUF_SZ,
6829a0b11d4SHarish Chegondi 				    stream->per_xecore_buf_size / SZ_256K);
6839a0b11d4SHarish Chegondi 	reg_value |= XEHPC_EUSTALL_BASE_ENABLE_SAMPLING;
6849a0b11d4SHarish Chegondi 	xe_gt_mcr_multicast_write(gt, XEHPC_EUSTALL_BASE, reg_value);
6859a0b11d4SHarish Chegondi 
6869a0b11d4SHarish Chegondi 	return 0;
6879a0b11d4SHarish Chegondi }
6889a0b11d4SHarish Chegondi 
eu_stall_data_buf_poll_work_fn(struct work_struct * work)689760edec9SHarish Chegondi static void eu_stall_data_buf_poll_work_fn(struct work_struct *work)
690760edec9SHarish Chegondi {
691760edec9SHarish Chegondi 	struct xe_eu_stall_data_stream *stream =
692760edec9SHarish Chegondi 		container_of(work, typeof(*stream), buf_poll_work.work);
693760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
694760edec9SHarish Chegondi 
695760edec9SHarish Chegondi 	if (eu_stall_data_buf_poll(stream)) {
696760edec9SHarish Chegondi 		stream->pollin = true;
697760edec9SHarish Chegondi 		wake_up(&stream->poll_wq);
698760edec9SHarish Chegondi 	}
699760edec9SHarish Chegondi 	queue_delayed_work(gt->eu_stall->buf_ptr_poll_wq,
700760edec9SHarish Chegondi 			   &stream->buf_poll_work,
701760edec9SHarish Chegondi 			   msecs_to_jiffies(POLL_PERIOD_MS));
702760edec9SHarish Chegondi }
703760edec9SHarish Chegondi 
xe_eu_stall_stream_init(struct xe_eu_stall_data_stream * stream,struct eu_stall_open_properties * props)7049a0b11d4SHarish Chegondi static int xe_eu_stall_stream_init(struct xe_eu_stall_data_stream *stream,
7059a0b11d4SHarish Chegondi 				   struct eu_stall_open_properties *props)
7069a0b11d4SHarish Chegondi {
7079a0b11d4SHarish Chegondi 	unsigned int max_wait_num_reports, xecore, last_xecore, num_xecores;
7089a0b11d4SHarish Chegondi 	struct per_xecore_buf *xecore_buf;
7099a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
7109a0b11d4SHarish Chegondi 	xe_dss_mask_t all_xecores;
7119a0b11d4SHarish Chegondi 	u16 group, instance;
7129a0b11d4SHarish Chegondi 	u32 vaddr_offset;
7139a0b11d4SHarish Chegondi 	int ret;
7149a0b11d4SHarish Chegondi 
7159a0b11d4SHarish Chegondi 	bitmap_or(all_xecores, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask,
7169a0b11d4SHarish Chegondi 		  XE_MAX_DSS_FUSE_BITS);
7179a0b11d4SHarish Chegondi 	num_xecores = bitmap_weight(all_xecores, XE_MAX_DSS_FUSE_BITS);
7189a0b11d4SHarish Chegondi 	last_xecore = xe_gt_topology_mask_last_dss(all_xecores) + 1;
7199a0b11d4SHarish Chegondi 
7209a0b11d4SHarish Chegondi 	max_wait_num_reports = num_data_rows(per_xecore_buf_size * num_xecores);
7219a0b11d4SHarish Chegondi 	if (props->wait_num_reports == 0 || props->wait_num_reports > max_wait_num_reports) {
7229a0b11d4SHarish Chegondi 		xe_gt_dbg(gt, "Invalid EU stall event report count %u\n",
7239a0b11d4SHarish Chegondi 			  props->wait_num_reports);
7249a0b11d4SHarish Chegondi 		xe_gt_dbg(gt, "Minimum event report count is 1, maximum is %u\n",
7259a0b11d4SHarish Chegondi 			  max_wait_num_reports);
7269a0b11d4SHarish Chegondi 		return -EINVAL;
7279a0b11d4SHarish Chegondi 	}
728760edec9SHarish Chegondi 
729760edec9SHarish Chegondi 	init_waitqueue_head(&stream->poll_wq);
7305a295badSHarish Chegondi 	mutex_init(&stream->xecore_buf_lock);
731760edec9SHarish Chegondi 	INIT_DELAYED_WORK(&stream->buf_poll_work, eu_stall_data_buf_poll_work_fn);
7329a0b11d4SHarish Chegondi 	stream->per_xecore_buf_size = per_xecore_buf_size;
7339a0b11d4SHarish Chegondi 	stream->sampling_rate_mult = props->sampling_rate_mult;
7349a0b11d4SHarish Chegondi 	stream->wait_num_reports = props->wait_num_reports;
7359a0b11d4SHarish Chegondi 	stream->data_record_size = xe_eu_stall_data_record_size(gt_to_xe(gt));
7369a0b11d4SHarish Chegondi 
7379a0b11d4SHarish Chegondi 	ret = xe_eu_stall_data_buf_alloc(stream, last_xecore);
7389a0b11d4SHarish Chegondi 	if (ret)
7399a0b11d4SHarish Chegondi 		return ret;
7409a0b11d4SHarish Chegondi 
7419a0b11d4SHarish Chegondi 	for_each_dss_steering(xecore, gt, group, instance) {
7429a0b11d4SHarish Chegondi 		xecore_buf = &stream->xecore_buf[xecore];
7439a0b11d4SHarish Chegondi 		vaddr_offset = xecore * stream->per_xecore_buf_size;
7449a0b11d4SHarish Chegondi 		xecore_buf->vaddr = stream->bo->vmap.vaddr + vaddr_offset;
7459a0b11d4SHarish Chegondi 	}
7469a0b11d4SHarish Chegondi 	return 0;
7479a0b11d4SHarish Chegondi }
7489a0b11d4SHarish Chegondi 
xe_eu_stall_stream_poll_locked(struct xe_eu_stall_data_stream * stream,struct file * file,poll_table * wait)749760edec9SHarish Chegondi static __poll_t xe_eu_stall_stream_poll_locked(struct xe_eu_stall_data_stream *stream,
750760edec9SHarish Chegondi 					       struct file *file, poll_table *wait)
751760edec9SHarish Chegondi {
752760edec9SHarish Chegondi 	__poll_t events = 0;
753760edec9SHarish Chegondi 
754760edec9SHarish Chegondi 	poll_wait(file, &stream->poll_wq, wait);
755760edec9SHarish Chegondi 
756760edec9SHarish Chegondi 	if (stream->pollin)
757760edec9SHarish Chegondi 		events |= EPOLLIN;
758760edec9SHarish Chegondi 
759760edec9SHarish Chegondi 	return events;
760760edec9SHarish Chegondi }
761760edec9SHarish Chegondi 
xe_eu_stall_stream_poll(struct file * file,poll_table * wait)7621537ec85SHarish Chegondi static __poll_t xe_eu_stall_stream_poll(struct file *file, poll_table *wait)
7631537ec85SHarish Chegondi {
764760edec9SHarish Chegondi 	struct xe_eu_stall_data_stream *stream = file->private_data;
765760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
766760edec9SHarish Chegondi 	__poll_t ret;
767760edec9SHarish Chegondi 
768760edec9SHarish Chegondi 	mutex_lock(&gt->eu_stall->stream_lock);
769760edec9SHarish Chegondi 	ret = xe_eu_stall_stream_poll_locked(stream, file, wait);
770760edec9SHarish Chegondi 	mutex_unlock(&gt->eu_stall->stream_lock);
7711537ec85SHarish Chegondi 
7721537ec85SHarish Chegondi 	return ret;
7731537ec85SHarish Chegondi }
7741537ec85SHarish Chegondi 
xe_eu_stall_enable_locked(struct xe_eu_stall_data_stream * stream)7759a0b11d4SHarish Chegondi static int xe_eu_stall_enable_locked(struct xe_eu_stall_data_stream *stream)
7769a0b11d4SHarish Chegondi {
777760edec9SHarish Chegondi 	struct xe_gt *gt = stream->gt;
7789a0b11d4SHarish Chegondi 	int ret = 0;
7799a0b11d4SHarish Chegondi 
7809a0b11d4SHarish Chegondi 	if (stream->enabled)
7819a0b11d4SHarish Chegondi 		return ret;
7829a0b11d4SHarish Chegondi 
7839a0b11d4SHarish Chegondi 	stream->enabled = true;
7849a0b11d4SHarish Chegondi 
7859a0b11d4SHarish Chegondi 	ret = xe_eu_stall_stream_enable(stream);
786760edec9SHarish Chegondi 
787760edec9SHarish Chegondi 	queue_delayed_work(gt->eu_stall->buf_ptr_poll_wq,
788760edec9SHarish Chegondi 			   &stream->buf_poll_work,
789760edec9SHarish Chegondi 			   msecs_to_jiffies(POLL_PERIOD_MS));
7909a0b11d4SHarish Chegondi 	return ret;
7919a0b11d4SHarish Chegondi }
7929a0b11d4SHarish Chegondi 
xe_eu_stall_disable_locked(struct xe_eu_stall_data_stream * stream)7939a0b11d4SHarish Chegondi static int xe_eu_stall_disable_locked(struct xe_eu_stall_data_stream *stream)
7949a0b11d4SHarish Chegondi {
7959a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
7969a0b11d4SHarish Chegondi 
7979a0b11d4SHarish Chegondi 	if (!stream->enabled)
7989a0b11d4SHarish Chegondi 		return 0;
7999a0b11d4SHarish Chegondi 
8009a0b11d4SHarish Chegondi 	stream->enabled = false;
8019a0b11d4SHarish Chegondi 
8029a0b11d4SHarish Chegondi 	xe_gt_mcr_multicast_write(gt, XEHPC_EUSTALL_BASE, 0);
8039a0b11d4SHarish Chegondi 
804760edec9SHarish Chegondi 	cancel_delayed_work_sync(&stream->buf_poll_work);
805760edec9SHarish Chegondi 
806e67a35bcSHarish Chegondi 	if (XE_WA(gt, 22016596838))
807e67a35bcSHarish Chegondi 		xe_gt_mcr_multicast_write(gt, ROW_CHICKEN2,
808e67a35bcSHarish Chegondi 					  _MASKED_BIT_DISABLE(DISABLE_DOP_GATING));
809e67a35bcSHarish Chegondi 
8109a0b11d4SHarish Chegondi 	xe_force_wake_put(gt_to_fw(gt), XE_FW_RENDER);
8119a0b11d4SHarish Chegondi 	xe_pm_runtime_put(gt_to_xe(gt));
8129a0b11d4SHarish Chegondi 
8139a0b11d4SHarish Chegondi 	return 0;
8149a0b11d4SHarish Chegondi }
8159a0b11d4SHarish Chegondi 
xe_eu_stall_stream_ioctl_locked(struct xe_eu_stall_data_stream * stream,unsigned int cmd,unsigned long arg)8169a0b11d4SHarish Chegondi static long xe_eu_stall_stream_ioctl_locked(struct xe_eu_stall_data_stream *stream,
8179a0b11d4SHarish Chegondi 					    unsigned int cmd, unsigned long arg)
8189a0b11d4SHarish Chegondi {
8199a0b11d4SHarish Chegondi 	switch (cmd) {
8209a0b11d4SHarish Chegondi 	case DRM_XE_OBSERVATION_IOCTL_ENABLE:
8219a0b11d4SHarish Chegondi 		return xe_eu_stall_enable_locked(stream);
8229a0b11d4SHarish Chegondi 	case DRM_XE_OBSERVATION_IOCTL_DISABLE:
8239a0b11d4SHarish Chegondi 		return xe_eu_stall_disable_locked(stream);
8249a0b11d4SHarish Chegondi 	}
8259a0b11d4SHarish Chegondi 
8269a0b11d4SHarish Chegondi 	return -EINVAL;
8279a0b11d4SHarish Chegondi }
8289a0b11d4SHarish Chegondi 
xe_eu_stall_stream_ioctl(struct file * file,unsigned int cmd,unsigned long arg)8291537ec85SHarish Chegondi static long xe_eu_stall_stream_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
8301537ec85SHarish Chegondi {
8319a0b11d4SHarish Chegondi 	struct xe_eu_stall_data_stream *stream = file->private_data;
8329a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
8339a0b11d4SHarish Chegondi 	long ret;
8349a0b11d4SHarish Chegondi 
8359a0b11d4SHarish Chegondi 	mutex_lock(&gt->eu_stall->stream_lock);
8369a0b11d4SHarish Chegondi 	ret = xe_eu_stall_stream_ioctl_locked(stream, cmd, arg);
8379a0b11d4SHarish Chegondi 	mutex_unlock(&gt->eu_stall->stream_lock);
8389a0b11d4SHarish Chegondi 
8399a0b11d4SHarish Chegondi 	return ret;
8401537ec85SHarish Chegondi }
8411537ec85SHarish Chegondi 
xe_eu_stall_stream_close(struct inode * inode,struct file * file)8421537ec85SHarish Chegondi static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)
8431537ec85SHarish Chegondi {
8449a0b11d4SHarish Chegondi 	struct xe_eu_stall_data_stream *stream = file->private_data;
8459a0b11d4SHarish Chegondi 	struct xe_gt *gt = stream->gt;
8469a0b11d4SHarish Chegondi 
8479a0b11d4SHarish Chegondi 	drm_dev_put(&gt->tile->xe->drm);
8489a0b11d4SHarish Chegondi 
8499a0b11d4SHarish Chegondi 	mutex_lock(&gt->eu_stall->stream_lock);
8509a0b11d4SHarish Chegondi 	xe_eu_stall_disable_locked(stream);
8519a0b11d4SHarish Chegondi 	xe_eu_stall_data_buf_destroy(stream);
8529a0b11d4SHarish Chegondi 	xe_eu_stall_stream_free(stream);
8539a0b11d4SHarish Chegondi 	mutex_unlock(&gt->eu_stall->stream_lock);
8549a0b11d4SHarish Chegondi 
8551537ec85SHarish Chegondi 	return 0;
8561537ec85SHarish Chegondi }
8571537ec85SHarish Chegondi 
8581537ec85SHarish Chegondi static const struct file_operations fops_eu_stall = {
8591537ec85SHarish Chegondi 	.owner		= THIS_MODULE,
8601537ec85SHarish Chegondi 	.llseek		= noop_llseek,
8611537ec85SHarish Chegondi 	.release	= xe_eu_stall_stream_close,
8621537ec85SHarish Chegondi 	.poll		= xe_eu_stall_stream_poll,
8631537ec85SHarish Chegondi 	.read		= xe_eu_stall_stream_read,
8641537ec85SHarish Chegondi 	.unlocked_ioctl = xe_eu_stall_stream_ioctl,
8651537ec85SHarish Chegondi 	.compat_ioctl   = xe_eu_stall_stream_ioctl,
8661537ec85SHarish Chegondi };
8671537ec85SHarish Chegondi 
xe_eu_stall_stream_open_locked(struct drm_device * dev,struct eu_stall_open_properties * props,struct drm_file * file)8689a0b11d4SHarish Chegondi static int xe_eu_stall_stream_open_locked(struct drm_device *dev,
8699a0b11d4SHarish Chegondi 					  struct eu_stall_open_properties *props,
8709a0b11d4SHarish Chegondi 					  struct drm_file *file)
8719a0b11d4SHarish Chegondi {
8729a0b11d4SHarish Chegondi 	struct xe_eu_stall_data_stream *stream;
8739a0b11d4SHarish Chegondi 	struct xe_gt *gt = props->gt;
8749a0b11d4SHarish Chegondi 	unsigned long f_flags = 0;
8759a0b11d4SHarish Chegondi 	int ret, stream_fd;
8769a0b11d4SHarish Chegondi 
8779a0b11d4SHarish Chegondi 	/* Only one session can be active at any time */
8789a0b11d4SHarish Chegondi 	if (gt->eu_stall->stream) {
8799a0b11d4SHarish Chegondi 		xe_gt_dbg(gt, "EU stall sampling session already active\n");
8809a0b11d4SHarish Chegondi 		return -EBUSY;
8819a0b11d4SHarish Chegondi 	}
8829a0b11d4SHarish Chegondi 
8839a0b11d4SHarish Chegondi 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
8849a0b11d4SHarish Chegondi 	if (!stream)
8859a0b11d4SHarish Chegondi 		return -ENOMEM;
8869a0b11d4SHarish Chegondi 
8879a0b11d4SHarish Chegondi 	gt->eu_stall->stream = stream;
8889a0b11d4SHarish Chegondi 	stream->gt = gt;
8899a0b11d4SHarish Chegondi 
8909a0b11d4SHarish Chegondi 	ret = xe_eu_stall_stream_init(stream, props);
8919a0b11d4SHarish Chegondi 	if (ret) {
8929a0b11d4SHarish Chegondi 		xe_gt_dbg(gt, "EU stall stream init failed : %d\n", ret);
8939a0b11d4SHarish Chegondi 		goto err_free;
8949a0b11d4SHarish Chegondi 	}
8959a0b11d4SHarish Chegondi 
8969a0b11d4SHarish Chegondi 	stream_fd = anon_inode_getfd("[xe_eu_stall]", &fops_eu_stall, stream, f_flags);
8979a0b11d4SHarish Chegondi 	if (stream_fd < 0) {
8989a0b11d4SHarish Chegondi 		ret = stream_fd;
8999a0b11d4SHarish Chegondi 		xe_gt_dbg(gt, "EU stall inode get fd failed : %d\n", ret);
9009a0b11d4SHarish Chegondi 		goto err_destroy;
9019a0b11d4SHarish Chegondi 	}
9029a0b11d4SHarish Chegondi 
9039a0b11d4SHarish Chegondi 	/* Take a reference on the driver that will be kept with stream_fd
9049a0b11d4SHarish Chegondi 	 * until its release.
9059a0b11d4SHarish Chegondi 	 */
9069a0b11d4SHarish Chegondi 	drm_dev_get(&gt->tile->xe->drm);
9079a0b11d4SHarish Chegondi 
9089a0b11d4SHarish Chegondi 	return stream_fd;
9099a0b11d4SHarish Chegondi 
9109a0b11d4SHarish Chegondi err_destroy:
9119a0b11d4SHarish Chegondi 	xe_eu_stall_data_buf_destroy(stream);
9129a0b11d4SHarish Chegondi err_free:
9139a0b11d4SHarish Chegondi 	xe_eu_stall_stream_free(stream);
9149a0b11d4SHarish Chegondi 	return ret;
9151537ec85SHarish Chegondi }
9161537ec85SHarish Chegondi 
9171537ec85SHarish Chegondi /**
9181537ec85SHarish Chegondi  * xe_eu_stall_stream_open - Open a xe EU stall data stream fd
9191537ec85SHarish Chegondi  *
9201537ec85SHarish Chegondi  * @dev: DRM device pointer
9211537ec85SHarish Chegondi  * @data: pointer to first struct @drm_xe_ext_set_property in
9221537ec85SHarish Chegondi  *	  the chain of input properties from the user space.
9231537ec85SHarish Chegondi  * @file: DRM file pointer
9241537ec85SHarish Chegondi  *
9251537ec85SHarish Chegondi  * This function opens a EU stall data stream with input properties from
9261537ec85SHarish Chegondi  * the user space.
9271537ec85SHarish Chegondi  *
9281537ec85SHarish Chegondi  * Returns: EU stall data stream fd on success or a negative error code.
9291537ec85SHarish Chegondi  */
xe_eu_stall_stream_open(struct drm_device * dev,u64 data,struct drm_file * file)9301537ec85SHarish Chegondi int xe_eu_stall_stream_open(struct drm_device *dev, u64 data, struct drm_file *file)
9311537ec85SHarish Chegondi {
9321537ec85SHarish Chegondi 	struct xe_device *xe = to_xe_device(dev);
9331537ec85SHarish Chegondi 	struct eu_stall_open_properties props = {};
9349a0b11d4SHarish Chegondi 	int ret;
9351537ec85SHarish Chegondi 
936cd5bbb25SHarish Chegondi 	if (!xe_eu_stall_supported_on_platform(xe)) {
9371537ec85SHarish Chegondi 		drm_dbg(&xe->drm, "EU stall monitoring is not supported on this platform\n");
9381537ec85SHarish Chegondi 		return -ENODEV;
9391537ec85SHarish Chegondi 	}
9401537ec85SHarish Chegondi 
9411537ec85SHarish Chegondi 	if (xe_observation_paranoid && !perfmon_capable()) {
9421537ec85SHarish Chegondi 		drm_dbg(&xe->drm,  "Insufficient privileges for EU stall monitoring\n");
9431537ec85SHarish Chegondi 		return -EACCES;
9441537ec85SHarish Chegondi 	}
9451537ec85SHarish Chegondi 
9469a0b11d4SHarish Chegondi 	/* Initialize and set default values */
9479a0b11d4SHarish Chegondi 	props.wait_num_reports = 1;
9489a0b11d4SHarish Chegondi 	props.sampling_rate_mult = 4;
9499a0b11d4SHarish Chegondi 
9501537ec85SHarish Chegondi 	ret = xe_eu_stall_user_extensions(xe, data, 0, &props);
9511537ec85SHarish Chegondi 	if (ret)
9521537ec85SHarish Chegondi 		return ret;
9531537ec85SHarish Chegondi 
9541537ec85SHarish Chegondi 	if (!props.gt) {
9551537ec85SHarish Chegondi 		drm_dbg(&xe->drm, "GT ID not provided for EU stall sampling\n");
9561537ec85SHarish Chegondi 		return -EINVAL;
9571537ec85SHarish Chegondi 	}
9581537ec85SHarish Chegondi 
9599a0b11d4SHarish Chegondi 	mutex_lock(&props.gt->eu_stall->stream_lock);
9609a0b11d4SHarish Chegondi 	ret = xe_eu_stall_stream_open_locked(dev, &props, file);
9619a0b11d4SHarish Chegondi 	mutex_unlock(&props.gt->eu_stall->stream_lock);
9621537ec85SHarish Chegondi 
9639a0b11d4SHarish Chegondi 	return ret;
9641537ec85SHarish Chegondi }
965