drm/xe: Skip device access during PCI error recovery

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>
This commit is contained in:
Riana Tauro
2026-06-29 13:58:05 +05:30
parent 0a0fae3327
commit e46ee82f12
5 changed files with 36 additions and 8 deletions

View 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);

View 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. */

View 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 @@ static void gt_reset_worker(struct work_struct *w)
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)

View 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 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
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),

View 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);