Eviction recovery must not run while the suspend worker holds userq_mutex
or is in a DMA-fence signalling critical section. Queue the reset after
dropping both, and retry a requested eviction after successful recovery.
Meanwhile, retry and force signal the pending signal eviction fence to
avoid the dead userq attached the reservation fences forever.
Fixes: c8ed2de0f2ee ("drm/amdgpu: rework userq reset work handling")
Signed-off-by: Prike Liang <[email protected]>
---
.../drm/amd/amdgpu/amdgpu_eviction_fence.c | 14 +++++++++---
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 22 ++++++++++++-------
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 2 +-
3 files changed, 26 insertions(+), 12 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..15897c3eacb7 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,21 +80,28 @@ 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);
/*
* Signaling the eviction fence must be done while holding the
* userq_mutex. Otherwise we won't resume the queues before issuing the
* next fence.
*/
- dma_fence_signal(ev_fence);
+ if (!r)
+ dma_fence_signal(ev_fence);
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) {
+ /* Failed removal does not establish that DMA has stopped. */
+ amdgpu_reset_domain_schedule(uq_mgr->adev->reset_domain,
+ &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 75d5ceaa53c6..fa8ffa060fa5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -91,6 +91,8 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct
*work)
reset_work);
struct amdgpu_device *adev = uq_mgr->adev;
struct amdgpu_reset_context reset_context;
+ struct amdgpu_fpriv *fpriv = uq_mgr->file->driver_priv;
+ struct dma_fence *ev_fence;
if (unlikely(adev->debug_disable_gpu_ring_reset)) {
dev_err(adev->dev, "userq reset disabled by debug mask\n");
@@ -112,7 +114,15 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct
*work)
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
- amdgpu_device_gpu_recover(adev, NULL, &reset_context);
+ if (amdgpu_device_gpu_recover(adev, NULL, &reset_context))
+ return;
+
+ /* Retry a pending eviction only after successful recovery. */
+ ev_fence = amdgpu_evf_mgr_get_fence(&fpriv->evf_mgr);
+ if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &ev_fence->flags) &&
+ !dma_fence_is_signaled(ev_fence))
+ schedule_work(&fpriv->evf_mgr.suspend_work);
+ dma_fence_put(ev_fence);
}
static void amdgpu_userq_hang_detect_work(struct work_struct *work)
@@ -368,8 +378,7 @@ static int amdgpu_userq_unmap_helper(struct
amdgpu_usermode_queue *queue)
r = userq_funcs->unmap(queue);
if (r) {
- trace_amdgpu_userq_state_changed(queue,
AMDGPU_USERQ_STATE_HUNG);
- queue->state = AMDGPU_USERQ_STATE_HUNG;
+ /* Keep removal retryable until hardware quiescence is
known. */
return r;
} else {
trace_amdgpu_userq_state_changed(queue,
AMDGPU_USERQ_STATE_UNMAPPED);
@@ -1287,9 +1296,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;
}
@@ -1310,10 +1316,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