An individual BO can leave the VM idle list while drm_exec backs off on contention during userq restore. The retry prelocks that BO and retains it in exec->objects, but the restarted VM-list walk can skip its drm_exec_prepare_obj() call.
amdgpu_evf_mgr_rearm() still attaches an eviction fence to every locked object. With CONFIG_DEBUG_MUTEXES, the preceding unlock resets max_fences to num_fences. If ttm_bo_validate() returns without moving the BO and no existing fence can be replaced, dma_resv_add_fence() hits its capacity BUG. Signed-off-by: Prike Liang <[email protected]> --- .../drm/amd/amdgpu/amdgpu_eviction_fence.c | 7 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 26 ++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c index f0cc49213c01..8b2e25770bdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c @@ -159,11 +159,10 @@ int amdgpu_evf_mgr_rearm(struct amdgpu_eviction_fence_mgr *evf_mgr, dma_fence_put(evf_mgr->ev_fence); evf_mgr->ev_fence = &ev_fence->base; - /* And add it to all existing BOs */ + /* The caller has validated and reserved space on every locked BO. */ drm_exec_for_each_locked_object(exec, index, obj) { - struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); - - amdgpu_evf_mgr_attach_fence(evf_mgr, bo); + dma_resv_add_fence(obj->resv, &ev_fence->base, + DMA_RESV_USAGE_BOOKKEEP); } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index e6ce9d12bdb4..0f509e67ca1a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1105,6 +1105,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; @@ -1184,7 +1185,21 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) invalidated = false; } - ret = amdgpu_vm_handle_moved(adev, vm, NULL); + /* + * A contended BO can change VM lists while drm_exec drops the locks. + * Prepare every finally locked object before updating PTEs or publishing + * the replacement eviction fence, including prelocked retry objects. + */ + drm_exec_for_each_locked_object(&exec, tmp_key, obj) { + ret = dma_resv_reserve_fences(obj->resv, TTM_NUM_MOVE_FENCES + 1); + if (ret) + goto unlock_all; + ret = amdgpu_userq_validate_vm(NULL, gem_to_amdgpu_bo(obj)); + if (ret) + goto unlock_all; + } + + ret = amdgpu_vm_handle_moved(adev, vm, &exec.ticket); if (ret) goto unlock_all; @@ -1255,6 +1270,8 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) */ list_for_each_entry(bo_va, &vm->always_valid.idle, base.vm_status) dma_fence_wait(bo_va->last_pt_update, false); + list_for_each_entry(bo_va, &vm->individual.idle, base.vm_status) + dma_fence_wait(bo_va->last_pt_update, false); /* * The PRT bo_va is kept off the state lists, so its PTE update fence * lands in prt_va->last_pt_update rather than vm->last_update; wait on @@ -1281,6 +1298,13 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(bo); } + /* Page-table updates may have consumed the earlier reservation slots. */ + drm_exec_for_each_locked_object(&exec, tmp_key, obj) { + ret = dma_resv_reserve_fences(obj->resv, 1); + if (ret) + goto unlock_all; + } + /* Back off without publishing a fence if recovery owns the hardware. */ if (!down_read_trylock(&adev->reset_domain->sem)) { ret = -EAGAIN; -- 2.34.1
