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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.