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]> --- 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); +} -- 2.53.0
