summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorOlivier Kaloudoff <olivier.kaloudoff@gmail.com>2026-10-13 20:53:11 +0200
committerAlex Deucher <alexander.deucher@amd.com>2026-10-27 17:02:38 -0400
commit1233dd17f99c75787a31035656ecfeff80522421 (patch)
treed77fe80cacb558a088820d310757607deec0cab4 /drivers/gpu
parent90d91a192751cd9a7d9d2286299bc72ec1c28179 (diff)
drm/amdkfd: tear down KFD processes before early fini_sw on disconnect
On surprise removal, amdgpu_device_fini_hw() calls amdgpu_amdkfd_device_fini_sw() when pci_dev_is_disconnected() is true. fini_sw frees kfd.dev, but KFD processes may still be alive and hold references to it: kfd_process_destroy() dereferences kfd.dev via kfd_processes_remove(), and svm_range_list_fini() / kfd_process_free_outstanding_kfd_bos() touch per-device SVM state. The kfd_processes_count wait only happens later in kgd2kfd_teardown_processes(), called from the top-half remove path well after fini_sw. In the observed failure the killed KFD process (SIGBUS on unplug) stuck in D state on its exit path, so kfd_processes_count never drained and the PCIe removal thread wedged permanently in cond_resched(), producing soft-lockup and hung-task splats. Tear KFD processes down before freeing kfd.dev on the disconnect path, and guard kgd2kfd_teardown_processes() against kfd.dev already being gone when it runs a second time. Cc: Xiaogang Chen <xiaogang.chen@amd.com> Signed-off-by: Olivier Kaloudoff <olivier.kaloudoff@gmail.com> Signed-off-by: Felix Kuehling <felix.kuehling@amd.com> Reviewed-by: Felix Kuehling <felix.kuehling@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit 836f44ba87ed7b1d83e2b7bfc788f8c6437b03a7) Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c9
2 files changed, 12 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index f147c0c459da..c65bc575a57a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4331,8 +4331,11 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
* before ip_fini_early to prevent kfd locking refcount issues by calling
* amdgpu_amdkfd_suspend()
*/
- if (pci_dev_is_disconnected(adev->pdev))
+ if (pci_dev_is_disconnected(adev->pdev)) {
+ /* Drain KFD processes while kfd.dev is still valid */
+ amdgpu_amdkfd_teardown_processes(adev);
amdgpu_amdkfd_device_fini_sw(adev);
+ }
amdgpu_coredump_fini(adev);
amdgpu_device_ip_fini_early(adev);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index bb4c6695f3cf..0f96c9e3fa4d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -1814,7 +1814,14 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev)
mutex_unlock(&kfd_processes_mutex);
- /* wait all kfd processes use adev terminate */
+ /* kfd.dev may already be freed on surprise removal */
+ if (!adev->kfd.dev)
+ return;
+
+ /*
+ * Wait for all KFD processes using adev to terminate. Must be
+ * unbounded: device state is freed once they are gone.
+ */
while (!!atomic_read(&adev->kfd.dev->kfd_processes_count))
cond_resched();
}