When userq eviction fails, the eviction fence suspend worker flushes
reset_work while holding userq_mutex and from inside a DMA-fence
signalling critical section.
The reset worker runs GPU recovery, which calls amdgpu_userq_suspend()
and tries to acquire the same userq_mutex. The suspend worker therefore
waits for reset_work while reset_work waits for the suspend worker to
release the mutex.
Propagate the eviction error to the suspend worker, set the error on the
eviction fence and do not schedule queue restore. Signal the failed
fence, release userq_mutex, and then run reset recovery synchronously.
This preserves teardown ordering without holding userq_mutex across the
reset.
Fixes: c8ed2de0f2ee ("drm/amdgpu: rework userq reset work handling")
Signed-off-by: Prike Liang <[email protected]>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c | 13 +++++++++++--
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 7 ++-----
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 +-
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
index a0802012de49..2ea8553c82f0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
@@ -65,6 +65,7 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
struct dma_fence *ev_fence;
bool cookie;
+ int r;
mutex_lock(&uq_mgr->userq_mutex);
@@ -79,7 +80,9 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
cookie = dma_fence_begin_signalling();
ev_fence = amdgpu_evf_mgr_get_fence(evf_mgr);
- amdgpu_userq_evict(uq_mgr);
+ r = amdgpu_userq_evict(uq_mgr);
+ if (r)
+ dma_fence_set_error(ev_fence, r);
/*
* Signaling the eviction fence must be done while holding the
@@ -90,10 +93,16 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct
*work)
dma_fence_end_signalling(cookie);
dma_fence_put(ev_fence);
- if (!evf_mgr->shutdown)
+ if (!r && !evf_mgr->shutdown)
schedule_delayed_work(&uq_mgr->resume_work, 0);
mutex_unlock(&uq_mgr->userq_mutex);
+
+ if (r) {
+ amdgpu_reset_domain_schedule(uq_mgr->adev->reset_domain,
+ &uq_mgr->reset_work);
+ flush_work(&uq_mgr->reset_work);
+ }
}
int amdgpu_evf_mgr_attach_fence(struct amdgpu_eviction_fence_mgr *evf_mgr,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index a7b68fd2360e..2534e4a1a530 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -1265,9 +1265,6 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
if (ret) {
drm_file_err(uq_mgr->file,
"Couldn't unmap all the queues, eviction failed
ret=%d\n", ret);
- amdgpu_reset_domain_schedule(uq_mgr->adev->reset_domain,
- &uq_mgr->reset_work);
- flush_work(&uq_mgr->reset_work);
}
return ret;
}
@@ -1288,10 +1285,10 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr
*uq_mgr)
}
}
-void
+int
amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr)
{
- amdgpu_userq_evict_all(uq_mgr);
+ return amdgpu_userq_evict_all(uq_mgr);
}
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file
*file_priv,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index 488dc21d7c81..4dcf6151de6a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -163,7 +163,7 @@ void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr
*userq_mgr);
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr);
-void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
+int amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,
struct amdgpu_eviction_fence_mgr *evf_mgr);
--
2.34.1