From: Arvind Yadav <arvind.yadav@intel.com>
To: intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: matthew.brost@intel.com, himal.prasad.ghimiray@intel.com,
thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com
Subject: [PATCH v2 11/15] drm/xe: Isolate a wedged device before notifying userspace
Date: Tue, 22 Sep 2026 15:46:56 +0530 [thread overview]
Message-ID: <20260922101721.1583542-12-arvind.yadav@intel.com> (raw)
In-Reply-To: <20260922101721.1583542-1-arvind.yadav@intel.com>
A permanently wedged device must stop interrupt and DMA activity before
userspace is notified that recovery is required.
Run the sleepable isolation steps from the wedge worker. Shut down and
unregister the display, suspend interrupts and clear PCI bus mastering,
then invalidate VRAM mappings. Mapping teardown does not access hardware,
so it runs after DMA has stopped
Track display and isolation state so later teardown does not repeat these
steps. Display shutdown already disables display power, so skip the
runtime PM disable when unregister follows shutdown.
System suspend may see the wedge flag before the worker is queued. Use a
completion to close this window and flush the worker before skipping
normal device suspend. The IRQ serialization keeps a racing resume from
enabling interrupts after isolation.
Resume always balances pci_disable_device() with pci_enable_device().
If the device is wedged, clear bus mastering and skip xe_pm_resume().
v2:
- Run the common PCI suspend path for wedged devices so
the D3Cold toggles remain paired. (Sashiko)
- Move pci_enable_device() before the resume wedge check to
balance pci_disable_device() even if the device wedges
during suspend. (Sashiko)
- Reuse the common device I/O SRCU gate
- Remove the separate VRAM fault SRCU domain
- Protect driver suspend and resume with the common SRCU gate
- Wait for isolation when the device wedges during PM
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>
---
drivers/gpu/drm/xe/display/xe_display.c | 17 +++++++--
drivers/gpu/drm/xe/xe_device.c | 45 +++++++++++++++++++---
drivers/gpu/drm/xe/xe_device_types.h | 9 +++++
drivers/gpu/drm/xe/xe_pci.c | 51 +++++++++++++++++++++----
4 files changed, 106 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
index 7b25c0814674..74a6afd78263 100644
--- a/drivers/gpu/drm/xe/display/xe_display.c
+++ b/drivers/gpu/drm/xe/display/xe_display.c
@@ -150,21 +150,27 @@ void xe_display_register(struct xe_device *xe)
{
struct intel_display *display = xe->display;
- if (!xe->info.probe_display)
+ if (!xe->info.probe_display || xe->display_registered)
return;
intel_display_driver_register(display);
intel_display_driver_runtime_pm_enable(display);
+
+ xe->display_registered = true;
}
void xe_display_unregister(struct xe_device *xe)
{
struct intel_display *display = xe->display;
- if (!xe->info.probe_display)
+ if (!xe->info.probe_display || !xe->display_registered)
return;
- intel_display_driver_runtime_pm_disable(display);
+ xe->display_registered = false;
+
+ if (!xe->display_shutdown)
+ intel_display_driver_runtime_pm_disable(display);
+
intel_display_driver_unregister(display);
}
@@ -172,7 +178,8 @@ void xe_display_shutdown(struct xe_device *xe)
{
struct intel_display *display = xe->display;
- if (!xe->info.probe_display)
+ if (!xe->info.probe_display || !xe->display_registered ||
+ xe->display_shutdown)
return;
intel_display_driver_shutdown(display);
@@ -180,6 +187,8 @@ void xe_display_shutdown(struct xe_device *xe)
intel_opregion_suspend(display, PCI_D3cold);
intel_dmc_suspend(display);
+
+ xe->display_shutdown = true;
}
void xe_display_shutdown_late(struct xe_device *xe)
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 3549cf89a353..549504d2a9c4 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -469,6 +469,7 @@ int xe_device_init_early(struct xe_device *xe)
int err;
INIT_WORK(&xe->wedged.work, xe_device_wedged_work);
+ init_completion(&xe->wedged.prepared);
xe->wedged.reported_method = ~0UL;
err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev,
@@ -889,6 +890,41 @@ static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
}
#endif
+/*
+ * Isolate a permanently wedged device.
+ *
+ * May sleep and must be called from process context.
+ */
+static void xe_device_wedged_isolate(struct xe_device *xe)
+{
+ /*
+ * Wait until xe_device_declare_wedged() has finished scanning GT
+ * submission state before isolating the device.
+ */
+ wait_for_completion(&xe->wedged.prepared);
+
+ if (xe->wedged.isolated)
+ return;
+
+ /*
+ * GT wedging has signalled pending fences. Drain existing hardware
+ * users before isolation starts.
+ */
+ xe_device_io_drain(xe);
+
+ /* Shut down display hardware before stopping device access. */
+ xe_display_shutdown(xe);
+ xe_display_unregister(xe);
+
+ /* Stop interrupt and DMA activity before changing mappings. */
+ xe_irq_suspend(xe);
+ pci_clear_master(to_pci_dev(xe->drm.dev));
+
+ xe_bo_wedged_invalidate_mmaps(xe);
+
+ xe->wedged.isolated = true;
+}
+
static void xe_device_wedged_work(struct work_struct *work)
{
struct xe_device *xe =
@@ -896,9 +932,7 @@ static void xe_device_wedged_work(struct work_struct *work)
unsigned long method;
int err;
- /* Drain active faults before invalidating VRAM mappings. */
- xe_device_io_drain(xe);
- xe_bo_wedged_invalidate_mmaps(xe);
+ xe_device_wedged_isolate(xe);
/* Report at most one recovery method per worker invocation. */
method = READ_ONCE(xe->wedged.method);
@@ -1164,7 +1198,6 @@ int xe_device_probe(struct xe_device *xe)
void xe_device_remove(struct xe_device *xe)
{
xe_device_wedged_disable(xe);
-
xe_display_unregister(xe);
drm_dev_unplug(&xe->drm);
@@ -1180,7 +1213,6 @@ void xe_device_shutdown(struct xe_device *xe)
drm_dbg(&xe->drm, "Shutting down device\n");
xe_device_wedged_disable(xe);
-
xe_display_shutdown(xe);
xe_irq_suspend(xe);
@@ -1502,6 +1534,9 @@ void xe_device_declare_wedged(struct xe_device *xe)
READ_ONCE(xe->wedged.method) !=
READ_ONCE(xe->wedged.reported_method)))
queue_work(xe->unordered_wq, &xe->wedged.work);
+
+ if (first)
+ complete_all(&xe->wedged.prepared);
}
/**
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index f89d539df010..93bb38ed5975 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/completion.h>
#include <linux/mutex.h>
#include <linux/pci.h>
@@ -113,6 +114,10 @@ struct xe_device {
#if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
/** @display: display device data, must be placed after drm device member */
struct intel_display *display;
+ /** @display_registered: Display userspace interfaces are registered */
+ bool display_registered;
+ /** @display_shutdown: Display hardware shutdown has completed */
+ bool display_shutdown;
#endif
/** @devcoredump: device coredump */
@@ -562,8 +567,12 @@ struct xe_device {
struct work_struct work;
/** @wedged.stopping: Blocks worker requeue and repeated disable */
atomic_t stopping;
+ /** @wedged.prepared: First wedge declaration finished and work was queued */
+ struct completion prepared;
/** @wedged.reported_method: Last recovery method reported to userspace */
unsigned long reported_method;
+ /** @wedged.isolated: Terminal device isolation has completed */
+ bool isolated;
} wedged;
/** @devres_group: devres group */
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index d64e873d9e71..25992e4fad43 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -1326,19 +1326,38 @@ static int xe_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct xe_device *xe = pdev_to_xe_device(pdev);
+ int io_idx;
int err;
if (xe_survivability_mode_is_boot_enabled(xe))
return -EBUSY;
- err = xe_pm_suspend(xe);
- if (err)
- return err;
+ /*
+ * Wait until wedge work is queued, then wait for isolation to
+ * finish before skipping driver-level suspend.
+ */
+ err = xe_device_io_get(xe, &io_idx);
+ if (err) {
+ if (!xe_device_wedged(xe))
+ return err;
+
+ wait_for_completion(&xe->wedged.prepared);
+ flush_work(&xe->wedged.work);
+ } else {
+ err = xe_pm_suspend(xe);
+ xe_device_io_put(io_idx);
+
+ if (xe_device_wedged(xe)) {
+ wait_for_completion(&xe->wedged.prepared);
+ flush_work(&xe->wedged.work);
+ } else if (err) {
+ return err;
+ }
+ }
/*
- * Enabling D3Cold is needed for S2Idle/S0ix.
- * It is save to allow here since xe_pm_suspend has evicted
- * the local memory and the direct complete optimization is disabled.
+ * Keep PCI suspend common to both paths so resume performs
+ * matching PCI enable and D3Cold operations.
*/
d3cold_toggle(pdev, D3COLD_ENABLE);
@@ -1352,6 +1371,8 @@ static int xe_pci_suspend(struct device *dev)
static int xe_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct xe_device *xe = pdev_to_xe_device(pdev);
+ int io_idx;
int err;
/* Give back the D3Cold decision to the runtime P M*/
@@ -1363,13 +1384,29 @@ static int xe_pci_resume(struct device *dev)
pci_restore_state(pdev);
+ /* Balance PCI suspend regardless of the current wedge state. */
err = pci_enable_device(pdev);
if (err)
return err;
+ err = xe_device_io_get(xe, &io_idx);
+ if (err) {
+ pci_clear_master(pdev);
+ return xe_device_wedged(xe) ? 0 : err;
+ }
+
pci_set_master(pdev);
- err = xe_pm_resume(pdev_to_xe_device(pdev));
+ err = xe_pm_resume(xe);
+ xe_device_io_put(io_idx);
+
+ if (xe_device_wedged(xe)) {
+ wait_for_completion(&xe->wedged.prepared);
+ flush_work(&xe->wedged.work);
+ pci_clear_master(pdev);
+ return 0;
+ }
+
if (err)
return err;
--
2.43.0
next prev parent reply other threads:[~2026-09-22 10:18 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 10:16 [PATCH v2 00/15] drm/xe: Isolate wedged devices from hardware access Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 01/15] drm/xe/irq: Always free requested IRQs on uninstall Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 02/15] drm/drv: Export drm_dev_srcu_synchronize() Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 03/15] drm/xe: Separate AER reset state from device wedging Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 04/15] drm/xe: Protect device I/O with DRM device SRCU Arvind Yadav
2026-09-22 10:28 ` sashiko-bot
2026-09-22 10:16 ` [PATCH v2 05/15] drm/xe: Drop queued page faults when device I/O is blocked Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 06/15] drm/xe: Stop VM work " Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 07/15] drm/xe: Send wedged notification from a worker Arvind Yadav
2026-09-22 10:27 ` sashiko-bot
2026-09-22 10:16 ` [PATCH v2 08/15] drm/xe: Reuse one dummy page per BO after wedge Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 09/15] drm/xe: Invalidate existing VRAM mappings on wedge Arvind Yadav
2026-09-22 10:30 ` sashiko-bot
2026-09-22 10:16 ` [PATCH v2 10/15] drm/xe/irq: Protect IRQ state during wedge isolation Arvind Yadav
2026-09-22 10:16 ` Arvind Yadav [this message]
2026-09-22 10:31 ` [PATCH v2 11/15] drm/xe: Isolate a wedged device before notifying userspace sashiko-bot
2026-09-22 10:16 ` [PATCH v2 12/15] drm/xe/ttm: Reject VRAM allocations on wedged devices Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 13/15] drm/xe/guc: Skip timeout recovery on a wedged device Arvind Yadav
2026-09-22 10:16 ` [PATCH v2 14/15] drm/xe: Skip PM notifier preparation when device I/O is blocked Arvind Yadav
2026-09-22 10:17 ` [PATCH v2 15/15] drm/xe: Block BO VM access when device I/O is unavailable Arvind Yadav
2026-09-22 10:27 ` ✓ CI.KUnit: success for drm/xe: Isolate wedged devices from hardware access (rev2) Patchwork
2026-09-22 12:26 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-09-22 20:50 ` ✗ Xe.CI.FULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260922101721.1583542-12-arvind.yadav@intel.com \
--to=arvind.yadav@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=himal.prasad.ghimiray@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.brost@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=thomas.hellstrom@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox