RE: [PATCH v3] drm/amdgpu: keep PRT mappings off the vm_bo state lists
"Zhang, Jesse(Jie)" <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <DM4PR12MB51523C01D30B1ABB7E9B49F0E3DD2@DM4PR12MB5152.namprd12.prod.outlook.com> |
AMD General Ping ... > -----Original Message----- > From: Jesse Zhang <[email protected]> > Sent: Wednesday, August 5, 2026 6:22 PM > To: [email protected] > Cc: Deucher, Alexander <[email protected]>; Koenig, Christian > <[email protected]>; Zhang, Jesse(Jie) <[email protected]> > Subject: [PATCH v3] drm/amdgpu: keep PRT mappings off the vm_bo state lists > > 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. Because the PRT bo_va is off the state lists, its PTE update fence lands > in prt_va->last_pt_update rather than vm->last_update, so wait on it explicitly before > restarting the queues (mirroring how the CS path syncs that fence). > > 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) > > v3: > - the PRT PTEs are updated separately, so their fence is in > prt_va->last_pt_update, not vm->last_update; wait on it in the userq > restore path before restarting queues, otherwise the queues could > restart before the sparse PTEs are written (Christian) > > Suggested-by: Christian König <[email protected]> > Signed-off-by: Jesse Zhang <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++++++++++++ > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 8 +++++++- > 2 files changed, 23 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c > index 6d3ed55e9ab4..bcfbd7213dd6 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) { @@ > -1127,6 +1137,12 @@ 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); > + /* > + * 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 > + * it explicitly (as the CS path syncs it) before restarting queues. > + */ > + dma_fence_wait(fpriv->prt_va->last_pt_update, false); > dma_fence_wait(vm->last_update, false); > > xa_for_each(&uq_mgr->userq_xa, tmp_key, queue) { 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