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