Wedge isolation suspends interrupts from a worker. This can race with
PM resume and allow resume to enable interrupts after isolation has
disabled them.
Add a managed mutex around IRQ suspend and resume. Check the wedged state
while holding the mutex so either ordering leaves interrupts disabled.
Cc: Matthew Brost <[email protected]>
Cc: Thomas Hellström <[email protected]>
Cc: Himal Prasad Ghimiray <[email protected]>
Cc: Rodrigo Vivi <[email protected]>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Arvind Yadav <[email protected]>
---
drivers/gpu/drm/xe/xe_device_types.h | 4 ++++
drivers/gpu/drm/xe/xe_irq.c | 26 +++++++++++++++++++++++---
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_device_types.h
b/drivers/gpu/drm/xe/xe_device_types.h
index 43a86564adf0..dda4d9919ca6 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -6,6 +6,7 @@
#ifndef _XE_DEVICE_TYPES_H_
#define _XE_DEVICE_TYPES_H_
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/srcu.h>
@@ -266,6 +267,9 @@ struct xe_device {
/** @irq.lock: lock for processing irq's on this device */
spinlock_t lock;
+ /** @irq.pm_lock: Serializes IRQ suspend and resume */
+ struct mutex pm_lock;
+
/** @irq.enabled: interrupts enabled on this device */
atomic_t enabled;
diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
index d314993b14a1..9cdcb16f3ca8 100644
--- a/drivers/gpu/drm/xe/xe_irq.c
+++ b/drivers/gpu/drm/xe/xe_irq.c
@@ -797,8 +797,14 @@ static void irq_uninstall(void *arg)
int xe_irq_init(struct xe_device *xe)
{
+ int err;
+
spin_lock_init(&xe->irq.lock);
+ err = drmm_mutex_init(&xe->drm, &xe->irq.pm_lock);
+ if (err)
+ return err;
+
return xe_irq_msix_init(xe);
}
@@ -843,6 +849,8 @@ static void xe_irq_msi_synchronize_irq(struct xe_device *xe)
void xe_irq_suspend(struct xe_device *xe)
{
+ mutex_lock(&xe->irq.pm_lock);
+
atomic_set(&xe->irq.enabled, 0); /* no new irqs */
/* flush irqs */
@@ -851,6 +859,8 @@ void xe_irq_suspend(struct xe_device *xe)
else
xe_irq_msi_synchronize_irq(xe);
xe_irq_reset(xe); /* turn irqs off */
+
+ mutex_unlock(&xe->irq.pm_lock);
}
void xe_irq_resume(struct xe_device *xe)
@@ -858,10 +868,17 @@ void xe_irq_resume(struct xe_device *xe)
struct xe_gt *gt;
int id;
+ mutex_lock(&xe->irq.pm_lock);
+
+ if (xe_device_wedged(xe))
+ goto out_unlock;
+
/*
- * lock not needed:
- * 1. no irq will arrive before the postinstall
- * 2. display is not yet resumed
+ * pm_lock serializes resume against wedge isolation.