]> git.hungrycats.org Git - linux/commitdiff
drm/xe: Skip device access during PCI error recovery
authorRiana Tauro <riana.tauro@intel.com>
Mon, 29 Jun 2026 08:28:05 +0000 (13:58 +0530)
committerRiana Tauro <riana.tauro@intel.com>
Thu, 2 Jul 2026 08:09:38 +0000 (13:39 +0530)
When a fatal error occurs and the error_detected callback is
invoked the device is inaccessible. The error_detected callback
wedges the device causing the jobs to timeout.

The timedout handler acquires forcewake to dump devcoredump and
triggers a GT reset. Since the device is inaccessible this causes
errors. Skip all mmio accesses and gt reset when the device
is in reset.

Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Reviewed-by: Mallesh Koujalagi <mallesh.koujalagi@intel.com>
Link: https://patch.msgid.link/20260629082802.3690896-9-riana.tauro@intel.com
Signed-off-by: Riana Tauro <riana.tauro@intel.com>
drivers/gpu/drm/xe/xe_device.h
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_gt.c
drivers/gpu/drm/xe/xe_guc_submit.c
drivers/gpu/drm/xe/xe_pci_error.c

index 8056d8bd7d6d837c47b42b13cc555fa246771156..a03760d0ce38620c8eefa777b1b27a862375ace6 100644 (file)
@@ -181,6 +181,21 @@ static inline bool xe_device_has_mert(const struct xe_device *xe)
        return xe->info.has_mert;
 }
 
+static inline bool xe_device_is_in_reset(struct xe_device *xe)
+{
+       return atomic_read(&xe->in_reset);
+}
+
+static inline void xe_device_set_in_reset(struct xe_device *xe)
+{
+       atomic_set(&xe->in_reset, 1);
+}
+
+static inline void xe_device_clear_in_reset(struct xe_device *xe)
+{
+       atomic_set(&xe->in_reset, 0);
+}
+
 u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size);
 
 void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p);
index 9d42edba374b44da38edf7966a61c43d80c4d193..022e08205897d939592dc552739ffc142eafd562 100644 (file)
@@ -483,6 +483,9 @@ struct xe_device {
        /** @needs_flr_on_fini: requests function-reset on fini */
        bool needs_flr_on_fini;
 
+       /** @in_reset: Indicates if device is in reset */
+       atomic_t in_reset;
+
        /** @wedged: Struct to control Wedged States and mode */
        struct {
                /** @wedged.flag: Xe device faced a critical error and is now blocked. */
index 783eb6d631b5cd1d77b9f45b7d677aa18770536b..d904527a88983f99bd74f6dc16f5944e43da95e8 100644 (file)
@@ -917,6 +917,9 @@ static void gt_reset_worker(struct work_struct *w)
        if (xe_device_wedged(gt_to_xe(gt)))
                goto err_pm_put;
 
+       if (xe_device_is_in_reset(gt_to_xe(gt)))
+               goto err_pm_put;
+
        /* We only support GT resets with GuC submission */
        if (!xe_device_uc_enabled(gt_to_xe(gt)))
                goto err_pm_put;
@@ -977,18 +980,21 @@ err_pm_put:
 
 void xe_gt_reset_async(struct xe_gt *gt)
 {
-       xe_gt_info(gt, "trying reset from %ps\n", __builtin_return_address(0));
+       struct xe_device *xe = gt_to_xe(gt);
+
+       if (xe_device_is_in_reset(xe))
+               return;
 
        /* Don't do a reset while one is already in flight */
        if (!xe_fault_inject_gt_reset() && xe_uc_reset_prepare(&gt->uc))
                return;
 
-       xe_gt_info(gt, "reset queued\n");
+       xe_gt_info(gt, "reset queued from %ps\n", __builtin_return_address(0));
 
        /* Pair with put in gt_reset_worker() if work is enqueued */
-       xe_pm_runtime_get_noresume(gt_to_xe(gt));
+       xe_pm_runtime_get_noresume(xe);
        if (!queue_work(gt->ordered_wq, &gt->reset.worker))
-               xe_pm_runtime_put(gt_to_xe(gt));
+               xe_pm_runtime_put(xe);
 }
 
 void xe_gt_suspend_prepare(struct xe_gt *gt)
index 9458bf477fa6e96b9ccd5d90876d22bed63207ca..12416bfa32557c1042003b5e3318f451e5797bda 100644 (file)
@@ -1532,7 +1532,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
         * If devcoredump not captured and GuC capture for the job is not ready
         * do manual capture first and decide later if we need to use it
         */
-       if (!exec_queue_killed(q) && !xe->devcoredump.captured &&
+       if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q) && !xe->devcoredump.captured &&
            !xe_guc_capture_get_matching_and_lock(q)) {
                /* take force wake before engine register manual capture */
                CLASS(xe_force_wake, fw_ref)(gt_to_fw(q->gt), XE_FORCEWAKE_ALL);
@@ -1554,8 +1554,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
        set_exec_queue_banned(q);
 
        /* Kick job / queue off hardware */
-       if (!wedged && (exec_queue_enabled(primary) ||
-                       exec_queue_pending_disable(primary))) {
+       if (!xe_device_is_in_reset(xe) && !wedged &&
+           (exec_queue_enabled(primary) || exec_queue_pending_disable(primary))) {
                int ret;
 
                if (exec_queue_reset(primary))
@@ -1623,7 +1623,8 @@ trigger_reset:
 
        trace_xe_sched_job_timedout(job);
 
-       if (!exec_queue_killed(q))
+       /* Do not access device if in reset */
+       if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q))
                xe_devcoredump(q, job,
                               "Timedout job - seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx",
                               xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
index 2f7316266333a6f9f3817e5a0f7d3aca11e081d3..9b78cc0d3293a12dde60a8b9515056b12da59a2d 100644 (file)
@@ -26,6 +26,8 @@ static void prepare_device_for_reset(struct pci_dev *pdev)
        if (!atomic_xchg(&xe->wedged.flag, 1))
                xe_pm_runtime_get_noresume(xe);
 
+       xe_device_set_in_reset(xe);
+
        for_each_gt(gt, xe, id)
                xe_gt_declare_wedged(gt);
 
@@ -88,6 +90,7 @@ static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev)
         * TODO: optimize by re-initializing only the hardware state and re-creating
         * kernel BOs.
         */
+       xe_device_clear_in_reset(xe);
        pdev->driver->remove(pdev);
        devres_release_group(&pdev->dev, xe->devres_group);