On Thursday, September 17, 2026 1:01:48 PM Central European Summer Time Huang Yu wrote: > From: Christian König <[email protected]> > > Allocate some PDs/PTs which just point to the dummy page. > > Those can be used in page faults to redirect recoverable page faults > to the dummy page. > > Signed-off-by: Christian König <[email protected]>
Makes good sense. Reviewed-by: Timur Kristóf <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 11 +++- > drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 5 +- > .../gpu/drm/amd/amdgpu/amdgpu_vm_internal.h | 2 + > drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c | 57 +++++++++++++++++++ > 4 files changed, 73 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 517490946a9c..5675925ca656 > 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c > @@ -2843,8 +2843,10 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, > struct amdgpu_vm *vm) * > * Initialize the VM manager structures > */ > -void amdgpu_vm_manager_init(struct amdgpu_device *adev) > +int amdgpu_vm_manager_init(struct amdgpu_device *adev) > { > + int r; > + > /* Concurrent flushes are only possible starting with Vega10 and > * are broken on Navi10 and Navi14. > */ > @@ -2856,6 +2858,10 @@ void amdgpu_vm_manager_init(struct amdgpu_device > *adev) spin_lock_init(&adev->vm_manager.prt_lock); > atomic_set(&adev->vm_manager.num_prt_users, 0); > > + r = amdgpu_vm_pt_alloc_dummies(adev); > + if (r) > + return r; > + > /* If not overridden by the user, by default, only in large BAR systems > * Compute VM tables will be updated by CPU > */ > @@ -2875,6 +2881,8 @@ void amdgpu_vm_manager_init(struct amdgpu_device > *adev) #else > adev->vm_manager.vm_update_mode = 0; > #endif > + > + return 0; > } > > /** > @@ -2886,6 +2894,7 @@ void amdgpu_vm_manager_init(struct amdgpu_device > *adev) */ > void amdgpu_vm_manager_fini(struct amdgpu_device *adev) > { > + amdgpu_vm_pt_free_dummies(adev); > amdgpu_vmid_mgr_fini(adev); > amdgpu_pasid_mgr_cleanup(); > } > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index ac3b8e8525c1..826406522b24 > 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h > @@ -409,6 +409,9 @@ struct amdgpu_vm_manager { > > /* Global registration of recent page fault information */ > struct amdgpu_vm_fault_info fault_info; > + > + struct amdgpu_bo *dummy_pd[AMDGPU_VM_PTB + 1]; > + uint64_t dummy_dst[AMDGPU_VM_PTB + 1]; > }; > > struct amdgpu_bo_va_mapping; > @@ -420,7 +423,7 @@ struct amdgpu_bo_va_mapping; > extern const struct amdgpu_vm_update_funcs amdgpu_vm_cpu_funcs; > extern const struct amdgpu_vm_update_funcs amdgpu_vm_sdma_funcs; > > -void amdgpu_vm_manager_init(struct amdgpu_device *adev); > +int amdgpu_vm_manager_init(struct amdgpu_device *adev); > void amdgpu_vm_manager_fini(struct amdgpu_device *adev); > > long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout); > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h index > 447195cc4593..16cc0d5f5894 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_internal.h > @@ -125,6 +125,8 @@ void amdgpu_vm_pt_free_work(struct work_struct *work); > void amdgpu_vm_pt_free_list(struct amdgpu_device *adev, > struct amdgpu_vm_update_params *params); > int amdgpu_vm_pt_map_tables(struct amdgpu_device *adev, struct amdgpu_vm > *vm); +int amdgpu_vm_pt_alloc_dummies(struct amdgpu_device *adev); > +void amdgpu_vm_pt_free_dummies(struct amdgpu_device *adev); > > /* > * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index > b85b70a1a428..3a6449d60988 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c > @@ -963,3 +963,60 @@ int amdgpu_vm_pt_map_tables(struct amdgpu_device *adev, > struct amdgpu_vm *vm) > > return 0; > } > + > +/* amdgpu_vm_pt_alloc_dummies - allocate dummy PDs/PTs > + * > + * @adev: the amdgpu device pointer > + * > + * Allocate some dummy PDs/PTs which can be used to redirect page faults to > the + * dummy page. > + */ > +int amdgpu_vm_pt_alloc_dummies(struct amdgpu_device *adev) > +{ > + struct amdgpu_vm_manager *vm_mgr = &adev->vm_manager; > + int r; > + > + for (int level = AMDGPU_VM_PTB; level != vm_mgr->root_level; level--) { > + size_t size = amdgpu_vm_pt_size(adev, level); > + uint64_t addr, flags; > + void *ptr; > + > + r = amdgpu_bo_create_kernel(adev, size, 0, > + AMDGPU_GEM_DOMAIN_VRAM, > + &vm_mgr- >dummy_pd[level], > + &vm_mgr- >dummy_dst[level], > + &ptr); > + if (r) > + return r; > + > + if (level == AMDGPU_VM_PTB) { > + addr = adev->dummy_page_addr; > + /* > + * TODO: We want to have separate dummies for reads and > + * writes. > + */ > + flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED | > + AMDGPU_PTE_SYSTEM | AMDGPU_PTE_EXECUTABLE | > + AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE; > + } else { > + amdgpu_gmc_get_pde_for_bo(vm_mgr- >dummy_pd[level + 1], > + level, &addr, &flags); > + } > + > + for (int i = 0; i < amdgpu_vm_pt_num_entries(adev, level); i++) > + amdgpu_gmc_set_pte_pde(adev, ptr, i, addr, flags); > + } > + > + return 0; > +} > + > +void amdgpu_vm_pt_free_dummies(struct amdgpu_device *adev) > +{ > + struct amdgpu_vm_manager *vm_mgr = &adev->vm_manager; > + void *ptr; > + > + for (int level = AMDGPU_VM_PTB; level != vm_mgr->root_level; level--) > + amdgpu_bo_free_kernel(&vm_mgr->dummy_pd[level], > + &vm_mgr->dummy_dst[level], > + &ptr); > +}
