From: Vitaly Prosyak <[email protected]>

During amd_deadlock userq reset testing, the restore worker reached
amdgpu_evf_mgr_rearm() with a locked reservation object whose fence list had
been rebuilt after validation. When all previous fences had completed, the
rebuilt list contained no active fences and dma_resv_reset_max_fences() left
num_fences and max_fences at zero. dma_resv_add_fence() then triggered:

  BUG_ON(fobj->num_fences >= fobj->max_fences)

while adding the replacement BOOKKEEP eviction fence.

The v1 proposal attempted to call dma_resv_reserve_fences() from inside
amdgpu_evf_mgr_rearm(), immediately before dma_resv_add_fence(). This is not
valid. dma_resv_reserve_fences() may allocate memory and replace the
reservation-fence list. If the replacement eviction fence has already been
created by rearm, that allocation can invalidate the newly created fence
state again. This is the ordering problem identified by Christian during
review.

v2 reserves the slot in the restore caller, before rearm creates the
replacement fence. After validation and GART work have completed, the caller
still owns every reservation through the DRM execution context. It refreshes
one slot for every locked object, allowing all possible reservation-list
allocations to finish before amdgpu_evf_mgr_rearm() creates and attaches the
new BOOKKEEP fence.

The reservation remains caller-side. The eviction-fence helper does not
reserve memory and only consumes capacity prepared by its caller. The initial
caller-side preparation is still required for WPTR BOs and VM BOs, because it
covers validation and migration fences; the final refresh is required because
later validation can rebuild a reservation list and discard unused capacity.

This v2 supersedes the v1 helper-side approach and the intermediate
caller-side allocation commits that did not refresh capacity after
validation.

Fixes: 91a358fe99d86 (drm/amdgpu: dont pin wptr bo instead use eviction fence)

Reported-by: IGT amd_deadlock test
Cc: Christian König <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Prike Liang <[email protected]>
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Vitaly Prosyak <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 75d5ceaa53c6..a1b6ce8b348e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -1034,6 +1034,7 @@ amdgpu_userq_vm_validate_and_restore_queue(struct 
amdgpu_userq_mgr *uq_mgr)
        struct amdgpu_bo_va *bo_va;
        struct amdgpu_usermode_queue *queue;
        struct amdgpu_bo *bo;
+       struct drm_gem_object *obj;
        struct drm_exec exec;
        struct xarray xa;
        int ret;
@@ -1210,6 +1211,13 @@ amdgpu_userq_vm_validate_and_restore_queue(struct 
amdgpu_userq_mgr *uq_mgr)
                queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(bo);
        }
 
+       /* Re-reserve the rearm slot after validation may have rebuilt the 
lists. */
+       drm_exec_for_each_locked_object(&exec, tmp_key, obj) {
+               ret = dma_resv_reserve_fences(obj->resv, 1);
+               if (ret)
+                       goto unlock_all;
+       }
+
        ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
        if (ret) {
                drm_file_err(uq_mgr->file, "Failed to replace eviction 
fence\n");
-- 
2.43.0

Reply via email to