mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-23 11:55:58 -04:00
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:
@@ -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);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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(>->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, >->reset.worker))
|
||||
xe_pm_runtime_put(gt_to_xe(gt));
|
||||
xe_pm_runtime_put(xe);
|
||||
}
|
||||
|
||||
void xe_gt_suspend_prepare(struct xe_gt *gt)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user