If updating page table free the page table BOs, add fence to the BOs to ensure the page table BOs are not freed and reused before TLB is flushed.
Signed-off-by: Philip Yang <philip.y...@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c | 33 +++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c index dea1a64be44d..16eb9472d469 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c @@ -633,8 +633,10 @@ static int amdgpu_vm_pt_alloc(struct amdgpu_device *adev, * amdgpu_vm_pt_free - free one PD/PT * * @entry: PDE to free + * @fence: fence added the freed page table BO */ -static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) +static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry, + struct dma_fence *fence) { struct amdgpu_bo *shadow; @@ -643,6 +645,9 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) shadow = amdgpu_bo_shadowed(entry->bo); if (shadow) { ttm_bo_set_bulk_move(&shadow->tbo, NULL); + if (fence && !dma_resv_reserve_fences(shadow->tbo.base.resv, 1)) + dma_resv_add_fence(shadow->tbo.base.resv, fence, + DMA_RESV_USAGE_BOOKKEEP); amdgpu_bo_unref(&shadow); } ttm_bo_set_bulk_move(&entry->bo->tbo, NULL); @@ -651,6 +656,9 @@ static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) spin_lock(&entry->vm->status_lock); list_del(&entry->vm_status); spin_unlock(&entry->vm->status_lock); + if (fence && !dma_resv_reserve_fences(entry->bo->tbo.base.resv, 1)) + dma_resv_add_fence(entry->bo->tbo.base.resv, fence, + DMA_RESV_USAGE_BOOKKEEP); amdgpu_bo_unref(&entry->bo); } @@ -670,7 +678,7 @@ void amdgpu_vm_pt_free_work(struct work_struct *work) amdgpu_bo_reserve(vm->root.bo, true); list_for_each_entry_safe(entry, next, &pt_freed, vm_status) - amdgpu_vm_pt_free(entry); + amdgpu_vm_pt_free(entry, NULL); amdgpu_bo_unreserve(vm->root.bo); } @@ -682,13 +690,15 @@ void amdgpu_vm_pt_free_work(struct work_struct *work) * @vm: amdgpu vm structure * @start: optional cursor where to start freeing PDs/PTs * @unlocked: vm resv unlock status + * @fence: page table fence added to the freed BOs * * Free the page directory or page table level and all sub levels. */ static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_vm_pt_cursor *start, - bool unlocked) + bool unlocked, + struct dma_fence *fence) { struct amdgpu_vm_pt_cursor cursor; struct amdgpu_vm_bo_base *entry; @@ -706,10 +716,10 @@ static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, } for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) - amdgpu_vm_pt_free(entry); + amdgpu_vm_pt_free(entry, fence); if (start) - amdgpu_vm_pt_free(start->entry); + amdgpu_vm_pt_free(start->entry, fence); } /** @@ -721,7 +731,7 @@ static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, */ void amdgpu_vm_pt_free_root(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - amdgpu_vm_pt_free_dfs(adev, vm, NULL, false); + amdgpu_vm_pt_free_dfs(adev, vm, NULL, false, NULL); } /** @@ -905,6 +915,7 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, struct amdgpu_device *adev = params->adev; struct amdgpu_vm_pt_cursor cursor; uint64_t frag_start = start, frag_end; + struct amdgpu_vm *vm = params->vm; unsigned int frag; int r; @@ -913,7 +924,7 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, &frag_end); /* walk over the address space and update the PTs */ - amdgpu_vm_pt_start(adev, params->vm, start, &cursor); + amdgpu_vm_pt_start(adev, vm, start, &cursor); while (cursor.pfn < end) { unsigned int shift, parent_shift, mask; uint64_t incr, entry_end, pe_start; @@ -923,7 +934,7 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, /* make sure that the page tables covering the * address range are actually allocated */ - r = amdgpu_vm_pt_alloc(params->adev, params->vm, + r = amdgpu_vm_pt_alloc(params->adev, vm, &cursor, params->immediate); if (r) return r; @@ -986,7 +997,6 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, entry_end = min(entry_end, end); do { - struct amdgpu_vm *vm = params->vm; uint64_t upd_end = min(entry_end, frag_end); unsigned int nptes = (upd_end - frag_start) >> shift; uint64_t upd_flags = flags | AMDGPU_PTE_FRAG(frag); @@ -1029,9 +1039,10 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, /* Make sure previous mapping is freed */ if (cursor.entry->bo) { params->table_freed = true; - amdgpu_vm_pt_free_dfs(adev, params->vm, + amdgpu_vm_pt_free_dfs(adev, vm, &cursor, - params->unlocked); + params->unlocked, + vm->pt_fence); } amdgpu_vm_pt_next(adev, &cursor); } -- 2.35.1