[PATCH v2] drm/amdgpu: keep PRT mappings off the vm_bo state lists
Jesse Zhang <[email protected]> Wed, 5 Aug 2026 14:25:23 +0800
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
A PRT/sparse mapping has no backing BO, so its bo_va->base.bo is NULL. amdgpu_vm_bo_base_init() deliberately keeps such a bo_va off the vm_bo state lists, but the tail of amdgpu_vm_bo_update() unconditionally called amdgpu_vm_bo_idle() for the !always_valid case, putting the NULL-bo PRT bo_va onto the individual.idle list. On a GPU reset amdgpu_vm_bo_reset_state_machine() moves individual.idle to individual.needs_update with moved=true, and amdgpu_vm_handle_moved() then dereferences bo_va->base.bo to read its reservation object, crashing on the NULL bo (e.g. the userq eviction restore worker running during a reset while a user queue is torn down): BUG: kernel NULL pointer dereference, address: 0000000000000158 RIP: 0010:amdgpu_vm_handle_moved+0x17a/0x200 [amdgpu] Call Trace: amdgpu_userq_vm_validate_and_restore_queue+0x2ce/0x920 [amdgpu] amdgpu_userq_restore_worker+0xce/0x210 [amdgpu] Skip amdgpu_vm_bo_idle() when bo is NULL so a PRT mapping never lands on a state list in the first place, and refresh the PRT page tables explicitly in the userq restore path (as the CS path already does) so sparse mappings survive a VRAM-lost reset. v2: - keep the PRT bo_va off the vm_bo state lists instead of NULL-guarding bo inside amdgpu_vm_handle_moved(); a PRT mapping should never be on the moved list in the first place (Christian) Signed-off-by: Jesse Zhang <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 10 ++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 770635ab5298..fa67d76237d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -1070,6 +1070,16 @@ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) if (ret) goto unlock_all; + /* + * PRT/sparse mappings are kept off the vm_bo state lists, so + * amdgpu_vm_handle_moved() does not touch them. Refresh their PTEs + * explicitly here (as the CS path does) so sparse mappings survive a + * VRAM-lost reset. + */ + ret = amdgpu_vm_bo_update(adev, fpriv->prt_va, false); + if (ret) + goto unlock_all; + key = 0; /* Validate User Ptr BOs */ list_for_each_entry(bo_va, &vm->always_valid.idle, base.vm_status) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 4c90e88e2e30..02e2e576f154 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1391,7 +1391,13 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, amdgpu_vm_bo_evicted(&bo_va->base); else amdgpu_vm_bo_idle(&bo_va->base); - } else { + } else if (bo) { + /* + * A PRT/sparse mapping has no BO and is kept off the vm_bo + * state lists (see amdgpu_vm_bo_base_init()); putting it on the + * idle list here would let amdgpu_vm_handle_moved() dereference + * the NULL bo after a reset. + */ amdgpu_vm_bo_idle(&bo_va->base); } -- 2.49.0