On 2026-10-10 12:27, William Palacek wrote:
A GPU reset issued while processes are using the device can Oops the
host in munmap() (free_swap_cache) after SDMA write faults from a user
queue whose process has already exited.

amdgpu_device_gpu_recover() takes reset_domain->sem for write before
amdgpu_amdkfd_pre_reset(), so the down_read_trylock() in
unmap_queues_cpsch() and execute_queues_cpsch() fails with -EIO and no
unmap is sent. stop_cpsch() still clears sched_running, so user queues
keep running while their memory is freed.

Make amdgpu_amdkfd_pre_reset() take the reset device list and call it
once from gpu_recover() before the reset domain is locked. PCI error
handling keeps calling it under the lock, as before. Return -EIO from
unmap_queues_cpsch() when the HWS is already known to be hung, instead
of waiting out the preemption timeout again.

Signed-off-by: William Palacek <[email protected]>

Reviewed-by: Felix Kuehling <[email protected]>


---
v3:
- Make amdgpu_amdkfd_pre_reset() take the device list instead of adding a
   similarly named wrapper (Felix)
- Drop kfd_dqm_can_reach_hw(); pci_channel_state is only valid after
   amdgpu_pci_error_detected() (Felix)
- Return -EIO from unmap_queues_cpsch() when the HWS is hung (Felix)
- PCI error handling keeps calling pre_reset under the reset lock

v2:
- Drop the SRC_USER gate and the helper; run for every reset source
- Cover amdgpu_pci_error_detected() as well as gpu_recover()

  drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c          | 13 ++++++-------
  drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h          |  4 ++--
  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c          |  6 ++++--
  .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c   |  2 ++
  4 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index e023cc734ebc..fcd857fb7d09 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -314,15 +314,14 @@ int amdgpu_amdkfd_resume_process(struct amdgpu_device 
*adev)
        return r;
  }
-int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev,
-                           struct amdgpu_reset_context *reset_context)
+void amdgpu_amdkfd_pre_reset(struct list_head *device_list,
+                            struct amdgpu_reset_context *reset_context)
  {
-       int r = 0;
-
-       if (adev->kfd.dev)
-               r = kgd2kfd_pre_reset(adev->kfd.dev, reset_context);
+       struct amdgpu_device *adev;
- return r;
+       list_for_each_entry(adev, device_list, reset_list)
+               if (adev->kfd.dev)
+                       kgd2kfd_pre_reset(adev->kfd.dev, reset_context);
  }
int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index e3da382ceb3c..7419d3614c47 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -180,8 +180,8 @@ bool amdgpu_amdkfd_have_atomics_support(struct 
amdgpu_device *adev);
bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); -int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev,
-                           struct amdgpu_reset_context *reset_context);
+void amdgpu_amdkfd_pre_reset(struct list_head *device_list,
+                            struct amdgpu_reset_context *reset_context);
int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index e0014611f039..7e928d09db34 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -5534,8 +5534,6 @@ static void amdgpu_device_halt_activities(struct 
amdgpu_device *adev,
cancel_delayed_work_sync(&tmp_adev->delayed_init_work); - amdgpu_amdkfd_pre_reset(tmp_adev, reset_context);
-
                /*
                 * Mark these ASICs to be reset as untracked first
                 * And add them back after reset completed
@@ -5784,6 +5782,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
        /* Cannot be called after locking reset domain */
        amdgpu_ras_pre_reset(adev, &device_list);
+ /* Dequeueing takes reset_domain->sem for read */
+       amdgpu_amdkfd_pre_reset(&device_list, reset_context);
+
        /* We need to lock reset domain only once both for XGMI and single 
device */
        amdgpu_device_recovery_get_reset_lock(adev, &device_list);
@@ -6233,6 +6234,7 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta amdgpu_device_recovery_prepare(adev, &device_list, hive);
                amdgpu_device_recovery_get_reset_lock(adev, &device_list);
+               amdgpu_amdkfd_pre_reset(&device_list, &reset_context);
                amdgpu_device_halt_activities(adev, NULL, &reset_context, 
&device_list,
                                              hive, false);
                if (hive)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 5e57576fba21..c2b069832dbe 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -2832,6 +2832,8 @@ static int unmap_queues_cpsch(struct device_queue_manager 
*dqm,
if (!dqm->sched_running)
                return 0;
+       if (dqm->is_hws_hang)
+               return -EIO;
        if (!dqm->active_runlist)
                return 0;
        if (!down_read_trylock(&dqm->dev->adev->reset_domain->sem))

Reply via email to