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

Reply via email to