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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, vm, entry); 13208c2ecf20Sopenharmony_ci if (r) 13218c2ecf20Sopenharmony_ci goto error; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci r = vm->update_funcs->commit(¶ms, &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(¶ms, 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(¶ms, resv, sync_mode); 16388c2ecf20Sopenharmony_ci if (r) 16398c2ecf20Sopenharmony_ci goto error_unlock; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci r = amdgpu_vm_update_ptes(¶ms, start, last + 1, addr, flags); 16428c2ecf20Sopenharmony_ci if (r) 16438c2ecf20Sopenharmony_ci goto error_unlock; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci r = vm->update_funcs->commit(¶ms, 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