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. + * + * irq.lock is not needed because: + * 1. no IRQ arrives before postinstall; + * 2. display has not been resumed yet. */ atomic_set(&xe->irq.enabled, 1); xe_irq_reset(xe); @@ -869,6 +886,9 @@ void xe_irq_resume(struct xe_device *xe) for_each_gt(gt, xe, id) xe_irq_enable_hwe(gt); + +out_unlock: + mutex_unlock(&xe->irq.pm_lock); } /* MSI-X related definitions and functions below. */ -- 2.43.0
