[PATCH] drm/xe/eustall: Resolve circular locking dependency

Ashutosh Dixit ashutosh.dixit at intel.com
Mon Apr 21 16:04:35 UTC 2025


Resolve circular locking depedendency, and possible deadlock, caused by the
lock order inversion in the following code paths:

	eu_stall_data_buf_poll_work_fn queue_delayed_work():
	workqueue_lock -> stream_lock

	Enable/disable
	stream_lock -> workqueue_lock -> stream_lock

Rather than introduce a new lock, the taken here is drop stream_lock before
calling workqueue functions in the enable/disable functions.

Signed-off-by: Ashutosh Dixit <ashutosh.dixit at intel.com>
---
 drivers/gpu/drm/xe/xe_eu_stall.c | 63 +++++++++++++++++---------------
 1 file changed, 33 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c
index f2bb9168967c2..4f406228b633b 100644
--- a/drivers/gpu/drm/xe/xe_eu_stall.c
+++ b/drivers/gpu/drm/xe/xe_eu_stall.c
@@ -44,6 +44,8 @@ struct per_xecore_buf {
 struct xe_eu_stall_data_stream {
 	bool pollin;
 	bool enabled;
+	bool in_enable;
+	bool in_disable;
 	int wait_num_reports;
 	int sampling_rate_mult;
 	wait_queue_head_t poll_wq;
@@ -762,73 +764,74 @@ static __poll_t xe_eu_stall_stream_poll(struct file *file, poll_table *wait)
 	return ret;
 }
 
-static int xe_eu_stall_enable_locked(struct xe_eu_stall_data_stream *stream)
+static int xe_eu_stall_enable(struct xe_eu_stall_data_stream *stream)
 {
 	struct xe_gt *gt = stream->gt;
 	int ret = 0;
 
-	if (stream->enabled)
-		return ret;
-
-	stream->enabled = true;
+	mutex_lock(&gt->eu_stall->stream_lock);
+	if (stream->enabled || stream->in_enable)
+		goto exit;
 
+	stream->in_enable = true;
 	ret = xe_eu_stall_stream_enable(stream);
+	if (ret)
+		goto exit;
+	mutex_unlock(&gt->eu_stall->stream_lock);
 
 	queue_delayed_work(gt->eu_stall->buf_ptr_poll_wq,
 			   &stream->buf_poll_work,
 			   msecs_to_jiffies(POLL_PERIOD_MS));
+
+	mutex_lock(&gt->eu_stall->stream_lock);
+	stream->enabled = true;
+	stream->in_enable = false;
+exit:
+	mutex_unlock(&gt->eu_stall->stream_lock);
 	return ret;
 }
 
-static int xe_eu_stall_disable_locked(struct xe_eu_stall_data_stream *stream)
+static int xe_eu_stall_disable(struct xe_eu_stall_data_stream *stream)
 {
 	struct xe_gt *gt = stream->gt;
 
-	if (!stream->enabled)
-		return 0;
-
-	stream->enabled = false;
-
+	mutex_lock(&gt->eu_stall->stream_lock);
+	if (!stream->enabled || stream->in_disable)
+		goto exit;
+	stream->in_disable = true;
 	xe_gt_mcr_multicast_write(gt, XEHPC_EUSTALL_BASE, 0);
+	mutex_unlock(&gt->eu_stall->stream_lock);
 
 	cancel_delayed_work_sync(&stream->buf_poll_work);
 
+	mutex_lock(&gt->eu_stall->stream_lock);
 	if (XE_WA(gt, 22016596838))
 		xe_gt_mcr_multicast_write(gt, ROW_CHICKEN2,
 					  _MASKED_BIT_DISABLE(DISABLE_DOP_GATING));
 
 	xe_force_wake_put(gt_to_fw(gt), XE_FW_RENDER);
 	xe_pm_runtime_put(gt_to_xe(gt));
-
+	stream->enabled = false;
+	stream->in_disable = false;
+exit:
+	mutex_unlock(&gt->eu_stall->stream_lock);
 	return 0;
 }
 
-static long xe_eu_stall_stream_ioctl_locked(struct xe_eu_stall_data_stream *stream,
-					    unsigned int cmd, unsigned long arg)
+static long xe_eu_stall_stream_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+	struct xe_eu_stall_data_stream *stream = file->private_data;
+
 	switch (cmd) {
 	case DRM_XE_OBSERVATION_IOCTL_ENABLE:
-		return xe_eu_stall_enable_locked(stream);
+		return xe_eu_stall_enable(stream);
 	case DRM_XE_OBSERVATION_IOCTL_DISABLE:
-		return xe_eu_stall_disable_locked(stream);
+		return xe_eu_stall_disable(stream);
 	}
 
 	return -EINVAL;
 }
 
-static long xe_eu_stall_stream_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct xe_eu_stall_data_stream *stream = file->private_data;
-	struct xe_gt *gt = stream->gt;
-	long ret;
-
-	mutex_lock(&gt->eu_stall->stream_lock);
-	ret = xe_eu_stall_stream_ioctl_locked(stream, cmd, arg);
-	mutex_unlock(&gt->eu_stall->stream_lock);
-
-	return ret;
-}
-
 static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)
 {
 	struct xe_eu_stall_data_stream *stream = file->private_data;
@@ -836,8 +839,8 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file)
 
 	drm_dev_put(&gt->tile->xe->drm);
 
+	xe_eu_stall_disable(stream);
 	mutex_lock(&gt->eu_stall->stream_lock);
-	xe_eu_stall_disable_locked(stream);
 	xe_eu_stall_data_buf_destroy(stream);
 	xe_eu_stall_stream_free(stream);
 	mutex_unlock(&gt->eu_stall->stream_lock);
-- 
2.48.1



More information about the Intel-gfx-trybot mailing list