* [PATCH v1] drm/xe: Introduce xe_wedge
@ 2026-08-25 11:42 Raag Jadav
2026-08-26 21:10 ` Rodrigo Vivi
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Raag Jadav @ 2026-08-25 11:42 UTC (permalink / raw)
To: intel-xe
Cc: riana.tauro, michal.wajdeczko, lukasz.laguna, matthew.d.roper,
matthew.brost, rodrigo.vivi, Raag Jadav
Consolidates all wedging implementation into a dedicated xe_wedge
component. While at it, add a worker to schedule the wedge handling to
be done async making xe_device_declare_wedged() safe for atomic callers.
Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
PS: The original intent was a bug fix, but that's just a matter of opinion.
Documentation/gpu/xe/xe_device.rst | 2 +-
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
drivers/gpu/drm/xe/xe_device.h | 11 +-
drivers/gpu/drm/xe/xe_device_types.h | 19 +--
drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
drivers/gpu/drm/xe/xe_wedge.h | 24 +++
drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
8 files changed, 271 insertions(+), 197 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
index d3a022362ade..8baed81580c9 100644
--- a/Documentation/gpu/xe/xe_device.rst
+++ b/Documentation/gpu/xe/xe_device.rst
@@ -6,7 +6,7 @@
Xe Device Wedging
==================
-.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
+.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
:doc: Xe Device Wedging
====================
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index adc2de37e768..c739a50b6896 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -152,6 +152,7 @@ xe-y += xe_bb.o \
xe_vsec.o \
xe_wa.o \
xe_wait_user_fence.o \
+ xe_wedge.o \
xe_wopcm.o
xe-$(CONFIG_I2C) += xe_i2c.o \
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 74d566693dfd..d3a7034fac01 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
*/
assert_lmem_ready(xe);
- xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
- XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
- drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
- xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
+ xe_device_wedged_init_early(xe);
err = xe_device_vram_alloc(xe);
if (err)
@@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
}
}
-static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
-{
- struct xe_device *xe = arg;
-
- if (atomic_read(&xe->wedged.flag))
- xe_pm_runtime_put(xe);
-}
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
{
@@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
detect_preproduction_hw(xe);
- err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
+ err = xe_device_wedged_init(xe);
if (err)
goto err_unregister_display;
@@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
}
-/**
- * DOC: Xe Device Wedging
- *
- * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
- * When device is in wedged state, every IOCTL will be blocked and GT cannot
- * be used. The conditions under which the driver declares the device wedged
- * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
- * default recovery method for a wedged state is rebind/bus-reset.
- *
- * Another recovery method is vendor-specific. Below are the cases that send
- * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
- *
- * Case: Firmware Flash
- * --------------------
- *
- * Identification Hint
- * +++++++++++++++++++
- *
- * ``WEDGED=vendor-specific`` drm device wedged uevent with
- * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
- * admin/userspace consumer about the need for a firmware flash.
- *
- * Recovery Procedure
- * ++++++++++++++++++
- *
- * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
- * the below steps
- *
- * - Check Runtime Survivability mode sysfs.
- * If enabled, firmware flash is required to recover the device.
- *
- * /sys/bus/pci/devices/<device>/survivability_mode
- *
- * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
- * firmware and restore device to normal operation.
- */
-
-/**
- * xe_device_set_wedged_method - Set wedged recovery method
- * @xe: xe device instance
- * @method: recovery method to set
- *
- * Set wedged recovery method to be sent in drm wedged uevent.
- */
-void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
-{
- xe->wedged.method = method;
-}
-
-#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
-#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
-
-/**
- * xe_device_declare_wedged - Declare device wedged
- * @xe: xe device instance
- *
- * This is a final state that can only be cleared with the recovery method
- * specified in the drm wedged uevent. The method can be set using
- * xe_device_set_wedged_method before declaring the device as wedged. If no method
- * is set, reprobe (unbind/re-bind) will be sent by default.
- *
- * In this state every IOCTL will be blocked so the GT cannot be used.
- * In general it will be called upon any critical error such as gt reset
- * failure or guc loading failure. Userspace will be notified of this state
- * through device wedged uevent.
- * If xe.wedged module parameter is set to 2, this function will be called
- * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
- * snapshot capture. In this mode, GT reset won't be attempted so the state of
- * the issue is preserved for further debugging.
- */
-void xe_device_declare_wedged(struct xe_device *xe)
-{
- struct xe_gt *gt;
- u8 id;
-
- if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
- drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
- return;
- }
-
- if (!atomic_xchg(&xe->wedged.flag, 1)) {
- xe->needs_flr_on_fini = true;
- xe_pm_runtime_get_noresume(xe);
-
- xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
- xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
- "For recovery procedure, refer to %s\n"
- "Please file a _new_ bug report at %s\n",
- WEDGED_URL, XE_BUG_URL);
- }
-
- for_each_gt(gt, xe, id)
- xe_gt_declare_wedged(gt);
-
- if (xe_device_wedged(xe)) {
- /*
- * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
- * hangs, so wedge the device with 'none' recovery method and have
- * it available to the user for debugging.
- */
- if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
- /* If no wedge recovery method is set, use default */
- else if (!xe->wedged.method)
- xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
- DRM_WEDGE_RECOVERY_BUS_RESET);
-
- /* Notify userspace of wedged device */
- drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
- }
-}
-
-/**
- * xe_device_validate_wedged_mode - Check if given mode is supported
- * @xe: the &xe_device
- * @mode: requested mode to validate
- *
- * Check whether the provided wedged mode is supported.
- *
- * Return: 0 if mode is supported, error code otherwise.
- */
-int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
-{
- if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
- drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
- return -EINVAL;
- } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
- (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
- drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
- mode, xe_wedged_mode_to_string(mode),
- xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
- return -EPERM;
- }
-
- return 0;
-}
-
-/**
- * xe_wedged_mode_to_string - Convert enum value to string.
- * @mode: the &xe_wedged_mode to convert
- *
- * Returns: wedged mode as a user friendly string.
- */
-const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
-{
- switch (mode) {
- case XE_WEDGED_MODE_NEVER:
- return "never";
- case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
- return "upon-critical-error";
- case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
- return "upon-any-hang-no-reset";
- default:
- return "<invalid>";
- }
-}
-
/**
* xe_device_asid_to_vm() - Find VM from ASID
* @xe: the &xe_device
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 6c4cfaebc44a..c984972bd0f8 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -11,6 +11,7 @@
#include "xe_device_types.h"
#include "xe_gt_types.h"
#include "xe_sriov.h"
+#include "xe_wedge.h"
struct xe_vm;
@@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
void xe_device_td_flush(struct xe_device *xe);
void xe_device_l2_flush(struct xe_device *xe);
-static inline bool xe_device_wedged(struct xe_device *xe)
-{
- return atomic_read(&xe->wedged.flag);
-}
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
static inline bool xe_debug_page_size_supported(struct xe_device *xe)
{
@@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
}
#endif
-void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
-void xe_device_declare_wedged(struct xe_device *xe);
-int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
-const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
-
struct xe_file *xe_file_get(struct xe_file *xef);
void xe_file_put(struct xe_file *xef);
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 180d450a6deb..f307d7e5e6b6 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -30,6 +30,7 @@
#include "xe_sysctrl_types.h"
#include "xe_tile_types.h"
#include "xe_validation.h"
+#include "xe_wedge_types.h"
#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
#define TEST_VM_OPS_ERROR
@@ -45,22 +46,6 @@ struct xe_pxp;
struct xe_ttm_stolen_mgr;
struct xe_vram_region;
-/**
- * enum xe_wedged_mode - possible wedged modes
- * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
- * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
- * when critical error occurs like GT reset failure or firmware failure.
- * This is the default mode.
- * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
- * any hang. In this mode, engine resets are disabled to avoid automatic
- * recovery attempts. This mode is primarily intended for debugging hangs.
- */
-enum xe_wedged_mode {
- XE_WEDGED_MODE_NEVER = 0,
- XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
- XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
-};
-
#ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
/**
* enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
@@ -534,6 +519,8 @@ struct xe_device {
unsigned long method;
/** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
bool inconsistent_reset;
+ /** @wedged.work: Worker for wedge handling to be done async */
+ struct work_struct work;
} wedged;
/** @devres_group: devres group */
diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
new file mode 100644
index 000000000000..52d4661a2dee
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+
+#include "xe_defaults.h"
+#include "xe_device_types.h"
+#include "xe_gt.h"
+#include "xe_log.h"
+#include "xe_module.h"
+#include "xe_pm.h"
+#include "xe_printk.h"
+#include "xe_wedge.h"
+
+/**
+ * DOC: Xe Device Wedging
+ *
+ * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
+ * When device is in wedged state, every IOCTL will be blocked and GT cannot
+ * be used. The conditions under which the driver declares the device wedged
+ * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
+ * default recovery method for a wedged state is rebind/bus-reset.
+ *
+ * Another recovery method is vendor-specific. Below are the cases that send
+ * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
+ *
+ * Case: Firmware Flash
+ * --------------------
+ *
+ * Identification Hint
+ * +++++++++++++++++++
+ *
+ * ``WEDGED=vendor-specific`` drm device wedged uevent with
+ * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
+ * admin/userspace consumer about the need for a firmware flash.
+ *
+ * Recovery Procedure
+ * ++++++++++++++++++
+ *
+ * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
+ * the below steps
+ *
+ * - Check Runtime Survivability mode sysfs.
+ * If enabled, firmware flash is required to recover the device.
+ *
+ * /sys/bus/pci/devices/<device>/survivability_mode
+ *
+ * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
+ * firmware and restore device to normal operation.
+ */
+
+/**
+ * xe_device_set_wedged_method() - Set wedged recovery method
+ * @xe: xe device instance
+ * @method: recovery method to set
+ *
+ * Set wedged recovery method to be sent in drm wedged uevent.
+ */
+void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
+{
+ xe->wedged.method = method;
+}
+
+/**
+ * xe_device_wedged() - Check for wedged device
+ * @xe: xe device instance
+ *
+ * Returns: %true if device is wedged, %false otherwise.
+ */
+bool xe_device_wedged(struct xe_device *xe)
+{
+ return atomic_read(&xe->wedged.flag);
+}
+
+#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
+#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
+
+static void wedged_work(struct work_struct *work)
+{
+ struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
+ struct xe_gt *gt;
+ u8 id;
+
+ for_each_gt(gt, xe, id)
+ xe_gt_declare_wedged(gt);
+
+ /*
+ * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
+ * hangs, so wedge the device with 'none' recovery method and have
+ * it available to the user for debugging.
+ */
+ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
+ xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
+ /* If no wedge recovery method is set, use default */
+ else if (!xe->wedged.method)
+ xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
+ DRM_WEDGE_RECOVERY_BUS_RESET);
+
+ /* Notify userspace of wedged device */
+ drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
+}
+
+/**
+ * xe_device_declare_wedged - Declare device wedged
+ * @xe: xe device instance
+ *
+ * This is a final state that can only be cleared with the recovery method
+ * specified in the drm wedged uevent. The method can be set using
+ * xe_device_set_wedged_method before declaring the device as wedged. If no method
+ * is set, reprobe (unbind/re-bind) will be sent by default.
+ *
+ * In this state every IOCTL will be blocked so the GT cannot be used.
+ * In general it will be called upon any critical error such as gt reset
+ * failure or guc loading failure. Userspace will be notified of this state
+ * through device wedged uevent.
+ * If xe.wedged module parameter is set to 2, this function will be called
+ * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
+ * snapshot capture. In this mode, GT reset won't be attempted so the state of
+ * the issue is preserved for further debugging.
+ */
+void xe_device_declare_wedged(struct xe_device *xe)
+{
+ if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
+ drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
+ return;
+ }
+
+ if (!atomic_xchg(&xe->wedged.flag, 1)) {
+ xe->needs_flr_on_fini = true;
+ xe_pm_runtime_get_noresume(xe);
+
+ xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
+ xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
+ "For recovery procedure, refer to %s\n"
+ "Please file a _new_ bug report at %s\n",
+ WEDGED_URL, XE_BUG_URL);
+
+ schedule_work(&xe->wedged.work);
+ }
+}
+
+/**
+ * xe_device_validate_wedged_mode - Check if given mode is supported
+ * @xe: the &xe_device
+ * @mode: requested mode to validate
+ *
+ * Check whether the provided wedged mode is supported.
+ *
+ * Return: 0 if mode is supported, error code otherwise.
+ */
+int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
+{
+ if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
+ drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
+ return -EINVAL;
+ } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
+ (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
+ drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
+ mode, xe_wedged_mode_to_string(mode),
+ xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/**
+ * xe_wedged_mode_to_string - Convert enum value to string.
+ * @mode: the &xe_wedged_mode to convert
+ *
+ * Returns: wedged mode as a user friendly string.
+ */
+const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
+{
+ switch (mode) {
+ case XE_WEDGED_MODE_NEVER:
+ return "never";
+ case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
+ return "upon-critical-error";
+ case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
+ return "upon-any-hang-no-reset";
+ default:
+ return "<invalid>";
+ }
+}
+
+void xe_device_wedged_init_early(struct xe_device *xe)
+{
+ xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
+ XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
+ drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
+ xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
+}
+
+static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
+{
+ struct xe_device *xe = arg;
+
+ disable_work_sync(&xe->wedged.work);
+
+ if (atomic_read(&xe->wedged.flag))
+ xe_pm_runtime_put(xe);
+}
+
+int xe_device_wedged_init(struct xe_device *xe)
+{
+ INIT_WORK(&xe->wedged.work, wedged_work);
+
+ return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
+}
+
diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
new file mode 100644
index 000000000000..fedb30c99398
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_WEDGE_H_
+#define _XE_WEDGE_H_
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "xe_wedge_types.h"
+
+struct xe_device;
+
+void xe_device_wedged_init_early(struct xe_device *xe);
+int xe_device_wedged_init(struct xe_device *xe);
+void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
+void xe_device_declare_wedged(struct xe_device *xe);
+bool xe_device_wedged(struct xe_device *xe);
+int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
+const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
+
+#endif
diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
new file mode 100644
index 000000000000..ffe7f9c64166
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_wedge_types.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#ifndef _XE_WEDGE_TYPES_H_
+#define _XE_WEDGE_TYPES_H_
+
+/**
+ * enum xe_wedged_mode - possible wedged modes
+ * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
+ * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
+ * when critical error occurs like GT reset failure or firmware failure.
+ * This is the default mode.
+ * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
+ * any hang. In this mode, engine resets are disabled to avoid automatic
+ * recovery attempts. This mode is primarily intended for debugging hangs.
+ */
+enum xe_wedged_mode {
+ XE_WEDGED_MODE_NEVER = 0,
+ XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
+ XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
+};
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-25 11:42 [PATCH v1] drm/xe: Introduce xe_wedge Raag Jadav
@ 2026-08-26 21:10 ` Rodrigo Vivi
2026-08-27 6:20 ` Raag Jadav
2026-08-27 6:33 ` Laguna, Lukasz
2026-08-27 17:38 ` Michal Wajdeczko
2 siblings, 1 reply; 8+ messages in thread
From: Rodrigo Vivi @ 2026-08-26 21:10 UTC (permalink / raw)
To: Raag Jadav
Cc: intel-xe, riana.tauro, michal.wajdeczko, lukasz.laguna,
matthew.d.roper, matthew.brost
On Tue, Aug 25, 2026 at 05:12:43PM +0530, Raag Jadav wrote:
> Consolidates all wedging implementation into a dedicated xe_wedge
> component. While at it, add a worker to schedule the wedge handling to
> be done async making xe_device_declare_wedged() safe for atomic callers.
>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> PS: The original intent was a bug fix, but that's just a matter of opinion.
I had thought about this spin-off a very long time ago too...
But please, split into 2 patches, one with the consolidation and one with
the worker. This one is painful to review as is right now.
Also, please use 'xe_wedge_' as the new prefix for any non static functions.
Thanks,
Rodrigo.
>
> Documentation/gpu/xe/xe_device.rst | 2 +-
> drivers/gpu/drm/xe/Makefile | 1 +
> drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> drivers/gpu/drm/xe/xe_device.h | 11 +-
> drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> 8 files changed, 271 insertions(+), 197 deletions(-)
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
>
> diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> index d3a022362ade..8baed81580c9 100644
> --- a/Documentation/gpu/xe/xe_device.rst
> +++ b/Documentation/gpu/xe/xe_device.rst
> @@ -6,7 +6,7 @@
> Xe Device Wedging
> ==================
>
> -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> :doc: Xe Device Wedging
>
> ====================
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index adc2de37e768..c739a50b6896 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> xe_vsec.o \
> xe_wa.o \
> xe_wait_user_fence.o \
> + xe_wedge.o \
> xe_wopcm.o
>
> xe-$(CONFIG_I2C) += xe_i2c.o \
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 74d566693dfd..d3a7034fac01 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> */
> assert_lmem_ready(xe);
>
> - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> + xe_device_wedged_init_early(xe);
>
> err = xe_device_vram_alloc(xe);
> if (err)
> @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> }
> }
>
> -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> -{
> - struct xe_device *xe = arg;
> -
> - if (atomic_read(&xe->wedged.flag))
> - xe_pm_runtime_put(xe);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> {
> @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
>
> detect_preproduction_hw(xe);
>
> - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> + err = xe_device_wedged_init(xe);
> if (err)
> goto err_unregister_display;
>
> @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> }
>
> -/**
> - * DOC: Xe Device Wedging
> - *
> - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> - * be used. The conditions under which the driver declares the device wedged
> - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> - * default recovery method for a wedged state is rebind/bus-reset.
> - *
> - * Another recovery method is vendor-specific. Below are the cases that send
> - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> - *
> - * Case: Firmware Flash
> - * --------------------
> - *
> - * Identification Hint
> - * +++++++++++++++++++
> - *
> - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> - * admin/userspace consumer about the need for a firmware flash.
> - *
> - * Recovery Procedure
> - * ++++++++++++++++++
> - *
> - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> - * the below steps
> - *
> - * - Check Runtime Survivability mode sysfs.
> - * If enabled, firmware flash is required to recover the device.
> - *
> - * /sys/bus/pci/devices/<device>/survivability_mode
> - *
> - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> - * firmware and restore device to normal operation.
> - */
> -
> -/**
> - * xe_device_set_wedged_method - Set wedged recovery method
> - * @xe: xe device instance
> - * @method: recovery method to set
> - *
> - * Set wedged recovery method to be sent in drm wedged uevent.
> - */
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> -{
> - xe->wedged.method = method;
> -}
> -
> -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> -
> -/**
> - * xe_device_declare_wedged - Declare device wedged
> - * @xe: xe device instance
> - *
> - * This is a final state that can only be cleared with the recovery method
> - * specified in the drm wedged uevent. The method can be set using
> - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> - * is set, reprobe (unbind/re-bind) will be sent by default.
> - *
> - * In this state every IOCTL will be blocked so the GT cannot be used.
> - * In general it will be called upon any critical error such as gt reset
> - * failure or guc loading failure. Userspace will be notified of this state
> - * through device wedged uevent.
> - * If xe.wedged module parameter is set to 2, this function will be called
> - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> - * the issue is preserved for further debugging.
> - */
> -void xe_device_declare_wedged(struct xe_device *xe)
> -{
> - struct xe_gt *gt;
> - u8 id;
> -
> - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> - return;
> - }
> -
> - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> - xe->needs_flr_on_fini = true;
> - xe_pm_runtime_get_noresume(xe);
> -
> - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> - "For recovery procedure, refer to %s\n"
> - "Please file a _new_ bug report at %s\n",
> - WEDGED_URL, XE_BUG_URL);
> - }
> -
> - for_each_gt(gt, xe, id)
> - xe_gt_declare_wedged(gt);
> -
> - if (xe_device_wedged(xe)) {
> - /*
> - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> - * hangs, so wedge the device with 'none' recovery method and have
> - * it available to the user for debugging.
> - */
> - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> - /* If no wedge recovery method is set, use default */
> - else if (!xe->wedged.method)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> - DRM_WEDGE_RECOVERY_BUS_RESET);
> -
> - /* Notify userspace of wedged device */
> - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> - }
> -}
> -
> -/**
> - * xe_device_validate_wedged_mode - Check if given mode is supported
> - * @xe: the &xe_device
> - * @mode: requested mode to validate
> - *
> - * Check whether the provided wedged mode is supported.
> - *
> - * Return: 0 if mode is supported, error code otherwise.
> - */
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> -{
> - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> - return -EINVAL;
> - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> - mode, xe_wedged_mode_to_string(mode),
> - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> - return -EPERM;
> - }
> -
> - return 0;
> -}
> -
> -/**
> - * xe_wedged_mode_to_string - Convert enum value to string.
> - * @mode: the &xe_wedged_mode to convert
> - *
> - * Returns: wedged mode as a user friendly string.
> - */
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> -{
> - switch (mode) {
> - case XE_WEDGED_MODE_NEVER:
> - return "never";
> - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> - return "upon-critical-error";
> - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> - return "upon-any-hang-no-reset";
> - default:
> - return "<invalid>";
> - }
> -}
> -
> /**
> * xe_device_asid_to_vm() - Find VM from ASID
> * @xe: the &xe_device
> diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> index 6c4cfaebc44a..c984972bd0f8 100644
> --- a/drivers/gpu/drm/xe/xe_device.h
> +++ b/drivers/gpu/drm/xe/xe_device.h
> @@ -11,6 +11,7 @@
> #include "xe_device_types.h"
> #include "xe_gt_types.h"
> #include "xe_sriov.h"
> +#include "xe_wedge.h"
>
> struct xe_vm;
>
> @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> void xe_device_td_flush(struct xe_device *xe);
> void xe_device_l2_flush(struct xe_device *xe);
>
> -static inline bool xe_device_wedged(struct xe_device *xe)
> -{
> - return atomic_read(&xe->wedged.flag);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> {
> @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> }
> #endif
>
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> -void xe_device_declare_wedged(struct xe_device *xe);
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> -
> struct xe_file *xe_file_get(struct xe_file *xef);
> void xe_file_put(struct xe_file *xef);
>
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 180d450a6deb..f307d7e5e6b6 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -30,6 +30,7 @@
> #include "xe_sysctrl_types.h"
> #include "xe_tile_types.h"
> #include "xe_validation.h"
> +#include "xe_wedge_types.h"
>
> #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> #define TEST_VM_OPS_ERROR
> @@ -45,22 +46,6 @@ struct xe_pxp;
> struct xe_ttm_stolen_mgr;
> struct xe_vram_region;
>
> -/**
> - * enum xe_wedged_mode - possible wedged modes
> - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> - * when critical error occurs like GT reset failure or firmware failure.
> - * This is the default mode.
> - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> - * any hang. In this mode, engine resets are disabled to avoid automatic
> - * recovery attempts. This mode is primarily intended for debugging hangs.
> - */
> -enum xe_wedged_mode {
> - XE_WEDGED_MODE_NEVER = 0,
> - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> -};
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> /**
> * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> @@ -534,6 +519,8 @@ struct xe_device {
> unsigned long method;
> /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> bool inconsistent_reset;
> + /** @wedged.work: Worker for wedge handling to be done async */
> + struct work_struct work;
> } wedged;
>
> /** @devres_group: devres group */
> diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> new file mode 100644
> index 000000000000..52d4661a2dee
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.c
> @@ -0,0 +1,214 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_managed.h>
> +
> +#include "xe_defaults.h"
> +#include "xe_device_types.h"
> +#include "xe_gt.h"
> +#include "xe_log.h"
> +#include "xe_module.h"
> +#include "xe_pm.h"
> +#include "xe_printk.h"
> +#include "xe_wedge.h"
> +
> +/**
> + * DOC: Xe Device Wedging
> + *
> + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> + * be used. The conditions under which the driver declares the device wedged
> + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> + * default recovery method for a wedged state is rebind/bus-reset.
> + *
> + * Another recovery method is vendor-specific. Below are the cases that send
> + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> + *
> + * Case: Firmware Flash
> + * --------------------
> + *
> + * Identification Hint
> + * +++++++++++++++++++
> + *
> + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> + * admin/userspace consumer about the need for a firmware flash.
> + *
> + * Recovery Procedure
> + * ++++++++++++++++++
> + *
> + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> + * the below steps
> + *
> + * - Check Runtime Survivability mode sysfs.
> + * If enabled, firmware flash is required to recover the device.
> + *
> + * /sys/bus/pci/devices/<device>/survivability_mode
> + *
> + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> + * firmware and restore device to normal operation.
> + */
> +
> +/**
> + * xe_device_set_wedged_method() - Set wedged recovery method
> + * @xe: xe device instance
> + * @method: recovery method to set
> + *
> + * Set wedged recovery method to be sent in drm wedged uevent.
> + */
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> +{
> + xe->wedged.method = method;
> +}
> +
> +/**
> + * xe_device_wedged() - Check for wedged device
> + * @xe: xe device instance
> + *
> + * Returns: %true if device is wedged, %false otherwise.
> + */
> +bool xe_device_wedged(struct xe_device *xe)
> +{
> + return atomic_read(&xe->wedged.flag);
> +}
> +
> +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> +
> +static void wedged_work(struct work_struct *work)
> +{
> + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> + struct xe_gt *gt;
> + u8 id;
> +
> + for_each_gt(gt, xe, id)
> + xe_gt_declare_wedged(gt);
> +
> + /*
> + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> + * hangs, so wedge the device with 'none' recovery method and have
> + * it available to the user for debugging.
> + */
> + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> + /* If no wedge recovery method is set, use default */
> + else if (!xe->wedged.method)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> + DRM_WEDGE_RECOVERY_BUS_RESET);
> +
> + /* Notify userspace of wedged device */
> + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> +}
> +
> +/**
> + * xe_device_declare_wedged - Declare device wedged
> + * @xe: xe device instance
> + *
> + * This is a final state that can only be cleared with the recovery method
> + * specified in the drm wedged uevent. The method can be set using
> + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> + * is set, reprobe (unbind/re-bind) will be sent by default.
> + *
> + * In this state every IOCTL will be blocked so the GT cannot be used.
> + * In general it will be called upon any critical error such as gt reset
> + * failure or guc loading failure. Userspace will be notified of this state
> + * through device wedged uevent.
> + * If xe.wedged module parameter is set to 2, this function will be called
> + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> + * the issue is preserved for further debugging.
> + */
> +void xe_device_declare_wedged(struct xe_device *xe)
> +{
> + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> + return;
> + }
> +
> + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> + xe->needs_flr_on_fini = true;
> + xe_pm_runtime_get_noresume(xe);
> +
> + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> + "For recovery procedure, refer to %s\n"
> + "Please file a _new_ bug report at %s\n",
> + WEDGED_URL, XE_BUG_URL);
> +
> + schedule_work(&xe->wedged.work);
> + }
> +}
> +
> +/**
> + * xe_device_validate_wedged_mode - Check if given mode is supported
> + * @xe: the &xe_device
> + * @mode: requested mode to validate
> + *
> + * Check whether the provided wedged mode is supported.
> + *
> + * Return: 0 if mode is supported, error code otherwise.
> + */
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> +{
> + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> + return -EINVAL;
> + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> + mode, xe_wedged_mode_to_string(mode),
> + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> + return -EPERM;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * xe_wedged_mode_to_string - Convert enum value to string.
> + * @mode: the &xe_wedged_mode to convert
> + *
> + * Returns: wedged mode as a user friendly string.
> + */
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> +{
> + switch (mode) {
> + case XE_WEDGED_MODE_NEVER:
> + return "never";
> + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> + return "upon-critical-error";
> + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> + return "upon-any-hang-no-reset";
> + default:
> + return "<invalid>";
> + }
> +}
> +
> +void xe_device_wedged_init_early(struct xe_device *xe)
> +{
> + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> +}
> +
> +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> +{
> + struct xe_device *xe = arg;
> +
> + disable_work_sync(&xe->wedged.work);
> +
> + if (atomic_read(&xe->wedged.flag))
> + xe_pm_runtime_put(xe);
> +}
> +
> +int xe_device_wedged_init(struct xe_device *xe)
> +{
> + INIT_WORK(&xe->wedged.work, wedged_work);
> +
> + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> +}
> +
> diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> new file mode 100644
> index 000000000000..fedb30c99398
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_H_
> +#define _XE_WEDGE_H_
> +
> +#include <linux/atomic.h>
> +#include <linux/types.h>
> +
> +#include "xe_wedge_types.h"
> +
> +struct xe_device;
> +
> +void xe_device_wedged_init_early(struct xe_device *xe);
> +int xe_device_wedged_init(struct xe_device *xe);
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> +void xe_device_declare_wedged(struct xe_device *xe);
> +bool xe_device_wedged(struct xe_device *xe);
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> new file mode 100644
> index 000000000000..ffe7f9c64166
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_TYPES_H_
> +#define _XE_WEDGE_TYPES_H_
> +
> +/**
> + * enum xe_wedged_mode - possible wedged modes
> + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> + * when critical error occurs like GT reset failure or firmware failure.
> + * This is the default mode.
> + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> + * any hang. In this mode, engine resets are disabled to avoid automatic
> + * recovery attempts. This mode is primarily intended for debugging hangs.
> + */
> +enum xe_wedged_mode {
> + XE_WEDGED_MODE_NEVER = 0,
> + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> +};
> +
> +#endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-26 21:10 ` Rodrigo Vivi
@ 2026-08-27 6:20 ` Raag Jadav
2026-08-28 15:30 ` Rodrigo Vivi
0 siblings, 1 reply; 8+ messages in thread
From: Raag Jadav @ 2026-08-27 6:20 UTC (permalink / raw)
To: Rodrigo Vivi
Cc: intel-xe, riana.tauro, michal.wajdeczko, lukasz.laguna,
matthew.d.roper, matthew.brost
On Wed, Aug 26, 2026 at 05:10:44PM -0400, Rodrigo Vivi wrote:
> On Tue, Aug 25, 2026 at 05:12:43PM +0530, Raag Jadav wrote:
> > Consolidates all wedging implementation into a dedicated xe_wedge
> > component. While at it, add a worker to schedule the wedge handling to
> > be done async making xe_device_declare_wedged() safe for atomic callers.
> >
> > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > ---
> > PS: The original intent was a bug fix, but that's just a matter of opinion.
>
> I had thought about this spin-off a very long time ago too...
>
> But please, split into 2 patches, one with the consolidation and one with
> the worker. This one is painful to review as is right now.
This was meant more as an RFC and needs a bit of discussion, sorry I
didn't update the subject prefix.
xe_pm_runtime_get_noresume() has checks against 'current' task and I'm
wondering if it's reliable in atomic context?
> Also, please use 'xe_wedge_' as the new prefix for any non static functions.
Sure.
Raag
> > Documentation/gpu/xe/xe_device.rst | 2 +-
> > drivers/gpu/drm/xe/Makefile | 1 +
> > drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> > drivers/gpu/drm/xe/xe_device.h | 11 +-
> > drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> > drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> > drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> > drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> > 8 files changed, 271 insertions(+), 197 deletions(-)
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
> >
> > diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> > index d3a022362ade..8baed81580c9 100644
> > --- a/Documentation/gpu/xe/xe_device.rst
> > +++ b/Documentation/gpu/xe/xe_device.rst
> > @@ -6,7 +6,7 @@
> > Xe Device Wedging
> > ==================
> >
> > -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> > +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> > :doc: Xe Device Wedging
> >
> > ====================
> > diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> > index adc2de37e768..c739a50b6896 100644
> > --- a/drivers/gpu/drm/xe/Makefile
> > +++ b/drivers/gpu/drm/xe/Makefile
> > @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> > xe_vsec.o \
> > xe_wa.o \
> > xe_wait_user_fence.o \
> > + xe_wedge.o \
> > xe_wopcm.o
> >
> > xe-$(CONFIG_I2C) += xe_i2c.o \
> > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > index 74d566693dfd..d3a7034fac01 100644
> > --- a/drivers/gpu/drm/xe/xe_device.c
> > +++ b/drivers/gpu/drm/xe/xe_device.c
> > @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> > */
> > assert_lmem_ready(xe);
> >
> > - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > + xe_device_wedged_init_early(xe);
> >
> > err = xe_device_vram_alloc(xe);
> > if (err)
> > @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> > }
> > }
> >
> > -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > -{
> > - struct xe_device *xe = arg;
> > -
> > - if (atomic_read(&xe->wedged.flag))
> > - xe_pm_runtime_put(xe);
> > -}
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> > {
> > @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
> >
> > detect_preproduction_hw(xe);
> >
> > - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > + err = xe_device_wedged_init(xe);
> > if (err)
> > goto err_unregister_display;
> >
> > @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> > return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> > }
> >
> > -/**
> > - * DOC: Xe Device Wedging
> > - *
> > - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > - * be used. The conditions under which the driver declares the device wedged
> > - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > - * default recovery method for a wedged state is rebind/bus-reset.
> > - *
> > - * Another recovery method is vendor-specific. Below are the cases that send
> > - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > - *
> > - * Case: Firmware Flash
> > - * --------------------
> > - *
> > - * Identification Hint
> > - * +++++++++++++++++++
> > - *
> > - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > - * admin/userspace consumer about the need for a firmware flash.
> > - *
> > - * Recovery Procedure
> > - * ++++++++++++++++++
> > - *
> > - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > - * the below steps
> > - *
> > - * - Check Runtime Survivability mode sysfs.
> > - * If enabled, firmware flash is required to recover the device.
> > - *
> > - * /sys/bus/pci/devices/<device>/survivability_mode
> > - *
> > - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > - * firmware and restore device to normal operation.
> > - */
> > -
> > -/**
> > - * xe_device_set_wedged_method - Set wedged recovery method
> > - * @xe: xe device instance
> > - * @method: recovery method to set
> > - *
> > - * Set wedged recovery method to be sent in drm wedged uevent.
> > - */
> > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > -{
> > - xe->wedged.method = method;
> > -}
> > -
> > -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > -
> > -/**
> > - * xe_device_declare_wedged - Declare device wedged
> > - * @xe: xe device instance
> > - *
> > - * This is a final state that can only be cleared with the recovery method
> > - * specified in the drm wedged uevent. The method can be set using
> > - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > - * is set, reprobe (unbind/re-bind) will be sent by default.
> > - *
> > - * In this state every IOCTL will be blocked so the GT cannot be used.
> > - * In general it will be called upon any critical error such as gt reset
> > - * failure or guc loading failure. Userspace will be notified of this state
> > - * through device wedged uevent.
> > - * If xe.wedged module parameter is set to 2, this function will be called
> > - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > - * the issue is preserved for further debugging.
> > - */
> > -void xe_device_declare_wedged(struct xe_device *xe)
> > -{
> > - struct xe_gt *gt;
> > - u8 id;
> > -
> > - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > - return;
> > - }
> > -
> > - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > - xe->needs_flr_on_fini = true;
> > - xe_pm_runtime_get_noresume(xe);
> > -
> > - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > - "For recovery procedure, refer to %s\n"
> > - "Please file a _new_ bug report at %s\n",
> > - WEDGED_URL, XE_BUG_URL);
> > - }
> > -
> > - for_each_gt(gt, xe, id)
> > - xe_gt_declare_wedged(gt);
> > -
> > - if (xe_device_wedged(xe)) {
> > - /*
> > - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > - * hangs, so wedge the device with 'none' recovery method and have
> > - * it available to the user for debugging.
> > - */
> > - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > - /* If no wedge recovery method is set, use default */
> > - else if (!xe->wedged.method)
> > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > - DRM_WEDGE_RECOVERY_BUS_RESET);
> > -
> > - /* Notify userspace of wedged device */
> > - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > - }
> > -}
> > -
> > -/**
> > - * xe_device_validate_wedged_mode - Check if given mode is supported
> > - * @xe: the &xe_device
> > - * @mode: requested mode to validate
> > - *
> > - * Check whether the provided wedged mode is supported.
> > - *
> > - * Return: 0 if mode is supported, error code otherwise.
> > - */
> > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > -{
> > - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > - return -EINVAL;
> > - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > - mode, xe_wedged_mode_to_string(mode),
> > - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > - return -EPERM;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -/**
> > - * xe_wedged_mode_to_string - Convert enum value to string.
> > - * @mode: the &xe_wedged_mode to convert
> > - *
> > - * Returns: wedged mode as a user friendly string.
> > - */
> > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > -{
> > - switch (mode) {
> > - case XE_WEDGED_MODE_NEVER:
> > - return "never";
> > - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > - return "upon-critical-error";
> > - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > - return "upon-any-hang-no-reset";
> > - default:
> > - return "<invalid>";
> > - }
> > -}
> > -
> > /**
> > * xe_device_asid_to_vm() - Find VM from ASID
> > * @xe: the &xe_device
> > diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> > index 6c4cfaebc44a..c984972bd0f8 100644
> > --- a/drivers/gpu/drm/xe/xe_device.h
> > +++ b/drivers/gpu/drm/xe/xe_device.h
> > @@ -11,6 +11,7 @@
> > #include "xe_device_types.h"
> > #include "xe_gt_types.h"
> > #include "xe_sriov.h"
> > +#include "xe_wedge.h"
> >
> > struct xe_vm;
> >
> > @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> > void xe_device_td_flush(struct xe_device *xe);
> > void xe_device_l2_flush(struct xe_device *xe);
> >
> > -static inline bool xe_device_wedged(struct xe_device *xe)
> > -{
> > - return atomic_read(&xe->wedged.flag);
> > -}
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> > {
> > @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> > }
> > #endif
> >
> > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > -void xe_device_declare_wedged(struct xe_device *xe);
> > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> > -
> > struct xe_file *xe_file_get(struct xe_file *xef);
> > void xe_file_put(struct xe_file *xef);
> >
> > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > index 180d450a6deb..f307d7e5e6b6 100644
> > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > @@ -30,6 +30,7 @@
> > #include "xe_sysctrl_types.h"
> > #include "xe_tile_types.h"
> > #include "xe_validation.h"
> > +#include "xe_wedge_types.h"
> >
> > #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> > #define TEST_VM_OPS_ERROR
> > @@ -45,22 +46,6 @@ struct xe_pxp;
> > struct xe_ttm_stolen_mgr;
> > struct xe_vram_region;
> >
> > -/**
> > - * enum xe_wedged_mode - possible wedged modes
> > - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > - * when critical error occurs like GT reset failure or firmware failure.
> > - * This is the default mode.
> > - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > - * any hang. In this mode, engine resets are disabled to avoid automatic
> > - * recovery attempts. This mode is primarily intended for debugging hangs.
> > - */
> > -enum xe_wedged_mode {
> > - XE_WEDGED_MODE_NEVER = 0,
> > - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > -};
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > /**
> > * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> > @@ -534,6 +519,8 @@ struct xe_device {
> > unsigned long method;
> > /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> > bool inconsistent_reset;
> > + /** @wedged.work: Worker for wedge handling to be done async */
> > + struct work_struct work;
> > } wedged;
> >
> > /** @devres_group: devres group */
> > diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> > new file mode 100644
> > index 000000000000..52d4661a2dee
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge.c
> > @@ -0,0 +1,214 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#include <drm/drm_drv.h>
> > +#include <drm/drm_managed.h>
> > +
> > +#include "xe_defaults.h"
> > +#include "xe_device_types.h"
> > +#include "xe_gt.h"
> > +#include "xe_log.h"
> > +#include "xe_module.h"
> > +#include "xe_pm.h"
> > +#include "xe_printk.h"
> > +#include "xe_wedge.h"
> > +
> > +/**
> > + * DOC: Xe Device Wedging
> > + *
> > + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > + * be used. The conditions under which the driver declares the device wedged
> > + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > + * default recovery method for a wedged state is rebind/bus-reset.
> > + *
> > + * Another recovery method is vendor-specific. Below are the cases that send
> > + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > + *
> > + * Case: Firmware Flash
> > + * --------------------
> > + *
> > + * Identification Hint
> > + * +++++++++++++++++++
> > + *
> > + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > + * admin/userspace consumer about the need for a firmware flash.
> > + *
> > + * Recovery Procedure
> > + * ++++++++++++++++++
> > + *
> > + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > + * the below steps
> > + *
> > + * - Check Runtime Survivability mode sysfs.
> > + * If enabled, firmware flash is required to recover the device.
> > + *
> > + * /sys/bus/pci/devices/<device>/survivability_mode
> > + *
> > + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > + * firmware and restore device to normal operation.
> > + */
> > +
> > +/**
> > + * xe_device_set_wedged_method() - Set wedged recovery method
> > + * @xe: xe device instance
> > + * @method: recovery method to set
> > + *
> > + * Set wedged recovery method to be sent in drm wedged uevent.
> > + */
> > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > +{
> > + xe->wedged.method = method;
> > +}
> > +
> > +/**
> > + * xe_device_wedged() - Check for wedged device
> > + * @xe: xe device instance
> > + *
> > + * Returns: %true if device is wedged, %false otherwise.
> > + */
> > +bool xe_device_wedged(struct xe_device *xe)
> > +{
> > + return atomic_read(&xe->wedged.flag);
> > +}
> > +
> > +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > +
> > +static void wedged_work(struct work_struct *work)
> > +{
> > + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> > + struct xe_gt *gt;
> > + u8 id;
> > +
> > + for_each_gt(gt, xe, id)
> > + xe_gt_declare_wedged(gt);
> > +
> > + /*
> > + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > + * hangs, so wedge the device with 'none' recovery method and have
> > + * it available to the user for debugging.
> > + */
> > + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > + /* If no wedge recovery method is set, use default */
> > + else if (!xe->wedged.method)
> > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > + DRM_WEDGE_RECOVERY_BUS_RESET);
> > +
> > + /* Notify userspace of wedged device */
> > + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > +}
> > +
> > +/**
> > + * xe_device_declare_wedged - Declare device wedged
> > + * @xe: xe device instance
> > + *
> > + * This is a final state that can only be cleared with the recovery method
> > + * specified in the drm wedged uevent. The method can be set using
> > + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > + * is set, reprobe (unbind/re-bind) will be sent by default.
> > + *
> > + * In this state every IOCTL will be blocked so the GT cannot be used.
> > + * In general it will be called upon any critical error such as gt reset
> > + * failure or guc loading failure. Userspace will be notified of this state
> > + * through device wedged uevent.
> > + * If xe.wedged module parameter is set to 2, this function will be called
> > + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > + * the issue is preserved for further debugging.
> > + */
> > +void xe_device_declare_wedged(struct xe_device *xe)
> > +{
> > + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > + return;
> > + }
> > +
> > + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > + xe->needs_flr_on_fini = true;
> > + xe_pm_runtime_get_noresume(xe);
> > +
> > + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > + "For recovery procedure, refer to %s\n"
> > + "Please file a _new_ bug report at %s\n",
> > + WEDGED_URL, XE_BUG_URL);
> > +
> > + schedule_work(&xe->wedged.work);
> > + }
> > +}
> > +
> > +/**
> > + * xe_device_validate_wedged_mode - Check if given mode is supported
> > + * @xe: the &xe_device
> > + * @mode: requested mode to validate
> > + *
> > + * Check whether the provided wedged mode is supported.
> > + *
> > + * Return: 0 if mode is supported, error code otherwise.
> > + */
> > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > +{
> > + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > + return -EINVAL;
> > + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > + mode, xe_wedged_mode_to_string(mode),
> > + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > + return -EPERM;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * xe_wedged_mode_to_string - Convert enum value to string.
> > + * @mode: the &xe_wedged_mode to convert
> > + *
> > + * Returns: wedged mode as a user friendly string.
> > + */
> > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > +{
> > + switch (mode) {
> > + case XE_WEDGED_MODE_NEVER:
> > + return "never";
> > + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > + return "upon-critical-error";
> > + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > + return "upon-any-hang-no-reset";
> > + default:
> > + return "<invalid>";
> > + }
> > +}
> > +
> > +void xe_device_wedged_init_early(struct xe_device *xe)
> > +{
> > + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > +}
> > +
> > +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > +{
> > + struct xe_device *xe = arg;
> > +
> > + disable_work_sync(&xe->wedged.work);
> > +
> > + if (atomic_read(&xe->wedged.flag))
> > + xe_pm_runtime_put(xe);
> > +}
> > +
> > +int xe_device_wedged_init(struct xe_device *xe)
> > +{
> > + INIT_WORK(&xe->wedged.work, wedged_work);
> > +
> > + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > +}
> > +
> > diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> > new file mode 100644
> > index 000000000000..fedb30c99398
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _XE_WEDGE_H_
> > +#define _XE_WEDGE_H_
> > +
> > +#include <linux/atomic.h>
> > +#include <linux/types.h>
> > +
> > +#include "xe_wedge_types.h"
> > +
> > +struct xe_device;
> > +
> > +void xe_device_wedged_init_early(struct xe_device *xe);
> > +int xe_device_wedged_init(struct xe_device *xe);
> > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > +void xe_device_declare_wedged(struct xe_device *xe);
> > +bool xe_device_wedged(struct xe_device *xe);
> > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> > +
> > +#endif
> > diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> > new file mode 100644
> > index 000000000000..ffe7f9c64166
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _XE_WEDGE_TYPES_H_
> > +#define _XE_WEDGE_TYPES_H_
> > +
> > +/**
> > + * enum xe_wedged_mode - possible wedged modes
> > + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > + * when critical error occurs like GT reset failure or firmware failure.
> > + * This is the default mode.
> > + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > + * any hang. In this mode, engine resets are disabled to avoid automatic
> > + * recovery attempts. This mode is primarily intended for debugging hangs.
> > + */
> > +enum xe_wedged_mode {
> > + XE_WEDGED_MODE_NEVER = 0,
> > + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > +};
> > +
> > +#endif
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-25 11:42 [PATCH v1] drm/xe: Introduce xe_wedge Raag Jadav
2026-08-26 21:10 ` Rodrigo Vivi
@ 2026-08-27 6:33 ` Laguna, Lukasz
2026-08-28 15:29 ` Rodrigo Vivi
2026-08-27 17:38 ` Michal Wajdeczko
2 siblings, 1 reply; 8+ messages in thread
From: Laguna, Lukasz @ 2026-08-27 6:33 UTC (permalink / raw)
To: Raag Jadav, intel-xe
Cc: riana.tauro, michal.wajdeczko, matthew.d.roper, matthew.brost,
rodrigo.vivi
On 8/25/2026 13:42, Raag Jadav wrote:
> Consolidates all wedging implementation into a dedicated xe_wedge
> component. While at it, add a worker to schedule the wedge handling to
> be done async making xe_device_declare_wedged() safe for atomic callers.
Fixes: drm/xe/mert: Improve handling of MERT CAT errors ?
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> PS: The original intent was a bug fix, but that's just a matter of opinion.
>
> Documentation/gpu/xe/xe_device.rst | 2 +-
> drivers/gpu/drm/xe/Makefile | 1 +
> drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> drivers/gpu/drm/xe/xe_device.h | 11 +-
> drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> 8 files changed, 271 insertions(+), 197 deletions(-)
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
>
> diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> index d3a022362ade..8baed81580c9 100644
> --- a/Documentation/gpu/xe/xe_device.rst
> +++ b/Documentation/gpu/xe/xe_device.rst
> @@ -6,7 +6,7 @@
> Xe Device Wedging
> ==================
>
> -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> :doc: Xe Device Wedging
>
> ====================
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index adc2de37e768..c739a50b6896 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> xe_vsec.o \
> xe_wa.o \
> xe_wait_user_fence.o \
> + xe_wedge.o \
> xe_wopcm.o
>
> xe-$(CONFIG_I2C) += xe_i2c.o \
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 74d566693dfd..d3a7034fac01 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> */
> assert_lmem_ready(xe);
>
> - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> + xe_device_wedged_init_early(xe);
>
> err = xe_device_vram_alloc(xe);
> if (err)
> @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> }
> }
>
> -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> -{
> - struct xe_device *xe = arg;
> -
> - if (atomic_read(&xe->wedged.flag))
> - xe_pm_runtime_put(xe);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> {
> @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
>
> detect_preproduction_hw(xe);
>
> - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> + err = xe_device_wedged_init(xe);
> if (err)
> goto err_unregister_display;
>
> @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> }
>
> -/**
> - * DOC: Xe Device Wedging
> - *
> - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> - * be used. The conditions under which the driver declares the device wedged
> - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> - * default recovery method for a wedged state is rebind/bus-reset.
> - *
> - * Another recovery method is vendor-specific. Below are the cases that send
> - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> - *
> - * Case: Firmware Flash
> - * --------------------
> - *
> - * Identification Hint
> - * +++++++++++++++++++
> - *
> - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> - * admin/userspace consumer about the need for a firmware flash.
> - *
> - * Recovery Procedure
> - * ++++++++++++++++++
> - *
> - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> - * the below steps
> - *
> - * - Check Runtime Survivability mode sysfs.
> - * If enabled, firmware flash is required to recover the device.
> - *
> - * /sys/bus/pci/devices/<device>/survivability_mode
> - *
> - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> - * firmware and restore device to normal operation.
> - */
> -
> -/**
> - * xe_device_set_wedged_method - Set wedged recovery method
> - * @xe: xe device instance
> - * @method: recovery method to set
> - *
> - * Set wedged recovery method to be sent in drm wedged uevent.
> - */
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> -{
> - xe->wedged.method = method;
> -}
> -
> -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> -
> -/**
> - * xe_device_declare_wedged - Declare device wedged
> - * @xe: xe device instance
> - *
> - * This is a final state that can only be cleared with the recovery method
> - * specified in the drm wedged uevent. The method can be set using
> - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> - * is set, reprobe (unbind/re-bind) will be sent by default.
> - *
> - * In this state every IOCTL will be blocked so the GT cannot be used.
> - * In general it will be called upon any critical error such as gt reset
> - * failure or guc loading failure. Userspace will be notified of this state
> - * through device wedged uevent.
> - * If xe.wedged module parameter is set to 2, this function will be called
> - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> - * the issue is preserved for further debugging.
> - */
> -void xe_device_declare_wedged(struct xe_device *xe)
> -{
> - struct xe_gt *gt;
> - u8 id;
> -
> - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> - return;
> - }
> -
> - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> - xe->needs_flr_on_fini = true;
> - xe_pm_runtime_get_noresume(xe);
> -
> - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> - "For recovery procedure, refer to %s\n"
> - "Please file a _new_ bug report at %s\n",
> - WEDGED_URL, XE_BUG_URL);
> - }
> -
> - for_each_gt(gt, xe, id)
> - xe_gt_declare_wedged(gt);
> -
> - if (xe_device_wedged(xe)) {
> - /*
> - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> - * hangs, so wedge the device with 'none' recovery method and have
> - * it available to the user for debugging.
> - */
> - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> - /* If no wedge recovery method is set, use default */
> - else if (!xe->wedged.method)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> - DRM_WEDGE_RECOVERY_BUS_RESET);
> -
> - /* Notify userspace of wedged device */
> - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> - }
> -}
> -
> -/**
> - * xe_device_validate_wedged_mode - Check if given mode is supported
> - * @xe: the &xe_device
> - * @mode: requested mode to validate
> - *
> - * Check whether the provided wedged mode is supported.
> - *
> - * Return: 0 if mode is supported, error code otherwise.
> - */
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> -{
> - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> - return -EINVAL;
> - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> - mode, xe_wedged_mode_to_string(mode),
> - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> - return -EPERM;
> - }
> -
> - return 0;
> -}
> -
> -/**
> - * xe_wedged_mode_to_string - Convert enum value to string.
> - * @mode: the &xe_wedged_mode to convert
> - *
> - * Returns: wedged mode as a user friendly string.
> - */
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> -{
> - switch (mode) {
> - case XE_WEDGED_MODE_NEVER:
> - return "never";
> - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> - return "upon-critical-error";
> - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> - return "upon-any-hang-no-reset";
> - default:
> - return "<invalid>";
> - }
> -}
> -
> /**
> * xe_device_asid_to_vm() - Find VM from ASID
> * @xe: the &xe_device
> diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> index 6c4cfaebc44a..c984972bd0f8 100644
> --- a/drivers/gpu/drm/xe/xe_device.h
> +++ b/drivers/gpu/drm/xe/xe_device.h
> @@ -11,6 +11,7 @@
> #include "xe_device_types.h"
> #include "xe_gt_types.h"
> #include "xe_sriov.h"
> +#include "xe_wedge.h"
>
> struct xe_vm;
>
> @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> void xe_device_td_flush(struct xe_device *xe);
> void xe_device_l2_flush(struct xe_device *xe);
>
> -static inline bool xe_device_wedged(struct xe_device *xe)
> -{
> - return atomic_read(&xe->wedged.flag);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> {
> @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> }
> #endif
>
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> -void xe_device_declare_wedged(struct xe_device *xe);
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> -
> struct xe_file *xe_file_get(struct xe_file *xef);
> void xe_file_put(struct xe_file *xef);
>
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 180d450a6deb..f307d7e5e6b6 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -30,6 +30,7 @@
> #include "xe_sysctrl_types.h"
> #include "xe_tile_types.h"
> #include "xe_validation.h"
> +#include "xe_wedge_types.h"
>
> #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> #define TEST_VM_OPS_ERROR
> @@ -45,22 +46,6 @@ struct xe_pxp;
> struct xe_ttm_stolen_mgr;
> struct xe_vram_region;
>
> -/**
> - * enum xe_wedged_mode - possible wedged modes
> - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> - * when critical error occurs like GT reset failure or firmware failure.
> - * This is the default mode.
> - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> - * any hang. In this mode, engine resets are disabled to avoid automatic
> - * recovery attempts. This mode is primarily intended for debugging hangs.
> - */
> -enum xe_wedged_mode {
> - XE_WEDGED_MODE_NEVER = 0,
> - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> -};
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> /**
> * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> @@ -534,6 +519,8 @@ struct xe_device {
> unsigned long method;
> /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> bool inconsistent_reset;
> + /** @wedged.work: Worker for wedge handling to be done async */
nit: "Worker for wedge handling" seems sufficient
> + struct work_struct work;
> } wedged;
>
> /** @devres_group: devres group */
> diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> new file mode 100644
> index 000000000000..52d4661a2dee
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.c
> @@ -0,0 +1,214 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_managed.h>
> +
> +#include "xe_defaults.h"
> +#include "xe_device_types.h"
> +#include "xe_gt.h"
> +#include "xe_log.h"
> +#include "xe_module.h"
> +#include "xe_pm.h"
> +#include "xe_printk.h"
> +#include "xe_wedge.h"
> +
> +/**
> + * DOC: Xe Device Wedging
> + *
> + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> + * be used. The conditions under which the driver declares the device wedged
> + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> + * default recovery method for a wedged state is rebind/bus-reset.
> + *
> + * Another recovery method is vendor-specific. Below are the cases that send
> + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> + *
> + * Case: Firmware Flash
> + * --------------------
> + *
> + * Identification Hint
> + * +++++++++++++++++++
> + *
> + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> + * admin/userspace consumer about the need for a firmware flash.
> + *
> + * Recovery Procedure
> + * ++++++++++++++++++
> + *
> + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> + * the below steps
> + *
> + * - Check Runtime Survivability mode sysfs.
> + * If enabled, firmware flash is required to recover the device.
> + *
> + * /sys/bus/pci/devices/<device>/survivability_mode
> + *
> + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> + * firmware and restore device to normal operation.
> + */
> +
> +/**
> + * xe_device_set_wedged_method() - Set wedged recovery method
> + * @xe: xe device instance
> + * @method: recovery method to set
> + *
> + * Set wedged recovery method to be sent in drm wedged uevent.
> + */
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> +{
> + xe->wedged.method = method;
> +}
> +
> +/**
> + * xe_device_wedged() - Check for wedged device
> + * @xe: xe device instance
> + *
> + * Returns: %true if device is wedged, %false otherwise.
> + */
> +bool xe_device_wedged(struct xe_device *xe)
> +{
> + return atomic_read(&xe->wedged.flag);
> +}
> +
> +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> +
> +static void wedged_work(struct work_struct *work)
> +{
> + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> + struct xe_gt *gt;
> + u8 id;
> +
> + for_each_gt(gt, xe, id)
> + xe_gt_declare_wedged(gt);
> +
> + /*
> + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> + * hangs, so wedge the device with 'none' recovery method and have
> + * it available to the user for debugging.
> + */
> + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> + /* If no wedge recovery method is set, use default */
> + else if (!xe->wedged.method)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> + DRM_WEDGE_RECOVERY_BUS_RESET);
> +
> + /* Notify userspace of wedged device */
> + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> +}
> +
> +/**
> + * xe_device_declare_wedged - Declare device wedged
xe_device_declare_wedged()
> + * @xe: xe device instance
> + *
> + * This is a final state that can only be cleared with the recovery method
> + * specified in the drm wedged uevent. The method can be set using
> + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> + * is set, reprobe (unbind/re-bind) will be sent by default.
> + *
> + * In this state every IOCTL will be blocked so the GT cannot be used.
> + * In general it will be called upon any critical error such as gt reset
> + * failure or guc loading failure. Userspace will be notified of this state
> + * through device wedged uevent.
> + * If xe.wedged module parameter is set to 2, this function will be called
> + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> + * the issue is preserved for further debugging.
> + */
> +void xe_device_declare_wedged(struct xe_device *xe)
> +{
> + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> + return;
> + }
> +
> + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> + xe->needs_flr_on_fini = true;
> + xe_pm_runtime_get_noresume(xe);
> +
> + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> + "For recovery procedure, refer to %s\n"
> + "Please file a _new_ bug report at %s\n",
> + WEDGED_URL, XE_BUG_URL);
> +
> + schedule_work(&xe->wedged.work);
> + }
> +}
> +
> +/**
> + * xe_device_validate_wedged_mode - Check if given mode is supported
> + * @xe: the &xe_device
> + * @mode: requested mode to validate
> + *
> + * Check whether the provided wedged mode is supported.
> + *
> + * Return: 0 if mode is supported, error code otherwise.
> + */
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> +{
> + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> + return -EINVAL;
> + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> + mode, xe_wedged_mode_to_string(mode),
> + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> + return -EPERM;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * xe_wedged_mode_to_string - Convert enum value to string.
> + * @mode: the &xe_wedged_mode to convert
> + *
> + * Returns: wedged mode as a user friendly string.
> + */
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> +{
> + switch (mode) {
> + case XE_WEDGED_MODE_NEVER:
> + return "never";
> + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> + return "upon-critical-error";
> + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> + return "upon-any-hang-no-reset";
> + default:
> + return "<invalid>";
> + }
> +}
> +
> +void xe_device_wedged_init_early(struct xe_device *xe)
> +{
> + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> +}
> +
> +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> +{
> + struct xe_device *xe = arg;
> +
> + disable_work_sync(&xe->wedged.work);
> +
> + if (atomic_read(&xe->wedged.flag))
> + xe_pm_runtime_put(xe);
> +}
> +
> +int xe_device_wedged_init(struct xe_device *xe)
> +{
> + INIT_WORK(&xe->wedged.work, wedged_work);
> +
> + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> +}
> +
> diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> new file mode 100644
> index 000000000000..fedb30c99398
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_H_
> +#define _XE_WEDGE_H_
> +
> +#include <linux/atomic.h>
not needed
> +#include <linux/types.h>
> +
> +#include "xe_wedge_types.h"
> +
> +struct xe_device;
> +
> +void xe_device_wedged_init_early(struct xe_device *xe);
> +int xe_device_wedged_init(struct xe_device *xe);
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> +void xe_device_declare_wedged(struct xe_device *xe);
> +bool xe_device_wedged(struct xe_device *xe);
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
I agree about naming convention. I was already thinking about something
like this:
xe_wedge_init_early()
xe_wedge_init()
xe_wedge_set_recovery_method()
xe_device_declare_wedged() / xe_device_wedge()
xe_device_wedged() / xe_device_is_wedged()
xe_wedge_validate_mode()
xe_wedge_mode_to_string
Also, wedged_mode_set logic from xe_debugfs.c could be wrapped into
xe_wedge_set_mode() in xe_wedge.c.
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> new file mode 100644
> index 000000000000..ffe7f9c64166
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_TYPES_H_
> +#define _XE_WEDGE_TYPES_H_
> +
> +/**
> + * enum xe_wedged_mode - possible wedged modes
> + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> + * when critical error occurs like GT reset failure or firmware failure.
> + * This is the default mode.
> + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> + * any hang. In this mode, engine resets are disabled to avoid automatic
> + * recovery attempts. This mode is primarily intended for debugging hangs.
> + */
> +enum xe_wedged_mode {
> + XE_WEDGED_MODE_NEVER = 0,
> + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> +};
> +
Let's move the wedge struct here: struct xe_wedge {}.
Lukasz
> +#endif
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-25 11:42 [PATCH v1] drm/xe: Introduce xe_wedge Raag Jadav
2026-08-26 21:10 ` Rodrigo Vivi
2026-08-27 6:33 ` Laguna, Lukasz
@ 2026-08-27 17:38 ` Michal Wajdeczko
2026-08-28 4:21 ` Raag Jadav
2 siblings, 1 reply; 8+ messages in thread
From: Michal Wajdeczko @ 2026-08-27 17:38 UTC (permalink / raw)
To: Raag Jadav, intel-xe
Cc: riana.tauro, lukasz.laguna, matthew.d.roper, matthew.brost,
rodrigo.vivi
On 8/25/2026 1:42 PM, Raag Jadav wrote:
> Consolidates all wedging implementation into a dedicated xe_wedge
> component. While at it, add a worker to schedule the wedge handling to
as Rodrigo said, split into at least two patches
more comments below
> be done async making xe_device_declare_wedged() safe for atomic callers.
>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> ---
> PS: The original intent was a bug fix, but that's just a matter of opinion.
>
> Documentation/gpu/xe/xe_device.rst | 2 +-
> drivers/gpu/drm/xe/Makefile | 1 +
> drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> drivers/gpu/drm/xe/xe_device.h | 11 +-
> drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> 8 files changed, 271 insertions(+), 197 deletions(-)
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
>
> diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> index d3a022362ade..8baed81580c9 100644
> --- a/Documentation/gpu/xe/xe_device.rst
> +++ b/Documentation/gpu/xe/xe_device.rst
> @@ -6,7 +6,7 @@
> Xe Device Wedging
> ==================
>
> -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> :doc: Xe Device Wedging
>
> ====================
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index adc2de37e768..c739a50b6896 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> xe_vsec.o \
> xe_wa.o \
> xe_wait_user_fence.o \
> + xe_wedge.o \
> xe_wopcm.o
>
> xe-$(CONFIG_I2C) += xe_i2c.o \
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 74d566693dfd..d3a7034fac01 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> */
> assert_lmem_ready(xe);
>
> - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> + xe_device_wedged_init_early(xe);
>
> err = xe_device_vram_alloc(xe);
> if (err)
> @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> }
> }
>
> -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> -{
> - struct xe_device *xe = arg;
> -
> - if (atomic_read(&xe->wedged.flag))
> - xe_pm_runtime_put(xe);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> {
> @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
>
> detect_preproduction_hw(xe);
>
> - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> + err = xe_device_wedged_init(xe);
> if (err)
> goto err_unregister_display;
>
> @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> }
>
> -/**
> - * DOC: Xe Device Wedging
> - *
> - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> - * be used. The conditions under which the driver declares the device wedged
> - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> - * default recovery method for a wedged state is rebind/bus-reset.
> - *
> - * Another recovery method is vendor-specific. Below are the cases that send
> - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> - *
> - * Case: Firmware Flash
> - * --------------------
> - *
> - * Identification Hint
> - * +++++++++++++++++++
> - *
> - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> - * admin/userspace consumer about the need for a firmware flash.
> - *
> - * Recovery Procedure
> - * ++++++++++++++++++
> - *
> - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> - * the below steps
> - *
> - * - Check Runtime Survivability mode sysfs.
> - * If enabled, firmware flash is required to recover the device.
> - *
> - * /sys/bus/pci/devices/<device>/survivability_mode
> - *
> - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> - * firmware and restore device to normal operation.
> - */
> -
> -/**
> - * xe_device_set_wedged_method - Set wedged recovery method
> - * @xe: xe device instance
> - * @method: recovery method to set
> - *
> - * Set wedged recovery method to be sent in drm wedged uevent.
> - */
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> -{
> - xe->wedged.method = method;
> -}
> -
> -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> -
> -/**
> - * xe_device_declare_wedged - Declare device wedged
> - * @xe: xe device instance
> - *
> - * This is a final state that can only be cleared with the recovery method
> - * specified in the drm wedged uevent. The method can be set using
> - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> - * is set, reprobe (unbind/re-bind) will be sent by default.
> - *
> - * In this state every IOCTL will be blocked so the GT cannot be used.
> - * In general it will be called upon any critical error such as gt reset
> - * failure or guc loading failure. Userspace will be notified of this state
> - * through device wedged uevent.
> - * If xe.wedged module parameter is set to 2, this function will be called
> - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> - * the issue is preserved for further debugging.
> - */
> -void xe_device_declare_wedged(struct xe_device *xe)
> -{
> - struct xe_gt *gt;
> - u8 id;
> -
> - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> - return;
> - }
> -
> - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> - xe->needs_flr_on_fini = true;
> - xe_pm_runtime_get_noresume(xe);
> -
> - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> - "For recovery procedure, refer to %s\n"
> - "Please file a _new_ bug report at %s\n",
> - WEDGED_URL, XE_BUG_URL);
> - }
> -
> - for_each_gt(gt, xe, id)
> - xe_gt_declare_wedged(gt);
> -
> - if (xe_device_wedged(xe)) {
> - /*
> - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> - * hangs, so wedge the device with 'none' recovery method and have
> - * it available to the user for debugging.
> - */
> - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> - /* If no wedge recovery method is set, use default */
> - else if (!xe->wedged.method)
> - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> - DRM_WEDGE_RECOVERY_BUS_RESET);
> -
> - /* Notify userspace of wedged device */
> - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> - }
> -}
> -
> -/**
> - * xe_device_validate_wedged_mode - Check if given mode is supported
> - * @xe: the &xe_device
> - * @mode: requested mode to validate
> - *
> - * Check whether the provided wedged mode is supported.
> - *
> - * Return: 0 if mode is supported, error code otherwise.
> - */
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> -{
> - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> - return -EINVAL;
> - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> - mode, xe_wedged_mode_to_string(mode),
> - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> - return -EPERM;
> - }
> -
> - return 0;
> -}
> -
> -/**
> - * xe_wedged_mode_to_string - Convert enum value to string.
> - * @mode: the &xe_wedged_mode to convert
> - *
> - * Returns: wedged mode as a user friendly string.
> - */
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> -{
> - switch (mode) {
> - case XE_WEDGED_MODE_NEVER:
> - return "never";
> - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> - return "upon-critical-error";
> - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> - return "upon-any-hang-no-reset";
> - default:
> - return "<invalid>";
> - }
> -}
> -
> /**
> * xe_device_asid_to_vm() - Find VM from ASID
> * @xe: the &xe_device
> diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> index 6c4cfaebc44a..c984972bd0f8 100644
> --- a/drivers/gpu/drm/xe/xe_device.h
> +++ b/drivers/gpu/drm/xe/xe_device.h
> @@ -11,6 +11,7 @@
> #include "xe_device_types.h"
> #include "xe_gt_types.h"
> #include "xe_sriov.h"
> +#include "xe_wedge.h"
why? just add that include in any .c that needs this
>
> struct xe_vm;
>
> @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> void xe_device_td_flush(struct xe_device *xe);
> void xe_device_l2_flush(struct xe_device *xe);
>
> -static inline bool xe_device_wedged(struct xe_device *xe)
> -{
> - return atomic_read(&xe->wedged.flag);
> -}
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> {
> @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> }
> #endif
>
> -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> -void xe_device_declare_wedged(struct xe_device *xe);
> -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> -
> struct xe_file *xe_file_get(struct xe_file *xef);
> void xe_file_put(struct xe_file *xef);
>
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index 180d450a6deb..f307d7e5e6b6 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -30,6 +30,7 @@
> #include "xe_sysctrl_types.h"
> #include "xe_tile_types.h"
> #include "xe_validation.h"
> +#include "xe_wedge_types.h"
>
> #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> #define TEST_VM_OPS_ERROR
> @@ -45,22 +46,6 @@ struct xe_pxp;
> struct xe_ttm_stolen_mgr;
> struct xe_vram_region;
>
> -/**
> - * enum xe_wedged_mode - possible wedged modes
> - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> - * when critical error occurs like GT reset failure or firmware failure.
> - * This is the default mode.
> - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> - * any hang. In this mode, engine resets are disabled to avoid automatic
> - * recovery attempts. This mode is primarily intended for debugging hangs.
> - */
> -enum xe_wedged_mode {
> - XE_WEDGED_MODE_NEVER = 0,
> - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> -};
> -
> #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> /**
> * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> @@ -534,6 +519,8 @@ struct xe_device {
> unsigned long method;
> /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> bool inconsistent_reset;
> + /** @wedged.work: Worker for wedge handling to be done async */
> + struct work_struct work;
> } wedged;
shouldn't this struct be defined in xe_wedge_types.h ?
>
> /** @devres_group: devres group */
> diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> new file mode 100644
> index 000000000000..52d4661a2dee
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.c
> @@ -0,0 +1,214 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_managed.h>
> +
> +#include "xe_defaults.h"
> +#include "xe_device_types.h"
> +#include "xe_gt.h"
> +#include "xe_log.h"
> +#include "xe_module.h"
> +#include "xe_pm.h"
> +#include "xe_printk.h"
> +#include "xe_wedge.h"
> +
> +/**
> + * DOC: Xe Device Wedging
> + *
> + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> + * be used. The conditions under which the driver declares the device wedged
> + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> + * default recovery method for a wedged state is rebind/bus-reset.
> + *
> + * Another recovery method is vendor-specific. Below are the cases that send
> + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> + *
> + * Case: Firmware Flash
> + * --------------------
> + *
> + * Identification Hint
> + * +++++++++++++++++++
> + *
> + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> + * admin/userspace consumer about the need for a firmware flash.
> + *
> + * Recovery Procedure
> + * ++++++++++++++++++
> + *
> + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> + * the below steps
> + *
> + * - Check Runtime Survivability mode sysfs.
> + * If enabled, firmware flash is required to recover the device.
> + *
> + * /sys/bus/pci/devices/<device>/survivability_mode
> + *
> + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> + * firmware and restore device to normal operation.
> + */
> +
> +/**
> + * xe_device_set_wedged_method() - Set wedged recovery method
> + * @xe: xe device instance
> + * @method: recovery method to set
> + *
> + * Set wedged recovery method to be sent in drm wedged uevent.
> + */
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
as we are adding/renaming functions, should we combine two old:
xe_device_declare_wedged(xe)
and xe_device_set_wedged_method(xe, method)
functions into single new:
xe_wedge_declare(xe, method)
as we either already know the recovery method or can use
default one
> +{
> + xe->wedged.method = method;
> +}
> +
> +/**
> + * xe_device_wedged() - Check for wedged device
> + * @xe: xe device instance
> + *
> + * Returns: %true if device is wedged, %false otherwise.
> + */
> +bool xe_device_wedged(struct xe_device *xe)
> +{
> + return atomic_read(&xe->wedged.flag);
> +}
> +
> +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> +
> +static void wedged_work(struct work_struct *work)
> +{
> + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> + struct xe_gt *gt;
> + u8 id;
> +
> + for_each_gt(gt, xe, id)
> + xe_gt_declare_wedged(gt);
is it ok to do that in the async worker?
the idea was to move uvent notification to the worker
> +
> + /*
> + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> + * hangs, so wedge the device with 'none' recovery method and have
> + * it available to the user for debugging.
> + */
> + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> + /* If no wedge recovery method is set, use default */
> + else if (!xe->wedged.method)
> + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> + DRM_WEDGE_RECOVERY_BUS_RESET);
> +
> + /* Notify userspace of wedged device */
> + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> +}
> +
> +/**
> + * xe_device_declare_wedged - Declare device wedged
nit: there should be () after function name
> + * @xe: xe device instance
> + *
> + * This is a final state that can only be cleared with the recovery method
> + * specified in the drm wedged uevent. The method can be set using
> + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> + * is set, reprobe (unbind/re-bind) will be sent by default.
> + *
> + * In this state every IOCTL will be blocked so the GT cannot be used.
> + * In general it will be called upon any critical error such as gt reset
> + * failure or guc loading failure. Userspace will be notified of this state
> + * through device wedged uevent.
> + * If xe.wedged module parameter is set to 2, this function will be called
> + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> + * the issue is preserved for further debugging.
> + */
> +void xe_device_declare_wedged(struct xe_device *xe)
> +{
> + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
you can use:
xe_dbg(xe, ...)
> + return;
> + }
> +
> + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> + xe->needs_flr_on_fini = true;
> + xe_pm_runtime_get_noresume(xe);
> +
> + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
recently there was a discussion about the error code to be used
here, and one suggestion was to allow caller to pass the err parameter
as we are renaming functions, maybe we can add err param?
> + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> + "For recovery procedure, refer to %s\n"
> + "Please file a _new_ bug report at %s\n",
> + WEDGED_URL, XE_BUG_URL);
> +
> + schedule_work(&xe->wedged.work);
> + }
> +}
> +
> +/**
> + * xe_device_validate_wedged_mode - Check if given mode is supported
> + * @xe: the &xe_device
> + * @mode: requested mode to validate
> + *
> + * Check whether the provided wedged mode is supported.
> + *
> + * Return: 0 if mode is supported, error code otherwise.
> + */
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
maybe this can be static - all we need is to move here also
debugfs stuff that adds "wedged_mode" attribute
> +{
> + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> + return -EINVAL;
> + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> + mode, xe_wedged_mode_to_string(mode),
> + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
xe_dbg() ?
> + return -EPERM;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * xe_wedged_mode_to_string - Convert enum value to string.
> + * @mode: the &xe_wedged_mode to convert
> + *
> + * Returns: wedged mode as a user friendly string.
> + */
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> +{
> + switch (mode) {
> + case XE_WEDGED_MODE_NEVER:
> + return "never";
> + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> + return "upon-critical-error";
> + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> + return "upon-any-hang-no-reset";
> + default:
> + return "<invalid>";
> + }
> +}
> +
missing kernel doc
> +void xe_device_wedged_init_early(struct xe_device *xe)
> +{
> + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> +}
> +
> +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> +{
> + struct xe_device *xe = arg;
> +
> + disable_work_sync(&xe->wedged.work);
> +
> + if (atomic_read(&xe->wedged.flag))
> + xe_pm_runtime_put(xe);
> +}
> +
missing kernel-doc
> +int xe_device_wedged_init(struct xe_device *xe)
> +{
> + INIT_WORK(&xe->wedged.work, wedged_work);
this could be don in _early()
> +
> + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> +}
> +
> diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> new file mode 100644
> index 000000000000..fedb30c99398
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_H_
> +#define _XE_WEDGE_H_
> +
> +#include <linux/atomic.h>
> +#include <linux/types.h>
not needed?
> +
> +#include "xe_wedge_types.h"
simple forward decl also works:
enum xe_wedged_mode mode;
> +
> +struct xe_device;
> +
> +void xe_device_wedged_init_early(struct xe_device *xe);
> +int xe_device_wedged_init(struct xe_device *xe);
> +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> +void xe_device_declare_wedged(struct xe_device *xe);
> +bool xe_device_wedged(struct xe_device *xe);
> +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> +
> +#endif
> diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> new file mode 100644
> index 000000000000..ffe7f9c64166
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +#ifndef _XE_WEDGE_TYPES_H_
> +#define _XE_WEDGE_TYPES_H_
> +
> +/**
> + * enum xe_wedged_mode - possible wedged modes
> + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> + * when critical error occurs like GT reset failure or firmware failure.
> + * This is the default mode.
> + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> + * any hang. In this mode, engine resets are disabled to avoid automatic
> + * recovery attempts. This mode is primarily intended for debugging hangs.
> + */
> +enum xe_wedged_mode {
> + XE_WEDGED_MODE_NEVER = 0,
> + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> +};
> +
> +#endif
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-27 17:38 ` Michal Wajdeczko
@ 2026-08-28 4:21 ` Raag Jadav
0 siblings, 0 replies; 8+ messages in thread
From: Raag Jadav @ 2026-08-28 4:21 UTC (permalink / raw)
To: Michal Wajdeczko
Cc: intel-xe, riana.tauro, lukasz.laguna, matthew.d.roper,
matthew.brost, rodrigo.vivi
On Thu, Aug 27, 2026 at 07:38:14PM +0200, Michal Wajdeczko wrote:
> On 8/25/2026 1:42 PM, Raag Jadav wrote:
> > Consolidates all wedging implementation into a dedicated xe_wedge
> > component. While at it, add a worker to schedule the wedge handling to
...
> > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
>
> as we are adding/renaming functions, should we combine two old:
>
> xe_device_declare_wedged(xe)
> and xe_device_set_wedged_method(xe, method)
>
> functions into single new:
>
> xe_wedge_declare(xe, method)
>
> as we either already know the recovery method or can use
> default one
This was already on my backlog after FLR, including other improvements
to xe_gt_declare_wedged().
...
> > +static void wedged_work(struct work_struct *work)
> > +{
> > + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> > + struct xe_gt *gt;
> > + u8 id;
> > +
> > + for_each_gt(gt, xe, id)
> > + xe_gt_declare_wedged(gt);
>
> is it ok to do that in the async worker?
There are mutexes deep inside it. I have a cleanup in mind but it
requires landing FLR series.
...
> > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
>
> maybe this can be static - all we need is to move here also
> debugfs stuff that adds "wedged_mode" attribute
Shouldn't it be the other way around? Keep it consolidated into debugfs?
Raag
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-27 6:33 ` Laguna, Lukasz
@ 2026-08-28 15:29 ` Rodrigo Vivi
0 siblings, 0 replies; 8+ messages in thread
From: Rodrigo Vivi @ 2026-08-28 15:29 UTC (permalink / raw)
To: Laguna, Lukasz
Cc: Raag Jadav, intel-xe, riana.tauro, michal.wajdeczko,
matthew.d.roper, matthew.brost
On Thu, Aug 27, 2026 at 08:33:29AM +0200, Laguna, Lukasz wrote:
>
> On 8/25/2026 13:42, Raag Jadav wrote:
> > Consolidates all wedging implementation into a dedicated xe_wedge
> > component. While at it, add a worker to schedule the wedge handling to
> > be done async making xe_device_declare_wedged() safe for atomic callers.
>
> Fixes: drm/xe/mert: Improve handling of MERT CAT errors ?
if so, please send the stand alone fix that can be backported.
All the refactor later.
>
> > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > ---
> > PS: The original intent was a bug fix, but that's just a matter of opinion.
> >
> > Documentation/gpu/xe/xe_device.rst | 2 +-
> > drivers/gpu/drm/xe/Makefile | 1 +
> > drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> > drivers/gpu/drm/xe/xe_device.h | 11 +-
> > drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> > drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> > drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> > drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> > 8 files changed, 271 insertions(+), 197 deletions(-)
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> > create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
> >
> > diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> > index d3a022362ade..8baed81580c9 100644
> > --- a/Documentation/gpu/xe/xe_device.rst
> > +++ b/Documentation/gpu/xe/xe_device.rst
> > @@ -6,7 +6,7 @@
> > Xe Device Wedging
> > ==================
> > -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> > +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> > :doc: Xe Device Wedging
> > ====================
> > diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> > index adc2de37e768..c739a50b6896 100644
> > --- a/drivers/gpu/drm/xe/Makefile
> > +++ b/drivers/gpu/drm/xe/Makefile
> > @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> > xe_vsec.o \
> > xe_wa.o \
> > xe_wait_user_fence.o \
> > + xe_wedge.o \
> > xe_wopcm.o
> > xe-$(CONFIG_I2C) += xe_i2c.o \
> > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > index 74d566693dfd..d3a7034fac01 100644
> > --- a/drivers/gpu/drm/xe/xe_device.c
> > +++ b/drivers/gpu/drm/xe/xe_device.c
> > @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> > */
> > assert_lmem_ready(xe);
> > - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > + xe_device_wedged_init_early(xe);
> > err = xe_device_vram_alloc(xe);
> > if (err)
> > @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> > }
> > }
> > -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > -{
> > - struct xe_device *xe = arg;
> > -
> > - if (atomic_read(&xe->wedged.flag))
> > - xe_pm_runtime_put(xe);
> > -}
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> > {
> > @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
> > detect_preproduction_hw(xe);
> > - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > + err = xe_device_wedged_init(xe);
> > if (err)
> > goto err_unregister_display;
> > @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> > return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> > }
> > -/**
> > - * DOC: Xe Device Wedging
> > - *
> > - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > - * be used. The conditions under which the driver declares the device wedged
> > - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > - * default recovery method for a wedged state is rebind/bus-reset.
> > - *
> > - * Another recovery method is vendor-specific. Below are the cases that send
> > - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > - *
> > - * Case: Firmware Flash
> > - * --------------------
> > - *
> > - * Identification Hint
> > - * +++++++++++++++++++
> > - *
> > - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > - * admin/userspace consumer about the need for a firmware flash.
> > - *
> > - * Recovery Procedure
> > - * ++++++++++++++++++
> > - *
> > - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > - * the below steps
> > - *
> > - * - Check Runtime Survivability mode sysfs.
> > - * If enabled, firmware flash is required to recover the device.
> > - *
> > - * /sys/bus/pci/devices/<device>/survivability_mode
> > - *
> > - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > - * firmware and restore device to normal operation.
> > - */
> > -
> > -/**
> > - * xe_device_set_wedged_method - Set wedged recovery method
> > - * @xe: xe device instance
> > - * @method: recovery method to set
> > - *
> > - * Set wedged recovery method to be sent in drm wedged uevent.
> > - */
> > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > -{
> > - xe->wedged.method = method;
> > -}
> > -
> > -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > -
> > -/**
> > - * xe_device_declare_wedged - Declare device wedged
> > - * @xe: xe device instance
> > - *
> > - * This is a final state that can only be cleared with the recovery method
> > - * specified in the drm wedged uevent. The method can be set using
> > - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > - * is set, reprobe (unbind/re-bind) will be sent by default.
> > - *
> > - * In this state every IOCTL will be blocked so the GT cannot be used.
> > - * In general it will be called upon any critical error such as gt reset
> > - * failure or guc loading failure. Userspace will be notified of this state
> > - * through device wedged uevent.
> > - * If xe.wedged module parameter is set to 2, this function will be called
> > - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > - * the issue is preserved for further debugging.
> > - */
> > -void xe_device_declare_wedged(struct xe_device *xe)
> > -{
> > - struct xe_gt *gt;
> > - u8 id;
> > -
> > - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > - return;
> > - }
> > -
> > - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > - xe->needs_flr_on_fini = true;
> > - xe_pm_runtime_get_noresume(xe);
> > -
> > - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > - "For recovery procedure, refer to %s\n"
> > - "Please file a _new_ bug report at %s\n",
> > - WEDGED_URL, XE_BUG_URL);
> > - }
> > -
> > - for_each_gt(gt, xe, id)
> > - xe_gt_declare_wedged(gt);
> > -
> > - if (xe_device_wedged(xe)) {
> > - /*
> > - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > - * hangs, so wedge the device with 'none' recovery method and have
> > - * it available to the user for debugging.
> > - */
> > - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > - /* If no wedge recovery method is set, use default */
> > - else if (!xe->wedged.method)
> > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > - DRM_WEDGE_RECOVERY_BUS_RESET);
> > -
> > - /* Notify userspace of wedged device */
> > - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > - }
> > -}
> > -
> > -/**
> > - * xe_device_validate_wedged_mode - Check if given mode is supported
> > - * @xe: the &xe_device
> > - * @mode: requested mode to validate
> > - *
> > - * Check whether the provided wedged mode is supported.
> > - *
> > - * Return: 0 if mode is supported, error code otherwise.
> > - */
> > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > -{
> > - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > - return -EINVAL;
> > - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > - mode, xe_wedged_mode_to_string(mode),
> > - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > - return -EPERM;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -/**
> > - * xe_wedged_mode_to_string - Convert enum value to string.
> > - * @mode: the &xe_wedged_mode to convert
> > - *
> > - * Returns: wedged mode as a user friendly string.
> > - */
> > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > -{
> > - switch (mode) {
> > - case XE_WEDGED_MODE_NEVER:
> > - return "never";
> > - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > - return "upon-critical-error";
> > - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > - return "upon-any-hang-no-reset";
> > - default:
> > - return "<invalid>";
> > - }
> > -}
> > -
> > /**
> > * xe_device_asid_to_vm() - Find VM from ASID
> > * @xe: the &xe_device
> > diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> > index 6c4cfaebc44a..c984972bd0f8 100644
> > --- a/drivers/gpu/drm/xe/xe_device.h
> > +++ b/drivers/gpu/drm/xe/xe_device.h
> > @@ -11,6 +11,7 @@
> > #include "xe_device_types.h"
> > #include "xe_gt_types.h"
> > #include "xe_sriov.h"
> > +#include "xe_wedge.h"
> > struct xe_vm;
> > @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> > void xe_device_td_flush(struct xe_device *xe);
> > void xe_device_l2_flush(struct xe_device *xe);
> > -static inline bool xe_device_wedged(struct xe_device *xe)
> > -{
> > - return atomic_read(&xe->wedged.flag);
> > -}
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> > {
> > @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> > }
> > #endif
> > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > -void xe_device_declare_wedged(struct xe_device *xe);
> > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> > -
> > struct xe_file *xe_file_get(struct xe_file *xef);
> > void xe_file_put(struct xe_file *xef);
> > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > index 180d450a6deb..f307d7e5e6b6 100644
> > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > @@ -30,6 +30,7 @@
> > #include "xe_sysctrl_types.h"
> > #include "xe_tile_types.h"
> > #include "xe_validation.h"
> > +#include "xe_wedge_types.h"
> > #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> > #define TEST_VM_OPS_ERROR
> > @@ -45,22 +46,6 @@ struct xe_pxp;
> > struct xe_ttm_stolen_mgr;
> > struct xe_vram_region;
> > -/**
> > - * enum xe_wedged_mode - possible wedged modes
> > - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > - * when critical error occurs like GT reset failure or firmware failure.
> > - * This is the default mode.
> > - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > - * any hang. In this mode, engine resets are disabled to avoid automatic
> > - * recovery attempts. This mode is primarily intended for debugging hangs.
> > - */
> > -enum xe_wedged_mode {
> > - XE_WEDGED_MODE_NEVER = 0,
> > - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > -};
> > -
> > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > /**
> > * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> > @@ -534,6 +519,8 @@ struct xe_device {
> > unsigned long method;
> > /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> > bool inconsistent_reset;
> > + /** @wedged.work: Worker for wedge handling to be done async */
>
> nit: "Worker for wedge handling" seems sufficient
>
> > + struct work_struct work;
> > } wedged;
> > /** @devres_group: devres group */
> > diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> > new file mode 100644
> > index 000000000000..52d4661a2dee
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge.c
> > @@ -0,0 +1,214 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#include <drm/drm_drv.h>
> > +#include <drm/drm_managed.h>
> > +
> > +#include "xe_defaults.h"
> > +#include "xe_device_types.h"
> > +#include "xe_gt.h"
> > +#include "xe_log.h"
> > +#include "xe_module.h"
> > +#include "xe_pm.h"
> > +#include "xe_printk.h"
> > +#include "xe_wedge.h"
> > +
> > +/**
> > + * DOC: Xe Device Wedging
> > + *
> > + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > + * be used. The conditions under which the driver declares the device wedged
> > + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > + * default recovery method for a wedged state is rebind/bus-reset.
> > + *
> > + * Another recovery method is vendor-specific. Below are the cases that send
> > + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > + *
> > + * Case: Firmware Flash
> > + * --------------------
> > + *
> > + * Identification Hint
> > + * +++++++++++++++++++
> > + *
> > + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > + * admin/userspace consumer about the need for a firmware flash.
> > + *
> > + * Recovery Procedure
> > + * ++++++++++++++++++
> > + *
> > + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > + * the below steps
> > + *
> > + * - Check Runtime Survivability mode sysfs.
> > + * If enabled, firmware flash is required to recover the device.
> > + *
> > + * /sys/bus/pci/devices/<device>/survivability_mode
> > + *
> > + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > + * firmware and restore device to normal operation.
> > + */
> > +
> > +/**
> > + * xe_device_set_wedged_method() - Set wedged recovery method
> > + * @xe: xe device instance
> > + * @method: recovery method to set
> > + *
> > + * Set wedged recovery method to be sent in drm wedged uevent.
> > + */
> > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > +{
> > + xe->wedged.method = method;
> > +}
> > +
> > +/**
> > + * xe_device_wedged() - Check for wedged device
> > + * @xe: xe device instance
> > + *
> > + * Returns: %true if device is wedged, %false otherwise.
> > + */
> > +bool xe_device_wedged(struct xe_device *xe)
> > +{
> > + return atomic_read(&xe->wedged.flag);
> > +}
> > +
> > +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > +
> > +static void wedged_work(struct work_struct *work)
> > +{
> > + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> > + struct xe_gt *gt;
> > + u8 id;
> > +
> > + for_each_gt(gt, xe, id)
> > + xe_gt_declare_wedged(gt);
> > +
> > + /*
> > + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > + * hangs, so wedge the device with 'none' recovery method and have
> > + * it available to the user for debugging.
> > + */
> > + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > + /* If no wedge recovery method is set, use default */
> > + else if (!xe->wedged.method)
> > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > + DRM_WEDGE_RECOVERY_BUS_RESET);
> > +
> > + /* Notify userspace of wedged device */
> > + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > +}
> > +
> > +/**
> > + * xe_device_declare_wedged - Declare device wedged
>
> xe_device_declare_wedged()
>
> > + * @xe: xe device instance
> > + *
> > + * This is a final state that can only be cleared with the recovery method
> > + * specified in the drm wedged uevent. The method can be set using
> > + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > + * is set, reprobe (unbind/re-bind) will be sent by default.
> > + *
> > + * In this state every IOCTL will be blocked so the GT cannot be used.
> > + * In general it will be called upon any critical error such as gt reset
> > + * failure or guc loading failure. Userspace will be notified of this state
> > + * through device wedged uevent.
> > + * If xe.wedged module parameter is set to 2, this function will be called
> > + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > + * the issue is preserved for further debugging.
> > + */
> > +void xe_device_declare_wedged(struct xe_device *xe)
> > +{
> > + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > + return;
> > + }
> > +
> > + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > + xe->needs_flr_on_fini = true;
> > + xe_pm_runtime_get_noresume(xe);
> > +
> > + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > + "For recovery procedure, refer to %s\n"
> > + "Please file a _new_ bug report at %s\n",
> > + WEDGED_URL, XE_BUG_URL);
> > +
> > + schedule_work(&xe->wedged.work);
> > + }
> > +}
> > +
> > +/**
> > + * xe_device_validate_wedged_mode - Check if given mode is supported
> > + * @xe: the &xe_device
> > + * @mode: requested mode to validate
> > + *
> > + * Check whether the provided wedged mode is supported.
> > + *
> > + * Return: 0 if mode is supported, error code otherwise.
> > + */
> > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > +{
> > + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > + return -EINVAL;
> > + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > + mode, xe_wedged_mode_to_string(mode),
> > + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > + return -EPERM;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * xe_wedged_mode_to_string - Convert enum value to string.
> > + * @mode: the &xe_wedged_mode to convert
> > + *
> > + * Returns: wedged mode as a user friendly string.
> > + */
> > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > +{
> > + switch (mode) {
> > + case XE_WEDGED_MODE_NEVER:
> > + return "never";
> > + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > + return "upon-critical-error";
> > + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > + return "upon-any-hang-no-reset";
> > + default:
> > + return "<invalid>";
> > + }
> > +}
> > +
> > +void xe_device_wedged_init_early(struct xe_device *xe)
> > +{
> > + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > +}
> > +
> > +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > +{
> > + struct xe_device *xe = arg;
> > +
> > + disable_work_sync(&xe->wedged.work);
> > +
> > + if (atomic_read(&xe->wedged.flag))
> > + xe_pm_runtime_put(xe);
> > +}
> > +
> > +int xe_device_wedged_init(struct xe_device *xe)
> > +{
> > + INIT_WORK(&xe->wedged.work, wedged_work);
> > +
> > + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > +}
> > +
> > diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> > new file mode 100644
> > index 000000000000..fedb30c99398
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _XE_WEDGE_H_
> > +#define _XE_WEDGE_H_
> > +
> > +#include <linux/atomic.h>
>
> not needed
>
> > +#include <linux/types.h>
> > +
> > +#include "xe_wedge_types.h"
> > +
> > +struct xe_device;
> > +
> > +void xe_device_wedged_init_early(struct xe_device *xe);
> > +int xe_device_wedged_init(struct xe_device *xe);
> > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > +void xe_device_declare_wedged(struct xe_device *xe);
> > +bool xe_device_wedged(struct xe_device *xe);
> > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
>
> I agree about naming convention. I was already thinking about something like
> this:
> xe_wedge_init_early()
> xe_wedge_init()
> xe_wedge_set_recovery_method()
> xe_device_declare_wedged() / xe_device_wedge()
> xe_device_wedged() / xe_device_is_wedged()
> xe_wedge_validate_mode()
> xe_wedge_mode_to_string
>
>
> Also, wedged_mode_set logic from xe_debugfs.c could be wrapped into
> xe_wedge_set_mode() in xe_wedge.c.
>
> > +
> > +#endif
> > diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> > new file mode 100644
> > index 000000000000..ffe7f9c64166
> > --- /dev/null
> > +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: MIT */
> > +/*
> > + * Copyright © 2026 Intel Corporation
> > + */
> > +
> > +#ifndef _XE_WEDGE_TYPES_H_
> > +#define _XE_WEDGE_TYPES_H_
> > +
> > +/**
> > + * enum xe_wedged_mode - possible wedged modes
> > + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > + * when critical error occurs like GT reset failure or firmware failure.
> > + * This is the default mode.
> > + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > + * any hang. In this mode, engine resets are disabled to avoid automatic
> > + * recovery attempts. This mode is primarily intended for debugging hangs.
> > + */
> > +enum xe_wedged_mode {
> > + XE_WEDGED_MODE_NEVER = 0,
> > + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > +};
> > +
>
> Let's move the wedge struct here: struct xe_wedge {}.
>
> Lukasz
>
>
> > +#endif
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1] drm/xe: Introduce xe_wedge
2026-08-27 6:20 ` Raag Jadav
@ 2026-08-28 15:30 ` Rodrigo Vivi
0 siblings, 0 replies; 8+ messages in thread
From: Rodrigo Vivi @ 2026-08-28 15:30 UTC (permalink / raw)
To: Raag Jadav
Cc: intel-xe, riana.tauro, michal.wajdeczko, lukasz.laguna,
matthew.d.roper, matthew.brost
On Thu, Aug 27, 2026 at 08:20:10AM +0200, Raag Jadav wrote:
> On Wed, Aug 26, 2026 at 05:10:44PM -0400, Rodrigo Vivi wrote:
> > On Tue, Aug 25, 2026 at 05:12:43PM +0530, Raag Jadav wrote:
> > > Consolidates all wedging implementation into a dedicated xe_wedge
> > > component. While at it, add a worker to schedule the wedge handling to
> > > be done async making xe_device_declare_wedged() safe for atomic callers.
> > >
> > > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > > ---
> > > PS: The original intent was a bug fix, but that's just a matter of opinion.
> >
> > I had thought about this spin-off a very long time ago too...
> >
> > But please, split into 2 patches, one with the consolidation and one with
> > the worker. This one is painful to review as is right now.
>
> This was meant more as an RFC and needs a bit of discussion, sorry I
> didn't update the subject prefix.
ack on overall movement...
>
> xe_pm_runtime_get_noresume() has checks against 'current' task and I'm
> wondering if it's reliable in atomic context?
it should be... it is only not reliable in thread/work-queue contexts...
>
> > Also, please use 'xe_wedge_' as the new prefix for any non static functions.
>
> Sure.
>
> Raag
>
> > > Documentation/gpu/xe/xe_device.rst | 2 +-
> > > drivers/gpu/drm/xe/Makefile | 1 +
> > > drivers/gpu/drm/xe/xe_device.c | 172 +--------------------
> > > drivers/gpu/drm/xe/xe_device.h | 11 +-
> > > drivers/gpu/drm/xe/xe_device_types.h | 19 +--
> > > drivers/gpu/drm/xe/xe_wedge.c | 214 +++++++++++++++++++++++++++
> > > drivers/gpu/drm/xe/xe_wedge.h | 24 +++
> > > drivers/gpu/drm/xe/xe_wedge_types.h | 25 ++++
> > > 8 files changed, 271 insertions(+), 197 deletions(-)
> > > create mode 100644 drivers/gpu/drm/xe/xe_wedge.c
> > > create mode 100644 drivers/gpu/drm/xe/xe_wedge.h
> > > create mode 100644 drivers/gpu/drm/xe/xe_wedge_types.h
> > >
> > > diff --git a/Documentation/gpu/xe/xe_device.rst b/Documentation/gpu/xe/xe_device.rst
> > > index d3a022362ade..8baed81580c9 100644
> > > --- a/Documentation/gpu/xe/xe_device.rst
> > > +++ b/Documentation/gpu/xe/xe_device.rst
> > > @@ -6,7 +6,7 @@
> > > Xe Device Wedging
> > > ==================
> > >
> > > -.. kernel-doc:: drivers/gpu/drm/xe/xe_device.c
> > > +.. kernel-doc:: drivers/gpu/drm/xe/xe_wedge.c
> > > :doc: Xe Device Wedging
> > >
> > > ====================
> > > diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> > > index adc2de37e768..c739a50b6896 100644
> > > --- a/drivers/gpu/drm/xe/Makefile
> > > +++ b/drivers/gpu/drm/xe/Makefile
> > > @@ -152,6 +152,7 @@ xe-y += xe_bb.o \
> > > xe_vsec.o \
> > > xe_wa.o \
> > > xe_wait_user_fence.o \
> > > + xe_wedge.o \
> > > xe_wopcm.o
> > >
> > > xe-$(CONFIG_I2C) += xe_i2c.o \
> > > diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> > > index 74d566693dfd..d3a7034fac01 100644
> > > --- a/drivers/gpu/drm/xe/xe_device.c
> > > +++ b/drivers/gpu/drm/xe/xe_device.c
> > > @@ -829,10 +829,7 @@ int xe_device_probe_early(struct xe_device *xe)
> > > */
> > > assert_lmem_ready(xe);
> > >
> > > - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > > - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > > - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > > - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > > + xe_device_wedged_init_early(xe);
> > >
> > > err = xe_device_vram_alloc(xe);
> > > if (err)
> > > @@ -924,14 +921,6 @@ static void detect_preproduction_hw(struct xe_device *xe)
> > > }
> > > }
> > >
> > > -static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > > -{
> > > - struct xe_device *xe = arg;
> > > -
> > > - if (atomic_read(&xe->wedged.flag))
> > > - xe_pm_runtime_put(xe);
> > > -}
> > > -
> > > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > > static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe)
> > > {
> > > @@ -1148,7 +1137,7 @@ int xe_device_probe(struct xe_device *xe)
> > >
> > > detect_preproduction_hw(xe);
> > >
> > > - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > > + err = xe_device_wedged_init(xe);
> > > if (err)
> > > goto err_unregister_display;
> > >
> > > @@ -1394,163 +1383,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
> > > return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
> > > }
> > >
> > > -/**
> > > - * DOC: Xe Device Wedging
> > > - *
> > > - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > > - * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > > - * be used. The conditions under which the driver declares the device wedged
> > > - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > > - * default recovery method for a wedged state is rebind/bus-reset.
> > > - *
> > > - * Another recovery method is vendor-specific. Below are the cases that send
> > > - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > > - *
> > > - * Case: Firmware Flash
> > > - * --------------------
> > > - *
> > > - * Identification Hint
> > > - * +++++++++++++++++++
> > > - *
> > > - * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > > - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > > - * admin/userspace consumer about the need for a firmware flash.
> > > - *
> > > - * Recovery Procedure
> > > - * ++++++++++++++++++
> > > - *
> > > - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > > - * the below steps
> > > - *
> > > - * - Check Runtime Survivability mode sysfs.
> > > - * If enabled, firmware flash is required to recover the device.
> > > - *
> > > - * /sys/bus/pci/devices/<device>/survivability_mode
> > > - *
> > > - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > > - * firmware and restore device to normal operation.
> > > - */
> > > -
> > > -/**
> > > - * xe_device_set_wedged_method - Set wedged recovery method
> > > - * @xe: xe device instance
> > > - * @method: recovery method to set
> > > - *
> > > - * Set wedged recovery method to be sent in drm wedged uevent.
> > > - */
> > > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > > -{
> > > - xe->wedged.method = method;
> > > -}
> > > -
> > > -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > > -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > > -
> > > -/**
> > > - * xe_device_declare_wedged - Declare device wedged
> > > - * @xe: xe device instance
> > > - *
> > > - * This is a final state that can only be cleared with the recovery method
> > > - * specified in the drm wedged uevent. The method can be set using
> > > - * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > > - * is set, reprobe (unbind/re-bind) will be sent by default.
> > > - *
> > > - * In this state every IOCTL will be blocked so the GT cannot be used.
> > > - * In general it will be called upon any critical error such as gt reset
> > > - * failure or guc loading failure. Userspace will be notified of this state
> > > - * through device wedged uevent.
> > > - * If xe.wedged module parameter is set to 2, this function will be called
> > > - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > > - * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > > - * the issue is preserved for further debugging.
> > > - */
> > > -void xe_device_declare_wedged(struct xe_device *xe)
> > > -{
> > > - struct xe_gt *gt;
> > > - u8 id;
> > > -
> > > - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > > - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > > - return;
> > > - }
> > > -
> > > - if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > > - xe->needs_flr_on_fini = true;
> > > - xe_pm_runtime_get_noresume(xe);
> > > -
> > > - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > > - xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > > - "For recovery procedure, refer to %s\n"
> > > - "Please file a _new_ bug report at %s\n",
> > > - WEDGED_URL, XE_BUG_URL);
> > > - }
> > > -
> > > - for_each_gt(gt, xe, id)
> > > - xe_gt_declare_wedged(gt);
> > > -
> > > - if (xe_device_wedged(xe)) {
> > > - /*
> > > - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > > - * hangs, so wedge the device with 'none' recovery method and have
> > > - * it available to the user for debugging.
> > > - */
> > > - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > > - /* If no wedge recovery method is set, use default */
> > > - else if (!xe->wedged.method)
> > > - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > > - DRM_WEDGE_RECOVERY_BUS_RESET);
> > > -
> > > - /* Notify userspace of wedged device */
> > > - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > > - }
> > > -}
> > > -
> > > -/**
> > > - * xe_device_validate_wedged_mode - Check if given mode is supported
> > > - * @xe: the &xe_device
> > > - * @mode: requested mode to validate
> > > - *
> > > - * Check whether the provided wedged mode is supported.
> > > - *
> > > - * Return: 0 if mode is supported, error code otherwise.
> > > - */
> > > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > > -{
> > > - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > > - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > > - return -EINVAL;
> > > - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > > - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > > - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > > - mode, xe_wedged_mode_to_string(mode),
> > > - xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > > - return -EPERM;
> > > - }
> > > -
> > > - return 0;
> > > -}
> > > -
> > > -/**
> > > - * xe_wedged_mode_to_string - Convert enum value to string.
> > > - * @mode: the &xe_wedged_mode to convert
> > > - *
> > > - * Returns: wedged mode as a user friendly string.
> > > - */
> > > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > > -{
> > > - switch (mode) {
> > > - case XE_WEDGED_MODE_NEVER:
> > > - return "never";
> > > - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > > - return "upon-critical-error";
> > > - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > > - return "upon-any-hang-no-reset";
> > > - default:
> > > - return "<invalid>";
> > > - }
> > > -}
> > > -
> > > /**
> > > * xe_device_asid_to_vm() - Find VM from ASID
> > > * @xe: the &xe_device
> > > diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
> > > index 6c4cfaebc44a..c984972bd0f8 100644
> > > --- a/drivers/gpu/drm/xe/xe_device.h
> > > +++ b/drivers/gpu/drm/xe/xe_device.h
> > > @@ -11,6 +11,7 @@
> > > #include "xe_device_types.h"
> > > #include "xe_gt_types.h"
> > > #include "xe_sriov.h"
> > > +#include "xe_wedge.h"
> > >
> > > struct xe_vm;
> > >
> > > @@ -207,11 +208,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe);
> > > void xe_device_td_flush(struct xe_device *xe);
> > > void xe_device_l2_flush(struct xe_device *xe);
> > >
> > > -static inline bool xe_device_wedged(struct xe_device *xe)
> > > -{
> > > - return atomic_read(&xe->wedged.flag);
> > > -}
> > > -
> > > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > > static inline bool xe_debug_page_size_supported(struct xe_device *xe)
> > > {
> > > @@ -260,11 +256,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe)
> > > }
> > > #endif
> > >
> > > -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > > -void xe_device_declare_wedged(struct xe_device *xe);
> > > -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > > -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> > > -
> > > struct xe_file *xe_file_get(struct xe_file *xef);
> > > void xe_file_put(struct xe_file *xef);
> > >
> > > diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> > > index 180d450a6deb..f307d7e5e6b6 100644
> > > --- a/drivers/gpu/drm/xe/xe_device_types.h
> > > +++ b/drivers/gpu/drm/xe/xe_device_types.h
> > > @@ -30,6 +30,7 @@
> > > #include "xe_sysctrl_types.h"
> > > #include "xe_tile_types.h"
> > > #include "xe_validation.h"
> > > +#include "xe_wedge_types.h"
> > >
> > > #if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
> > > #define TEST_VM_OPS_ERROR
> > > @@ -45,22 +46,6 @@ struct xe_pxp;
> > > struct xe_ttm_stolen_mgr;
> > > struct xe_vram_region;
> > >
> > > -/**
> > > - * enum xe_wedged_mode - possible wedged modes
> > > - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > > - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > > - * when critical error occurs like GT reset failure or firmware failure.
> > > - * This is the default mode.
> > > - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > > - * any hang. In this mode, engine resets are disabled to avoid automatic
> > > - * recovery attempts. This mode is primarily intended for debugging hangs.
> > > - */
> > > -enum xe_wedged_mode {
> > > - XE_WEDGED_MODE_NEVER = 0,
> > > - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > > - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > > -};
> > > -
> > > #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE
> > > /**
> > > * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes
> > > @@ -534,6 +519,8 @@ struct xe_device {
> > > unsigned long method;
> > > /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
> > > bool inconsistent_reset;
> > > + /** @wedged.work: Worker for wedge handling to be done async */
> > > + struct work_struct work;
> > > } wedged;
> > >
> > > /** @devres_group: devres group */
> > > diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c
> > > new file mode 100644
> > > index 000000000000..52d4661a2dee
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/xe_wedge.c
> > > @@ -0,0 +1,214 @@
> > > +// SPDX-License-Identifier: MIT
> > > +/*
> > > + * Copyright © 2026 Intel Corporation
> > > + */
> > > +
> > > +#include <drm/drm_drv.h>
> > > +#include <drm/drm_managed.h>
> > > +
> > > +#include "xe_defaults.h"
> > > +#include "xe_device_types.h"
> > > +#include "xe_gt.h"
> > > +#include "xe_log.h"
> > > +#include "xe_module.h"
> > > +#include "xe_pm.h"
> > > +#include "xe_printk.h"
> > > +#include "xe_wedge.h"
> > > +
> > > +/**
> > > + * DOC: Xe Device Wedging
> > > + *
> > > + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
> > > + * When device is in wedged state, every IOCTL will be blocked and GT cannot
> > > + * be used. The conditions under which the driver declares the device wedged
> > > + * depend on the wedged mode configuration (see &enum xe_wedged_mode). The
> > > + * default recovery method for a wedged state is rebind/bus-reset.
> > > + *
> > > + * Another recovery method is vendor-specific. Below are the cases that send
> > > + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
> > > + *
> > > + * Case: Firmware Flash
> > > + * --------------------
> > > + *
> > > + * Identification Hint
> > > + * +++++++++++++++++++
> > > + *
> > > + * ``WEDGED=vendor-specific`` drm device wedged uevent with
> > > + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify
> > > + * admin/userspace consumer about the need for a firmware flash.
> > > + *
> > > + * Recovery Procedure
> > > + * ++++++++++++++++++
> > > + *
> > > + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow
> > > + * the below steps
> > > + *
> > > + * - Check Runtime Survivability mode sysfs.
> > > + * If enabled, firmware flash is required to recover the device.
> > > + *
> > > + * /sys/bus/pci/devices/<device>/survivability_mode
> > > + *
> > > + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash
> > > + * firmware and restore device to normal operation.
> > > + */
> > > +
> > > +/**
> > > + * xe_device_set_wedged_method() - Set wedged recovery method
> > > + * @xe: xe device instance
> > > + * @method: recovery method to set
> > > + *
> > > + * Set wedged recovery method to be sent in drm wedged uevent.
> > > + */
> > > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method)
> > > +{
> > > + xe->wedged.method = method;
> > > +}
> > > +
> > > +/**
> > > + * xe_device_wedged() - Check for wedged device
> > > + * @xe: xe device instance
> > > + *
> > > + * Returns: %true if device is wedged, %false otherwise.
> > > + */
> > > +bool xe_device_wedged(struct xe_device *xe)
> > > +{
> > > + return atomic_read(&xe->wedged.flag);
> > > +}
> > > +
> > > +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging"
> > > +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new"
> > > +
> > > +static void wedged_work(struct work_struct *work)
> > > +{
> > > + struct xe_device *xe = container_of(work, struct xe_device, wedged.work);
> > > + struct xe_gt *gt;
> > > + u8 id;
> > > +
> > > + for_each_gt(gt, xe, id)
> > > + xe_gt_declare_wedged(gt);
> > > +
> > > + /*
> > > + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging
> > > + * hangs, so wedge the device with 'none' recovery method and have
> > > + * it available to the user for debugging.
> > > + */
> > > + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
> > > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE);
> > > + /* If no wedge recovery method is set, use default */
> > > + else if (!xe->wedged.method)
> > > + xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND |
> > > + DRM_WEDGE_RECOVERY_BUS_RESET);
> > > +
> > > + /* Notify userspace of wedged device */
> > > + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
> > > +}
> > > +
> > > +/**
> > > + * xe_device_declare_wedged - Declare device wedged
> > > + * @xe: xe device instance
> > > + *
> > > + * This is a final state that can only be cleared with the recovery method
> > > + * specified in the drm wedged uevent. The method can be set using
> > > + * xe_device_set_wedged_method before declaring the device as wedged. If no method
> > > + * is set, reprobe (unbind/re-bind) will be sent by default.
> > > + *
> > > + * In this state every IOCTL will be blocked so the GT cannot be used.
> > > + * In general it will be called upon any critical error such as gt reset
> > > + * failure or guc loading failure. Userspace will be notified of this state
> > > + * through device wedged uevent.
> > > + * If xe.wedged module parameter is set to 2, this function will be called
> > > + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump
> > > + * snapshot capture. In this mode, GT reset won't be attempted so the state of
> > > + * the issue is preserved for further debugging.
> > > + */
> > > +void xe_device_declare_wedged(struct xe_device *xe)
> > > +{
> > > + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
> > > + drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
> > > + return;
> > > + }
> > > +
> > > + if (!atomic_xchg(&xe->wedged.flag, 1)) {
> > > + xe->needs_flr_on_fini = true;
> > > + xe_pm_runtime_get_noresume(xe);
> > > +
> > > + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n");
> > > + xe_err_once(xe, "IOCTLs and executions are now blocked!\n"
> > > + "For recovery procedure, refer to %s\n"
> > > + "Please file a _new_ bug report at %s\n",
> > > + WEDGED_URL, XE_BUG_URL);
> > > +
> > > + schedule_work(&xe->wedged.work);
> > > + }
> > > +}
> > > +
> > > +/**
> > > + * xe_device_validate_wedged_mode - Check if given mode is supported
> > > + * @xe: the &xe_device
> > > + * @mode: requested mode to validate
> > > + *
> > > + * Check whether the provided wedged mode is supported.
> > > + *
> > > + * Return: 0 if mode is supported, error code otherwise.
> > > + */
> > > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
> > > +{
> > > + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
> > > + drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
> > > + return -EINVAL;
> > > + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
> > > + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
> > > + drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
> > > + mode, xe_wedged_mode_to_string(mode),
> > > + xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
> > > + return -EPERM;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +/**
> > > + * xe_wedged_mode_to_string - Convert enum value to string.
> > > + * @mode: the &xe_wedged_mode to convert
> > > + *
> > > + * Returns: wedged mode as a user friendly string.
> > > + */
> > > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
> > > +{
> > > + switch (mode) {
> > > + case XE_WEDGED_MODE_NEVER:
> > > + return "never";
> > > + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
> > > + return "upon-critical-error";
> > > + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
> > > + return "upon-any-hang-no-reset";
> > > + default:
> > > + return "<invalid>";
> > > + }
> > > +}
> > > +
> > > +void xe_device_wedged_init_early(struct xe_device *xe)
> > > +{
> > > + xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
> > > + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode;
> > > + drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
> > > + xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
> > > +}
> > > +
> > > +static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
> > > +{
> > > + struct xe_device *xe = arg;
> > > +
> > > + disable_work_sync(&xe->wedged.work);
> > > +
> > > + if (atomic_read(&xe->wedged.flag))
> > > + xe_pm_runtime_put(xe);
> > > +}
> > > +
> > > +int xe_device_wedged_init(struct xe_device *xe)
> > > +{
> > > + INIT_WORK(&xe->wedged.work, wedged_work);
> > > +
> > > + return drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
> > > +}
> > > +
> > > diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h
> > > new file mode 100644
> > > index 000000000000..fedb30c99398
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/xe_wedge.h
> > > @@ -0,0 +1,24 @@
> > > +/* SPDX-License-Identifier: MIT */
> > > +/*
> > > + * Copyright © 2026 Intel Corporation
> > > + */
> > > +
> > > +#ifndef _XE_WEDGE_H_
> > > +#define _XE_WEDGE_H_
> > > +
> > > +#include <linux/atomic.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include "xe_wedge_types.h"
> > > +
> > > +struct xe_device;
> > > +
> > > +void xe_device_wedged_init_early(struct xe_device *xe);
> > > +int xe_device_wedged_init(struct xe_device *xe);
> > > +void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
> > > +void xe_device_declare_wedged(struct xe_device *xe);
> > > +bool xe_device_wedged(struct xe_device *xe);
> > > +int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
> > > +const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h
> > > new file mode 100644
> > > index 000000000000..ffe7f9c64166
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/xe/xe_wedge_types.h
> > > @@ -0,0 +1,25 @@
> > > +/* SPDX-License-Identifier: MIT */
> > > +/*
> > > + * Copyright © 2026 Intel Corporation
> > > + */
> > > +
> > > +#ifndef _XE_WEDGE_TYPES_H_
> > > +#define _XE_WEDGE_TYPES_H_
> > > +
> > > +/**
> > > + * enum xe_wedged_mode - possible wedged modes
> > > + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
> > > + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
> > > + * when critical error occurs like GT reset failure or firmware failure.
> > > + * This is the default mode.
> > > + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
> > > + * any hang. In this mode, engine resets are disabled to avoid automatic
> > > + * recovery attempts. This mode is primarily intended for debugging hangs.
> > > + */
> > > +enum xe_wedged_mode {
> > > + XE_WEDGED_MODE_NEVER = 0,
> > > + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
> > > + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
> > > +};
> > > +
> > > +#endif
> > > --
> > > 2.43.0
> > >
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-28 15:30 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25 11:42 [PATCH v1] drm/xe: Introduce xe_wedge Raag Jadav
2026-08-26 21:10 ` Rodrigo Vivi
2026-08-27 6:20 ` Raag Jadav
2026-08-28 15:30 ` Rodrigo Vivi
2026-08-27 6:33 ` Laguna, Lukasz
2026-08-28 15:29 ` Rodrigo Vivi
2026-08-27 17:38 ` Michal Wajdeczko
2026-08-28 4:21 ` Raag Jadav
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox