18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc.
48c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
148c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
198c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
228c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * Authors: Dave Airlie
258c2ecf20Sopenharmony_ci *          Alex Deucher
268c2ecf20Sopenharmony_ci *          Jerome Glisse
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#include <linux/dma-fence-array.h>
298c2ecf20Sopenharmony_ci#include <linux/interval_tree_generic.h>
308c2ecf20Sopenharmony_ci#include <linux/idr.h>
318c2ecf20Sopenharmony_ci#include <linux/dma-buf.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <drm/amdgpu_drm.h>
348c2ecf20Sopenharmony_ci#include "amdgpu.h"
358c2ecf20Sopenharmony_ci#include "amdgpu_trace.h"
368c2ecf20Sopenharmony_ci#include "amdgpu_amdkfd.h"
378c2ecf20Sopenharmony_ci#include "amdgpu_gmc.h"
388c2ecf20Sopenharmony_ci#include "amdgpu_xgmi.h"
398c2ecf20Sopenharmony_ci#include "amdgpu_dma_buf.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/**
428c2ecf20Sopenharmony_ci * DOC: GPUVM
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * GPUVM is similar to the legacy gart on older asics, however
458c2ecf20Sopenharmony_ci * rather than there being a single global gart table
468c2ecf20Sopenharmony_ci * for the entire GPU, there are multiple VM page tables active
478c2ecf20Sopenharmony_ci * at any given time.  The VM page tables can contain a mix
488c2ecf20Sopenharmony_ci * vram pages and system memory pages and system memory pages
498c2ecf20Sopenharmony_ci * can be mapped as snooped (cached system pages) or unsnooped
508c2ecf20Sopenharmony_ci * (uncached system pages).
518c2ecf20Sopenharmony_ci * Each VM has an ID associated with it and there is a page table
528c2ecf20Sopenharmony_ci * associated with each VMID.  When execting a command buffer,
538c2ecf20Sopenharmony_ci * the kernel tells the the ring what VMID to use for that command
548c2ecf20Sopenharmony_ci * buffer.  VMIDs are allocated dynamically as commands are submitted.
558c2ecf20Sopenharmony_ci * The userspace drivers maintain their own address space and the kernel
568c2ecf20Sopenharmony_ci * sets up their pages tables accordingly when they submit their
578c2ecf20Sopenharmony_ci * command buffers and a VMID is assigned.
588c2ecf20Sopenharmony_ci * Cayman/Trinity support up to 8 active VMs at any given time;
598c2ecf20Sopenharmony_ci * SI supports 16.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define START(node) ((node)->start)
638c2ecf20Sopenharmony_ci#define LAST(node) ((node)->last)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciINTERVAL_TREE_DEFINE(struct amdgpu_bo_va_mapping, rb, uint64_t, __subtree_last,
668c2ecf20Sopenharmony_ci		     START, LAST, static, amdgpu_vm_it)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#undef START
698c2ecf20Sopenharmony_ci#undef LAST
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/**
728c2ecf20Sopenharmony_ci * struct amdgpu_prt_cb - Helper to disable partial resident texture feature from a fence callback
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistruct amdgpu_prt_cb {
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/**
778c2ecf20Sopenharmony_ci	 * @adev: amdgpu device
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	struct amdgpu_device *adev;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/**
828c2ecf20Sopenharmony_ci	 * @cb: callback
838c2ecf20Sopenharmony_ci	 */
848c2ecf20Sopenharmony_ci	struct dma_fence_cb cb;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/*
888c2ecf20Sopenharmony_ci * vm eviction_lock can be taken in MMU notifiers. Make sure no reclaim-FS
898c2ecf20Sopenharmony_ci * happens while holding this lock anywhere to prevent deadlocks when
908c2ecf20Sopenharmony_ci * an MMU notifier runs in reclaim-FS context.
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic inline void amdgpu_vm_eviction_lock(struct amdgpu_vm *vm)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	mutex_lock(&vm->eviction_lock);
958c2ecf20Sopenharmony_ci	vm->saved_flags = memalloc_nofs_save();
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic inline int amdgpu_vm_eviction_trylock(struct amdgpu_vm *vm)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	if (mutex_trylock(&vm->eviction_lock)) {
1018c2ecf20Sopenharmony_ci		vm->saved_flags = memalloc_nofs_save();
1028c2ecf20Sopenharmony_ci		return 1;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline void amdgpu_vm_eviction_unlock(struct amdgpu_vm *vm)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	memalloc_nofs_restore(vm->saved_flags);
1108c2ecf20Sopenharmony_ci	mutex_unlock(&vm->eviction_lock);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * amdgpu_vm_level_shift - return the addr shift for each level
1158c2ecf20Sopenharmony_ci *
1168c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
1178c2ecf20Sopenharmony_ci * @level: VMPT level
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci * Returns:
1208c2ecf20Sopenharmony_ci * The number of bits the pfn needs to be right shifted for a level.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_cistatic unsigned amdgpu_vm_level_shift(struct amdgpu_device *adev,
1238c2ecf20Sopenharmony_ci				      unsigned level)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	switch (level) {
1268c2ecf20Sopenharmony_ci	case AMDGPU_VM_PDB2:
1278c2ecf20Sopenharmony_ci	case AMDGPU_VM_PDB1:
1288c2ecf20Sopenharmony_ci	case AMDGPU_VM_PDB0:
1298c2ecf20Sopenharmony_ci		return 9 * (AMDGPU_VM_PDB0 - level) +
1308c2ecf20Sopenharmony_ci			adev->vm_manager.block_size;
1318c2ecf20Sopenharmony_ci	case AMDGPU_VM_PTB:
1328c2ecf20Sopenharmony_ci		return 0;
1338c2ecf20Sopenharmony_ci	default:
1348c2ecf20Sopenharmony_ci		return ~0;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/**
1398c2ecf20Sopenharmony_ci * amdgpu_vm_num_entries - return the number of entries in a PD/PT
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
1428c2ecf20Sopenharmony_ci * @level: VMPT level
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * Returns:
1458c2ecf20Sopenharmony_ci * The number of entries in a page directory or page table.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistatic unsigned amdgpu_vm_num_entries(struct amdgpu_device *adev,
1488c2ecf20Sopenharmony_ci				      unsigned level)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	unsigned shift = amdgpu_vm_level_shift(adev,
1518c2ecf20Sopenharmony_ci					       adev->vm_manager.root_level);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (level == adev->vm_manager.root_level)
1548c2ecf20Sopenharmony_ci		/* For the root directory */
1558c2ecf20Sopenharmony_ci		return round_up(adev->vm_manager.max_pfn, 1ULL << shift)
1568c2ecf20Sopenharmony_ci			>> shift;
1578c2ecf20Sopenharmony_ci	else if (level != AMDGPU_VM_PTB)
1588c2ecf20Sopenharmony_ci		/* Everything in between */
1598c2ecf20Sopenharmony_ci		return 512;
1608c2ecf20Sopenharmony_ci	else
1618c2ecf20Sopenharmony_ci		/* For the page tables on the leaves */
1628c2ecf20Sopenharmony_ci		return AMDGPU_VM_PTE_COUNT(adev);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/**
1668c2ecf20Sopenharmony_ci * amdgpu_vm_num_ats_entries - return the number of ATS entries in the root PD
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci * Returns:
1718c2ecf20Sopenharmony_ci * The number of entries in the root page directory which needs the ATS setting.
1728c2ecf20Sopenharmony_ci */
1738c2ecf20Sopenharmony_cistatic unsigned amdgpu_vm_num_ats_entries(struct amdgpu_device *adev)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	unsigned shift;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	shift = amdgpu_vm_level_shift(adev, adev->vm_manager.root_level);
1788c2ecf20Sopenharmony_ci	return AMDGPU_GMC_HOLE_START >> (shift + AMDGPU_GPU_PAGE_SHIFT);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/**
1828c2ecf20Sopenharmony_ci * amdgpu_vm_entries_mask - the mask to get the entry number of a PD/PT
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
1858c2ecf20Sopenharmony_ci * @level: VMPT level
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * Returns:
1888c2ecf20Sopenharmony_ci * The mask to extract the entry number of a PD/PT from an address.
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_cistatic uint32_t amdgpu_vm_entries_mask(struct amdgpu_device *adev,
1918c2ecf20Sopenharmony_ci				       unsigned int level)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	if (level <= adev->vm_manager.root_level)
1948c2ecf20Sopenharmony_ci		return 0xffffffff;
1958c2ecf20Sopenharmony_ci	else if (level != AMDGPU_VM_PTB)
1968c2ecf20Sopenharmony_ci		return 0x1ff;
1978c2ecf20Sopenharmony_ci	else
1988c2ecf20Sopenharmony_ci		return AMDGPU_VM_PTE_COUNT(adev) - 1;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/**
2028c2ecf20Sopenharmony_ci * amdgpu_vm_bo_size - returns the size of the BOs in bytes
2038c2ecf20Sopenharmony_ci *
2048c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
2058c2ecf20Sopenharmony_ci * @level: VMPT level
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci * Returns:
2088c2ecf20Sopenharmony_ci * The size of the BO for a page directory or page table in bytes.
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_cistatic unsigned amdgpu_vm_bo_size(struct amdgpu_device *adev, unsigned level)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	return AMDGPU_GPU_PAGE_ALIGN(amdgpu_vm_num_entries(adev, level) * 8);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/**
2168c2ecf20Sopenharmony_ci * amdgpu_vm_bo_evicted - vm_bo is evicted
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is evicted
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * State for PDs/PTs and per VM BOs which are not at the location they should
2218c2ecf20Sopenharmony_ci * be.
2228c2ecf20Sopenharmony_ci */
2238c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = vm_bo->vm;
2268c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = vm_bo->bo;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	vm_bo->moved = true;
2298c2ecf20Sopenharmony_ci	if (bo->tbo.type == ttm_bo_type_kernel)
2308c2ecf20Sopenharmony_ci		list_move(&vm_bo->vm_status, &vm->evicted);
2318c2ecf20Sopenharmony_ci	else
2328c2ecf20Sopenharmony_ci		list_move_tail(&vm_bo->vm_status, &vm->evicted);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci/**
2358c2ecf20Sopenharmony_ci * amdgpu_vm_bo_moved - vm_bo is moved
2368c2ecf20Sopenharmony_ci *
2378c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is moved
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * State for per VM BOs which are moved, but that change is not yet reflected
2408c2ecf20Sopenharmony_ci * in the page tables.
2418c2ecf20Sopenharmony_ci */
2428c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	list_move(&vm_bo->vm_status, &vm_bo->vm->moved);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/**
2488c2ecf20Sopenharmony_ci * amdgpu_vm_bo_idle - vm_bo is idle
2498c2ecf20Sopenharmony_ci *
2508c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is now idle
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * State for PDs/PTs and per VM BOs which have gone through the state machine
2538c2ecf20Sopenharmony_ci * and are now idle.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	list_move(&vm_bo->vm_status, &vm_bo->vm->idle);
2588c2ecf20Sopenharmony_ci	vm_bo->moved = false;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/**
2628c2ecf20Sopenharmony_ci * amdgpu_vm_bo_invalidated - vm_bo is invalidated
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is now invalidated
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci * State for normal BOs which are invalidated and that change not yet reflected
2678c2ecf20Sopenharmony_ci * in the PTs.
2688c2ecf20Sopenharmony_ci */
2698c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_invalidated(struct amdgpu_vm_bo_base *vm_bo)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	spin_lock(&vm_bo->vm->invalidated_lock);
2728c2ecf20Sopenharmony_ci	list_move(&vm_bo->vm_status, &vm_bo->vm->invalidated);
2738c2ecf20Sopenharmony_ci	spin_unlock(&vm_bo->vm->invalidated_lock);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/**
2778c2ecf20Sopenharmony_ci * amdgpu_vm_bo_relocated - vm_bo is reloacted
2788c2ecf20Sopenharmony_ci *
2798c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is relocated
2808c2ecf20Sopenharmony_ci *
2818c2ecf20Sopenharmony_ci * State for PDs/PTs which needs to update their parent PD.
2828c2ecf20Sopenharmony_ci * For the root PD, just move to idle state.
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_relocated(struct amdgpu_vm_bo_base *vm_bo)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	if (vm_bo->bo->parent)
2878c2ecf20Sopenharmony_ci		list_move(&vm_bo->vm_status, &vm_bo->vm->relocated);
2888c2ecf20Sopenharmony_ci	else
2898c2ecf20Sopenharmony_ci		amdgpu_vm_bo_idle(vm_bo);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/**
2938c2ecf20Sopenharmony_ci * amdgpu_vm_bo_done - vm_bo is done
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * @vm_bo: vm_bo which is now done
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci * State for normal BOs which are invalidated and that change has been updated
2988c2ecf20Sopenharmony_ci * in the PTs.
2998c2ecf20Sopenharmony_ci */
3008c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_done(struct amdgpu_vm_bo_base *vm_bo)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	spin_lock(&vm_bo->vm->invalidated_lock);
3038c2ecf20Sopenharmony_ci	list_del_init(&vm_bo->vm_status);
3048c2ecf20Sopenharmony_ci	spin_unlock(&vm_bo->vm->invalidated_lock);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/**
3088c2ecf20Sopenharmony_ci * amdgpu_vm_bo_base_init - Adds bo to the list of bos associated with the vm
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci * @base: base structure for tracking BO usage in a VM
3118c2ecf20Sopenharmony_ci * @vm: vm to which bo is to be added
3128c2ecf20Sopenharmony_ci * @bo: amdgpu buffer object
3138c2ecf20Sopenharmony_ci *
3148c2ecf20Sopenharmony_ci * Initialize a bo_va_base structure and add it to the appropriate lists
3158c2ecf20Sopenharmony_ci *
3168c2ecf20Sopenharmony_ci */
3178c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base,
3188c2ecf20Sopenharmony_ci				   struct amdgpu_vm *vm,
3198c2ecf20Sopenharmony_ci				   struct amdgpu_bo *bo)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	base->vm = vm;
3228c2ecf20Sopenharmony_ci	base->bo = bo;
3238c2ecf20Sopenharmony_ci	base->next = NULL;
3248c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&base->vm_status);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!bo)
3278c2ecf20Sopenharmony_ci		return;
3288c2ecf20Sopenharmony_ci	base->next = bo->vm_bo;
3298c2ecf20Sopenharmony_ci	bo->vm_bo = base;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (bo->tbo.base.resv != vm->root.base.bo->tbo.base.resv)
3328c2ecf20Sopenharmony_ci		return;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	vm->bulk_moveable = false;
3358c2ecf20Sopenharmony_ci	if (bo->tbo.type == ttm_bo_type_kernel && bo->parent)
3368c2ecf20Sopenharmony_ci		amdgpu_vm_bo_relocated(base);
3378c2ecf20Sopenharmony_ci	else
3388c2ecf20Sopenharmony_ci		amdgpu_vm_bo_idle(base);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (bo->preferred_domains &
3418c2ecf20Sopenharmony_ci	    amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type))
3428c2ecf20Sopenharmony_ci		return;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/*
3458c2ecf20Sopenharmony_ci	 * we checked all the prerequisites, but it looks like this per vm bo
3468c2ecf20Sopenharmony_ci	 * is currently evicted. add the bo to the evicted list to make sure it
3478c2ecf20Sopenharmony_ci	 * is validated on next vm use to avoid fault.
3488c2ecf20Sopenharmony_ci	 * */
3498c2ecf20Sopenharmony_ci	amdgpu_vm_bo_evicted(base);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci/**
3538c2ecf20Sopenharmony_ci * amdgpu_vm_pt_parent - get the parent page directory
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * @pt: child page table
3568c2ecf20Sopenharmony_ci *
3578c2ecf20Sopenharmony_ci * Helper to get the parent entry for the child page table. NULL if we are at
3588c2ecf20Sopenharmony_ci * the root page directory.
3598c2ecf20Sopenharmony_ci */
3608c2ecf20Sopenharmony_cistatic struct amdgpu_vm_pt *amdgpu_vm_pt_parent(struct amdgpu_vm_pt *pt)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct amdgpu_bo *parent = pt->base.bo->parent;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (!parent)
3658c2ecf20Sopenharmony_ci		return NULL;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return container_of(parent->vm_bo, struct amdgpu_vm_pt, base);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci/*
3718c2ecf20Sopenharmony_ci * amdgpu_vm_pt_cursor - state for for_each_amdgpu_vm_pt
3728c2ecf20Sopenharmony_ci */
3738c2ecf20Sopenharmony_cistruct amdgpu_vm_pt_cursor {
3748c2ecf20Sopenharmony_ci	uint64_t pfn;
3758c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *parent;
3768c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *entry;
3778c2ecf20Sopenharmony_ci	unsigned level;
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/**
3818c2ecf20Sopenharmony_ci * amdgpu_vm_pt_start - start PD/PT walk
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
3848c2ecf20Sopenharmony_ci * @vm: amdgpu_vm structure
3858c2ecf20Sopenharmony_ci * @start: start address of the walk
3868c2ecf20Sopenharmony_ci * @cursor: state to initialize
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * Initialize a amdgpu_vm_pt_cursor to start a walk.
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_cistatic void amdgpu_vm_pt_start(struct amdgpu_device *adev,
3918c2ecf20Sopenharmony_ci			       struct amdgpu_vm *vm, uint64_t start,
3928c2ecf20Sopenharmony_ci			       struct amdgpu_vm_pt_cursor *cursor)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	cursor->pfn = start;
3958c2ecf20Sopenharmony_ci	cursor->parent = NULL;
3968c2ecf20Sopenharmony_ci	cursor->entry = &vm->root;
3978c2ecf20Sopenharmony_ci	cursor->level = adev->vm_manager.root_level;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/**
4018c2ecf20Sopenharmony_ci * amdgpu_vm_pt_descendant - go to child node
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
4048c2ecf20Sopenharmony_ci * @cursor: current state
4058c2ecf20Sopenharmony_ci *
4068c2ecf20Sopenharmony_ci * Walk to the child node of the current node.
4078c2ecf20Sopenharmony_ci * Returns:
4088c2ecf20Sopenharmony_ci * True if the walk was possible, false otherwise.
4098c2ecf20Sopenharmony_ci */
4108c2ecf20Sopenharmony_cistatic bool amdgpu_vm_pt_descendant(struct amdgpu_device *adev,
4118c2ecf20Sopenharmony_ci				    struct amdgpu_vm_pt_cursor *cursor)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	unsigned mask, shift, idx;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (!cursor->entry->entries)
4168c2ecf20Sopenharmony_ci		return false;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	BUG_ON(!cursor->entry->base.bo);
4198c2ecf20Sopenharmony_ci	mask = amdgpu_vm_entries_mask(adev, cursor->level);
4208c2ecf20Sopenharmony_ci	shift = amdgpu_vm_level_shift(adev, cursor->level);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	++cursor->level;
4238c2ecf20Sopenharmony_ci	idx = (cursor->pfn >> shift) & mask;
4248c2ecf20Sopenharmony_ci	cursor->parent = cursor->entry;
4258c2ecf20Sopenharmony_ci	cursor->entry = &cursor->entry->entries[idx];
4268c2ecf20Sopenharmony_ci	return true;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci/**
4308c2ecf20Sopenharmony_ci * amdgpu_vm_pt_sibling - go to sibling node
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
4338c2ecf20Sopenharmony_ci * @cursor: current state
4348c2ecf20Sopenharmony_ci *
4358c2ecf20Sopenharmony_ci * Walk to the sibling node of the current node.
4368c2ecf20Sopenharmony_ci * Returns:
4378c2ecf20Sopenharmony_ci * True if the walk was possible, false otherwise.
4388c2ecf20Sopenharmony_ci */
4398c2ecf20Sopenharmony_cistatic bool amdgpu_vm_pt_sibling(struct amdgpu_device *adev,
4408c2ecf20Sopenharmony_ci				 struct amdgpu_vm_pt_cursor *cursor)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	unsigned shift, num_entries;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* Root doesn't have a sibling */
4458c2ecf20Sopenharmony_ci	if (!cursor->parent)
4468c2ecf20Sopenharmony_ci		return false;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Go to our parents and see if we got a sibling */
4498c2ecf20Sopenharmony_ci	shift = amdgpu_vm_level_shift(adev, cursor->level - 1);
4508c2ecf20Sopenharmony_ci	num_entries = amdgpu_vm_num_entries(adev, cursor->level - 1);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (cursor->entry == &cursor->parent->entries[num_entries - 1])
4538c2ecf20Sopenharmony_ci		return false;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	cursor->pfn += 1ULL << shift;
4568c2ecf20Sopenharmony_ci	cursor->pfn &= ~((1ULL << shift) - 1);
4578c2ecf20Sopenharmony_ci	++cursor->entry;
4588c2ecf20Sopenharmony_ci	return true;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci/**
4628c2ecf20Sopenharmony_ci * amdgpu_vm_pt_ancestor - go to parent node
4638c2ecf20Sopenharmony_ci *
4648c2ecf20Sopenharmony_ci * @cursor: current state
4658c2ecf20Sopenharmony_ci *
4668c2ecf20Sopenharmony_ci * Walk to the parent node of the current node.
4678c2ecf20Sopenharmony_ci * Returns:
4688c2ecf20Sopenharmony_ci * True if the walk was possible, false otherwise.
4698c2ecf20Sopenharmony_ci */
4708c2ecf20Sopenharmony_cistatic bool amdgpu_vm_pt_ancestor(struct amdgpu_vm_pt_cursor *cursor)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	if (!cursor->parent)
4738c2ecf20Sopenharmony_ci		return false;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	--cursor->level;
4768c2ecf20Sopenharmony_ci	cursor->entry = cursor->parent;
4778c2ecf20Sopenharmony_ci	cursor->parent = amdgpu_vm_pt_parent(cursor->parent);
4788c2ecf20Sopenharmony_ci	return true;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/**
4828c2ecf20Sopenharmony_ci * amdgpu_vm_pt_next - get next PD/PT in hieratchy
4838c2ecf20Sopenharmony_ci *
4848c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
4858c2ecf20Sopenharmony_ci * @cursor: current state
4868c2ecf20Sopenharmony_ci *
4878c2ecf20Sopenharmony_ci * Walk the PD/PT tree to the next node.
4888c2ecf20Sopenharmony_ci */
4898c2ecf20Sopenharmony_cistatic void amdgpu_vm_pt_next(struct amdgpu_device *adev,
4908c2ecf20Sopenharmony_ci			      struct amdgpu_vm_pt_cursor *cursor)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	/* First try a newborn child */
4938c2ecf20Sopenharmony_ci	if (amdgpu_vm_pt_descendant(adev, cursor))
4948c2ecf20Sopenharmony_ci		return;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* If that didn't worked try to find a sibling */
4978c2ecf20Sopenharmony_ci	while (!amdgpu_vm_pt_sibling(adev, cursor)) {
4988c2ecf20Sopenharmony_ci		/* No sibling, go to our parents and grandparents */
4998c2ecf20Sopenharmony_ci		if (!amdgpu_vm_pt_ancestor(cursor)) {
5008c2ecf20Sopenharmony_ci			cursor->pfn = ~0ll;
5018c2ecf20Sopenharmony_ci			return;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci/**
5078c2ecf20Sopenharmony_ci * amdgpu_vm_pt_first_dfs - start a deep first search
5088c2ecf20Sopenharmony_ci *
5098c2ecf20Sopenharmony_ci * @adev: amdgpu_device structure
5108c2ecf20Sopenharmony_ci * @vm: amdgpu_vm structure
5118c2ecf20Sopenharmony_ci * @start: optional cursor to start with
5128c2ecf20Sopenharmony_ci * @cursor: state to initialize
5138c2ecf20Sopenharmony_ci *
5148c2ecf20Sopenharmony_ci * Starts a deep first traversal of the PD/PT tree.
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistatic void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev,
5178c2ecf20Sopenharmony_ci				   struct amdgpu_vm *vm,
5188c2ecf20Sopenharmony_ci				   struct amdgpu_vm_pt_cursor *start,
5198c2ecf20Sopenharmony_ci				   struct amdgpu_vm_pt_cursor *cursor)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	if (start)
5228c2ecf20Sopenharmony_ci		*cursor = *start;
5238c2ecf20Sopenharmony_ci	else
5248c2ecf20Sopenharmony_ci		amdgpu_vm_pt_start(adev, vm, 0, cursor);
5258c2ecf20Sopenharmony_ci	while (amdgpu_vm_pt_descendant(adev, cursor));
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/**
5298c2ecf20Sopenharmony_ci * amdgpu_vm_pt_continue_dfs - check if the deep first search should continue
5308c2ecf20Sopenharmony_ci *
5318c2ecf20Sopenharmony_ci * @start: starting point for the search
5328c2ecf20Sopenharmony_ci * @entry: current entry
5338c2ecf20Sopenharmony_ci *
5348c2ecf20Sopenharmony_ci * Returns:
5358c2ecf20Sopenharmony_ci * True when the search should continue, false otherwise.
5368c2ecf20Sopenharmony_ci */
5378c2ecf20Sopenharmony_cistatic bool amdgpu_vm_pt_continue_dfs(struct amdgpu_vm_pt_cursor *start,
5388c2ecf20Sopenharmony_ci				      struct amdgpu_vm_pt *entry)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	return entry && (!start || entry != start->entry);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/**
5448c2ecf20Sopenharmony_ci * amdgpu_vm_pt_next_dfs - get the next node for a deep first search
5458c2ecf20Sopenharmony_ci *
5468c2ecf20Sopenharmony_ci * @adev: amdgpu_device structure
5478c2ecf20Sopenharmony_ci * @cursor: current state
5488c2ecf20Sopenharmony_ci *
5498c2ecf20Sopenharmony_ci * Move the cursor to the next node in a deep first search.
5508c2ecf20Sopenharmony_ci */
5518c2ecf20Sopenharmony_cistatic void amdgpu_vm_pt_next_dfs(struct amdgpu_device *adev,
5528c2ecf20Sopenharmony_ci				  struct amdgpu_vm_pt_cursor *cursor)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	if (!cursor->entry)
5558c2ecf20Sopenharmony_ci		return;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (!cursor->parent)
5588c2ecf20Sopenharmony_ci		cursor->entry = NULL;
5598c2ecf20Sopenharmony_ci	else if (amdgpu_vm_pt_sibling(adev, cursor))
5608c2ecf20Sopenharmony_ci		while (amdgpu_vm_pt_descendant(adev, cursor));
5618c2ecf20Sopenharmony_ci	else
5628c2ecf20Sopenharmony_ci		amdgpu_vm_pt_ancestor(cursor);
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci/*
5668c2ecf20Sopenharmony_ci * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_ci#define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)		\
5698c2ecf20Sopenharmony_ci	for (amdgpu_vm_pt_first_dfs((adev), (vm), (start), &(cursor)),		\
5708c2ecf20Sopenharmony_ci	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\
5718c2ecf20Sopenharmony_ci	     amdgpu_vm_pt_continue_dfs((start), (entry));			\
5728c2ecf20Sopenharmony_ci	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor)))
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci/**
5758c2ecf20Sopenharmony_ci * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
5768c2ecf20Sopenharmony_ci *
5778c2ecf20Sopenharmony_ci * @vm: vm providing the BOs
5788c2ecf20Sopenharmony_ci * @validated: head of validation list
5798c2ecf20Sopenharmony_ci * @entry: entry to add
5808c2ecf20Sopenharmony_ci *
5818c2ecf20Sopenharmony_ci * Add the page directory to the list of BOs to
5828c2ecf20Sopenharmony_ci * validate for command submission.
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_civoid amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm,
5858c2ecf20Sopenharmony_ci			 struct list_head *validated,
5868c2ecf20Sopenharmony_ci			 struct amdgpu_bo_list_entry *entry)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	entry->priority = 0;
5898c2ecf20Sopenharmony_ci	entry->tv.bo = &vm->root.base.bo->tbo;
5908c2ecf20Sopenharmony_ci	/* Two for VM updates, one for TTM and one for the CS job */
5918c2ecf20Sopenharmony_ci	entry->tv.num_shared = 4;
5928c2ecf20Sopenharmony_ci	entry->user_pages = NULL;
5938c2ecf20Sopenharmony_ci	list_add(&entry->tv.head, validated);
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/**
5978c2ecf20Sopenharmony_ci * amdgpu_vm_del_from_lru_notify - update bulk_moveable flag
5988c2ecf20Sopenharmony_ci *
5998c2ecf20Sopenharmony_ci * @bo: BO which was removed from the LRU
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * Make sure the bulk_moveable flag is updated when a BO is removed from the
6028c2ecf20Sopenharmony_ci * LRU.
6038c2ecf20Sopenharmony_ci */
6048c2ecf20Sopenharmony_civoid amdgpu_vm_del_from_lru_notify(struct ttm_buffer_object *bo)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct amdgpu_bo *abo;
6078c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *bo_base;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (!amdgpu_bo_is_amdgpu_bo(bo))
6108c2ecf20Sopenharmony_ci		return;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (bo->mem.placement & TTM_PL_FLAG_NO_EVICT)
6138c2ecf20Sopenharmony_ci		return;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	abo = ttm_to_amdgpu_bo(bo);
6168c2ecf20Sopenharmony_ci	if (!abo->parent)
6178c2ecf20Sopenharmony_ci		return;
6188c2ecf20Sopenharmony_ci	for (bo_base = abo->vm_bo; bo_base; bo_base = bo_base->next) {
6198c2ecf20Sopenharmony_ci		struct amdgpu_vm *vm = bo_base->vm;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		if (abo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
6228c2ecf20Sopenharmony_ci			vm->bulk_moveable = false;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci/**
6278c2ecf20Sopenharmony_ci * amdgpu_vm_move_to_lru_tail - move all BOs to the end of LRU
6288c2ecf20Sopenharmony_ci *
6298c2ecf20Sopenharmony_ci * @adev: amdgpu device pointer
6308c2ecf20Sopenharmony_ci * @vm: vm providing the BOs
6318c2ecf20Sopenharmony_ci *
6328c2ecf20Sopenharmony_ci * Move all BOs to the end of LRU and remember their positions to put them
6338c2ecf20Sopenharmony_ci * together.
6348c2ecf20Sopenharmony_ci */
6358c2ecf20Sopenharmony_civoid amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
6368c2ecf20Sopenharmony_ci				struct amdgpu_vm *vm)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *bo_base;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	if (vm->bulk_moveable) {
6418c2ecf20Sopenharmony_ci		spin_lock(&ttm_bo_glob.lru_lock);
6428c2ecf20Sopenharmony_ci		ttm_bo_bulk_move_lru_tail(&vm->lru_bulk_move);
6438c2ecf20Sopenharmony_ci		spin_unlock(&ttm_bo_glob.lru_lock);
6448c2ecf20Sopenharmony_ci		return;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	memset(&vm->lru_bulk_move, 0, sizeof(vm->lru_bulk_move));
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	spin_lock(&ttm_bo_glob.lru_lock);
6508c2ecf20Sopenharmony_ci	list_for_each_entry(bo_base, &vm->idle, vm_status) {
6518c2ecf20Sopenharmony_ci		struct amdgpu_bo *bo = bo_base->bo;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		if (!bo->parent)
6548c2ecf20Sopenharmony_ci			continue;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci		ttm_bo_move_to_lru_tail(&bo->tbo, &vm->lru_bulk_move);
6578c2ecf20Sopenharmony_ci		if (bo->shadow)
6588c2ecf20Sopenharmony_ci			ttm_bo_move_to_lru_tail(&bo->shadow->tbo,
6598c2ecf20Sopenharmony_ci						&vm->lru_bulk_move);
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci	spin_unlock(&ttm_bo_glob.lru_lock);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	vm->bulk_moveable = true;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci/**
6678c2ecf20Sopenharmony_ci * amdgpu_vm_validate_pt_bos - validate the page table BOs
6688c2ecf20Sopenharmony_ci *
6698c2ecf20Sopenharmony_ci * @adev: amdgpu device pointer
6708c2ecf20Sopenharmony_ci * @vm: vm providing the BOs
6718c2ecf20Sopenharmony_ci * @validate: callback to do the validation
6728c2ecf20Sopenharmony_ci * @param: parameter for the validation callback
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * Validate the page table BOs on command submission if neccessary.
6758c2ecf20Sopenharmony_ci *
6768c2ecf20Sopenharmony_ci * Returns:
6778c2ecf20Sopenharmony_ci * Validation result.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_ciint amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
6808c2ecf20Sopenharmony_ci			      int (*validate)(void *p, struct amdgpu_bo *bo),
6818c2ecf20Sopenharmony_ci			      void *param)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *bo_base, *tmp;
6848c2ecf20Sopenharmony_ci	int r;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	vm->bulk_moveable &= list_empty(&vm->evicted);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	list_for_each_entry_safe(bo_base, tmp, &vm->evicted, vm_status) {
6898c2ecf20Sopenharmony_ci		struct amdgpu_bo *bo = bo_base->bo;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		r = validate(param, bo);
6928c2ecf20Sopenharmony_ci		if (r)
6938c2ecf20Sopenharmony_ci			return r;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		if (bo->tbo.type != ttm_bo_type_kernel) {
6968c2ecf20Sopenharmony_ci			amdgpu_vm_bo_moved(bo_base);
6978c2ecf20Sopenharmony_ci		} else {
6988c2ecf20Sopenharmony_ci			vm->update_funcs->map_table(bo);
6998c2ecf20Sopenharmony_ci			amdgpu_vm_bo_relocated(bo_base);
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_lock(vm);
7048c2ecf20Sopenharmony_ci	vm->evicting = false;
7058c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_unlock(vm);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	return 0;
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci/**
7118c2ecf20Sopenharmony_ci * amdgpu_vm_ready - check VM is ready for updates
7128c2ecf20Sopenharmony_ci *
7138c2ecf20Sopenharmony_ci * @vm: VM to check
7148c2ecf20Sopenharmony_ci *
7158c2ecf20Sopenharmony_ci * Check if all VM PDs/PTs are ready for updates
7168c2ecf20Sopenharmony_ci *
7178c2ecf20Sopenharmony_ci * Returns:
7188c2ecf20Sopenharmony_ci * True if VM is not evicting.
7198c2ecf20Sopenharmony_ci */
7208c2ecf20Sopenharmony_cibool amdgpu_vm_ready(struct amdgpu_vm *vm)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	bool ret;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_lock(vm);
7258c2ecf20Sopenharmony_ci	ret = !vm->evicting;
7268c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_unlock(vm);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return ret && list_empty(&vm->evicted);
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci/**
7328c2ecf20Sopenharmony_ci * amdgpu_vm_clear_bo - initially clear the PDs/PTs
7338c2ecf20Sopenharmony_ci *
7348c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
7358c2ecf20Sopenharmony_ci * @vm: VM to clear BO from
7368c2ecf20Sopenharmony_ci * @bo: BO to clear
7378c2ecf20Sopenharmony_ci * @immediate: use an immediate update
7388c2ecf20Sopenharmony_ci *
7398c2ecf20Sopenharmony_ci * Root PD needs to be reserved when calling this.
7408c2ecf20Sopenharmony_ci *
7418c2ecf20Sopenharmony_ci * Returns:
7428c2ecf20Sopenharmony_ci * 0 on success, errno otherwise.
7438c2ecf20Sopenharmony_ci */
7448c2ecf20Sopenharmony_cistatic int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
7458c2ecf20Sopenharmony_ci			      struct amdgpu_vm *vm,
7468c2ecf20Sopenharmony_ci			      struct amdgpu_bo *bo,
7478c2ecf20Sopenharmony_ci			      bool immediate)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { true, false };
7508c2ecf20Sopenharmony_ci	unsigned level = adev->vm_manager.root_level;
7518c2ecf20Sopenharmony_ci	struct amdgpu_vm_update_params params;
7528c2ecf20Sopenharmony_ci	struct amdgpu_bo *ancestor = bo;
7538c2ecf20Sopenharmony_ci	unsigned entries, ats_entries;
7548c2ecf20Sopenharmony_ci	uint64_t addr;
7558c2ecf20Sopenharmony_ci	int r;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* Figure out our place in the hierarchy */
7588c2ecf20Sopenharmony_ci	if (ancestor->parent) {
7598c2ecf20Sopenharmony_ci		++level;
7608c2ecf20Sopenharmony_ci		while (ancestor->parent->parent) {
7618c2ecf20Sopenharmony_ci			++level;
7628c2ecf20Sopenharmony_ci			ancestor = ancestor->parent;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	entries = amdgpu_bo_size(bo) / 8;
7678c2ecf20Sopenharmony_ci	if (!vm->pte_support_ats) {
7688c2ecf20Sopenharmony_ci		ats_entries = 0;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	} else if (!bo->parent) {
7718c2ecf20Sopenharmony_ci		ats_entries = amdgpu_vm_num_ats_entries(adev);
7728c2ecf20Sopenharmony_ci		ats_entries = min(ats_entries, entries);
7738c2ecf20Sopenharmony_ci		entries -= ats_entries;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	} else {
7768c2ecf20Sopenharmony_ci		struct amdgpu_vm_pt *pt;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		pt = container_of(ancestor->vm_bo, struct amdgpu_vm_pt, base);
7798c2ecf20Sopenharmony_ci		ats_entries = amdgpu_vm_num_ats_entries(adev);
7808c2ecf20Sopenharmony_ci		if ((pt - vm->root.entries) >= ats_entries) {
7818c2ecf20Sopenharmony_ci			ats_entries = 0;
7828c2ecf20Sopenharmony_ci		} else {
7838c2ecf20Sopenharmony_ci			ats_entries = entries;
7848c2ecf20Sopenharmony_ci			entries = 0;
7858c2ecf20Sopenharmony_ci		}
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
7898c2ecf20Sopenharmony_ci	if (r)
7908c2ecf20Sopenharmony_ci		return r;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (bo->shadow) {
7938c2ecf20Sopenharmony_ci		r = ttm_bo_validate(&bo->shadow->tbo, &bo->shadow->placement,
7948c2ecf20Sopenharmony_ci				    &ctx);
7958c2ecf20Sopenharmony_ci		if (r)
7968c2ecf20Sopenharmony_ci			return r;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	r = vm->update_funcs->map_table(bo);
8008c2ecf20Sopenharmony_ci	if (r)
8018c2ecf20Sopenharmony_ci		return r;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
8048c2ecf20Sopenharmony_ci	params.adev = adev;
8058c2ecf20Sopenharmony_ci	params.vm = vm;
8068c2ecf20Sopenharmony_ci	params.immediate = immediate;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	r = vm->update_funcs->prepare(&params, NULL, AMDGPU_SYNC_EXPLICIT);
8098c2ecf20Sopenharmony_ci	if (r)
8108c2ecf20Sopenharmony_ci		return r;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	addr = 0;
8138c2ecf20Sopenharmony_ci	if (ats_entries) {
8148c2ecf20Sopenharmony_ci		uint64_t value = 0, flags;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		flags = AMDGPU_PTE_DEFAULT_ATC;
8178c2ecf20Sopenharmony_ci		if (level != AMDGPU_VM_PTB) {
8188c2ecf20Sopenharmony_ci			/* Handle leaf PDEs as PTEs */
8198c2ecf20Sopenharmony_ci			flags |= AMDGPU_PDE_PTE;
8208c2ecf20Sopenharmony_ci			amdgpu_gmc_get_vm_pde(adev, level, &value, &flags);
8218c2ecf20Sopenharmony_ci		}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci		r = vm->update_funcs->update(&params, bo, addr, 0, ats_entries,
8248c2ecf20Sopenharmony_ci					     value, flags);
8258c2ecf20Sopenharmony_ci		if (r)
8268c2ecf20Sopenharmony_ci			return r;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		addr += ats_entries * 8;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (entries) {
8328c2ecf20Sopenharmony_ci		uint64_t value = 0, flags = 0;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci		if (adev->asic_type >= CHIP_VEGA10) {
8358c2ecf20Sopenharmony_ci			if (level != AMDGPU_VM_PTB) {
8368c2ecf20Sopenharmony_ci				/* Handle leaf PDEs as PTEs */
8378c2ecf20Sopenharmony_ci				flags |= AMDGPU_PDE_PTE;
8388c2ecf20Sopenharmony_ci				amdgpu_gmc_get_vm_pde(adev, level,
8398c2ecf20Sopenharmony_ci						      &value, &flags);
8408c2ecf20Sopenharmony_ci			} else {
8418c2ecf20Sopenharmony_ci				/* Workaround for fault priority problem on GMC9 */
8428c2ecf20Sopenharmony_ci				flags = AMDGPU_PTE_EXECUTABLE;
8438c2ecf20Sopenharmony_ci			}
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		r = vm->update_funcs->update(&params, bo, addr, 0, entries,
8478c2ecf20Sopenharmony_ci					     value, flags);
8488c2ecf20Sopenharmony_ci		if (r)
8498c2ecf20Sopenharmony_ci			return r;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	return vm->update_funcs->commit(&params, NULL);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/**
8568c2ecf20Sopenharmony_ci * amdgpu_vm_bo_param - fill in parameters for PD/PT allocation
8578c2ecf20Sopenharmony_ci *
8588c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
8598c2ecf20Sopenharmony_ci * @vm: requesting vm
8608c2ecf20Sopenharmony_ci * @level: the page table level
8618c2ecf20Sopenharmony_ci * @immediate: use a immediate update
8628c2ecf20Sopenharmony_ci * @bp: resulting BO allocation parameters
8638c2ecf20Sopenharmony_ci */
8648c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_param(struct amdgpu_device *adev, struct amdgpu_vm *vm,
8658c2ecf20Sopenharmony_ci			       int level, bool immediate,
8668c2ecf20Sopenharmony_ci			       struct amdgpu_bo_param *bp)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	memset(bp, 0, sizeof(*bp));
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	bp->size = amdgpu_vm_bo_size(adev, level);
8718c2ecf20Sopenharmony_ci	bp->byte_align = AMDGPU_GPU_PAGE_SIZE;
8728c2ecf20Sopenharmony_ci	bp->domain = AMDGPU_GEM_DOMAIN_VRAM;
8738c2ecf20Sopenharmony_ci	bp->domain = amdgpu_bo_get_preferred_pin_domain(adev, bp->domain);
8748c2ecf20Sopenharmony_ci	bp->flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
8758c2ecf20Sopenharmony_ci		AMDGPU_GEM_CREATE_CPU_GTT_USWC;
8768c2ecf20Sopenharmony_ci	if (vm->use_cpu_for_update)
8778c2ecf20Sopenharmony_ci		bp->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
8788c2ecf20Sopenharmony_ci	else if (!vm->root.base.bo || vm->root.base.bo->shadow)
8798c2ecf20Sopenharmony_ci		bp->flags |= AMDGPU_GEM_CREATE_SHADOW;
8808c2ecf20Sopenharmony_ci	bp->type = ttm_bo_type_kernel;
8818c2ecf20Sopenharmony_ci	bp->no_wait_gpu = immediate;
8828c2ecf20Sopenharmony_ci	if (vm->root.base.bo)
8838c2ecf20Sopenharmony_ci		bp->resv = vm->root.base.bo->tbo.base.resv;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci/**
8878c2ecf20Sopenharmony_ci * amdgpu_vm_alloc_pts - Allocate a specific page table
8888c2ecf20Sopenharmony_ci *
8898c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
8908c2ecf20Sopenharmony_ci * @vm: VM to allocate page tables for
8918c2ecf20Sopenharmony_ci * @cursor: Which page table to allocate
8928c2ecf20Sopenharmony_ci * @immediate: use an immediate update
8938c2ecf20Sopenharmony_ci *
8948c2ecf20Sopenharmony_ci * Make sure a specific page table or directory is allocated.
8958c2ecf20Sopenharmony_ci *
8968c2ecf20Sopenharmony_ci * Returns:
8978c2ecf20Sopenharmony_ci * 1 if page table needed to be allocated, 0 if page table was already
8988c2ecf20Sopenharmony_ci * allocated, negative errno if an error occurred.
8998c2ecf20Sopenharmony_ci */
9008c2ecf20Sopenharmony_cistatic int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
9018c2ecf20Sopenharmony_ci			       struct amdgpu_vm *vm,
9028c2ecf20Sopenharmony_ci			       struct amdgpu_vm_pt_cursor *cursor,
9038c2ecf20Sopenharmony_ci			       bool immediate)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *entry = cursor->entry;
9068c2ecf20Sopenharmony_ci	struct amdgpu_bo_param bp;
9078c2ecf20Sopenharmony_ci	struct amdgpu_bo *pt;
9088c2ecf20Sopenharmony_ci	int r;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (cursor->level < AMDGPU_VM_PTB && !entry->entries) {
9118c2ecf20Sopenharmony_ci		unsigned num_entries;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci		num_entries = amdgpu_vm_num_entries(adev, cursor->level);
9148c2ecf20Sopenharmony_ci		entry->entries = kvmalloc_array(num_entries,
9158c2ecf20Sopenharmony_ci						sizeof(*entry->entries),
9168c2ecf20Sopenharmony_ci						GFP_KERNEL | __GFP_ZERO);
9178c2ecf20Sopenharmony_ci		if (!entry->entries)
9188c2ecf20Sopenharmony_ci			return -ENOMEM;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (entry->base.bo)
9228c2ecf20Sopenharmony_ci		return 0;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	amdgpu_vm_bo_param(adev, vm, cursor->level, immediate, &bp);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	r = amdgpu_bo_create(adev, &bp, &pt);
9278c2ecf20Sopenharmony_ci	if (r)
9288c2ecf20Sopenharmony_ci		return r;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	/* Keep a reference to the root directory to avoid
9318c2ecf20Sopenharmony_ci	 * freeing them up in the wrong order.
9328c2ecf20Sopenharmony_ci	 */
9338c2ecf20Sopenharmony_ci	pt->parent = amdgpu_bo_ref(cursor->parent->base.bo);
9348c2ecf20Sopenharmony_ci	amdgpu_vm_bo_base_init(&entry->base, vm, pt);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	r = amdgpu_vm_clear_bo(adev, vm, pt, immediate);
9378c2ecf20Sopenharmony_ci	if (r)
9388c2ecf20Sopenharmony_ci		goto error_free_pt;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	return 0;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cierror_free_pt:
9438c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&pt->shadow);
9448c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&pt);
9458c2ecf20Sopenharmony_ci	return r;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci/**
9498c2ecf20Sopenharmony_ci * amdgpu_vm_free_table - fre one PD/PT
9508c2ecf20Sopenharmony_ci *
9518c2ecf20Sopenharmony_ci * @entry: PDE to free
9528c2ecf20Sopenharmony_ci */
9538c2ecf20Sopenharmony_cistatic void amdgpu_vm_free_table(struct amdgpu_vm_pt *entry)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	if (entry->base.bo) {
9568c2ecf20Sopenharmony_ci		entry->base.bo->vm_bo = NULL;
9578c2ecf20Sopenharmony_ci		list_del(&entry->base.vm_status);
9588c2ecf20Sopenharmony_ci		amdgpu_bo_unref(&entry->base.bo->shadow);
9598c2ecf20Sopenharmony_ci		amdgpu_bo_unref(&entry->base.bo);
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci	kvfree(entry->entries);
9628c2ecf20Sopenharmony_ci	entry->entries = NULL;
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci/**
9668c2ecf20Sopenharmony_ci * amdgpu_vm_free_pts - free PD/PT levels
9678c2ecf20Sopenharmony_ci *
9688c2ecf20Sopenharmony_ci * @adev: amdgpu device structure
9698c2ecf20Sopenharmony_ci * @vm: amdgpu vm structure
9708c2ecf20Sopenharmony_ci * @start: optional cursor where to start freeing PDs/PTs
9718c2ecf20Sopenharmony_ci *
9728c2ecf20Sopenharmony_ci * Free the page directory or page table level and all sub levels.
9738c2ecf20Sopenharmony_ci */
9748c2ecf20Sopenharmony_cistatic void amdgpu_vm_free_pts(struct amdgpu_device *adev,
9758c2ecf20Sopenharmony_ci			       struct amdgpu_vm *vm,
9768c2ecf20Sopenharmony_ci			       struct amdgpu_vm_pt_cursor *start)
9778c2ecf20Sopenharmony_ci{
9788c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt_cursor cursor;
9798c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *entry;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	vm->bulk_moveable = false;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)
9848c2ecf20Sopenharmony_ci		amdgpu_vm_free_table(entry);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (start)
9878c2ecf20Sopenharmony_ci		amdgpu_vm_free_table(start->entry);
9888c2ecf20Sopenharmony_ci}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci/**
9918c2ecf20Sopenharmony_ci * amdgpu_vm_check_compute_bug - check whether asic has compute vm bug
9928c2ecf20Sopenharmony_ci *
9938c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
9948c2ecf20Sopenharmony_ci */
9958c2ecf20Sopenharmony_civoid amdgpu_vm_check_compute_bug(struct amdgpu_device *adev)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	const struct amdgpu_ip_block *ip_block;
9988c2ecf20Sopenharmony_ci	bool has_compute_vm_bug;
9998c2ecf20Sopenharmony_ci	struct amdgpu_ring *ring;
10008c2ecf20Sopenharmony_ci	int i;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	has_compute_vm_bug = false;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GFX);
10058c2ecf20Sopenharmony_ci	if (ip_block) {
10068c2ecf20Sopenharmony_ci		/* Compute has a VM bug for GFX version < 7.
10078c2ecf20Sopenharmony_ci		   Compute has a VM bug for GFX 8 MEC firmware version < 673.*/
10088c2ecf20Sopenharmony_ci		if (ip_block->version->major <= 7)
10098c2ecf20Sopenharmony_ci			has_compute_vm_bug = true;
10108c2ecf20Sopenharmony_ci		else if (ip_block->version->major == 8)
10118c2ecf20Sopenharmony_ci			if (adev->gfx.mec_fw_version < 673)
10128c2ecf20Sopenharmony_ci				has_compute_vm_bug = true;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	for (i = 0; i < adev->num_rings; i++) {
10168c2ecf20Sopenharmony_ci		ring = adev->rings[i];
10178c2ecf20Sopenharmony_ci		if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE)
10188c2ecf20Sopenharmony_ci			/* only compute rings */
10198c2ecf20Sopenharmony_ci			ring->has_compute_vm_bug = has_compute_vm_bug;
10208c2ecf20Sopenharmony_ci		else
10218c2ecf20Sopenharmony_ci			ring->has_compute_vm_bug = false;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci/**
10268c2ecf20Sopenharmony_ci * amdgpu_vm_need_pipeline_sync - Check if pipe sync is needed for job.
10278c2ecf20Sopenharmony_ci *
10288c2ecf20Sopenharmony_ci * @ring: ring on which the job will be submitted
10298c2ecf20Sopenharmony_ci * @job: job to submit
10308c2ecf20Sopenharmony_ci *
10318c2ecf20Sopenharmony_ci * Returns:
10328c2ecf20Sopenharmony_ci * True if sync is needed.
10338c2ecf20Sopenharmony_ci */
10348c2ecf20Sopenharmony_cibool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
10358c2ecf20Sopenharmony_ci				  struct amdgpu_job *job)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
10388c2ecf20Sopenharmony_ci	unsigned vmhub = ring->funcs->vmhub;
10398c2ecf20Sopenharmony_ci	struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
10408c2ecf20Sopenharmony_ci	struct amdgpu_vmid *id;
10418c2ecf20Sopenharmony_ci	bool gds_switch_needed;
10428c2ecf20Sopenharmony_ci	bool vm_flush_needed = job->vm_needs_flush || ring->has_compute_vm_bug;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (job->vmid == 0)
10458c2ecf20Sopenharmony_ci		return false;
10468c2ecf20Sopenharmony_ci	id = &id_mgr->ids[job->vmid];
10478c2ecf20Sopenharmony_ci	gds_switch_needed = ring->funcs->emit_gds_switch && (
10488c2ecf20Sopenharmony_ci		id->gds_base != job->gds_base ||
10498c2ecf20Sopenharmony_ci		id->gds_size != job->gds_size ||
10508c2ecf20Sopenharmony_ci		id->gws_base != job->gws_base ||
10518c2ecf20Sopenharmony_ci		id->gws_size != job->gws_size ||
10528c2ecf20Sopenharmony_ci		id->oa_base != job->oa_base ||
10538c2ecf20Sopenharmony_ci		id->oa_size != job->oa_size);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (amdgpu_vmid_had_gpu_reset(adev, id))
10568c2ecf20Sopenharmony_ci		return true;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return vm_flush_needed || gds_switch_needed;
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/**
10628c2ecf20Sopenharmony_ci * amdgpu_vm_flush - hardware flush the vm
10638c2ecf20Sopenharmony_ci *
10648c2ecf20Sopenharmony_ci * @ring: ring to use for flush
10658c2ecf20Sopenharmony_ci * @job:  related job
10668c2ecf20Sopenharmony_ci * @need_pipe_sync: is pipe sync needed
10678c2ecf20Sopenharmony_ci *
10688c2ecf20Sopenharmony_ci * Emit a VM flush when it is necessary.
10698c2ecf20Sopenharmony_ci *
10708c2ecf20Sopenharmony_ci * Returns:
10718c2ecf20Sopenharmony_ci * 0 on success, errno otherwise.
10728c2ecf20Sopenharmony_ci */
10738c2ecf20Sopenharmony_ciint amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
10748c2ecf20Sopenharmony_ci		    bool need_pipe_sync)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
10778c2ecf20Sopenharmony_ci	unsigned vmhub = ring->funcs->vmhub;
10788c2ecf20Sopenharmony_ci	struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
10798c2ecf20Sopenharmony_ci	struct amdgpu_vmid *id = &id_mgr->ids[job->vmid];
10808c2ecf20Sopenharmony_ci	bool gds_switch_needed = ring->funcs->emit_gds_switch && (
10818c2ecf20Sopenharmony_ci		id->gds_base != job->gds_base ||
10828c2ecf20Sopenharmony_ci		id->gds_size != job->gds_size ||
10838c2ecf20Sopenharmony_ci		id->gws_base != job->gws_base ||
10848c2ecf20Sopenharmony_ci		id->gws_size != job->gws_size ||
10858c2ecf20Sopenharmony_ci		id->oa_base != job->oa_base ||
10868c2ecf20Sopenharmony_ci		id->oa_size != job->oa_size);
10878c2ecf20Sopenharmony_ci	bool vm_flush_needed = job->vm_needs_flush;
10888c2ecf20Sopenharmony_ci	struct dma_fence *fence = NULL;
10898c2ecf20Sopenharmony_ci	bool pasid_mapping_needed = false;
10908c2ecf20Sopenharmony_ci	unsigned patch_offset = 0;
10918c2ecf20Sopenharmony_ci	bool update_spm_vmid_needed = (job->vm && (job->vm->reserved_vmid[vmhub] != NULL));
10928c2ecf20Sopenharmony_ci	int r;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (update_spm_vmid_needed && adev->gfx.rlc.funcs->update_spm_vmid)
10958c2ecf20Sopenharmony_ci		adev->gfx.rlc.funcs->update_spm_vmid(adev, job->vmid);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (amdgpu_vmid_had_gpu_reset(adev, id)) {
10988c2ecf20Sopenharmony_ci		gds_switch_needed = true;
10998c2ecf20Sopenharmony_ci		vm_flush_needed = true;
11008c2ecf20Sopenharmony_ci		pasid_mapping_needed = true;
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	mutex_lock(&id_mgr->lock);
11048c2ecf20Sopenharmony_ci	if (id->pasid != job->pasid || !id->pasid_mapping ||
11058c2ecf20Sopenharmony_ci	    !dma_fence_is_signaled(id->pasid_mapping))
11068c2ecf20Sopenharmony_ci		pasid_mapping_needed = true;
11078c2ecf20Sopenharmony_ci	mutex_unlock(&id_mgr->lock);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	gds_switch_needed &= !!ring->funcs->emit_gds_switch;
11108c2ecf20Sopenharmony_ci	vm_flush_needed &= !!ring->funcs->emit_vm_flush  &&
11118c2ecf20Sopenharmony_ci			job->vm_pd_addr != AMDGPU_BO_INVALID_OFFSET;
11128c2ecf20Sopenharmony_ci	pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping &&
11138c2ecf20Sopenharmony_ci		ring->funcs->emit_wreg;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync)
11168c2ecf20Sopenharmony_ci		return 0;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (ring->funcs->init_cond_exec)
11198c2ecf20Sopenharmony_ci		patch_offset = amdgpu_ring_init_cond_exec(ring);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (need_pipe_sync)
11228c2ecf20Sopenharmony_ci		amdgpu_ring_emit_pipeline_sync(ring);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (vm_flush_needed) {
11258c2ecf20Sopenharmony_ci		trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr);
11268c2ecf20Sopenharmony_ci		amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr);
11278c2ecf20Sopenharmony_ci	}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	if (pasid_mapping_needed)
11308c2ecf20Sopenharmony_ci		amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid);
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	if (vm_flush_needed || pasid_mapping_needed) {
11338c2ecf20Sopenharmony_ci		r = amdgpu_fence_emit(ring, &fence, 0);
11348c2ecf20Sopenharmony_ci		if (r)
11358c2ecf20Sopenharmony_ci			return r;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	if (vm_flush_needed) {
11398c2ecf20Sopenharmony_ci		mutex_lock(&id_mgr->lock);
11408c2ecf20Sopenharmony_ci		dma_fence_put(id->last_flush);
11418c2ecf20Sopenharmony_ci		id->last_flush = dma_fence_get(fence);
11428c2ecf20Sopenharmony_ci		id->current_gpu_reset_count =
11438c2ecf20Sopenharmony_ci			atomic_read(&adev->gpu_reset_counter);
11448c2ecf20Sopenharmony_ci		mutex_unlock(&id_mgr->lock);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (pasid_mapping_needed) {
11488c2ecf20Sopenharmony_ci		mutex_lock(&id_mgr->lock);
11498c2ecf20Sopenharmony_ci		id->pasid = job->pasid;
11508c2ecf20Sopenharmony_ci		dma_fence_put(id->pasid_mapping);
11518c2ecf20Sopenharmony_ci		id->pasid_mapping = dma_fence_get(fence);
11528c2ecf20Sopenharmony_ci		mutex_unlock(&id_mgr->lock);
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci	dma_fence_put(fence);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (ring->funcs->emit_gds_switch && gds_switch_needed) {
11578c2ecf20Sopenharmony_ci		id->gds_base = job->gds_base;
11588c2ecf20Sopenharmony_ci		id->gds_size = job->gds_size;
11598c2ecf20Sopenharmony_ci		id->gws_base = job->gws_base;
11608c2ecf20Sopenharmony_ci		id->gws_size = job->gws_size;
11618c2ecf20Sopenharmony_ci		id->oa_base = job->oa_base;
11628c2ecf20Sopenharmony_ci		id->oa_size = job->oa_size;
11638c2ecf20Sopenharmony_ci		amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
11648c2ecf20Sopenharmony_ci					    job->gds_size, job->gws_base,
11658c2ecf20Sopenharmony_ci					    job->gws_size, job->oa_base,
11668c2ecf20Sopenharmony_ci					    job->oa_size);
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (ring->funcs->patch_cond_exec)
11708c2ecf20Sopenharmony_ci		amdgpu_ring_patch_cond_exec(ring, patch_offset);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	/* the double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC */
11738c2ecf20Sopenharmony_ci	if (ring->funcs->emit_switch_buffer) {
11748c2ecf20Sopenharmony_ci		amdgpu_ring_emit_switch_buffer(ring);
11758c2ecf20Sopenharmony_ci		amdgpu_ring_emit_switch_buffer(ring);
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci	return 0;
11788c2ecf20Sopenharmony_ci}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci/**
11818c2ecf20Sopenharmony_ci * amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
11828c2ecf20Sopenharmony_ci *
11838c2ecf20Sopenharmony_ci * @vm: requested vm
11848c2ecf20Sopenharmony_ci * @bo: requested buffer object
11858c2ecf20Sopenharmony_ci *
11868c2ecf20Sopenharmony_ci * Find @bo inside the requested vm.
11878c2ecf20Sopenharmony_ci * Search inside the @bos vm list for the requested vm
11888c2ecf20Sopenharmony_ci * Returns the found bo_va or NULL if none is found
11898c2ecf20Sopenharmony_ci *
11908c2ecf20Sopenharmony_ci * Object has to be reserved!
11918c2ecf20Sopenharmony_ci *
11928c2ecf20Sopenharmony_ci * Returns:
11938c2ecf20Sopenharmony_ci * Found bo_va or NULL.
11948c2ecf20Sopenharmony_ci */
11958c2ecf20Sopenharmony_cistruct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
11968c2ecf20Sopenharmony_ci				       struct amdgpu_bo *bo)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *base;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	for (base = bo->vm_bo; base; base = base->next) {
12018c2ecf20Sopenharmony_ci		if (base->vm != vm)
12028c2ecf20Sopenharmony_ci			continue;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		return container_of(base, struct amdgpu_bo_va, base);
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci	return NULL;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci/**
12108c2ecf20Sopenharmony_ci * amdgpu_vm_map_gart - Resolve gart mapping of addr
12118c2ecf20Sopenharmony_ci *
12128c2ecf20Sopenharmony_ci * @pages_addr: optional DMA address to use for lookup
12138c2ecf20Sopenharmony_ci * @addr: the unmapped addr
12148c2ecf20Sopenharmony_ci *
12158c2ecf20Sopenharmony_ci * Look up the physical address of the page that the pte resolves
12168c2ecf20Sopenharmony_ci * to.
12178c2ecf20Sopenharmony_ci *
12188c2ecf20Sopenharmony_ci * Returns:
12198c2ecf20Sopenharmony_ci * The pointer for the page table entry.
12208c2ecf20Sopenharmony_ci */
12218c2ecf20Sopenharmony_ciuint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	uint64_t result;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	/* page table offset */
12268c2ecf20Sopenharmony_ci	result = pages_addr[addr >> PAGE_SHIFT];
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* in case cpu page size != gpu page size*/
12298c2ecf20Sopenharmony_ci	result |= addr & (~PAGE_MASK);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	result &= 0xFFFFFFFFFFFFF000ULL;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	return result;
12348c2ecf20Sopenharmony_ci}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci/**
12378c2ecf20Sopenharmony_ci * amdgpu_vm_update_pde - update a single level in the hierarchy
12388c2ecf20Sopenharmony_ci *
12398c2ecf20Sopenharmony_ci * @params: parameters for the update
12408c2ecf20Sopenharmony_ci * @vm: requested vm
12418c2ecf20Sopenharmony_ci * @entry: entry to update
12428c2ecf20Sopenharmony_ci *
12438c2ecf20Sopenharmony_ci * Makes sure the requested entry in parent is up to date.
12448c2ecf20Sopenharmony_ci */
12458c2ecf20Sopenharmony_cistatic int amdgpu_vm_update_pde(struct amdgpu_vm_update_params *params,
12468c2ecf20Sopenharmony_ci				struct amdgpu_vm *vm,
12478c2ecf20Sopenharmony_ci				struct amdgpu_vm_pt *entry)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *parent = amdgpu_vm_pt_parent(entry);
12508c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = parent->base.bo, *pbo;
12518c2ecf20Sopenharmony_ci	uint64_t pde, pt, flags;
12528c2ecf20Sopenharmony_ci	unsigned level;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	for (level = 0, pbo = bo->parent; pbo; ++level)
12558c2ecf20Sopenharmony_ci		pbo = pbo->parent;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	level += params->adev->vm_manager.root_level;
12588c2ecf20Sopenharmony_ci	amdgpu_gmc_get_pde_for_bo(entry->base.bo, level, &pt, &flags);
12598c2ecf20Sopenharmony_ci	pde = (entry - parent->entries) * 8;
12608c2ecf20Sopenharmony_ci	return vm->update_funcs->update(params, bo, pde, pt, 1, 0, flags);
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci/**
12648c2ecf20Sopenharmony_ci * amdgpu_vm_invalidate_pds - mark all PDs as invalid
12658c2ecf20Sopenharmony_ci *
12668c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
12678c2ecf20Sopenharmony_ci * @vm: related vm
12688c2ecf20Sopenharmony_ci *
12698c2ecf20Sopenharmony_ci * Mark all PD level as invalid after an error.
12708c2ecf20Sopenharmony_ci */
12718c2ecf20Sopenharmony_cistatic void amdgpu_vm_invalidate_pds(struct amdgpu_device *adev,
12728c2ecf20Sopenharmony_ci				     struct amdgpu_vm *vm)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt_cursor cursor;
12758c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt *entry;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, NULL, cursor, entry)
12788c2ecf20Sopenharmony_ci		if (entry->base.bo && !entry->base.moved)
12798c2ecf20Sopenharmony_ci			amdgpu_vm_bo_relocated(&entry->base);
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci/**
12838c2ecf20Sopenharmony_ci * amdgpu_vm_update_pdes - make sure that all directories are valid
12848c2ecf20Sopenharmony_ci *
12858c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
12868c2ecf20Sopenharmony_ci * @vm: requested vm
12878c2ecf20Sopenharmony_ci * @immediate: submit immediately to the paging queue
12888c2ecf20Sopenharmony_ci *
12898c2ecf20Sopenharmony_ci * Makes sure all directories are up to date.
12908c2ecf20Sopenharmony_ci *
12918c2ecf20Sopenharmony_ci * Returns:
12928c2ecf20Sopenharmony_ci * 0 for success, error for failure.
12938c2ecf20Sopenharmony_ci */
12948c2ecf20Sopenharmony_ciint amdgpu_vm_update_pdes(struct amdgpu_device *adev,
12958c2ecf20Sopenharmony_ci			  struct amdgpu_vm *vm, bool immediate)
12968c2ecf20Sopenharmony_ci{
12978c2ecf20Sopenharmony_ci	struct amdgpu_vm_update_params params;
12988c2ecf20Sopenharmony_ci	int r;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (list_empty(&vm->relocated))
13018c2ecf20Sopenharmony_ci		return 0;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
13048c2ecf20Sopenharmony_ci	params.adev = adev;
13058c2ecf20Sopenharmony_ci	params.vm = vm;
13068c2ecf20Sopenharmony_ci	params.immediate = immediate;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	r = vm->update_funcs->prepare(&params, NULL, AMDGPU_SYNC_EXPLICIT);
13098c2ecf20Sopenharmony_ci	if (r)
13108c2ecf20Sopenharmony_ci		return r;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	while (!list_empty(&vm->relocated)) {
13138c2ecf20Sopenharmony_ci		struct amdgpu_vm_pt *entry;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		entry = list_first_entry(&vm->relocated, struct amdgpu_vm_pt,
13168c2ecf20Sopenharmony_ci					 base.vm_status);
13178c2ecf20Sopenharmony_ci		amdgpu_vm_bo_idle(&entry->base);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		r = amdgpu_vm_update_pde(&params, vm, entry);
13208c2ecf20Sopenharmony_ci		if (r)
13218c2ecf20Sopenharmony_ci			goto error;
13228c2ecf20Sopenharmony_ci	}
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	r = vm->update_funcs->commit(&params, &vm->last_update);
13258c2ecf20Sopenharmony_ci	if (r)
13268c2ecf20Sopenharmony_ci		goto error;
13278c2ecf20Sopenharmony_ci	return 0;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_cierror:
13308c2ecf20Sopenharmony_ci	amdgpu_vm_invalidate_pds(adev, vm);
13318c2ecf20Sopenharmony_ci	return r;
13328c2ecf20Sopenharmony_ci}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci/*
13358c2ecf20Sopenharmony_ci * amdgpu_vm_update_flags - figure out flags for PTE updates
13368c2ecf20Sopenharmony_ci *
13378c2ecf20Sopenharmony_ci * Make sure to set the right flags for the PTEs at the desired level.
13388c2ecf20Sopenharmony_ci */
13398c2ecf20Sopenharmony_cistatic void amdgpu_vm_update_flags(struct amdgpu_vm_update_params *params,
13408c2ecf20Sopenharmony_ci				   struct amdgpu_bo *bo, unsigned level,
13418c2ecf20Sopenharmony_ci				   uint64_t pe, uint64_t addr,
13428c2ecf20Sopenharmony_ci				   unsigned count, uint32_t incr,
13438c2ecf20Sopenharmony_ci				   uint64_t flags)
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	if (level != AMDGPU_VM_PTB) {
13478c2ecf20Sopenharmony_ci		flags |= AMDGPU_PDE_PTE;
13488c2ecf20Sopenharmony_ci		amdgpu_gmc_get_vm_pde(params->adev, level, &addr, &flags);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	} else if (params->adev->asic_type >= CHIP_VEGA10 &&
13518c2ecf20Sopenharmony_ci		   !(flags & AMDGPU_PTE_VALID) &&
13528c2ecf20Sopenharmony_ci		   !(flags & AMDGPU_PTE_PRT)) {
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci		/* Workaround for fault priority problem on GMC9 */
13558c2ecf20Sopenharmony_ci		flags |= AMDGPU_PTE_EXECUTABLE;
13568c2ecf20Sopenharmony_ci	}
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	params->vm->update_funcs->update(params, bo, pe, addr, count, incr,
13598c2ecf20Sopenharmony_ci					 flags);
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci/**
13638c2ecf20Sopenharmony_ci * amdgpu_vm_fragment - get fragment for PTEs
13648c2ecf20Sopenharmony_ci *
13658c2ecf20Sopenharmony_ci * @params: see amdgpu_vm_update_params definition
13668c2ecf20Sopenharmony_ci * @start: first PTE to handle
13678c2ecf20Sopenharmony_ci * @end: last PTE to handle
13688c2ecf20Sopenharmony_ci * @flags: hw mapping flags
13698c2ecf20Sopenharmony_ci * @frag: resulting fragment size
13708c2ecf20Sopenharmony_ci * @frag_end: end of this fragment
13718c2ecf20Sopenharmony_ci *
13728c2ecf20Sopenharmony_ci * Returns the first possible fragment for the start and end address.
13738c2ecf20Sopenharmony_ci */
13748c2ecf20Sopenharmony_cistatic void amdgpu_vm_fragment(struct amdgpu_vm_update_params *params,
13758c2ecf20Sopenharmony_ci			       uint64_t start, uint64_t end, uint64_t flags,
13768c2ecf20Sopenharmony_ci			       unsigned int *frag, uint64_t *frag_end)
13778c2ecf20Sopenharmony_ci{
13788c2ecf20Sopenharmony_ci	/**
13798c2ecf20Sopenharmony_ci	 * The MC L1 TLB supports variable sized pages, based on a fragment
13808c2ecf20Sopenharmony_ci	 * field in the PTE. When this field is set to a non-zero value, page
13818c2ecf20Sopenharmony_ci	 * granularity is increased from 4KB to (1 << (12 + frag)). The PTE
13828c2ecf20Sopenharmony_ci	 * flags are considered valid for all PTEs within the fragment range
13838c2ecf20Sopenharmony_ci	 * and corresponding mappings are assumed to be physically contiguous.
13848c2ecf20Sopenharmony_ci	 *
13858c2ecf20Sopenharmony_ci	 * The L1 TLB can store a single PTE for the whole fragment,
13868c2ecf20Sopenharmony_ci	 * significantly increasing the space available for translation
13878c2ecf20Sopenharmony_ci	 * caching. This leads to large improvements in throughput when the
13888c2ecf20Sopenharmony_ci	 * TLB is under pressure.
13898c2ecf20Sopenharmony_ci	 *
13908c2ecf20Sopenharmony_ci	 * The L2 TLB distributes small and large fragments into two
13918c2ecf20Sopenharmony_ci	 * asymmetric partitions. The large fragment cache is significantly
13928c2ecf20Sopenharmony_ci	 * larger. Thus, we try to use large fragments wherever possible.
13938c2ecf20Sopenharmony_ci	 * Userspace can support this by aligning virtual base address and
13948c2ecf20Sopenharmony_ci	 * allocation size to the fragment size.
13958c2ecf20Sopenharmony_ci	 *
13968c2ecf20Sopenharmony_ci	 * Starting with Vega10 the fragment size only controls the L1. The L2
13978c2ecf20Sopenharmony_ci	 * is now directly feed with small/huge/giant pages from the walker.
13988c2ecf20Sopenharmony_ci	 */
13998c2ecf20Sopenharmony_ci	unsigned max_frag;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	if (params->adev->asic_type < CHIP_VEGA10)
14028c2ecf20Sopenharmony_ci		max_frag = params->adev->vm_manager.fragment_size;
14038c2ecf20Sopenharmony_ci	else
14048c2ecf20Sopenharmony_ci		max_frag = 31;
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	/* system pages are non continuously */
14078c2ecf20Sopenharmony_ci	if (params->pages_addr) {
14088c2ecf20Sopenharmony_ci		*frag = 0;
14098c2ecf20Sopenharmony_ci		*frag_end = end;
14108c2ecf20Sopenharmony_ci		return;
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	/* This intentionally wraps around if no bit is set */
14148c2ecf20Sopenharmony_ci	*frag = min((unsigned)ffs(start) - 1, (unsigned)fls64(end - start) - 1);
14158c2ecf20Sopenharmony_ci	if (*frag >= max_frag) {
14168c2ecf20Sopenharmony_ci		*frag = max_frag;
14178c2ecf20Sopenharmony_ci		*frag_end = end & ~((1ULL << max_frag) - 1);
14188c2ecf20Sopenharmony_ci	} else {
14198c2ecf20Sopenharmony_ci		*frag_end = start + (1 << *frag);
14208c2ecf20Sopenharmony_ci	}
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci/**
14248c2ecf20Sopenharmony_ci * amdgpu_vm_update_ptes - make sure that page tables are valid
14258c2ecf20Sopenharmony_ci *
14268c2ecf20Sopenharmony_ci * @params: see amdgpu_vm_update_params definition
14278c2ecf20Sopenharmony_ci * @start: start of GPU address range
14288c2ecf20Sopenharmony_ci * @end: end of GPU address range
14298c2ecf20Sopenharmony_ci * @dst: destination address to map to, the next dst inside the function
14308c2ecf20Sopenharmony_ci * @flags: mapping flags
14318c2ecf20Sopenharmony_ci *
14328c2ecf20Sopenharmony_ci * Update the page tables in the range @start - @end.
14338c2ecf20Sopenharmony_ci *
14348c2ecf20Sopenharmony_ci * Returns:
14358c2ecf20Sopenharmony_ci * 0 for success, -EINVAL for failure.
14368c2ecf20Sopenharmony_ci */
14378c2ecf20Sopenharmony_cistatic int amdgpu_vm_update_ptes(struct amdgpu_vm_update_params *params,
14388c2ecf20Sopenharmony_ci				 uint64_t start, uint64_t end,
14398c2ecf20Sopenharmony_ci				 uint64_t dst, uint64_t flags)
14408c2ecf20Sopenharmony_ci{
14418c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = params->adev;
14428c2ecf20Sopenharmony_ci	struct amdgpu_vm_pt_cursor cursor;
14438c2ecf20Sopenharmony_ci	uint64_t frag_start = start, frag_end;
14448c2ecf20Sopenharmony_ci	unsigned int frag;
14458c2ecf20Sopenharmony_ci	int r;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	/* figure out the initial fragment */
14488c2ecf20Sopenharmony_ci	amdgpu_vm_fragment(params, frag_start, end, flags, &frag, &frag_end);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	/* walk over the address space and update the PTs */
14518c2ecf20Sopenharmony_ci	amdgpu_vm_pt_start(adev, params->vm, start, &cursor);
14528c2ecf20Sopenharmony_ci	while (cursor.pfn < end) {
14538c2ecf20Sopenharmony_ci		unsigned shift, parent_shift, mask;
14548c2ecf20Sopenharmony_ci		uint64_t incr, entry_end, pe_start;
14558c2ecf20Sopenharmony_ci		struct amdgpu_bo *pt;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci		if (!params->unlocked) {
14588c2ecf20Sopenharmony_ci			/* make sure that the page tables covering the
14598c2ecf20Sopenharmony_ci			 * address range are actually allocated
14608c2ecf20Sopenharmony_ci			 */
14618c2ecf20Sopenharmony_ci			r = amdgpu_vm_alloc_pts(params->adev, params->vm,
14628c2ecf20Sopenharmony_ci						&cursor, params->immediate);
14638c2ecf20Sopenharmony_ci			if (r)
14648c2ecf20Sopenharmony_ci				return r;
14658c2ecf20Sopenharmony_ci		}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		shift = amdgpu_vm_level_shift(adev, cursor.level);
14688c2ecf20Sopenharmony_ci		parent_shift = amdgpu_vm_level_shift(adev, cursor.level - 1);
14698c2ecf20Sopenharmony_ci		if (params->unlocked) {
14708c2ecf20Sopenharmony_ci			/* Unlocked updates are only allowed on the leaves */
14718c2ecf20Sopenharmony_ci			if (amdgpu_vm_pt_descendant(adev, &cursor))
14728c2ecf20Sopenharmony_ci				continue;
14738c2ecf20Sopenharmony_ci		} else if (adev->asic_type < CHIP_VEGA10 &&
14748c2ecf20Sopenharmony_ci			   (flags & AMDGPU_PTE_VALID)) {
14758c2ecf20Sopenharmony_ci			/* No huge page support before GMC v9 */
14768c2ecf20Sopenharmony_ci			if (cursor.level != AMDGPU_VM_PTB) {
14778c2ecf20Sopenharmony_ci				if (!amdgpu_vm_pt_descendant(adev, &cursor))
14788c2ecf20Sopenharmony_ci					return -ENOENT;
14798c2ecf20Sopenharmony_ci				continue;
14808c2ecf20Sopenharmony_ci			}
14818c2ecf20Sopenharmony_ci		} else if (frag < shift) {
14828c2ecf20Sopenharmony_ci			/* We can't use this level when the fragment size is
14838c2ecf20Sopenharmony_ci			 * smaller than the address shift. Go to the next
14848c2ecf20Sopenharmony_ci			 * child entry and try again.
14858c2ecf20Sopenharmony_ci			 */
14868c2ecf20Sopenharmony_ci			if (amdgpu_vm_pt_descendant(adev, &cursor))
14878c2ecf20Sopenharmony_ci				continue;
14888c2ecf20Sopenharmony_ci		} else if (frag >= parent_shift) {
14898c2ecf20Sopenharmony_ci			/* If the fragment size is even larger than the parent
14908c2ecf20Sopenharmony_ci			 * shift we should go up one level and check it again.
14918c2ecf20Sopenharmony_ci			 */
14928c2ecf20Sopenharmony_ci			if (!amdgpu_vm_pt_ancestor(&cursor))
14938c2ecf20Sopenharmony_ci				return -EINVAL;
14948c2ecf20Sopenharmony_ci			continue;
14958c2ecf20Sopenharmony_ci		}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		pt = cursor.entry->base.bo;
14988c2ecf20Sopenharmony_ci		if (!pt) {
14998c2ecf20Sopenharmony_ci			/* We need all PDs and PTs for mapping something, */
15008c2ecf20Sopenharmony_ci			if (flags & AMDGPU_PTE_VALID)
15018c2ecf20Sopenharmony_ci				return -ENOENT;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci			/* but unmapping something can happen at a higher
15048c2ecf20Sopenharmony_ci			 * level.
15058c2ecf20Sopenharmony_ci			 */
15068c2ecf20Sopenharmony_ci			if (!amdgpu_vm_pt_ancestor(&cursor))
15078c2ecf20Sopenharmony_ci				return -EINVAL;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci			pt = cursor.entry->base.bo;
15108c2ecf20Sopenharmony_ci			shift = parent_shift;
15118c2ecf20Sopenharmony_ci			frag_end = max(frag_end, ALIGN(frag_start + 1,
15128c2ecf20Sopenharmony_ci				   1ULL << shift));
15138c2ecf20Sopenharmony_ci		}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci		/* Looks good so far, calculate parameters for the update */
15168c2ecf20Sopenharmony_ci		incr = (uint64_t)AMDGPU_GPU_PAGE_SIZE << shift;
15178c2ecf20Sopenharmony_ci		mask = amdgpu_vm_entries_mask(adev, cursor.level);
15188c2ecf20Sopenharmony_ci		pe_start = ((cursor.pfn >> shift) & mask) * 8;
15198c2ecf20Sopenharmony_ci		entry_end = ((uint64_t)mask + 1) << shift;
15208c2ecf20Sopenharmony_ci		entry_end += cursor.pfn & ~(entry_end - 1);
15218c2ecf20Sopenharmony_ci		entry_end = min(entry_end, end);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci		do {
15248c2ecf20Sopenharmony_ci			struct amdgpu_vm *vm = params->vm;
15258c2ecf20Sopenharmony_ci			uint64_t upd_end = min(entry_end, frag_end);
15268c2ecf20Sopenharmony_ci			unsigned nptes = (upd_end - frag_start) >> shift;
15278c2ecf20Sopenharmony_ci			uint64_t upd_flags = flags | AMDGPU_PTE_FRAG(frag);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci			/* This can happen when we set higher level PDs to
15308c2ecf20Sopenharmony_ci			 * silent to stop fault floods.
15318c2ecf20Sopenharmony_ci			 */
15328c2ecf20Sopenharmony_ci			nptes = max(nptes, 1u);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci			trace_amdgpu_vm_update_ptes(params, frag_start, upd_end,
15358c2ecf20Sopenharmony_ci						    nptes, dst, incr, upd_flags,
15368c2ecf20Sopenharmony_ci						    vm->task_info.pid,
15378c2ecf20Sopenharmony_ci						    vm->immediate.fence_context);
15388c2ecf20Sopenharmony_ci			amdgpu_vm_update_flags(params, pt, cursor.level,
15398c2ecf20Sopenharmony_ci					       pe_start, dst, nptes, incr,
15408c2ecf20Sopenharmony_ci					       upd_flags);
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci			pe_start += nptes * 8;
15438c2ecf20Sopenharmony_ci			dst += nptes * incr;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci			frag_start = upd_end;
15468c2ecf20Sopenharmony_ci			if (frag_start >= frag_end) {
15478c2ecf20Sopenharmony_ci				/* figure out the next fragment */
15488c2ecf20Sopenharmony_ci				amdgpu_vm_fragment(params, frag_start, end,
15498c2ecf20Sopenharmony_ci						   flags, &frag, &frag_end);
15508c2ecf20Sopenharmony_ci				if (frag < shift)
15518c2ecf20Sopenharmony_ci					break;
15528c2ecf20Sopenharmony_ci			}
15538c2ecf20Sopenharmony_ci		} while (frag_start < entry_end);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci		if (amdgpu_vm_pt_descendant(adev, &cursor)) {
15568c2ecf20Sopenharmony_ci			/* Free all child entries.
15578c2ecf20Sopenharmony_ci			 * Update the tables with the flags and addresses and free up subsequent
15588c2ecf20Sopenharmony_ci			 * tables in the case of huge pages or freed up areas.
15598c2ecf20Sopenharmony_ci			 * This is the maximum you can free, because all other page tables are not
15608c2ecf20Sopenharmony_ci			 * completely covered by the range and so potentially still in use.
15618c2ecf20Sopenharmony_ci			 */
15628c2ecf20Sopenharmony_ci			while (cursor.pfn < frag_start) {
15638c2ecf20Sopenharmony_ci				amdgpu_vm_free_pts(adev, params->vm, &cursor);
15648c2ecf20Sopenharmony_ci				amdgpu_vm_pt_next(adev, &cursor);
15658c2ecf20Sopenharmony_ci			}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci		} else if (frag >= shift) {
15688c2ecf20Sopenharmony_ci			/* or just move on to the next on the same level. */
15698c2ecf20Sopenharmony_ci			amdgpu_vm_pt_next(adev, &cursor);
15708c2ecf20Sopenharmony_ci		}
15718c2ecf20Sopenharmony_ci	}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	return 0;
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci/**
15778c2ecf20Sopenharmony_ci * amdgpu_vm_bo_update_mapping - update a mapping in the vm page table
15788c2ecf20Sopenharmony_ci *
15798c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
15808c2ecf20Sopenharmony_ci * @vm: requested vm
15818c2ecf20Sopenharmony_ci * @immediate: immediate submission in a page fault
15828c2ecf20Sopenharmony_ci * @unlocked: unlocked invalidation during MM callback
15838c2ecf20Sopenharmony_ci * @resv: fences we need to sync to
15848c2ecf20Sopenharmony_ci * @start: start of mapped range
15858c2ecf20Sopenharmony_ci * @last: last mapped entry
15868c2ecf20Sopenharmony_ci * @flags: flags for the entries
15878c2ecf20Sopenharmony_ci * @addr: addr to set the area to
15888c2ecf20Sopenharmony_ci * @pages_addr: DMA addresses to use for mapping
15898c2ecf20Sopenharmony_ci * @fence: optional resulting fence
15908c2ecf20Sopenharmony_ci *
15918c2ecf20Sopenharmony_ci * Fill in the page table entries between @start and @last.
15928c2ecf20Sopenharmony_ci *
15938c2ecf20Sopenharmony_ci * Returns:
15948c2ecf20Sopenharmony_ci * 0 for success, -EINVAL for failure.
15958c2ecf20Sopenharmony_ci */
15968c2ecf20Sopenharmony_cistatic int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
15978c2ecf20Sopenharmony_ci				       struct amdgpu_vm *vm, bool immediate,
15988c2ecf20Sopenharmony_ci				       bool unlocked, struct dma_resv *resv,
15998c2ecf20Sopenharmony_ci				       uint64_t start, uint64_t last,
16008c2ecf20Sopenharmony_ci				       uint64_t flags, uint64_t addr,
16018c2ecf20Sopenharmony_ci				       dma_addr_t *pages_addr,
16028c2ecf20Sopenharmony_ci				       struct dma_fence **fence)
16038c2ecf20Sopenharmony_ci{
16048c2ecf20Sopenharmony_ci	struct amdgpu_vm_update_params params;
16058c2ecf20Sopenharmony_ci	enum amdgpu_sync_mode sync_mode;
16068c2ecf20Sopenharmony_ci	int r;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
16098c2ecf20Sopenharmony_ci	params.adev = adev;
16108c2ecf20Sopenharmony_ci	params.vm = vm;
16118c2ecf20Sopenharmony_ci	params.immediate = immediate;
16128c2ecf20Sopenharmony_ci	params.pages_addr = pages_addr;
16138c2ecf20Sopenharmony_ci	params.unlocked = unlocked;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	/* Implicitly sync to command submissions in the same VM before
16168c2ecf20Sopenharmony_ci	 * unmapping. Sync to moving fences before mapping.
16178c2ecf20Sopenharmony_ci	 */
16188c2ecf20Sopenharmony_ci	if (!(flags & AMDGPU_PTE_VALID))
16198c2ecf20Sopenharmony_ci		sync_mode = AMDGPU_SYNC_EQ_OWNER;
16208c2ecf20Sopenharmony_ci	else
16218c2ecf20Sopenharmony_ci		sync_mode = AMDGPU_SYNC_EXPLICIT;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_lock(vm);
16248c2ecf20Sopenharmony_ci	if (vm->evicting) {
16258c2ecf20Sopenharmony_ci		r = -EBUSY;
16268c2ecf20Sopenharmony_ci		goto error_unlock;
16278c2ecf20Sopenharmony_ci	}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	if (!unlocked && !dma_fence_is_signaled(vm->last_unlocked)) {
16308c2ecf20Sopenharmony_ci		struct dma_fence *tmp = dma_fence_get_stub();
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci		amdgpu_bo_fence(vm->root.base.bo, vm->last_unlocked, true);
16338c2ecf20Sopenharmony_ci		swap(vm->last_unlocked, tmp);
16348c2ecf20Sopenharmony_ci		dma_fence_put(tmp);
16358c2ecf20Sopenharmony_ci	}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	r = vm->update_funcs->prepare(&params, resv, sync_mode);
16388c2ecf20Sopenharmony_ci	if (r)
16398c2ecf20Sopenharmony_ci		goto error_unlock;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	r = amdgpu_vm_update_ptes(&params, start, last + 1, addr, flags);
16428c2ecf20Sopenharmony_ci	if (r)
16438c2ecf20Sopenharmony_ci		goto error_unlock;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	r = vm->update_funcs->commit(&params, fence);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_cierror_unlock:
16488c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_unlock(vm);
16498c2ecf20Sopenharmony_ci	return r;
16508c2ecf20Sopenharmony_ci}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci/**
16538c2ecf20Sopenharmony_ci * amdgpu_vm_bo_split_mapping - split a mapping into smaller chunks
16548c2ecf20Sopenharmony_ci *
16558c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
16568c2ecf20Sopenharmony_ci * @resv: fences we need to sync to
16578c2ecf20Sopenharmony_ci * @pages_addr: DMA addresses to use for mapping
16588c2ecf20Sopenharmony_ci * @vm: requested vm
16598c2ecf20Sopenharmony_ci * @mapping: mapped range and flags to use for the update
16608c2ecf20Sopenharmony_ci * @flags: HW flags for the mapping
16618c2ecf20Sopenharmony_ci * @bo_adev: amdgpu_device pointer that bo actually been allocated
16628c2ecf20Sopenharmony_ci * @nodes: array of drm_mm_nodes with the MC addresses
16638c2ecf20Sopenharmony_ci * @fence: optional resulting fence
16648c2ecf20Sopenharmony_ci *
16658c2ecf20Sopenharmony_ci * Split the mapping into smaller chunks so that each update fits
16668c2ecf20Sopenharmony_ci * into a SDMA IB.
16678c2ecf20Sopenharmony_ci *
16688c2ecf20Sopenharmony_ci * Returns:
16698c2ecf20Sopenharmony_ci * 0 for success, -EINVAL for failure.
16708c2ecf20Sopenharmony_ci */
16718c2ecf20Sopenharmony_cistatic int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev,
16728c2ecf20Sopenharmony_ci				      struct dma_resv *resv,
16738c2ecf20Sopenharmony_ci				      dma_addr_t *pages_addr,
16748c2ecf20Sopenharmony_ci				      struct amdgpu_vm *vm,
16758c2ecf20Sopenharmony_ci				      struct amdgpu_bo_va_mapping *mapping,
16768c2ecf20Sopenharmony_ci				      uint64_t flags,
16778c2ecf20Sopenharmony_ci				      struct amdgpu_device *bo_adev,
16788c2ecf20Sopenharmony_ci				      struct drm_mm_node *nodes,
16798c2ecf20Sopenharmony_ci				      struct dma_fence **fence)
16808c2ecf20Sopenharmony_ci{
16818c2ecf20Sopenharmony_ci	unsigned min_linear_pages = 1 << adev->vm_manager.fragment_size;
16828c2ecf20Sopenharmony_ci	uint64_t pfn, start = mapping->start;
16838c2ecf20Sopenharmony_ci	int r;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	/* normally,bo_va->flags only contians READABLE and WIRTEABLE bit go here
16868c2ecf20Sopenharmony_ci	 * but in case of something, we filter the flags in first place
16878c2ecf20Sopenharmony_ci	 */
16888c2ecf20Sopenharmony_ci	if (!(mapping->flags & AMDGPU_PTE_READABLE))
16898c2ecf20Sopenharmony_ci		flags &= ~AMDGPU_PTE_READABLE;
16908c2ecf20Sopenharmony_ci	if (!(mapping->flags & AMDGPU_PTE_WRITEABLE))
16918c2ecf20Sopenharmony_ci		flags &= ~AMDGPU_PTE_WRITEABLE;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	/* Apply ASIC specific mapping flags */
16948c2ecf20Sopenharmony_ci	amdgpu_gmc_get_vm_pte(adev, mapping, &flags);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	trace_amdgpu_vm_bo_update(mapping);
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	pfn = mapping->offset >> PAGE_SHIFT;
16998c2ecf20Sopenharmony_ci	if (nodes) {
17008c2ecf20Sopenharmony_ci		while (pfn >= nodes->size) {
17018c2ecf20Sopenharmony_ci			pfn -= nodes->size;
17028c2ecf20Sopenharmony_ci			++nodes;
17038c2ecf20Sopenharmony_ci		}
17048c2ecf20Sopenharmony_ci	}
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	do {
17078c2ecf20Sopenharmony_ci		dma_addr_t *dma_addr = NULL;
17088c2ecf20Sopenharmony_ci		uint64_t max_entries;
17098c2ecf20Sopenharmony_ci		uint64_t addr, last;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci		max_entries = mapping->last - start + 1;
17128c2ecf20Sopenharmony_ci		if (nodes) {
17138c2ecf20Sopenharmony_ci			addr = nodes->start << PAGE_SHIFT;
17148c2ecf20Sopenharmony_ci			max_entries = min((nodes->size - pfn) *
17158c2ecf20Sopenharmony_ci				AMDGPU_GPU_PAGES_IN_CPU_PAGE, max_entries);
17168c2ecf20Sopenharmony_ci		} else {
17178c2ecf20Sopenharmony_ci			addr = 0;
17188c2ecf20Sopenharmony_ci		}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci		if (pages_addr) {
17218c2ecf20Sopenharmony_ci			uint64_t count;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci			for (count = 1;
17248c2ecf20Sopenharmony_ci			     count < max_entries / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
17258c2ecf20Sopenharmony_ci			     ++count) {
17268c2ecf20Sopenharmony_ci				uint64_t idx = pfn + count;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci				if (pages_addr[idx] !=
17298c2ecf20Sopenharmony_ci				    (pages_addr[idx - 1] + PAGE_SIZE))
17308c2ecf20Sopenharmony_ci					break;
17318c2ecf20Sopenharmony_ci			}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci			if (count < min_linear_pages) {
17348c2ecf20Sopenharmony_ci				addr = pfn << PAGE_SHIFT;
17358c2ecf20Sopenharmony_ci				dma_addr = pages_addr;
17368c2ecf20Sopenharmony_ci			} else {
17378c2ecf20Sopenharmony_ci				addr = pages_addr[pfn];
17388c2ecf20Sopenharmony_ci				max_entries = count *
17398c2ecf20Sopenharmony_ci					AMDGPU_GPU_PAGES_IN_CPU_PAGE;
17408c2ecf20Sopenharmony_ci			}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci		} else if (flags & (AMDGPU_PTE_VALID | AMDGPU_PTE_PRT)) {
17438c2ecf20Sopenharmony_ci			addr += bo_adev->vm_manager.vram_base_offset;
17448c2ecf20Sopenharmony_ci			addr += pfn << PAGE_SHIFT;
17458c2ecf20Sopenharmony_ci		}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci		last = start + max_entries - 1;
17488c2ecf20Sopenharmony_ci		r = amdgpu_vm_bo_update_mapping(adev, vm, false, false, resv,
17498c2ecf20Sopenharmony_ci						start, last, flags, addr,
17508c2ecf20Sopenharmony_ci						dma_addr, fence);
17518c2ecf20Sopenharmony_ci		if (r)
17528c2ecf20Sopenharmony_ci			return r;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci		pfn += (last - start + 1) / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
17558c2ecf20Sopenharmony_ci		if (nodes && nodes->size == pfn) {
17568c2ecf20Sopenharmony_ci			pfn = 0;
17578c2ecf20Sopenharmony_ci			++nodes;
17588c2ecf20Sopenharmony_ci		}
17598c2ecf20Sopenharmony_ci		start = last + 1;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	} while (unlikely(start != mapping->last + 1));
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	return 0;
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci/**
17678c2ecf20Sopenharmony_ci * amdgpu_vm_bo_update - update all BO mappings in the vm page table
17688c2ecf20Sopenharmony_ci *
17698c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
17708c2ecf20Sopenharmony_ci * @bo_va: requested BO and VM object
17718c2ecf20Sopenharmony_ci * @clear: if true clear the entries
17728c2ecf20Sopenharmony_ci *
17738c2ecf20Sopenharmony_ci * Fill in the page table entries for @bo_va.
17748c2ecf20Sopenharmony_ci *
17758c2ecf20Sopenharmony_ci * Returns:
17768c2ecf20Sopenharmony_ci * 0 for success, -EINVAL for failure.
17778c2ecf20Sopenharmony_ci */
17788c2ecf20Sopenharmony_ciint amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
17798c2ecf20Sopenharmony_ci			bool clear)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = bo_va->base.bo;
17828c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = bo_va->base.vm;
17838c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping;
17848c2ecf20Sopenharmony_ci	dma_addr_t *pages_addr = NULL;
17858c2ecf20Sopenharmony_ci	struct ttm_resource *mem;
17868c2ecf20Sopenharmony_ci	struct drm_mm_node *nodes;
17878c2ecf20Sopenharmony_ci	struct dma_fence **last_update;
17888c2ecf20Sopenharmony_ci	struct dma_resv *resv;
17898c2ecf20Sopenharmony_ci	uint64_t flags;
17908c2ecf20Sopenharmony_ci	struct amdgpu_device *bo_adev = adev;
17918c2ecf20Sopenharmony_ci	int r;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	if (clear || !bo) {
17948c2ecf20Sopenharmony_ci		mem = NULL;
17958c2ecf20Sopenharmony_ci		nodes = NULL;
17968c2ecf20Sopenharmony_ci		resv = vm->root.base.bo->tbo.base.resv;
17978c2ecf20Sopenharmony_ci	} else {
17988c2ecf20Sopenharmony_ci		struct drm_gem_object *obj = &bo->tbo.base;
17998c2ecf20Sopenharmony_ci		struct ttm_dma_tt *ttm;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci		resv = bo->tbo.base.resv;
18028c2ecf20Sopenharmony_ci		if (obj->import_attach && bo_va->is_xgmi) {
18038c2ecf20Sopenharmony_ci			struct dma_buf *dma_buf = obj->import_attach->dmabuf;
18048c2ecf20Sopenharmony_ci			struct drm_gem_object *gobj = dma_buf->priv;
18058c2ecf20Sopenharmony_ci			struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj);
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci			if (abo->tbo.mem.mem_type == TTM_PL_VRAM)
18088c2ecf20Sopenharmony_ci				bo = gem_to_amdgpu_bo(gobj);
18098c2ecf20Sopenharmony_ci		}
18108c2ecf20Sopenharmony_ci		mem = &bo->tbo.mem;
18118c2ecf20Sopenharmony_ci		nodes = mem->mm_node;
18128c2ecf20Sopenharmony_ci		if (mem->mem_type == TTM_PL_TT) {
18138c2ecf20Sopenharmony_ci			ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm);
18148c2ecf20Sopenharmony_ci			pages_addr = ttm->dma_address;
18158c2ecf20Sopenharmony_ci		}
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	if (bo) {
18198c2ecf20Sopenharmony_ci		flags = amdgpu_ttm_tt_pte_flags(adev, bo->tbo.ttm, mem);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci		if (amdgpu_bo_encrypted(bo))
18228c2ecf20Sopenharmony_ci			flags |= AMDGPU_PTE_TMZ;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci		bo_adev = amdgpu_ttm_adev(bo->tbo.bdev);
18258c2ecf20Sopenharmony_ci	} else {
18268c2ecf20Sopenharmony_ci		flags = 0x0;
18278c2ecf20Sopenharmony_ci	}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if (clear || (bo && bo->tbo.base.resv ==
18308c2ecf20Sopenharmony_ci		      vm->root.base.bo->tbo.base.resv))
18318c2ecf20Sopenharmony_ci		last_update = &vm->last_update;
18328c2ecf20Sopenharmony_ci	else
18338c2ecf20Sopenharmony_ci		last_update = &bo_va->last_pt_update;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	if (!clear && bo_va->base.moved) {
18368c2ecf20Sopenharmony_ci		bo_va->base.moved = false;
18378c2ecf20Sopenharmony_ci		list_splice_init(&bo_va->valids, &bo_va->invalids);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	} else if (bo_va->cleared != clear) {
18408c2ecf20Sopenharmony_ci		list_splice_init(&bo_va->valids, &bo_va->invalids);
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	list_for_each_entry(mapping, &bo_va->invalids, list) {
18448c2ecf20Sopenharmony_ci		r = amdgpu_vm_bo_split_mapping(adev, resv, pages_addr, vm,
18458c2ecf20Sopenharmony_ci					       mapping, flags, bo_adev, nodes,
18468c2ecf20Sopenharmony_ci					       last_update);
18478c2ecf20Sopenharmony_ci		if (r)
18488c2ecf20Sopenharmony_ci			return r;
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	/* If the BO is not in its preferred location add it back to
18528c2ecf20Sopenharmony_ci	 * the evicted list so that it gets validated again on the
18538c2ecf20Sopenharmony_ci	 * next command submission.
18548c2ecf20Sopenharmony_ci	 */
18558c2ecf20Sopenharmony_ci	if (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv) {
18568c2ecf20Sopenharmony_ci		uint32_t mem_type = bo->tbo.mem.mem_type;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci		if (!(bo->preferred_domains &
18598c2ecf20Sopenharmony_ci		      amdgpu_mem_type_to_domain(mem_type)))
18608c2ecf20Sopenharmony_ci			amdgpu_vm_bo_evicted(&bo_va->base);
18618c2ecf20Sopenharmony_ci		else
18628c2ecf20Sopenharmony_ci			amdgpu_vm_bo_idle(&bo_va->base);
18638c2ecf20Sopenharmony_ci	} else {
18648c2ecf20Sopenharmony_ci		amdgpu_vm_bo_done(&bo_va->base);
18658c2ecf20Sopenharmony_ci	}
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	list_splice_init(&bo_va->invalids, &bo_va->valids);
18688c2ecf20Sopenharmony_ci	bo_va->cleared = clear;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	if (trace_amdgpu_vm_bo_mapping_enabled()) {
18718c2ecf20Sopenharmony_ci		list_for_each_entry(mapping, &bo_va->valids, list)
18728c2ecf20Sopenharmony_ci			trace_amdgpu_vm_bo_mapping(mapping);
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	return 0;
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci/**
18798c2ecf20Sopenharmony_ci * amdgpu_vm_update_prt_state - update the global PRT state
18808c2ecf20Sopenharmony_ci *
18818c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
18828c2ecf20Sopenharmony_ci */
18838c2ecf20Sopenharmony_cistatic void amdgpu_vm_update_prt_state(struct amdgpu_device *adev)
18848c2ecf20Sopenharmony_ci{
18858c2ecf20Sopenharmony_ci	unsigned long flags;
18868c2ecf20Sopenharmony_ci	bool enable;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adev->vm_manager.prt_lock, flags);
18898c2ecf20Sopenharmony_ci	enable = !!atomic_read(&adev->vm_manager.num_prt_users);
18908c2ecf20Sopenharmony_ci	adev->gmc.gmc_funcs->set_prt(adev, enable);
18918c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags);
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci/**
18958c2ecf20Sopenharmony_ci * amdgpu_vm_prt_get - add a PRT user
18968c2ecf20Sopenharmony_ci *
18978c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
18988c2ecf20Sopenharmony_ci */
18998c2ecf20Sopenharmony_cistatic void amdgpu_vm_prt_get(struct amdgpu_device *adev)
19008c2ecf20Sopenharmony_ci{
19018c2ecf20Sopenharmony_ci	if (!adev->gmc.gmc_funcs->set_prt)
19028c2ecf20Sopenharmony_ci		return;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	if (atomic_inc_return(&adev->vm_manager.num_prt_users) == 1)
19058c2ecf20Sopenharmony_ci		amdgpu_vm_update_prt_state(adev);
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci/**
19098c2ecf20Sopenharmony_ci * amdgpu_vm_prt_put - drop a PRT user
19108c2ecf20Sopenharmony_ci *
19118c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
19128c2ecf20Sopenharmony_ci */
19138c2ecf20Sopenharmony_cistatic void amdgpu_vm_prt_put(struct amdgpu_device *adev)
19148c2ecf20Sopenharmony_ci{
19158c2ecf20Sopenharmony_ci	if (atomic_dec_return(&adev->vm_manager.num_prt_users) == 0)
19168c2ecf20Sopenharmony_ci		amdgpu_vm_update_prt_state(adev);
19178c2ecf20Sopenharmony_ci}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci/**
19208c2ecf20Sopenharmony_ci * amdgpu_vm_prt_cb - callback for updating the PRT status
19218c2ecf20Sopenharmony_ci *
19228c2ecf20Sopenharmony_ci * @fence: fence for the callback
19238c2ecf20Sopenharmony_ci * @_cb: the callback function
19248c2ecf20Sopenharmony_ci */
19258c2ecf20Sopenharmony_cistatic void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb)
19268c2ecf20Sopenharmony_ci{
19278c2ecf20Sopenharmony_ci	struct amdgpu_prt_cb *cb = container_of(_cb, struct amdgpu_prt_cb, cb);
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	amdgpu_vm_prt_put(cb->adev);
19308c2ecf20Sopenharmony_ci	kfree(cb);
19318c2ecf20Sopenharmony_ci}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci/**
19348c2ecf20Sopenharmony_ci * amdgpu_vm_add_prt_cb - add callback for updating the PRT status
19358c2ecf20Sopenharmony_ci *
19368c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
19378c2ecf20Sopenharmony_ci * @fence: fence for the callback
19388c2ecf20Sopenharmony_ci */
19398c2ecf20Sopenharmony_cistatic void amdgpu_vm_add_prt_cb(struct amdgpu_device *adev,
19408c2ecf20Sopenharmony_ci				 struct dma_fence *fence)
19418c2ecf20Sopenharmony_ci{
19428c2ecf20Sopenharmony_ci	struct amdgpu_prt_cb *cb;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	if (!adev->gmc.gmc_funcs->set_prt)
19458c2ecf20Sopenharmony_ci		return;
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	cb = kmalloc(sizeof(struct amdgpu_prt_cb), GFP_KERNEL);
19488c2ecf20Sopenharmony_ci	if (!cb) {
19498c2ecf20Sopenharmony_ci		/* Last resort when we are OOM */
19508c2ecf20Sopenharmony_ci		if (fence)
19518c2ecf20Sopenharmony_ci			dma_fence_wait(fence, false);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci		amdgpu_vm_prt_put(adev);
19548c2ecf20Sopenharmony_ci	} else {
19558c2ecf20Sopenharmony_ci		cb->adev = adev;
19568c2ecf20Sopenharmony_ci		if (!fence || dma_fence_add_callback(fence, &cb->cb,
19578c2ecf20Sopenharmony_ci						     amdgpu_vm_prt_cb))
19588c2ecf20Sopenharmony_ci			amdgpu_vm_prt_cb(fence, &cb->cb);
19598c2ecf20Sopenharmony_ci	}
19608c2ecf20Sopenharmony_ci}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci/**
19638c2ecf20Sopenharmony_ci * amdgpu_vm_free_mapping - free a mapping
19648c2ecf20Sopenharmony_ci *
19658c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
19668c2ecf20Sopenharmony_ci * @vm: requested vm
19678c2ecf20Sopenharmony_ci * @mapping: mapping to be freed
19688c2ecf20Sopenharmony_ci * @fence: fence of the unmap operation
19698c2ecf20Sopenharmony_ci *
19708c2ecf20Sopenharmony_ci * Free a mapping and make sure we decrease the PRT usage count if applicable.
19718c2ecf20Sopenharmony_ci */
19728c2ecf20Sopenharmony_cistatic void amdgpu_vm_free_mapping(struct amdgpu_device *adev,
19738c2ecf20Sopenharmony_ci				   struct amdgpu_vm *vm,
19748c2ecf20Sopenharmony_ci				   struct amdgpu_bo_va_mapping *mapping,
19758c2ecf20Sopenharmony_ci				   struct dma_fence *fence)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	if (mapping->flags & AMDGPU_PTE_PRT)
19788c2ecf20Sopenharmony_ci		amdgpu_vm_add_prt_cb(adev, fence);
19798c2ecf20Sopenharmony_ci	kfree(mapping);
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci/**
19838c2ecf20Sopenharmony_ci * amdgpu_vm_prt_fini - finish all prt mappings
19848c2ecf20Sopenharmony_ci *
19858c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
19868c2ecf20Sopenharmony_ci * @vm: requested vm
19878c2ecf20Sopenharmony_ci *
19888c2ecf20Sopenharmony_ci * Register a cleanup callback to disable PRT support after VM dies.
19898c2ecf20Sopenharmony_ci */
19908c2ecf20Sopenharmony_cistatic void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci	struct dma_resv *resv = vm->root.base.bo->tbo.base.resv;
19938c2ecf20Sopenharmony_ci	struct dma_fence *excl, **shared;
19948c2ecf20Sopenharmony_ci	unsigned i, shared_count;
19958c2ecf20Sopenharmony_ci	int r;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	r = dma_resv_get_fences_rcu(resv, &excl,
19988c2ecf20Sopenharmony_ci					      &shared_count, &shared);
19998c2ecf20Sopenharmony_ci	if (r) {
20008c2ecf20Sopenharmony_ci		/* Not enough memory to grab the fence list, as last resort
20018c2ecf20Sopenharmony_ci		 * block for all the fences to complete.
20028c2ecf20Sopenharmony_ci		 */
20038c2ecf20Sopenharmony_ci		dma_resv_wait_timeout_rcu(resv, true, false,
20048c2ecf20Sopenharmony_ci						    MAX_SCHEDULE_TIMEOUT);
20058c2ecf20Sopenharmony_ci		return;
20068c2ecf20Sopenharmony_ci	}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	/* Add a callback for each fence in the reservation object */
20098c2ecf20Sopenharmony_ci	amdgpu_vm_prt_get(adev);
20108c2ecf20Sopenharmony_ci	amdgpu_vm_add_prt_cb(adev, excl);
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	for (i = 0; i < shared_count; ++i) {
20138c2ecf20Sopenharmony_ci		amdgpu_vm_prt_get(adev);
20148c2ecf20Sopenharmony_ci		amdgpu_vm_add_prt_cb(adev, shared[i]);
20158c2ecf20Sopenharmony_ci	}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	kfree(shared);
20188c2ecf20Sopenharmony_ci}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci/**
20218c2ecf20Sopenharmony_ci * amdgpu_vm_clear_freed - clear freed BOs in the PT
20228c2ecf20Sopenharmony_ci *
20238c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
20248c2ecf20Sopenharmony_ci * @vm: requested vm
20258c2ecf20Sopenharmony_ci * @fence: optional resulting fence (unchanged if no work needed to be done
20268c2ecf20Sopenharmony_ci * or if an error occurred)
20278c2ecf20Sopenharmony_ci *
20288c2ecf20Sopenharmony_ci * Make sure all freed BOs are cleared in the PT.
20298c2ecf20Sopenharmony_ci * PTs have to be reserved and mutex must be locked!
20308c2ecf20Sopenharmony_ci *
20318c2ecf20Sopenharmony_ci * Returns:
20328c2ecf20Sopenharmony_ci * 0 for success.
20338c2ecf20Sopenharmony_ci *
20348c2ecf20Sopenharmony_ci */
20358c2ecf20Sopenharmony_ciint amdgpu_vm_clear_freed(struct amdgpu_device *adev,
20368c2ecf20Sopenharmony_ci			  struct amdgpu_vm *vm,
20378c2ecf20Sopenharmony_ci			  struct dma_fence **fence)
20388c2ecf20Sopenharmony_ci{
20398c2ecf20Sopenharmony_ci	struct dma_resv *resv = vm->root.base.bo->tbo.base.resv;
20408c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping;
20418c2ecf20Sopenharmony_ci	uint64_t init_pte_value = 0;
20428c2ecf20Sopenharmony_ci	struct dma_fence *f = NULL;
20438c2ecf20Sopenharmony_ci	int r;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	while (!list_empty(&vm->freed)) {
20468c2ecf20Sopenharmony_ci		mapping = list_first_entry(&vm->freed,
20478c2ecf20Sopenharmony_ci			struct amdgpu_bo_va_mapping, list);
20488c2ecf20Sopenharmony_ci		list_del(&mapping->list);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		if (vm->pte_support_ats &&
20518c2ecf20Sopenharmony_ci		    mapping->start < AMDGPU_GMC_HOLE_START)
20528c2ecf20Sopenharmony_ci			init_pte_value = AMDGPU_PTE_DEFAULT_ATC;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		r = amdgpu_vm_bo_update_mapping(adev, vm, false, false, resv,
20558c2ecf20Sopenharmony_ci						mapping->start, mapping->last,
20568c2ecf20Sopenharmony_ci						init_pte_value, 0, NULL, &f);
20578c2ecf20Sopenharmony_ci		amdgpu_vm_free_mapping(adev, vm, mapping, f);
20588c2ecf20Sopenharmony_ci		if (r) {
20598c2ecf20Sopenharmony_ci			dma_fence_put(f);
20608c2ecf20Sopenharmony_ci			return r;
20618c2ecf20Sopenharmony_ci		}
20628c2ecf20Sopenharmony_ci	}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	if (fence && f) {
20658c2ecf20Sopenharmony_ci		dma_fence_put(*fence);
20668c2ecf20Sopenharmony_ci		*fence = f;
20678c2ecf20Sopenharmony_ci	} else {
20688c2ecf20Sopenharmony_ci		dma_fence_put(f);
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	return 0;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci}
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci/**
20768c2ecf20Sopenharmony_ci * amdgpu_vm_handle_moved - handle moved BOs in the PT
20778c2ecf20Sopenharmony_ci *
20788c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
20798c2ecf20Sopenharmony_ci * @vm: requested vm
20808c2ecf20Sopenharmony_ci *
20818c2ecf20Sopenharmony_ci * Make sure all BOs which are moved are updated in the PTs.
20828c2ecf20Sopenharmony_ci *
20838c2ecf20Sopenharmony_ci * Returns:
20848c2ecf20Sopenharmony_ci * 0 for success.
20858c2ecf20Sopenharmony_ci *
20868c2ecf20Sopenharmony_ci * PTs have to be reserved!
20878c2ecf20Sopenharmony_ci */
20888c2ecf20Sopenharmony_ciint amdgpu_vm_handle_moved(struct amdgpu_device *adev,
20898c2ecf20Sopenharmony_ci			   struct amdgpu_vm *vm)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	struct amdgpu_bo_va *bo_va, *tmp;
20928c2ecf20Sopenharmony_ci	struct dma_resv *resv;
20938c2ecf20Sopenharmony_ci	bool clear;
20948c2ecf20Sopenharmony_ci	int r;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
20978c2ecf20Sopenharmony_ci		/* Per VM BOs never need to bo cleared in the page tables */
20988c2ecf20Sopenharmony_ci		r = amdgpu_vm_bo_update(adev, bo_va, false);
20998c2ecf20Sopenharmony_ci		if (r)
21008c2ecf20Sopenharmony_ci			return r;
21018c2ecf20Sopenharmony_ci	}
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	spin_lock(&vm->invalidated_lock);
21048c2ecf20Sopenharmony_ci	while (!list_empty(&vm->invalidated)) {
21058c2ecf20Sopenharmony_ci		bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
21068c2ecf20Sopenharmony_ci					 base.vm_status);
21078c2ecf20Sopenharmony_ci		resv = bo_va->base.bo->tbo.base.resv;
21088c2ecf20Sopenharmony_ci		spin_unlock(&vm->invalidated_lock);
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci		/* Try to reserve the BO to avoid clearing its ptes */
21118c2ecf20Sopenharmony_ci		if (!amdgpu_vm_debug && dma_resv_trylock(resv))
21128c2ecf20Sopenharmony_ci			clear = false;
21138c2ecf20Sopenharmony_ci		/* Somebody else is using the BO right now */
21148c2ecf20Sopenharmony_ci		else
21158c2ecf20Sopenharmony_ci			clear = true;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci		r = amdgpu_vm_bo_update(adev, bo_va, clear);
21188c2ecf20Sopenharmony_ci		if (r)
21198c2ecf20Sopenharmony_ci			return r;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci		if (!clear)
21228c2ecf20Sopenharmony_ci			dma_resv_unlock(resv);
21238c2ecf20Sopenharmony_ci		spin_lock(&vm->invalidated_lock);
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_ci	spin_unlock(&vm->invalidated_lock);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	return 0;
21288c2ecf20Sopenharmony_ci}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci/**
21318c2ecf20Sopenharmony_ci * amdgpu_vm_bo_add - add a bo to a specific vm
21328c2ecf20Sopenharmony_ci *
21338c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
21348c2ecf20Sopenharmony_ci * @vm: requested vm
21358c2ecf20Sopenharmony_ci * @bo: amdgpu buffer object
21368c2ecf20Sopenharmony_ci *
21378c2ecf20Sopenharmony_ci * Add @bo into the requested vm.
21388c2ecf20Sopenharmony_ci * Add @bo to the list of bos associated with the vm
21398c2ecf20Sopenharmony_ci *
21408c2ecf20Sopenharmony_ci * Returns:
21418c2ecf20Sopenharmony_ci * Newly added bo_va or NULL for failure
21428c2ecf20Sopenharmony_ci *
21438c2ecf20Sopenharmony_ci * Object has to be reserved!
21448c2ecf20Sopenharmony_ci */
21458c2ecf20Sopenharmony_cistruct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
21468c2ecf20Sopenharmony_ci				      struct amdgpu_vm *vm,
21478c2ecf20Sopenharmony_ci				      struct amdgpu_bo *bo)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	struct amdgpu_bo_va *bo_va;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	bo_va = kzalloc(sizeof(struct amdgpu_bo_va), GFP_KERNEL);
21528c2ecf20Sopenharmony_ci	if (bo_va == NULL) {
21538c2ecf20Sopenharmony_ci		return NULL;
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci	amdgpu_vm_bo_base_init(&bo_va->base, vm, bo);
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	bo_va->ref_count = 1;
21588c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bo_va->valids);
21598c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bo_va->invalids);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	if (!bo)
21628c2ecf20Sopenharmony_ci		return bo_va;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	if (amdgpu_dmabuf_is_xgmi_accessible(adev, bo)) {
21658c2ecf20Sopenharmony_ci		bo_va->is_xgmi = true;
21668c2ecf20Sopenharmony_ci		/* Power up XGMI if it can be potentially used */
21678c2ecf20Sopenharmony_ci		amdgpu_xgmi_set_pstate(adev, AMDGPU_XGMI_PSTATE_MAX_VEGA20);
21688c2ecf20Sopenharmony_ci	}
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	return bo_va;
21718c2ecf20Sopenharmony_ci}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci/**
21758c2ecf20Sopenharmony_ci * amdgpu_vm_bo_insert_mapping - insert a new mapping
21768c2ecf20Sopenharmony_ci *
21778c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
21788c2ecf20Sopenharmony_ci * @bo_va: bo_va to store the address
21798c2ecf20Sopenharmony_ci * @mapping: the mapping to insert
21808c2ecf20Sopenharmony_ci *
21818c2ecf20Sopenharmony_ci * Insert a new mapping into all structures.
21828c2ecf20Sopenharmony_ci */
21838c2ecf20Sopenharmony_cistatic void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev,
21848c2ecf20Sopenharmony_ci				    struct amdgpu_bo_va *bo_va,
21858c2ecf20Sopenharmony_ci				    struct amdgpu_bo_va_mapping *mapping)
21868c2ecf20Sopenharmony_ci{
21878c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = bo_va->base.vm;
21888c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = bo_va->base.bo;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	mapping->bo_va = bo_va;
21918c2ecf20Sopenharmony_ci	list_add(&mapping->list, &bo_va->invalids);
21928c2ecf20Sopenharmony_ci	amdgpu_vm_it_insert(mapping, &vm->va);
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	if (mapping->flags & AMDGPU_PTE_PRT)
21958c2ecf20Sopenharmony_ci		amdgpu_vm_prt_get(adev);
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	if (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv &&
21988c2ecf20Sopenharmony_ci	    !bo_va->base.moved) {
21998c2ecf20Sopenharmony_ci		list_move(&bo_va->base.vm_status, &vm->moved);
22008c2ecf20Sopenharmony_ci	}
22018c2ecf20Sopenharmony_ci	trace_amdgpu_vm_bo_map(bo_va, mapping);
22028c2ecf20Sopenharmony_ci}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci/* Validate operation parameters to prevent potential abuse */
22058c2ecf20Sopenharmony_cistatic int amdgpu_vm_verify_parameters(struct amdgpu_device *adev,
22068c2ecf20Sopenharmony_ci					  struct amdgpu_bo *bo,
22078c2ecf20Sopenharmony_ci					  uint64_t saddr,
22088c2ecf20Sopenharmony_ci					  uint64_t offset,
22098c2ecf20Sopenharmony_ci					  uint64_t size)
22108c2ecf20Sopenharmony_ci{
22118c2ecf20Sopenharmony_ci	uint64_t tmp, lpfn;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (saddr & AMDGPU_GPU_PAGE_MASK
22148c2ecf20Sopenharmony_ci	    || offset & AMDGPU_GPU_PAGE_MASK
22158c2ecf20Sopenharmony_ci	    || size & AMDGPU_GPU_PAGE_MASK)
22168c2ecf20Sopenharmony_ci		return -EINVAL;
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	if (check_add_overflow(saddr, size, &tmp)
22198c2ecf20Sopenharmony_ci	    || check_add_overflow(offset, size, &tmp)
22208c2ecf20Sopenharmony_ci	    || size == 0 /* which also leads to end < begin */)
22218c2ecf20Sopenharmony_ci		return -EINVAL;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/* make sure object fit at this offset */
22248c2ecf20Sopenharmony_ci	if (bo && offset + size > amdgpu_bo_size(bo))
22258c2ecf20Sopenharmony_ci		return -EINVAL;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	/* Ensure last pfn not exceed max_pfn */
22288c2ecf20Sopenharmony_ci	lpfn = (saddr + size - 1) >> AMDGPU_GPU_PAGE_SHIFT;
22298c2ecf20Sopenharmony_ci	if (lpfn >= adev->vm_manager.max_pfn)
22308c2ecf20Sopenharmony_ci		return -EINVAL;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	return 0;
22338c2ecf20Sopenharmony_ci}
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci/**
22368c2ecf20Sopenharmony_ci * amdgpu_vm_bo_map - map bo inside a vm
22378c2ecf20Sopenharmony_ci *
22388c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
22398c2ecf20Sopenharmony_ci * @bo_va: bo_va to store the address
22408c2ecf20Sopenharmony_ci * @saddr: where to map the BO
22418c2ecf20Sopenharmony_ci * @offset: requested offset in the BO
22428c2ecf20Sopenharmony_ci * @size: BO size in bytes
22438c2ecf20Sopenharmony_ci * @flags: attributes of pages (read/write/valid/etc.)
22448c2ecf20Sopenharmony_ci *
22458c2ecf20Sopenharmony_ci * Add a mapping of the BO at the specefied addr into the VM.
22468c2ecf20Sopenharmony_ci *
22478c2ecf20Sopenharmony_ci * Returns:
22488c2ecf20Sopenharmony_ci * 0 for success, error for failure.
22498c2ecf20Sopenharmony_ci *
22508c2ecf20Sopenharmony_ci * Object has to be reserved and unreserved outside!
22518c2ecf20Sopenharmony_ci */
22528c2ecf20Sopenharmony_ciint amdgpu_vm_bo_map(struct amdgpu_device *adev,
22538c2ecf20Sopenharmony_ci		     struct amdgpu_bo_va *bo_va,
22548c2ecf20Sopenharmony_ci		     uint64_t saddr, uint64_t offset,
22558c2ecf20Sopenharmony_ci		     uint64_t size, uint64_t flags)
22568c2ecf20Sopenharmony_ci{
22578c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping, *tmp;
22588c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = bo_va->base.bo;
22598c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = bo_va->base.vm;
22608c2ecf20Sopenharmony_ci	uint64_t eaddr;
22618c2ecf20Sopenharmony_ci	int r;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	r = amdgpu_vm_verify_parameters(adev, bo, saddr, offset, size);
22648c2ecf20Sopenharmony_ci	if (r)
22658c2ecf20Sopenharmony_ci		return r;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	saddr /= AMDGPU_GPU_PAGE_SIZE;
22688c2ecf20Sopenharmony_ci	eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr);
22718c2ecf20Sopenharmony_ci	if (tmp) {
22728c2ecf20Sopenharmony_ci		/* bo and tmp overlap, invalid addr */
22738c2ecf20Sopenharmony_ci		dev_err(adev->dev, "bo %p va 0x%010Lx-0x%010Lx conflict with "
22748c2ecf20Sopenharmony_ci			"0x%010Lx-0x%010Lx\n", bo, saddr, eaddr,
22758c2ecf20Sopenharmony_ci			tmp->start, tmp->last + 1);
22768c2ecf20Sopenharmony_ci		return -EINVAL;
22778c2ecf20Sopenharmony_ci	}
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
22808c2ecf20Sopenharmony_ci	if (!mapping)
22818c2ecf20Sopenharmony_ci		return -ENOMEM;
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	mapping->start = saddr;
22848c2ecf20Sopenharmony_ci	mapping->last = eaddr;
22858c2ecf20Sopenharmony_ci	mapping->offset = offset;
22868c2ecf20Sopenharmony_ci	mapping->flags = flags;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	amdgpu_vm_bo_insert_map(adev, bo_va, mapping);
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	return 0;
22918c2ecf20Sopenharmony_ci}
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci/**
22948c2ecf20Sopenharmony_ci * amdgpu_vm_bo_replace_map - map bo inside a vm, replacing existing mappings
22958c2ecf20Sopenharmony_ci *
22968c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
22978c2ecf20Sopenharmony_ci * @bo_va: bo_va to store the address
22988c2ecf20Sopenharmony_ci * @saddr: where to map the BO
22998c2ecf20Sopenharmony_ci * @offset: requested offset in the BO
23008c2ecf20Sopenharmony_ci * @size: BO size in bytes
23018c2ecf20Sopenharmony_ci * @flags: attributes of pages (read/write/valid/etc.)
23028c2ecf20Sopenharmony_ci *
23038c2ecf20Sopenharmony_ci * Add a mapping of the BO at the specefied addr into the VM. Replace existing
23048c2ecf20Sopenharmony_ci * mappings as we do so.
23058c2ecf20Sopenharmony_ci *
23068c2ecf20Sopenharmony_ci * Returns:
23078c2ecf20Sopenharmony_ci * 0 for success, error for failure.
23088c2ecf20Sopenharmony_ci *
23098c2ecf20Sopenharmony_ci * Object has to be reserved and unreserved outside!
23108c2ecf20Sopenharmony_ci */
23118c2ecf20Sopenharmony_ciint amdgpu_vm_bo_replace_map(struct amdgpu_device *adev,
23128c2ecf20Sopenharmony_ci			     struct amdgpu_bo_va *bo_va,
23138c2ecf20Sopenharmony_ci			     uint64_t saddr, uint64_t offset,
23148c2ecf20Sopenharmony_ci			     uint64_t size, uint64_t flags)
23158c2ecf20Sopenharmony_ci{
23168c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping;
23178c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = bo_va->base.bo;
23188c2ecf20Sopenharmony_ci	uint64_t eaddr;
23198c2ecf20Sopenharmony_ci	int r;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	r = amdgpu_vm_verify_parameters(adev, bo, saddr, offset, size);
23228c2ecf20Sopenharmony_ci	if (r)
23238c2ecf20Sopenharmony_ci		return r;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	/* Allocate all the needed memory */
23268c2ecf20Sopenharmony_ci	mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
23278c2ecf20Sopenharmony_ci	if (!mapping)
23288c2ecf20Sopenharmony_ci		return -ENOMEM;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	r = amdgpu_vm_bo_clear_mappings(adev, bo_va->base.vm, saddr, size);
23318c2ecf20Sopenharmony_ci	if (r) {
23328c2ecf20Sopenharmony_ci		kfree(mapping);
23338c2ecf20Sopenharmony_ci		return r;
23348c2ecf20Sopenharmony_ci	}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	saddr /= AMDGPU_GPU_PAGE_SIZE;
23378c2ecf20Sopenharmony_ci	eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE;
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	mapping->start = saddr;
23408c2ecf20Sopenharmony_ci	mapping->last = eaddr;
23418c2ecf20Sopenharmony_ci	mapping->offset = offset;
23428c2ecf20Sopenharmony_ci	mapping->flags = flags;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	amdgpu_vm_bo_insert_map(adev, bo_va, mapping);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	return 0;
23478c2ecf20Sopenharmony_ci}
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci/**
23508c2ecf20Sopenharmony_ci * amdgpu_vm_bo_unmap - remove bo mapping from vm
23518c2ecf20Sopenharmony_ci *
23528c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
23538c2ecf20Sopenharmony_ci * @bo_va: bo_va to remove the address from
23548c2ecf20Sopenharmony_ci * @saddr: where to the BO is mapped
23558c2ecf20Sopenharmony_ci *
23568c2ecf20Sopenharmony_ci * Remove a mapping of the BO at the specefied addr from the VM.
23578c2ecf20Sopenharmony_ci *
23588c2ecf20Sopenharmony_ci * Returns:
23598c2ecf20Sopenharmony_ci * 0 for success, error for failure.
23608c2ecf20Sopenharmony_ci *
23618c2ecf20Sopenharmony_ci * Object has to be reserved and unreserved outside!
23628c2ecf20Sopenharmony_ci */
23638c2ecf20Sopenharmony_ciint amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
23648c2ecf20Sopenharmony_ci		       struct amdgpu_bo_va *bo_va,
23658c2ecf20Sopenharmony_ci		       uint64_t saddr)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping;
23688c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = bo_va->base.vm;
23698c2ecf20Sopenharmony_ci	bool valid = true;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	saddr /= AMDGPU_GPU_PAGE_SIZE;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	list_for_each_entry(mapping, &bo_va->valids, list) {
23748c2ecf20Sopenharmony_ci		if (mapping->start == saddr)
23758c2ecf20Sopenharmony_ci			break;
23768c2ecf20Sopenharmony_ci	}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	if (&mapping->list == &bo_va->valids) {
23798c2ecf20Sopenharmony_ci		valid = false;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci		list_for_each_entry(mapping, &bo_va->invalids, list) {
23828c2ecf20Sopenharmony_ci			if (mapping->start == saddr)
23838c2ecf20Sopenharmony_ci				break;
23848c2ecf20Sopenharmony_ci		}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		if (&mapping->list == &bo_va->invalids)
23878c2ecf20Sopenharmony_ci			return -ENOENT;
23888c2ecf20Sopenharmony_ci	}
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	list_del(&mapping->list);
23918c2ecf20Sopenharmony_ci	amdgpu_vm_it_remove(mapping, &vm->va);
23928c2ecf20Sopenharmony_ci	mapping->bo_va = NULL;
23938c2ecf20Sopenharmony_ci	trace_amdgpu_vm_bo_unmap(bo_va, mapping);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	if (valid)
23968c2ecf20Sopenharmony_ci		list_add(&mapping->list, &vm->freed);
23978c2ecf20Sopenharmony_ci	else
23988c2ecf20Sopenharmony_ci		amdgpu_vm_free_mapping(adev, vm, mapping,
23998c2ecf20Sopenharmony_ci				       bo_va->last_pt_update);
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	return 0;
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci/**
24058c2ecf20Sopenharmony_ci * amdgpu_vm_bo_clear_mappings - remove all mappings in a specific range
24068c2ecf20Sopenharmony_ci *
24078c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
24088c2ecf20Sopenharmony_ci * @vm: VM structure to use
24098c2ecf20Sopenharmony_ci * @saddr: start of the range
24108c2ecf20Sopenharmony_ci * @size: size of the range
24118c2ecf20Sopenharmony_ci *
24128c2ecf20Sopenharmony_ci * Remove all mappings in a range, split them as appropriate.
24138c2ecf20Sopenharmony_ci *
24148c2ecf20Sopenharmony_ci * Returns:
24158c2ecf20Sopenharmony_ci * 0 for success, error for failure.
24168c2ecf20Sopenharmony_ci */
24178c2ecf20Sopenharmony_ciint amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
24188c2ecf20Sopenharmony_ci				struct amdgpu_vm *vm,
24198c2ecf20Sopenharmony_ci				uint64_t saddr, uint64_t size)
24208c2ecf20Sopenharmony_ci{
24218c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *before, *after, *tmp, *next;
24228c2ecf20Sopenharmony_ci	LIST_HEAD(removed);
24238c2ecf20Sopenharmony_ci	uint64_t eaddr;
24248c2ecf20Sopenharmony_ci	int r;
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci	r = amdgpu_vm_verify_parameters(adev, NULL, saddr, 0, size);
24278c2ecf20Sopenharmony_ci	if (r)
24288c2ecf20Sopenharmony_ci		return r;
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	saddr /= AMDGPU_GPU_PAGE_SIZE;
24318c2ecf20Sopenharmony_ci	eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE;
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	/* Allocate all the needed memory */
24348c2ecf20Sopenharmony_ci	before = kzalloc(sizeof(*before), GFP_KERNEL);
24358c2ecf20Sopenharmony_ci	if (!before)
24368c2ecf20Sopenharmony_ci		return -ENOMEM;
24378c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&before->list);
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	after = kzalloc(sizeof(*after), GFP_KERNEL);
24408c2ecf20Sopenharmony_ci	if (!after) {
24418c2ecf20Sopenharmony_ci		kfree(before);
24428c2ecf20Sopenharmony_ci		return -ENOMEM;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&after->list);
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	/* Now gather all removed mappings */
24478c2ecf20Sopenharmony_ci	tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr);
24488c2ecf20Sopenharmony_ci	while (tmp) {
24498c2ecf20Sopenharmony_ci		/* Remember mapping split at the start */
24508c2ecf20Sopenharmony_ci		if (tmp->start < saddr) {
24518c2ecf20Sopenharmony_ci			before->start = tmp->start;
24528c2ecf20Sopenharmony_ci			before->last = saddr - 1;
24538c2ecf20Sopenharmony_ci			before->offset = tmp->offset;
24548c2ecf20Sopenharmony_ci			before->flags = tmp->flags;
24558c2ecf20Sopenharmony_ci			before->bo_va = tmp->bo_va;
24568c2ecf20Sopenharmony_ci			list_add(&before->list, &tmp->bo_va->invalids);
24578c2ecf20Sopenharmony_ci		}
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci		/* Remember mapping split at the end */
24608c2ecf20Sopenharmony_ci		if (tmp->last > eaddr) {
24618c2ecf20Sopenharmony_ci			after->start = eaddr + 1;
24628c2ecf20Sopenharmony_ci			after->last = tmp->last;
24638c2ecf20Sopenharmony_ci			after->offset = tmp->offset;
24648c2ecf20Sopenharmony_ci			after->offset += (after->start - tmp->start) << PAGE_SHIFT;
24658c2ecf20Sopenharmony_ci			after->flags = tmp->flags;
24668c2ecf20Sopenharmony_ci			after->bo_va = tmp->bo_va;
24678c2ecf20Sopenharmony_ci			list_add(&after->list, &tmp->bo_va->invalids);
24688c2ecf20Sopenharmony_ci		}
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci		list_del(&tmp->list);
24718c2ecf20Sopenharmony_ci		list_add(&tmp->list, &removed);
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci		tmp = amdgpu_vm_it_iter_next(tmp, saddr, eaddr);
24748c2ecf20Sopenharmony_ci	}
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	/* And free them up */
24778c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tmp, next, &removed, list) {
24788c2ecf20Sopenharmony_ci		amdgpu_vm_it_remove(tmp, &vm->va);
24798c2ecf20Sopenharmony_ci		list_del(&tmp->list);
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci		if (tmp->start < saddr)
24828c2ecf20Sopenharmony_ci		    tmp->start = saddr;
24838c2ecf20Sopenharmony_ci		if (tmp->last > eaddr)
24848c2ecf20Sopenharmony_ci		    tmp->last = eaddr;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci		tmp->bo_va = NULL;
24878c2ecf20Sopenharmony_ci		list_add(&tmp->list, &vm->freed);
24888c2ecf20Sopenharmony_ci		trace_amdgpu_vm_bo_unmap(NULL, tmp);
24898c2ecf20Sopenharmony_ci	}
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	/* Insert partial mapping before the range */
24928c2ecf20Sopenharmony_ci	if (!list_empty(&before->list)) {
24938c2ecf20Sopenharmony_ci		amdgpu_vm_it_insert(before, &vm->va);
24948c2ecf20Sopenharmony_ci		if (before->flags & AMDGPU_PTE_PRT)
24958c2ecf20Sopenharmony_ci			amdgpu_vm_prt_get(adev);
24968c2ecf20Sopenharmony_ci	} else {
24978c2ecf20Sopenharmony_ci		kfree(before);
24988c2ecf20Sopenharmony_ci	}
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	/* Insert partial mapping after the range */
25018c2ecf20Sopenharmony_ci	if (!list_empty(&after->list)) {
25028c2ecf20Sopenharmony_ci		amdgpu_vm_it_insert(after, &vm->va);
25038c2ecf20Sopenharmony_ci		if (after->flags & AMDGPU_PTE_PRT)
25048c2ecf20Sopenharmony_ci			amdgpu_vm_prt_get(adev);
25058c2ecf20Sopenharmony_ci	} else {
25068c2ecf20Sopenharmony_ci		kfree(after);
25078c2ecf20Sopenharmony_ci	}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	return 0;
25108c2ecf20Sopenharmony_ci}
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci/**
25138c2ecf20Sopenharmony_ci * amdgpu_vm_bo_lookup_mapping - find mapping by address
25148c2ecf20Sopenharmony_ci *
25158c2ecf20Sopenharmony_ci * @vm: the requested VM
25168c2ecf20Sopenharmony_ci * @addr: the address
25178c2ecf20Sopenharmony_ci *
25188c2ecf20Sopenharmony_ci * Find a mapping by it's address.
25198c2ecf20Sopenharmony_ci *
25208c2ecf20Sopenharmony_ci * Returns:
25218c2ecf20Sopenharmony_ci * The amdgpu_bo_va_mapping matching for addr or NULL
25228c2ecf20Sopenharmony_ci *
25238c2ecf20Sopenharmony_ci */
25248c2ecf20Sopenharmony_cistruct amdgpu_bo_va_mapping *amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm *vm,
25258c2ecf20Sopenharmony_ci							 uint64_t addr)
25268c2ecf20Sopenharmony_ci{
25278c2ecf20Sopenharmony_ci	return amdgpu_vm_it_iter_first(&vm->va, addr, addr);
25288c2ecf20Sopenharmony_ci}
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci/**
25318c2ecf20Sopenharmony_ci * amdgpu_vm_bo_trace_cs - trace all reserved mappings
25328c2ecf20Sopenharmony_ci *
25338c2ecf20Sopenharmony_ci * @vm: the requested vm
25348c2ecf20Sopenharmony_ci * @ticket: CS ticket
25358c2ecf20Sopenharmony_ci *
25368c2ecf20Sopenharmony_ci * Trace all mappings of BOs reserved during a command submission.
25378c2ecf20Sopenharmony_ci */
25388c2ecf20Sopenharmony_civoid amdgpu_vm_bo_trace_cs(struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket)
25398c2ecf20Sopenharmony_ci{
25408c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping;
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	if (!trace_amdgpu_vm_bo_cs_enabled())
25438c2ecf20Sopenharmony_ci		return;
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	for (mapping = amdgpu_vm_it_iter_first(&vm->va, 0, U64_MAX); mapping;
25468c2ecf20Sopenharmony_ci	     mapping = amdgpu_vm_it_iter_next(mapping, 0, U64_MAX)) {
25478c2ecf20Sopenharmony_ci		if (mapping->bo_va && mapping->bo_va->base.bo) {
25488c2ecf20Sopenharmony_ci			struct amdgpu_bo *bo;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci			bo = mapping->bo_va->base.bo;
25518c2ecf20Sopenharmony_ci			if (dma_resv_locking_ctx(bo->tbo.base.resv) !=
25528c2ecf20Sopenharmony_ci			    ticket)
25538c2ecf20Sopenharmony_ci				continue;
25548c2ecf20Sopenharmony_ci		}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci		trace_amdgpu_vm_bo_cs(mapping);
25578c2ecf20Sopenharmony_ci	}
25588c2ecf20Sopenharmony_ci}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci/**
25618c2ecf20Sopenharmony_ci * amdgpu_vm_bo_rmv - remove a bo to a specific vm
25628c2ecf20Sopenharmony_ci *
25638c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
25648c2ecf20Sopenharmony_ci * @bo_va: requested bo_va
25658c2ecf20Sopenharmony_ci *
25668c2ecf20Sopenharmony_ci * Remove @bo_va->bo from the requested vm.
25678c2ecf20Sopenharmony_ci *
25688c2ecf20Sopenharmony_ci * Object have to be reserved!
25698c2ecf20Sopenharmony_ci */
25708c2ecf20Sopenharmony_civoid amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
25718c2ecf20Sopenharmony_ci		      struct amdgpu_bo_va *bo_va)
25728c2ecf20Sopenharmony_ci{
25738c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping, *next;
25748c2ecf20Sopenharmony_ci	struct amdgpu_bo *bo = bo_va->base.bo;
25758c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm = bo_va->base.vm;
25768c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base **base;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	if (bo) {
25798c2ecf20Sopenharmony_ci		if (bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
25808c2ecf20Sopenharmony_ci			vm->bulk_moveable = false;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci		for (base = &bo_va->base.bo->vm_bo; *base;
25838c2ecf20Sopenharmony_ci		     base = &(*base)->next) {
25848c2ecf20Sopenharmony_ci			if (*base != &bo_va->base)
25858c2ecf20Sopenharmony_ci				continue;
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci			*base = bo_va->base.next;
25888c2ecf20Sopenharmony_ci			break;
25898c2ecf20Sopenharmony_ci		}
25908c2ecf20Sopenharmony_ci	}
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	spin_lock(&vm->invalidated_lock);
25938c2ecf20Sopenharmony_ci	list_del(&bo_va->base.vm_status);
25948c2ecf20Sopenharmony_ci	spin_unlock(&vm->invalidated_lock);
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
25978c2ecf20Sopenharmony_ci		list_del(&mapping->list);
25988c2ecf20Sopenharmony_ci		amdgpu_vm_it_remove(mapping, &vm->va);
25998c2ecf20Sopenharmony_ci		mapping->bo_va = NULL;
26008c2ecf20Sopenharmony_ci		trace_amdgpu_vm_bo_unmap(bo_va, mapping);
26018c2ecf20Sopenharmony_ci		list_add(&mapping->list, &vm->freed);
26028c2ecf20Sopenharmony_ci	}
26038c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
26048c2ecf20Sopenharmony_ci		list_del(&mapping->list);
26058c2ecf20Sopenharmony_ci		amdgpu_vm_it_remove(mapping, &vm->va);
26068c2ecf20Sopenharmony_ci		amdgpu_vm_free_mapping(adev, vm, mapping,
26078c2ecf20Sopenharmony_ci				       bo_va->last_pt_update);
26088c2ecf20Sopenharmony_ci	}
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	dma_fence_put(bo_va->last_pt_update);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	if (bo && bo_va->is_xgmi)
26138c2ecf20Sopenharmony_ci		amdgpu_xgmi_set_pstate(adev, AMDGPU_XGMI_PSTATE_MIN);
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	kfree(bo_va);
26168c2ecf20Sopenharmony_ci}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci/**
26198c2ecf20Sopenharmony_ci * amdgpu_vm_evictable - check if we can evict a VM
26208c2ecf20Sopenharmony_ci *
26218c2ecf20Sopenharmony_ci * @bo: A page table of the VM.
26228c2ecf20Sopenharmony_ci *
26238c2ecf20Sopenharmony_ci * Check if it is possible to evict a VM.
26248c2ecf20Sopenharmony_ci */
26258c2ecf20Sopenharmony_cibool amdgpu_vm_evictable(struct amdgpu_bo *bo)
26268c2ecf20Sopenharmony_ci{
26278c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *bo_base = bo->vm_bo;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	/* Page tables of a destroyed VM can go away immediately */
26308c2ecf20Sopenharmony_ci	if (!bo_base || !bo_base->vm)
26318c2ecf20Sopenharmony_ci		return true;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	/* Don't evict VM page tables while they are busy */
26348c2ecf20Sopenharmony_ci	if (!dma_resv_test_signaled_rcu(bo->tbo.base.resv, true))
26358c2ecf20Sopenharmony_ci		return false;
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	/* Try to block ongoing updates */
26388c2ecf20Sopenharmony_ci	if (!amdgpu_vm_eviction_trylock(bo_base->vm))
26398c2ecf20Sopenharmony_ci		return false;
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci	/* Don't evict VM page tables while they are updated */
26428c2ecf20Sopenharmony_ci	if (!dma_fence_is_signaled(bo_base->vm->last_unlocked)) {
26438c2ecf20Sopenharmony_ci		amdgpu_vm_eviction_unlock(bo_base->vm);
26448c2ecf20Sopenharmony_ci		return false;
26458c2ecf20Sopenharmony_ci	}
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci	bo_base->vm->evicting = true;
26488c2ecf20Sopenharmony_ci	amdgpu_vm_eviction_unlock(bo_base->vm);
26498c2ecf20Sopenharmony_ci	return true;
26508c2ecf20Sopenharmony_ci}
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci/**
26538c2ecf20Sopenharmony_ci * amdgpu_vm_bo_invalidate - mark the bo as invalid
26548c2ecf20Sopenharmony_ci *
26558c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
26568c2ecf20Sopenharmony_ci * @bo: amdgpu buffer object
26578c2ecf20Sopenharmony_ci * @evicted: is the BO evicted
26588c2ecf20Sopenharmony_ci *
26598c2ecf20Sopenharmony_ci * Mark @bo as invalid.
26608c2ecf20Sopenharmony_ci */
26618c2ecf20Sopenharmony_civoid amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
26628c2ecf20Sopenharmony_ci			     struct amdgpu_bo *bo, bool evicted)
26638c2ecf20Sopenharmony_ci{
26648c2ecf20Sopenharmony_ci	struct amdgpu_vm_bo_base *bo_base;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	/* shadow bo doesn't have bo base, its validation needs its parent */
26678c2ecf20Sopenharmony_ci	if (bo->parent && bo->parent->shadow == bo)
26688c2ecf20Sopenharmony_ci		bo = bo->parent;
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) {
26718c2ecf20Sopenharmony_ci		struct amdgpu_vm *vm = bo_base->vm;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci		if (evicted && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv) {
26748c2ecf20Sopenharmony_ci			amdgpu_vm_bo_evicted(bo_base);
26758c2ecf20Sopenharmony_ci			continue;
26768c2ecf20Sopenharmony_ci		}
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci		if (bo_base->moved)
26798c2ecf20Sopenharmony_ci			continue;
26808c2ecf20Sopenharmony_ci		bo_base->moved = true;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci		if (bo->tbo.type == ttm_bo_type_kernel)
26838c2ecf20Sopenharmony_ci			amdgpu_vm_bo_relocated(bo_base);
26848c2ecf20Sopenharmony_ci		else if (bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv)
26858c2ecf20Sopenharmony_ci			amdgpu_vm_bo_moved(bo_base);
26868c2ecf20Sopenharmony_ci		else
26878c2ecf20Sopenharmony_ci			amdgpu_vm_bo_invalidated(bo_base);
26888c2ecf20Sopenharmony_ci	}
26898c2ecf20Sopenharmony_ci}
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci/**
26928c2ecf20Sopenharmony_ci * amdgpu_vm_get_block_size - calculate VM page table size as power of two
26938c2ecf20Sopenharmony_ci *
26948c2ecf20Sopenharmony_ci * @vm_size: VM size
26958c2ecf20Sopenharmony_ci *
26968c2ecf20Sopenharmony_ci * Returns:
26978c2ecf20Sopenharmony_ci * VM page table as power of two
26988c2ecf20Sopenharmony_ci */
26998c2ecf20Sopenharmony_cistatic uint32_t amdgpu_vm_get_block_size(uint64_t vm_size)
27008c2ecf20Sopenharmony_ci{
27018c2ecf20Sopenharmony_ci	/* Total bits covered by PD + PTs */
27028c2ecf20Sopenharmony_ci	unsigned bits = ilog2(vm_size) + 18;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	/* Make sure the PD is 4K in size up to 8GB address space.
27058c2ecf20Sopenharmony_ci	   Above that split equal between PD and PTs */
27068c2ecf20Sopenharmony_ci	if (vm_size <= 8)
27078c2ecf20Sopenharmony_ci		return (bits - 9);
27088c2ecf20Sopenharmony_ci	else
27098c2ecf20Sopenharmony_ci		return ((bits + 3) / 2);
27108c2ecf20Sopenharmony_ci}
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci/**
27138c2ecf20Sopenharmony_ci * amdgpu_vm_adjust_size - adjust vm size, block size and fragment size
27148c2ecf20Sopenharmony_ci *
27158c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
27168c2ecf20Sopenharmony_ci * @min_vm_size: the minimum vm size in GB if it's set auto
27178c2ecf20Sopenharmony_ci * @fragment_size_default: Default PTE fragment size
27188c2ecf20Sopenharmony_ci * @max_level: max VMPT level
27198c2ecf20Sopenharmony_ci * @max_bits: max address space size in bits
27208c2ecf20Sopenharmony_ci *
27218c2ecf20Sopenharmony_ci */
27228c2ecf20Sopenharmony_civoid amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size,
27238c2ecf20Sopenharmony_ci			   uint32_t fragment_size_default, unsigned max_level,
27248c2ecf20Sopenharmony_ci			   unsigned max_bits)
27258c2ecf20Sopenharmony_ci{
27268c2ecf20Sopenharmony_ci	unsigned int max_size = 1 << (max_bits - 30);
27278c2ecf20Sopenharmony_ci	unsigned int vm_size;
27288c2ecf20Sopenharmony_ci	uint64_t tmp;
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	/* adjust vm size first */
27318c2ecf20Sopenharmony_ci	if (amdgpu_vm_size != -1) {
27328c2ecf20Sopenharmony_ci		vm_size = amdgpu_vm_size;
27338c2ecf20Sopenharmony_ci		if (vm_size > max_size) {
27348c2ecf20Sopenharmony_ci			dev_warn(adev->dev, "VM size (%d) too large, max is %u GB\n",
27358c2ecf20Sopenharmony_ci				 amdgpu_vm_size, max_size);
27368c2ecf20Sopenharmony_ci			vm_size = max_size;
27378c2ecf20Sopenharmony_ci		}
27388c2ecf20Sopenharmony_ci	} else {
27398c2ecf20Sopenharmony_ci		struct sysinfo si;
27408c2ecf20Sopenharmony_ci		unsigned int phys_ram_gb;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci		/* Optimal VM size depends on the amount of physical
27438c2ecf20Sopenharmony_ci		 * RAM available. Underlying requirements and
27448c2ecf20Sopenharmony_ci		 * assumptions:
27458c2ecf20Sopenharmony_ci		 *
27468c2ecf20Sopenharmony_ci		 *  - Need to map system memory and VRAM from all GPUs
27478c2ecf20Sopenharmony_ci		 *     - VRAM from other GPUs not known here
27488c2ecf20Sopenharmony_ci		 *     - Assume VRAM <= system memory
27498c2ecf20Sopenharmony_ci		 *  - On GFX8 and older, VM space can be segmented for
27508c2ecf20Sopenharmony_ci		 *    different MTYPEs
27518c2ecf20Sopenharmony_ci		 *  - Need to allow room for fragmentation, guard pages etc.
27528c2ecf20Sopenharmony_ci		 *
27538c2ecf20Sopenharmony_ci		 * This adds up to a rough guess of system memory x3.
27548c2ecf20Sopenharmony_ci		 * Round up to power of two to maximize the available
27558c2ecf20Sopenharmony_ci		 * VM size with the given page table size.
27568c2ecf20Sopenharmony_ci		 */
27578c2ecf20Sopenharmony_ci		si_meminfo(&si);
27588c2ecf20Sopenharmony_ci		phys_ram_gb = ((uint64_t)si.totalram * si.mem_unit +
27598c2ecf20Sopenharmony_ci			       (1 << 30) - 1) >> 30;
27608c2ecf20Sopenharmony_ci		vm_size = roundup_pow_of_two(
27618c2ecf20Sopenharmony_ci			min(max(phys_ram_gb * 3, min_vm_size), max_size));
27628c2ecf20Sopenharmony_ci	}
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	adev->vm_manager.max_pfn = (uint64_t)vm_size << 18;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci	tmp = roundup_pow_of_two(adev->vm_manager.max_pfn);
27678c2ecf20Sopenharmony_ci	if (amdgpu_vm_block_size != -1)
27688c2ecf20Sopenharmony_ci		tmp >>= amdgpu_vm_block_size - 9;
27698c2ecf20Sopenharmony_ci	tmp = DIV_ROUND_UP(fls64(tmp) - 1, 9) - 1;
27708c2ecf20Sopenharmony_ci	adev->vm_manager.num_level = min(max_level, (unsigned)tmp);
27718c2ecf20Sopenharmony_ci	switch (adev->vm_manager.num_level) {
27728c2ecf20Sopenharmony_ci	case 3:
27738c2ecf20Sopenharmony_ci		adev->vm_manager.root_level = AMDGPU_VM_PDB2;
27748c2ecf20Sopenharmony_ci		break;
27758c2ecf20Sopenharmony_ci	case 2:
27768c2ecf20Sopenharmony_ci		adev->vm_manager.root_level = AMDGPU_VM_PDB1;
27778c2ecf20Sopenharmony_ci		break;
27788c2ecf20Sopenharmony_ci	case 1:
27798c2ecf20Sopenharmony_ci		adev->vm_manager.root_level = AMDGPU_VM_PDB0;
27808c2ecf20Sopenharmony_ci		break;
27818c2ecf20Sopenharmony_ci	default:
27828c2ecf20Sopenharmony_ci		dev_err(adev->dev, "VMPT only supports 2~4+1 levels\n");
27838c2ecf20Sopenharmony_ci	}
27848c2ecf20Sopenharmony_ci	/* block size depends on vm size and hw setup*/
27858c2ecf20Sopenharmony_ci	if (amdgpu_vm_block_size != -1)
27868c2ecf20Sopenharmony_ci		adev->vm_manager.block_size =
27878c2ecf20Sopenharmony_ci			min((unsigned)amdgpu_vm_block_size, max_bits
27888c2ecf20Sopenharmony_ci			    - AMDGPU_GPU_PAGE_SHIFT
27898c2ecf20Sopenharmony_ci			    - 9 * adev->vm_manager.num_level);
27908c2ecf20Sopenharmony_ci	else if (adev->vm_manager.num_level > 1)
27918c2ecf20Sopenharmony_ci		adev->vm_manager.block_size = 9;
27928c2ecf20Sopenharmony_ci	else
27938c2ecf20Sopenharmony_ci		adev->vm_manager.block_size = amdgpu_vm_get_block_size(tmp);
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci	if (amdgpu_vm_fragment_size == -1)
27968c2ecf20Sopenharmony_ci		adev->vm_manager.fragment_size = fragment_size_default;
27978c2ecf20Sopenharmony_ci	else
27988c2ecf20Sopenharmony_ci		adev->vm_manager.fragment_size = amdgpu_vm_fragment_size;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	DRM_INFO("vm size is %u GB, %u levels, block size is %u-bit, fragment size is %u-bit\n",
28018c2ecf20Sopenharmony_ci		 vm_size, adev->vm_manager.num_level + 1,
28028c2ecf20Sopenharmony_ci		 adev->vm_manager.block_size,
28038c2ecf20Sopenharmony_ci		 adev->vm_manager.fragment_size);
28048c2ecf20Sopenharmony_ci}
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci/**
28078c2ecf20Sopenharmony_ci * amdgpu_vm_wait_idle - wait for the VM to become idle
28088c2ecf20Sopenharmony_ci *
28098c2ecf20Sopenharmony_ci * @vm: VM object to wait for
28108c2ecf20Sopenharmony_ci * @timeout: timeout to wait for VM to become idle
28118c2ecf20Sopenharmony_ci */
28128c2ecf20Sopenharmony_cilong amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout)
28138c2ecf20Sopenharmony_ci{
28148c2ecf20Sopenharmony_ci	timeout = dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv,
28158c2ecf20Sopenharmony_ci					    true, true, timeout);
28168c2ecf20Sopenharmony_ci	if (timeout <= 0)
28178c2ecf20Sopenharmony_ci		return timeout;
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_ci	return dma_fence_wait_timeout(vm->last_unlocked, true, timeout);
28208c2ecf20Sopenharmony_ci}
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci/**
28238c2ecf20Sopenharmony_ci * amdgpu_vm_init - initialize a vm instance
28248c2ecf20Sopenharmony_ci *
28258c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
28268c2ecf20Sopenharmony_ci * @vm: requested vm
28278c2ecf20Sopenharmony_ci * @vm_context: Indicates if it GFX or Compute context
28288c2ecf20Sopenharmony_ci * @pasid: Process address space identifier
28298c2ecf20Sopenharmony_ci *
28308c2ecf20Sopenharmony_ci * Init @vm fields.
28318c2ecf20Sopenharmony_ci *
28328c2ecf20Sopenharmony_ci * Returns:
28338c2ecf20Sopenharmony_ci * 0 for success, error for failure.
28348c2ecf20Sopenharmony_ci */
28358c2ecf20Sopenharmony_ciint amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
28368c2ecf20Sopenharmony_ci		   int vm_context, u32 pasid)
28378c2ecf20Sopenharmony_ci{
28388c2ecf20Sopenharmony_ci	struct amdgpu_bo_param bp;
28398c2ecf20Sopenharmony_ci	struct amdgpu_bo *root;
28408c2ecf20Sopenharmony_ci	int r, i;
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci	vm->va = RB_ROOT_CACHED;
28438c2ecf20Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
28448c2ecf20Sopenharmony_ci		vm->reserved_vmid[i] = NULL;
28458c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->evicted);
28468c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->relocated);
28478c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->moved);
28488c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->idle);
28498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->invalidated);
28508c2ecf20Sopenharmony_ci	spin_lock_init(&vm->invalidated_lock);
28518c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vm->freed);
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	/* create scheduler entities for page table updates */
28558c2ecf20Sopenharmony_ci	r = drm_sched_entity_init(&vm->immediate, DRM_SCHED_PRIORITY_NORMAL,
28568c2ecf20Sopenharmony_ci				  adev->vm_manager.vm_pte_scheds,
28578c2ecf20Sopenharmony_ci				  adev->vm_manager.vm_pte_num_scheds, NULL);
28588c2ecf20Sopenharmony_ci	if (r)
28598c2ecf20Sopenharmony_ci		return r;
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci	r = drm_sched_entity_init(&vm->delayed, DRM_SCHED_PRIORITY_NORMAL,
28628c2ecf20Sopenharmony_ci				  adev->vm_manager.vm_pte_scheds,
28638c2ecf20Sopenharmony_ci				  adev->vm_manager.vm_pte_num_scheds, NULL);
28648c2ecf20Sopenharmony_ci	if (r)
28658c2ecf20Sopenharmony_ci		goto error_free_immediate;
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci	vm->pte_support_ats = false;
28688c2ecf20Sopenharmony_ci	vm->is_compute_context = false;
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci	if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE) {
28718c2ecf20Sopenharmony_ci		vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
28728c2ecf20Sopenharmony_ci						AMDGPU_VM_USE_CPU_FOR_COMPUTE);
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci		if (adev->asic_type == CHIP_RAVEN)
28758c2ecf20Sopenharmony_ci			vm->pte_support_ats = true;
28768c2ecf20Sopenharmony_ci	} else {
28778c2ecf20Sopenharmony_ci		vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
28788c2ecf20Sopenharmony_ci						AMDGPU_VM_USE_CPU_FOR_GFX);
28798c2ecf20Sopenharmony_ci	}
28808c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("VM update mode is %s\n",
28818c2ecf20Sopenharmony_ci			 vm->use_cpu_for_update ? "CPU" : "SDMA");
28828c2ecf20Sopenharmony_ci	WARN_ONCE((vm->use_cpu_for_update &&
28838c2ecf20Sopenharmony_ci		   !amdgpu_gmc_vram_full_visible(&adev->gmc)),
28848c2ecf20Sopenharmony_ci		  "CPU update of VM recommended only for large BAR system\n");
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci	if (vm->use_cpu_for_update)
28878c2ecf20Sopenharmony_ci		vm->update_funcs = &amdgpu_vm_cpu_funcs;
28888c2ecf20Sopenharmony_ci	else
28898c2ecf20Sopenharmony_ci		vm->update_funcs = &amdgpu_vm_sdma_funcs;
28908c2ecf20Sopenharmony_ci	vm->last_update = NULL;
28918c2ecf20Sopenharmony_ci	vm->last_unlocked = dma_fence_get_stub();
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci	mutex_init(&vm->eviction_lock);
28948c2ecf20Sopenharmony_ci	vm->evicting = false;
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_ci	amdgpu_vm_bo_param(adev, vm, adev->vm_manager.root_level, false, &bp);
28978c2ecf20Sopenharmony_ci	if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE)
28988c2ecf20Sopenharmony_ci		bp.flags &= ~AMDGPU_GEM_CREATE_SHADOW;
28998c2ecf20Sopenharmony_ci	r = amdgpu_bo_create(adev, &bp, &root);
29008c2ecf20Sopenharmony_ci	if (r)
29018c2ecf20Sopenharmony_ci		goto error_free_delayed;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	r = amdgpu_bo_reserve(root, true);
29048c2ecf20Sopenharmony_ci	if (r)
29058c2ecf20Sopenharmony_ci		goto error_free_root;
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci	r = dma_resv_reserve_shared(root->tbo.base.resv, 1);
29088c2ecf20Sopenharmony_ci	if (r)
29098c2ecf20Sopenharmony_ci		goto error_unreserve;
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	amdgpu_vm_bo_base_init(&vm->root.base, vm, root);
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci	r = amdgpu_vm_clear_bo(adev, vm, root, false);
29148c2ecf20Sopenharmony_ci	if (r)
29158c2ecf20Sopenharmony_ci		goto error_unreserve;
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	amdgpu_bo_unreserve(vm->root.base.bo);
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	if (pasid) {
29208c2ecf20Sopenharmony_ci		unsigned long flags;
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
29238c2ecf20Sopenharmony_ci		r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1,
29248c2ecf20Sopenharmony_ci			      GFP_ATOMIC);
29258c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
29268c2ecf20Sopenharmony_ci		if (r < 0)
29278c2ecf20Sopenharmony_ci			goto error_free_root;
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci		vm->pasid = pasid;
29308c2ecf20Sopenharmony_ci	}
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	INIT_KFIFO(vm->faults);
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci	return 0;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_cierror_unreserve:
29378c2ecf20Sopenharmony_ci	amdgpu_bo_unreserve(vm->root.base.bo);
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_cierror_free_root:
29408c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&vm->root.base.bo->shadow);
29418c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&vm->root.base.bo);
29428c2ecf20Sopenharmony_ci	vm->root.base.bo = NULL;
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_cierror_free_delayed:
29458c2ecf20Sopenharmony_ci	dma_fence_put(vm->last_unlocked);
29468c2ecf20Sopenharmony_ci	drm_sched_entity_destroy(&vm->delayed);
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_cierror_free_immediate:
29498c2ecf20Sopenharmony_ci	drm_sched_entity_destroy(&vm->immediate);
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	return r;
29528c2ecf20Sopenharmony_ci}
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci/**
29558c2ecf20Sopenharmony_ci * amdgpu_vm_check_clean_reserved - check if a VM is clean
29568c2ecf20Sopenharmony_ci *
29578c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
29588c2ecf20Sopenharmony_ci * @vm: the VM to check
29598c2ecf20Sopenharmony_ci *
29608c2ecf20Sopenharmony_ci * check all entries of the root PD, if any subsequent PDs are allocated,
29618c2ecf20Sopenharmony_ci * it means there are page table creating and filling, and is no a clean
29628c2ecf20Sopenharmony_ci * VM
29638c2ecf20Sopenharmony_ci *
29648c2ecf20Sopenharmony_ci * Returns:
29658c2ecf20Sopenharmony_ci *	0 if this VM is clean
29668c2ecf20Sopenharmony_ci */
29678c2ecf20Sopenharmony_cistatic int amdgpu_vm_check_clean_reserved(struct amdgpu_device *adev,
29688c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm)
29698c2ecf20Sopenharmony_ci{
29708c2ecf20Sopenharmony_ci	enum amdgpu_vm_level root = adev->vm_manager.root_level;
29718c2ecf20Sopenharmony_ci	unsigned int entries = amdgpu_vm_num_entries(adev, root);
29728c2ecf20Sopenharmony_ci	unsigned int i = 0;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	if (!(vm->root.entries))
29758c2ecf20Sopenharmony_ci		return 0;
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci	for (i = 0; i < entries; i++) {
29788c2ecf20Sopenharmony_ci		if (vm->root.entries[i].base.bo)
29798c2ecf20Sopenharmony_ci			return -EINVAL;
29808c2ecf20Sopenharmony_ci	}
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	return 0;
29838c2ecf20Sopenharmony_ci}
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci/**
29868c2ecf20Sopenharmony_ci * amdgpu_vm_make_compute - Turn a GFX VM into a compute VM
29878c2ecf20Sopenharmony_ci *
29888c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
29898c2ecf20Sopenharmony_ci * @vm: requested vm
29908c2ecf20Sopenharmony_ci * @pasid: pasid to use
29918c2ecf20Sopenharmony_ci *
29928c2ecf20Sopenharmony_ci * This only works on GFX VMs that don't have any BOs added and no
29938c2ecf20Sopenharmony_ci * page tables allocated yet.
29948c2ecf20Sopenharmony_ci *
29958c2ecf20Sopenharmony_ci * Changes the following VM parameters:
29968c2ecf20Sopenharmony_ci * - use_cpu_for_update
29978c2ecf20Sopenharmony_ci * - pte_supports_ats
29988c2ecf20Sopenharmony_ci * - pasid (old PASID is released, because compute manages its own PASIDs)
29998c2ecf20Sopenharmony_ci *
30008c2ecf20Sopenharmony_ci * Reinitializes the page directory to reflect the changed ATS
30018c2ecf20Sopenharmony_ci * setting.
30028c2ecf20Sopenharmony_ci *
30038c2ecf20Sopenharmony_ci * Returns:
30048c2ecf20Sopenharmony_ci * 0 for success, -errno for errors.
30058c2ecf20Sopenharmony_ci */
30068c2ecf20Sopenharmony_ciint amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm,
30078c2ecf20Sopenharmony_ci			   u32 pasid)
30088c2ecf20Sopenharmony_ci{
30098c2ecf20Sopenharmony_ci	bool pte_support_ats = (adev->asic_type == CHIP_RAVEN);
30108c2ecf20Sopenharmony_ci	int r;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	r = amdgpu_bo_reserve(vm->root.base.bo, true);
30138c2ecf20Sopenharmony_ci	if (r)
30148c2ecf20Sopenharmony_ci		return r;
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ci	/* Sanity checks */
30178c2ecf20Sopenharmony_ci	r = amdgpu_vm_check_clean_reserved(adev, vm);
30188c2ecf20Sopenharmony_ci	if (r)
30198c2ecf20Sopenharmony_ci		goto unreserve_bo;
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_ci	if (pasid) {
30228c2ecf20Sopenharmony_ci		unsigned long flags;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
30258c2ecf20Sopenharmony_ci		r = idr_alloc(&adev->vm_manager.pasid_idr, vm, pasid, pasid + 1,
30268c2ecf20Sopenharmony_ci			      GFP_ATOMIC);
30278c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci		if (r == -ENOSPC)
30308c2ecf20Sopenharmony_ci			goto unreserve_bo;
30318c2ecf20Sopenharmony_ci		r = 0;
30328c2ecf20Sopenharmony_ci	}
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	/* Check if PD needs to be reinitialized and do it before
30358c2ecf20Sopenharmony_ci	 * changing any other state, in case it fails.
30368c2ecf20Sopenharmony_ci	 */
30378c2ecf20Sopenharmony_ci	if (pte_support_ats != vm->pte_support_ats) {
30388c2ecf20Sopenharmony_ci		vm->pte_support_ats = pte_support_ats;
30398c2ecf20Sopenharmony_ci		r = amdgpu_vm_clear_bo(adev, vm, vm->root.base.bo, false);
30408c2ecf20Sopenharmony_ci		if (r)
30418c2ecf20Sopenharmony_ci			goto free_idr;
30428c2ecf20Sopenharmony_ci	}
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci	/* Update VM state */
30458c2ecf20Sopenharmony_ci	vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
30468c2ecf20Sopenharmony_ci				    AMDGPU_VM_USE_CPU_FOR_COMPUTE);
30478c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("VM update mode is %s\n",
30488c2ecf20Sopenharmony_ci			 vm->use_cpu_for_update ? "CPU" : "SDMA");
30498c2ecf20Sopenharmony_ci	WARN_ONCE((vm->use_cpu_for_update &&
30508c2ecf20Sopenharmony_ci		   !amdgpu_gmc_vram_full_visible(&adev->gmc)),
30518c2ecf20Sopenharmony_ci		  "CPU update of VM recommended only for large BAR system\n");
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	if (vm->use_cpu_for_update) {
30548c2ecf20Sopenharmony_ci		/* Sync with last SDMA update/clear before switching to CPU */
30558c2ecf20Sopenharmony_ci		r = amdgpu_bo_sync_wait(vm->root.base.bo,
30568c2ecf20Sopenharmony_ci					AMDGPU_FENCE_OWNER_UNDEFINED, true);
30578c2ecf20Sopenharmony_ci		if (r)
30588c2ecf20Sopenharmony_ci			goto free_idr;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci		vm->update_funcs = &amdgpu_vm_cpu_funcs;
30618c2ecf20Sopenharmony_ci	} else {
30628c2ecf20Sopenharmony_ci		vm->update_funcs = &amdgpu_vm_sdma_funcs;
30638c2ecf20Sopenharmony_ci	}
30648c2ecf20Sopenharmony_ci	dma_fence_put(vm->last_update);
30658c2ecf20Sopenharmony_ci	vm->last_update = NULL;
30668c2ecf20Sopenharmony_ci	vm->is_compute_context = true;
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci	if (vm->pasid) {
30698c2ecf20Sopenharmony_ci		unsigned long flags;
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
30728c2ecf20Sopenharmony_ci		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
30738c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci		/* Free the original amdgpu allocated pasid
30768c2ecf20Sopenharmony_ci		 * Will be replaced with kfd allocated pasid
30778c2ecf20Sopenharmony_ci		 */
30788c2ecf20Sopenharmony_ci		amdgpu_pasid_free(vm->pasid);
30798c2ecf20Sopenharmony_ci		vm->pasid = 0;
30808c2ecf20Sopenharmony_ci	}
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	/* Free the shadow bo for compute VM */
30838c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&vm->root.base.bo->shadow);
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci	if (pasid)
30868c2ecf20Sopenharmony_ci		vm->pasid = pasid;
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	goto unreserve_bo;
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_cifree_idr:
30918c2ecf20Sopenharmony_ci	if (pasid) {
30928c2ecf20Sopenharmony_ci		unsigned long flags;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
30958c2ecf20Sopenharmony_ci		idr_remove(&adev->vm_manager.pasid_idr, pasid);
30968c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
30978c2ecf20Sopenharmony_ci	}
30988c2ecf20Sopenharmony_ciunreserve_bo:
30998c2ecf20Sopenharmony_ci	amdgpu_bo_unreserve(vm->root.base.bo);
31008c2ecf20Sopenharmony_ci	return r;
31018c2ecf20Sopenharmony_ci}
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci/**
31048c2ecf20Sopenharmony_ci * amdgpu_vm_release_compute - release a compute vm
31058c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
31068c2ecf20Sopenharmony_ci * @vm: a vm turned into compute vm by calling amdgpu_vm_make_compute
31078c2ecf20Sopenharmony_ci *
31088c2ecf20Sopenharmony_ci * This is a correspondant of amdgpu_vm_make_compute. It decouples compute
31098c2ecf20Sopenharmony_ci * pasid from vm. Compute should stop use of vm after this call.
31108c2ecf20Sopenharmony_ci */
31118c2ecf20Sopenharmony_civoid amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm)
31128c2ecf20Sopenharmony_ci{
31138c2ecf20Sopenharmony_ci	if (vm->pasid) {
31148c2ecf20Sopenharmony_ci		unsigned long flags;
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
31178c2ecf20Sopenharmony_ci		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
31188c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
31198c2ecf20Sopenharmony_ci	}
31208c2ecf20Sopenharmony_ci	vm->pasid = 0;
31218c2ecf20Sopenharmony_ci	vm->is_compute_context = false;
31228c2ecf20Sopenharmony_ci}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci/**
31258c2ecf20Sopenharmony_ci * amdgpu_vm_fini - tear down a vm instance
31268c2ecf20Sopenharmony_ci *
31278c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
31288c2ecf20Sopenharmony_ci * @vm: requested vm
31298c2ecf20Sopenharmony_ci *
31308c2ecf20Sopenharmony_ci * Tear down @vm.
31318c2ecf20Sopenharmony_ci * Unbind the VM and remove all bos from the vm bo list
31328c2ecf20Sopenharmony_ci */
31338c2ecf20Sopenharmony_civoid amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
31348c2ecf20Sopenharmony_ci{
31358c2ecf20Sopenharmony_ci	struct amdgpu_bo_va_mapping *mapping, *tmp;
31368c2ecf20Sopenharmony_ci	bool prt_fini_needed = !!adev->gmc.gmc_funcs->set_prt;
31378c2ecf20Sopenharmony_ci	struct amdgpu_bo *root;
31388c2ecf20Sopenharmony_ci	int i;
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	amdgpu_amdkfd_gpuvm_destroy_cb(adev, vm);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	root = amdgpu_bo_ref(vm->root.base.bo);
31438c2ecf20Sopenharmony_ci	amdgpu_bo_reserve(root, true);
31448c2ecf20Sopenharmony_ci	if (vm->pasid) {
31458c2ecf20Sopenharmony_ci		unsigned long flags;
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
31488c2ecf20Sopenharmony_ci		idr_remove(&adev->vm_manager.pasid_idr, vm->pasid);
31498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
31508c2ecf20Sopenharmony_ci		vm->pasid = 0;
31518c2ecf20Sopenharmony_ci	}
31528c2ecf20Sopenharmony_ci
31538c2ecf20Sopenharmony_ci	dma_fence_wait(vm->last_unlocked, false);
31548c2ecf20Sopenharmony_ci	dma_fence_put(vm->last_unlocked);
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mapping, tmp, &vm->freed, list) {
31578c2ecf20Sopenharmony_ci		if (mapping->flags & AMDGPU_PTE_PRT && prt_fini_needed) {
31588c2ecf20Sopenharmony_ci			amdgpu_vm_prt_fini(adev, vm);
31598c2ecf20Sopenharmony_ci			prt_fini_needed = false;
31608c2ecf20Sopenharmony_ci		}
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci		list_del(&mapping->list);
31638c2ecf20Sopenharmony_ci		amdgpu_vm_free_mapping(adev, vm, mapping, NULL);
31648c2ecf20Sopenharmony_ci	}
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	amdgpu_vm_free_pts(adev, vm, NULL);
31678c2ecf20Sopenharmony_ci	amdgpu_bo_unreserve(root);
31688c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&root);
31698c2ecf20Sopenharmony_ci	WARN_ON(vm->root.base.bo);
31708c2ecf20Sopenharmony_ci
31718c2ecf20Sopenharmony_ci	drm_sched_entity_destroy(&vm->immediate);
31728c2ecf20Sopenharmony_ci	drm_sched_entity_destroy(&vm->delayed);
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	if (!RB_EMPTY_ROOT(&vm->va.rb_root)) {
31758c2ecf20Sopenharmony_ci		dev_err(adev->dev, "still active bo inside vm\n");
31768c2ecf20Sopenharmony_ci	}
31778c2ecf20Sopenharmony_ci	rbtree_postorder_for_each_entry_safe(mapping, tmp,
31788c2ecf20Sopenharmony_ci					     &vm->va.rb_root, rb) {
31798c2ecf20Sopenharmony_ci		/* Don't remove the mapping here, we don't want to trigger a
31808c2ecf20Sopenharmony_ci		 * rebalance and the tree is about to be destroyed anyway.
31818c2ecf20Sopenharmony_ci		 */
31828c2ecf20Sopenharmony_ci		list_del(&mapping->list);
31838c2ecf20Sopenharmony_ci		kfree(mapping);
31848c2ecf20Sopenharmony_ci	}
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	dma_fence_put(vm->last_update);
31878c2ecf20Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
31888c2ecf20Sopenharmony_ci		amdgpu_vmid_free_reserved(adev, vm, i);
31898c2ecf20Sopenharmony_ci}
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci/**
31928c2ecf20Sopenharmony_ci * amdgpu_vm_manager_init - init the VM manager
31938c2ecf20Sopenharmony_ci *
31948c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
31958c2ecf20Sopenharmony_ci *
31968c2ecf20Sopenharmony_ci * Initialize the VM manager structures
31978c2ecf20Sopenharmony_ci */
31988c2ecf20Sopenharmony_civoid amdgpu_vm_manager_init(struct amdgpu_device *adev)
31998c2ecf20Sopenharmony_ci{
32008c2ecf20Sopenharmony_ci	unsigned i;
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	/* Concurrent flushes are only possible starting with Vega10 and
32038c2ecf20Sopenharmony_ci	 * are broken on Navi10 and Navi14.
32048c2ecf20Sopenharmony_ci	 */
32058c2ecf20Sopenharmony_ci	adev->vm_manager.concurrent_flush = !(adev->asic_type < CHIP_VEGA10 ||
32068c2ecf20Sopenharmony_ci					      adev->asic_type == CHIP_NAVI10 ||
32078c2ecf20Sopenharmony_ci					      adev->asic_type == CHIP_NAVI14);
32088c2ecf20Sopenharmony_ci	amdgpu_vmid_mgr_init(adev);
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	adev->vm_manager.fence_context =
32118c2ecf20Sopenharmony_ci		dma_fence_context_alloc(AMDGPU_MAX_RINGS);
32128c2ecf20Sopenharmony_ci	for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
32138c2ecf20Sopenharmony_ci		adev->vm_manager.seqno[i] = 0;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	spin_lock_init(&adev->vm_manager.prt_lock);
32168c2ecf20Sopenharmony_ci	atomic_set(&adev->vm_manager.num_prt_users, 0);
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci	/* If not overridden by the user, by default, only in large BAR systems
32198c2ecf20Sopenharmony_ci	 * Compute VM tables will be updated by CPU
32208c2ecf20Sopenharmony_ci	 */
32218c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
32228c2ecf20Sopenharmony_ci	if (amdgpu_vm_update_mode == -1) {
32238c2ecf20Sopenharmony_ci		/* For asic with VF MMIO access protection
32248c2ecf20Sopenharmony_ci		 * avoid using CPU for VM table updates
32258c2ecf20Sopenharmony_ci		 */
32268c2ecf20Sopenharmony_ci		if (amdgpu_gmc_vram_full_visible(&adev->gmc) &&
32278c2ecf20Sopenharmony_ci		    !amdgpu_sriov_vf_mmio_access_protection(adev))
32288c2ecf20Sopenharmony_ci			adev->vm_manager.vm_update_mode =
32298c2ecf20Sopenharmony_ci				AMDGPU_VM_USE_CPU_FOR_COMPUTE;
32308c2ecf20Sopenharmony_ci		else
32318c2ecf20Sopenharmony_ci			adev->vm_manager.vm_update_mode = 0;
32328c2ecf20Sopenharmony_ci	} else
32338c2ecf20Sopenharmony_ci		adev->vm_manager.vm_update_mode = amdgpu_vm_update_mode;
32348c2ecf20Sopenharmony_ci#else
32358c2ecf20Sopenharmony_ci	adev->vm_manager.vm_update_mode = 0;
32368c2ecf20Sopenharmony_ci#endif
32378c2ecf20Sopenharmony_ci
32388c2ecf20Sopenharmony_ci	idr_init(&adev->vm_manager.pasid_idr);
32398c2ecf20Sopenharmony_ci	spin_lock_init(&adev->vm_manager.pasid_lock);
32408c2ecf20Sopenharmony_ci}
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci/**
32438c2ecf20Sopenharmony_ci * amdgpu_vm_manager_fini - cleanup VM manager
32448c2ecf20Sopenharmony_ci *
32458c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
32468c2ecf20Sopenharmony_ci *
32478c2ecf20Sopenharmony_ci * Cleanup the VM manager and free resources.
32488c2ecf20Sopenharmony_ci */
32498c2ecf20Sopenharmony_civoid amdgpu_vm_manager_fini(struct amdgpu_device *adev)
32508c2ecf20Sopenharmony_ci{
32518c2ecf20Sopenharmony_ci	WARN_ON(!idr_is_empty(&adev->vm_manager.pasid_idr));
32528c2ecf20Sopenharmony_ci	idr_destroy(&adev->vm_manager.pasid_idr);
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci	amdgpu_vmid_mgr_fini(adev);
32558c2ecf20Sopenharmony_ci}
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci/**
32588c2ecf20Sopenharmony_ci * amdgpu_vm_ioctl - Manages VMID reservation for vm hubs.
32598c2ecf20Sopenharmony_ci *
32608c2ecf20Sopenharmony_ci * @dev: drm device pointer
32618c2ecf20Sopenharmony_ci * @data: drm_amdgpu_vm
32628c2ecf20Sopenharmony_ci * @filp: drm file pointer
32638c2ecf20Sopenharmony_ci *
32648c2ecf20Sopenharmony_ci * Returns:
32658c2ecf20Sopenharmony_ci * 0 for success, -errno for errors.
32668c2ecf20Sopenharmony_ci */
32678c2ecf20Sopenharmony_ciint amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
32688c2ecf20Sopenharmony_ci{
32698c2ecf20Sopenharmony_ci	union drm_amdgpu_vm *args = data;
32708c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = drm_to_adev(dev);
32718c2ecf20Sopenharmony_ci	struct amdgpu_fpriv *fpriv = filp->driver_priv;
32728c2ecf20Sopenharmony_ci	long timeout = msecs_to_jiffies(2000);
32738c2ecf20Sopenharmony_ci	int r;
32748c2ecf20Sopenharmony_ci
32758c2ecf20Sopenharmony_ci	/* No valid flags defined yet */
32768c2ecf20Sopenharmony_ci	if (args->in.flags)
32778c2ecf20Sopenharmony_ci		return -EINVAL;
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	switch (args->in.op) {
32808c2ecf20Sopenharmony_ci	case AMDGPU_VM_OP_RESERVE_VMID:
32818c2ecf20Sopenharmony_ci		/* We only have requirement to reserve vmid from gfxhub */
32828c2ecf20Sopenharmony_ci		r = amdgpu_vmid_alloc_reserved(adev, &fpriv->vm,
32838c2ecf20Sopenharmony_ci					       AMDGPU_GFXHUB_0);
32848c2ecf20Sopenharmony_ci		if (r)
32858c2ecf20Sopenharmony_ci			return r;
32868c2ecf20Sopenharmony_ci		break;
32878c2ecf20Sopenharmony_ci	case AMDGPU_VM_OP_UNRESERVE_VMID:
32888c2ecf20Sopenharmony_ci		if (amdgpu_sriov_runtime(adev))
32898c2ecf20Sopenharmony_ci			timeout = 8 * timeout;
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci		/* Wait vm idle to make sure the vmid set in SPM_VMID is
32928c2ecf20Sopenharmony_ci		 * not referenced anymore.
32938c2ecf20Sopenharmony_ci		 */
32948c2ecf20Sopenharmony_ci		r = amdgpu_bo_reserve(fpriv->vm.root.base.bo, true);
32958c2ecf20Sopenharmony_ci		if (r)
32968c2ecf20Sopenharmony_ci			return r;
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci		r = amdgpu_vm_wait_idle(&fpriv->vm, timeout);
32998c2ecf20Sopenharmony_ci		if (r < 0)
33008c2ecf20Sopenharmony_ci			return r;
33018c2ecf20Sopenharmony_ci
33028c2ecf20Sopenharmony_ci		amdgpu_bo_unreserve(fpriv->vm.root.base.bo);
33038c2ecf20Sopenharmony_ci		amdgpu_vmid_free_reserved(adev, &fpriv->vm, AMDGPU_GFXHUB_0);
33048c2ecf20Sopenharmony_ci		break;
33058c2ecf20Sopenharmony_ci	default:
33068c2ecf20Sopenharmony_ci		return -EINVAL;
33078c2ecf20Sopenharmony_ci	}
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_ci	return 0;
33108c2ecf20Sopenharmony_ci}
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci/**
33138c2ecf20Sopenharmony_ci * amdgpu_vm_get_task_info - Extracts task info for a PASID.
33148c2ecf20Sopenharmony_ci *
33158c2ecf20Sopenharmony_ci * @adev: drm device pointer
33168c2ecf20Sopenharmony_ci * @pasid: PASID identifier for VM
33178c2ecf20Sopenharmony_ci * @task_info: task_info to fill.
33188c2ecf20Sopenharmony_ci */
33198c2ecf20Sopenharmony_civoid amdgpu_vm_get_task_info(struct amdgpu_device *adev, u32 pasid,
33208c2ecf20Sopenharmony_ci			 struct amdgpu_task_info *task_info)
33218c2ecf20Sopenharmony_ci{
33228c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm;
33238c2ecf20Sopenharmony_ci	unsigned long flags;
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adev->vm_manager.pasid_lock, flags);
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
33288c2ecf20Sopenharmony_ci	if (vm)
33298c2ecf20Sopenharmony_ci		*task_info = vm->task_info;
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
33328c2ecf20Sopenharmony_ci}
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci/**
33358c2ecf20Sopenharmony_ci * amdgpu_vm_set_task_info - Sets VMs task info.
33368c2ecf20Sopenharmony_ci *
33378c2ecf20Sopenharmony_ci * @vm: vm for which to set the info
33388c2ecf20Sopenharmony_ci */
33398c2ecf20Sopenharmony_civoid amdgpu_vm_set_task_info(struct amdgpu_vm *vm)
33408c2ecf20Sopenharmony_ci{
33418c2ecf20Sopenharmony_ci	if (vm->task_info.pid)
33428c2ecf20Sopenharmony_ci		return;
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_ci	vm->task_info.pid = current->pid;
33458c2ecf20Sopenharmony_ci	get_task_comm(vm->task_info.task_name, current);
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci	if (current->group_leader->mm != current->mm)
33488c2ecf20Sopenharmony_ci		return;
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	vm->task_info.tgid = current->group_leader->pid;
33518c2ecf20Sopenharmony_ci	get_task_comm(vm->task_info.process_name, current->group_leader);
33528c2ecf20Sopenharmony_ci}
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci/**
33558c2ecf20Sopenharmony_ci * amdgpu_vm_handle_fault - graceful handling of VM faults.
33568c2ecf20Sopenharmony_ci * @adev: amdgpu device pointer
33578c2ecf20Sopenharmony_ci * @pasid: PASID of the VM
33588c2ecf20Sopenharmony_ci * @addr: Address of the fault
33598c2ecf20Sopenharmony_ci *
33608c2ecf20Sopenharmony_ci * Try to gracefully handle a VM fault. Return true if the fault was handled and
33618c2ecf20Sopenharmony_ci * shouldn't be reported any more.
33628c2ecf20Sopenharmony_ci */
33638c2ecf20Sopenharmony_cibool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
33648c2ecf20Sopenharmony_ci			    uint64_t addr)
33658c2ecf20Sopenharmony_ci{
33668c2ecf20Sopenharmony_ci	struct amdgpu_bo *root;
33678c2ecf20Sopenharmony_ci	uint64_t value, flags;
33688c2ecf20Sopenharmony_ci	struct amdgpu_vm *vm;
33698c2ecf20Sopenharmony_ci	long r;
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci	spin_lock(&adev->vm_manager.pasid_lock);
33728c2ecf20Sopenharmony_ci	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
33738c2ecf20Sopenharmony_ci	if (vm)
33748c2ecf20Sopenharmony_ci		root = amdgpu_bo_ref(vm->root.base.bo);
33758c2ecf20Sopenharmony_ci	else
33768c2ecf20Sopenharmony_ci		root = NULL;
33778c2ecf20Sopenharmony_ci	spin_unlock(&adev->vm_manager.pasid_lock);
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	if (!root)
33808c2ecf20Sopenharmony_ci		return false;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	r = amdgpu_bo_reserve(root, true);
33838c2ecf20Sopenharmony_ci	if (r)
33848c2ecf20Sopenharmony_ci		goto error_unref;
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	/* Double check that the VM still exists */
33878c2ecf20Sopenharmony_ci	spin_lock(&adev->vm_manager.pasid_lock);
33888c2ecf20Sopenharmony_ci	vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
33898c2ecf20Sopenharmony_ci	if (vm && vm->root.base.bo != root)
33908c2ecf20Sopenharmony_ci		vm = NULL;
33918c2ecf20Sopenharmony_ci	spin_unlock(&adev->vm_manager.pasid_lock);
33928c2ecf20Sopenharmony_ci	if (!vm)
33938c2ecf20Sopenharmony_ci		goto error_unlock;
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci	addr /= AMDGPU_GPU_PAGE_SIZE;
33968c2ecf20Sopenharmony_ci	flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED |
33978c2ecf20Sopenharmony_ci		AMDGPU_PTE_SYSTEM;
33988c2ecf20Sopenharmony_ci
33998c2ecf20Sopenharmony_ci	if (vm->is_compute_context) {
34008c2ecf20Sopenharmony_ci		/* Intentionally setting invalid PTE flag
34018c2ecf20Sopenharmony_ci		 * combination to force a no-retry-fault
34028c2ecf20Sopenharmony_ci		 */
34038c2ecf20Sopenharmony_ci		flags = AMDGPU_PTE_EXECUTABLE | AMDGPU_PDE_PTE |
34048c2ecf20Sopenharmony_ci			AMDGPU_PTE_TF;
34058c2ecf20Sopenharmony_ci		value = 0;
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci	} else if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_NEVER) {
34088c2ecf20Sopenharmony_ci		/* Redirect the access to the dummy page */
34098c2ecf20Sopenharmony_ci		value = adev->dummy_page_addr;
34108c2ecf20Sopenharmony_ci		flags |= AMDGPU_PTE_EXECUTABLE | AMDGPU_PTE_READABLE |
34118c2ecf20Sopenharmony_ci			AMDGPU_PTE_WRITEABLE;
34128c2ecf20Sopenharmony_ci
34138c2ecf20Sopenharmony_ci	} else {
34148c2ecf20Sopenharmony_ci		/* Let the hw retry silently on the PTE */
34158c2ecf20Sopenharmony_ci		value = 0;
34168c2ecf20Sopenharmony_ci	}
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	r = amdgpu_vm_bo_update_mapping(adev, vm, true, false, NULL, addr,
34198c2ecf20Sopenharmony_ci					addr + 1, flags, value, NULL, NULL);
34208c2ecf20Sopenharmony_ci	if (r)
34218c2ecf20Sopenharmony_ci		goto error_unlock;
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	r = amdgpu_vm_update_pdes(adev, vm, true);
34248c2ecf20Sopenharmony_ci
34258c2ecf20Sopenharmony_cierror_unlock:
34268c2ecf20Sopenharmony_ci	amdgpu_bo_unreserve(root);
34278c2ecf20Sopenharmony_ci	if (r < 0)
34288c2ecf20Sopenharmony_ci		DRM_ERROR("Can't handle page fault (%ld)\n", r);
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_cierror_unref:
34318c2ecf20Sopenharmony_ci	amdgpu_bo_unref(&root);
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci	return false;
34348c2ecf20Sopenharmony_ci}
3435