v3 - lock both VM and WPTR BO (Christian)
v2 - get a reference (amdgpu_bo_ref(wptr_obj->obj)) before
     amdgpu_bo_unreserve() to avoid use-after-free issue

remove amdgpu_userq_map_gtt_bo_to_gart() and move its calls
into amdgpu_userq_create_wptr_mapping() to eliminate duplicated
calls.

Signed-off-by: David (Ming Qiang) Wu <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 89 ++++++++---------------
 1 file changed, 32 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index ebb0d8a9967f..59e593b3bae7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -1573,34 +1573,6 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, 
bool vram_lost)
        return r;
 }
 
-static int
-amdgpu_userq_map_gtt_bo_to_gart(struct amdgpu_device *adev, struct amdgpu_bo 
*bo)
-{
-       int ret;
-
-       ret = amdgpu_bo_reserve(bo, true);
-       if (ret) {
-               dev_err(adev->dev, "Failed to reserve bo. ret %d\n", ret);
-               goto err_reserve_bo_failed;
-       }
-
-       ret = amdgpu_ttm_alloc_gart(&bo->tbo);
-       if (ret) {
-               dev_err(adev->dev, "Failed to bind bo to GART. ret %d\n", ret);
-               goto err_map_bo_gart_failed;
-       }
-
-       amdgpu_bo_unreserve(bo);
-       bo = amdgpu_bo_ref(bo);
-
-       return 0;
-
-err_map_bo_gart_failed:
-       amdgpu_bo_unreserve(bo);
-err_reserve_bo_failed:
-       return ret;
-}
-
 int amdgpu_userq_create_wptr_mapping(struct amdgpu_userq_mgr *uq_mgr,
                              struct amdgpu_usermode_queue *queue,
                              uint64_t wptr)
@@ -1609,53 +1581,56 @@ int amdgpu_userq_create_wptr_mapping(struct 
amdgpu_userq_mgr *uq_mgr,
        struct amdgpu_bo_va_mapping *wptr_mapping;
        struct amdgpu_vm *wptr_vm;
        struct amdgpu_userq_obj *wptr_obj = &queue->wptr_obj;
+       struct drm_exec exec;
        int ret;
 
+       wptr &= AMDGPU_GMC_HOLE_MASK;
        wptr_vm = queue->vm;
-       ret = amdgpu_bo_reserve(wptr_vm->root.bo, false);
-       if (ret)
-               return ret;
+       drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
+       drm_exec_until_all_locked(&exec) {
+               ret = amdgpu_vm_lock_pd(wptr_vm, &exec, 0);
+               drm_exec_retry_on_contention(&exec);
+               if (unlikely(ret))
+                       goto out_unlock;
 
-       wptr &= AMDGPU_GMC_HOLE_MASK;
-       wptr_mapping = amdgpu_vm_bo_lookup_mapping(wptr_vm, wptr >> PAGE_SHIFT);
-       amdgpu_bo_unreserve(wptr_vm->root.bo);
-       if (!wptr_mapping) {
-               dev_err(adev->dev, "Failed to lookup wptr bo\n");
-               return -EINVAL;
+               wptr_mapping = amdgpu_vm_bo_lookup_mapping(wptr_vm, wptr >> 
PAGE_SHIFT);
+               if (!wptr_mapping) {
+                       dev_err(adev->dev, "Failed to lookup wptr bo\n");
+                       goto out_unlock;
+               }
+
+               wptr_obj->obj = wptr_mapping->bo_va->base.bo;
+               ret = drm_exec_lock_obj(&exec, &wptr_obj->obj->tbo.base);
+               drm_exec_retry_on_contention(&exec);
+               if (unlikely(ret))
+                       goto out_unlock;
        }
 
-       wptr_obj->obj = wptr_mapping->bo_va->base.bo;
+       /* Now both VM and WPTR BO are locked */
        if (wptr_obj->obj->tbo.base.size > PAGE_SIZE) {
                dev_err(adev->dev, "Requested GART mapping for wptr bo larger 
than one page\n");
-               return -EINVAL;
-       }
-
-       ret = amdgpu_userq_map_gtt_bo_to_gart(adev, wptr_obj->obj);
-       if (ret) {
-               dev_err(adev->dev, "Failed to map wptr bo to GART\n");
-               return ret;
-       }
-
-       ret = amdgpu_bo_reserve(wptr_obj->obj, true);
-       if (ret) {
-               dev_err(adev->dev, "Failed to reserve wptr bo\n");
-               return ret;
+               ret = -EINVAL;
+               goto out_unlock;
        }
 
        /* TODO use eviction fence instead of pinning. */
        ret = amdgpu_bo_pin(wptr_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
        if (ret) {
                drm_file_err(uq_mgr->file, "[Usermode queues] Failed to pin 
wptr bo\n");
-               goto unresv_bo;
+               goto out_unlock;
        }
 
+       ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
+       if (ret) {
+               dev_err(adev->dev, "Failed to bind bo to GART. ret %d\n", ret);
+               amdgpu_bo_unpin(wptr_obj->obj);
+               goto out_unlock;
+       }
        queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
-       amdgpu_bo_unreserve(wptr_obj->obj);
-
-       return 0;
+       amdgpu_bo_ref(wptr_obj->obj);
 
-unresv_bo:
-       amdgpu_bo_unreserve(wptr_obj->obj);
+out_unlock:
+       drm_exec_fini(&exec);
        return ret;
 
 }
-- 
2.43.0

Reply via email to