amdgpu_vm_bo_lock_lists() puts every BO which shares the resv of the
root PD and is a ttm_bo_type_kernel BO on the page table lists. The
CWSR TMA BO which amdgpu_cwsr_alloc() creates for every opened render
node is such a BO, so it is treated as a page table: after a VRAM
losing reset its bo_va moves to the page tables needing an update, and
amdgpu_vm_update_pdes() tries to write its PDE. It has no parent page
directory, so that fails, and fails again on every following
submission of the file.

On navi48, submitting on a render node, then amdgpu_gpu_recover and
submitting again, also with a new context:

  amdgpu 0000:03:00.0: VRAM is lost due to GPU reset!
  amdgpu 0000:03:00.0: GPU reset(1) succeeded!
  WARNING: amdgpu_vm_pt.c:671 at amdgpu_vm_pde_update+0x329/0x5d0 [amdgpu], 
CPU#0: vmreinit/2629
  Call Trace:
   amdgpu_vm_update_pdes+0x262/0x5e0 [amdgpu]
   amdgpu_cs_ioctl+0x35c9/0x7a00 [amdgpu]
   drm_ioctl_kernel+0x180/0x320 [drm]
   drm_ioctl+0x530/0xcb0 [drm]

and every command submission fails with -EINVAL from then on.

Don't look at the BO type. Give the PDs and PTs, which
amdgpu_bo_create_vm() creates, a destroy function of their own and tell
them by it, like the user and SVM BOs are told by theirs. The TMA BO
stays a kernel BO which userspace can't mmap.

v2: Keep the TMA BO a kernel BO, userspace must not be able to mmap it
    (Christian). Instead let the creator of the vm_bo tell whether it is
    a PD/PT, with a page_table flag in struct amdgpu_vm_bo_base next to
    the other bools, so the struct doesn't grow. Fixes the commit that
    added the TMA BO.
v3: Drop the flag, give the PDs/PTs a destroy function of their own and
    identify them by it, like the user and SVM BOs (Christian).

Fixes: 8a93aae9896b ("drm/amdgpu: Add CWSR infrastructure for user queues")
Signed-off-by: Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 22 ++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.h |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c     |  2 +-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 6aa895f63aea..d4651f2d437c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -71,6 +71,12 @@ static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo)
        kvfree(bo);
 }
 
+/* A function of its own, the page tables are told apart by it */
+static void amdgpu_bo_vm_destroy(struct ttm_buffer_object *tbo)
+{
+       amdgpu_bo_destroy(tbo);
+}
+
 static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo)
 {
        struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
@@ -94,6 +100,7 @@ static void amdgpu_bo_user_destroy(struct ttm_buffer_object 
*tbo)
 bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
 {
        if (bo->destroy == &amdgpu_bo_destroy ||
+           bo->destroy == &amdgpu_bo_vm_destroy ||
            bo->destroy == &amdgpu_bo_user_destroy ||
            bo->destroy == &svm_range_bo_destroy)
                return true;
@@ -101,6 +108,20 @@ bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
        return false;
 }
 
+/**
+ * amdgpu_bo_is_vm_bo - check if the buffer object is a page directory or table
+ * @bo: buffer object to be checked
+ *
+ * Uses the destroy function amdgpu_bo_create_vm() sets for the object.
+ *
+ * Returns:
+ * true if the object is a PD or PT of a VM, false if not.
+ */
+bool amdgpu_bo_is_vm_bo(struct amdgpu_bo *bo)
+{
+       return bo->tbo.destroy == &amdgpu_bo_vm_destroy;
+}
+
 /**
  * amdgpu_bo_placement_from_domain - set buffer's placement
  * @abo: &amdgpu_bo buffer object whose placement is to be set
@@ -813,6 +834,7 @@ int amdgpu_bo_create_vm(struct amdgpu_device *adev,
         * num of amdgpu_vm_pt entries.
         */
        BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo_vm));
+       bp->destroy = &amdgpu_bo_vm_destroy;
        r = amdgpu_bo_create(adev, bp, &bo_ptr);
        if (r)
                return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index 2e6a8e6f577a..8e67a8e60572 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -254,6 +254,7 @@ static inline bool amdgpu_bo_encrypted(struct amdgpu_bo *bo)
 }
 
 bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo);
+bool amdgpu_bo_is_vm_bo(struct amdgpu_bo *bo);
 void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain);
 
 int amdgpu_bo_create(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index a2814830dd2b..d5d9e2587661 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -162,7 +162,7 @@ amdgpu_vm_bo_lock_lists(struct amdgpu_vm_bo_base *vm_bo)
                /* No extra locking needed, protected by the root PD resv lock 
*/
                amdgpu_vm_assert_locked(vm);
 
-               if (bo->tbo.type == ttm_bo_type_kernel)
+               if (amdgpu_bo_is_vm_bo(bo))
                        return &vm->kernel;
 
                return &vm->always_valid;
-- 
2.50.1

Reply via email to