11bb76ff1Sjsg // SPDX-License-Identifier: GPL-2.0 OR MIT 21bb76ff1Sjsg /* 31bb76ff1Sjsg * Copyright 2022 Advanced Micro Devices, Inc. 41bb76ff1Sjsg * 51bb76ff1Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 61bb76ff1Sjsg * copy of this software and associated documentation files (the "Software"), 71bb76ff1Sjsg * to deal in the Software without restriction, including without limitation 81bb76ff1Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 91bb76ff1Sjsg * and/or sell copies of the Software, and to permit persons to whom the 101bb76ff1Sjsg * Software is furnished to do so, subject to the following conditions: 111bb76ff1Sjsg * 121bb76ff1Sjsg * The above copyright notice and this permission notice shall be included in 131bb76ff1Sjsg * all copies or substantial portions of the Software. 141bb76ff1Sjsg * 151bb76ff1Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161bb76ff1Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171bb76ff1Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181bb76ff1Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 191bb76ff1Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 201bb76ff1Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 211bb76ff1Sjsg * OTHER DEALINGS IN THE SOFTWARE. 221bb76ff1Sjsg */ 231bb76ff1Sjsg 241bb76ff1Sjsg #include <drm/drm_drv.h> 251bb76ff1Sjsg 261bb76ff1Sjsg #include "amdgpu.h" 271bb76ff1Sjsg #include "amdgpu_trace.h" 281bb76ff1Sjsg #include "amdgpu_vm.h" 291bb76ff1Sjsg 301bb76ff1Sjsg /* 311bb76ff1Sjsg * amdgpu_vm_pt_cursor - state for for_each_amdgpu_vm_pt 321bb76ff1Sjsg */ 331bb76ff1Sjsg struct amdgpu_vm_pt_cursor { 341bb76ff1Sjsg uint64_t pfn; 351bb76ff1Sjsg struct amdgpu_vm_bo_base *parent; 361bb76ff1Sjsg struct amdgpu_vm_bo_base *entry; 371bb76ff1Sjsg unsigned int level; 381bb76ff1Sjsg }; 391bb76ff1Sjsg 401bb76ff1Sjsg /** 411bb76ff1Sjsg * amdgpu_vm_pt_level_shift - return the addr shift for each level 421bb76ff1Sjsg * 431bb76ff1Sjsg * @adev: amdgpu_device pointer 441bb76ff1Sjsg * @level: VMPT level 451bb76ff1Sjsg * 461bb76ff1Sjsg * Returns: 471bb76ff1Sjsg * The number of bits the pfn needs to be right shifted for a level. 481bb76ff1Sjsg */ 491bb76ff1Sjsg static unsigned int amdgpu_vm_pt_level_shift(struct amdgpu_device *adev, 501bb76ff1Sjsg unsigned int level) 511bb76ff1Sjsg { 521bb76ff1Sjsg switch (level) { 531bb76ff1Sjsg case AMDGPU_VM_PDB2: 541bb76ff1Sjsg case AMDGPU_VM_PDB1: 551bb76ff1Sjsg case AMDGPU_VM_PDB0: 561bb76ff1Sjsg return 9 * (AMDGPU_VM_PDB0 - level) + 571bb76ff1Sjsg adev->vm_manager.block_size; 581bb76ff1Sjsg case AMDGPU_VM_PTB: 591bb76ff1Sjsg return 0; 601bb76ff1Sjsg default: 611bb76ff1Sjsg return ~0; 621bb76ff1Sjsg } 631bb76ff1Sjsg } 641bb76ff1Sjsg 651bb76ff1Sjsg /** 661bb76ff1Sjsg * amdgpu_vm_pt_num_entries - return the number of entries in a PD/PT 671bb76ff1Sjsg * 681bb76ff1Sjsg * @adev: amdgpu_device pointer 691bb76ff1Sjsg * @level: VMPT level 701bb76ff1Sjsg * 711bb76ff1Sjsg * Returns: 721bb76ff1Sjsg * The number of entries in a page directory or page table. 731bb76ff1Sjsg */ 741bb76ff1Sjsg static unsigned int amdgpu_vm_pt_num_entries(struct amdgpu_device *adev, 751bb76ff1Sjsg unsigned int level) 761bb76ff1Sjsg { 771bb76ff1Sjsg unsigned int shift; 781bb76ff1Sjsg 791bb76ff1Sjsg shift = amdgpu_vm_pt_level_shift(adev, adev->vm_manager.root_level); 801bb76ff1Sjsg if (level == adev->vm_manager.root_level) 811bb76ff1Sjsg /* For the root directory */ 821bb76ff1Sjsg return round_up(adev->vm_manager.max_pfn, 1ULL << shift) 831bb76ff1Sjsg >> shift; 841bb76ff1Sjsg else if (level != AMDGPU_VM_PTB) 851bb76ff1Sjsg /* Everything in between */ 861bb76ff1Sjsg return 512; 871bb76ff1Sjsg 881bb76ff1Sjsg /* For the page tables on the leaves */ 891bb76ff1Sjsg return AMDGPU_VM_PTE_COUNT(adev); 901bb76ff1Sjsg } 911bb76ff1Sjsg 921bb76ff1Sjsg /** 931bb76ff1Sjsg * amdgpu_vm_pt_num_ats_entries - return the number of ATS entries in the root PD 941bb76ff1Sjsg * 951bb76ff1Sjsg * @adev: amdgpu_device pointer 961bb76ff1Sjsg * 971bb76ff1Sjsg * Returns: 981bb76ff1Sjsg * The number of entries in the root page directory which needs the ATS setting. 991bb76ff1Sjsg */ 1001bb76ff1Sjsg static unsigned int amdgpu_vm_pt_num_ats_entries(struct amdgpu_device *adev) 1011bb76ff1Sjsg { 1021bb76ff1Sjsg unsigned int shift; 1031bb76ff1Sjsg 1041bb76ff1Sjsg shift = amdgpu_vm_pt_level_shift(adev, adev->vm_manager.root_level); 1051bb76ff1Sjsg return AMDGPU_GMC_HOLE_START >> (shift + AMDGPU_GPU_PAGE_SHIFT); 1061bb76ff1Sjsg } 1071bb76ff1Sjsg 1081bb76ff1Sjsg /** 1091bb76ff1Sjsg * amdgpu_vm_pt_entries_mask - the mask to get the entry number of a PD/PT 1101bb76ff1Sjsg * 1111bb76ff1Sjsg * @adev: amdgpu_device pointer 1121bb76ff1Sjsg * @level: VMPT level 1131bb76ff1Sjsg * 1141bb76ff1Sjsg * Returns: 1151bb76ff1Sjsg * The mask to extract the entry number of a PD/PT from an address. 1161bb76ff1Sjsg */ 1171bb76ff1Sjsg static uint32_t amdgpu_vm_pt_entries_mask(struct amdgpu_device *adev, 1181bb76ff1Sjsg unsigned int level) 1191bb76ff1Sjsg { 1201bb76ff1Sjsg if (level <= adev->vm_manager.root_level) 1211bb76ff1Sjsg return 0xffffffff; 1221bb76ff1Sjsg else if (level != AMDGPU_VM_PTB) 1231bb76ff1Sjsg return 0x1ff; 1241bb76ff1Sjsg else 1251bb76ff1Sjsg return AMDGPU_VM_PTE_COUNT(adev) - 1; 1261bb76ff1Sjsg } 1271bb76ff1Sjsg 1281bb76ff1Sjsg /** 1291bb76ff1Sjsg * amdgpu_vm_pt_size - returns the size of the page table in bytes 1301bb76ff1Sjsg * 1311bb76ff1Sjsg * @adev: amdgpu_device pointer 1321bb76ff1Sjsg * @level: VMPT level 1331bb76ff1Sjsg * 1341bb76ff1Sjsg * Returns: 1351bb76ff1Sjsg * The size of the BO for a page directory or page table in bytes. 1361bb76ff1Sjsg */ 1371bb76ff1Sjsg static unsigned int amdgpu_vm_pt_size(struct amdgpu_device *adev, 1381bb76ff1Sjsg unsigned int level) 1391bb76ff1Sjsg { 1401bb76ff1Sjsg return AMDGPU_GPU_PAGE_ALIGN(amdgpu_vm_pt_num_entries(adev, level) * 8); 1411bb76ff1Sjsg } 1421bb76ff1Sjsg 1431bb76ff1Sjsg /** 1441bb76ff1Sjsg * amdgpu_vm_pt_parent - get the parent page directory 1451bb76ff1Sjsg * 1461bb76ff1Sjsg * @pt: child page table 1471bb76ff1Sjsg * 1481bb76ff1Sjsg * Helper to get the parent entry for the child page table. NULL if we are at 1491bb76ff1Sjsg * the root page directory. 1501bb76ff1Sjsg */ 1511bb76ff1Sjsg static struct amdgpu_vm_bo_base * 1521bb76ff1Sjsg amdgpu_vm_pt_parent(struct amdgpu_vm_bo_base *pt) 1531bb76ff1Sjsg { 1541bb76ff1Sjsg struct amdgpu_bo *parent = pt->bo->parent; 1551bb76ff1Sjsg 1561bb76ff1Sjsg if (!parent) 1571bb76ff1Sjsg return NULL; 1581bb76ff1Sjsg 1591bb76ff1Sjsg return parent->vm_bo; 1601bb76ff1Sjsg } 1611bb76ff1Sjsg 1621bb76ff1Sjsg /** 1631bb76ff1Sjsg * amdgpu_vm_pt_start - start PD/PT walk 1641bb76ff1Sjsg * 1651bb76ff1Sjsg * @adev: amdgpu_device pointer 1661bb76ff1Sjsg * @vm: amdgpu_vm structure 1671bb76ff1Sjsg * @start: start address of the walk 1681bb76ff1Sjsg * @cursor: state to initialize 1691bb76ff1Sjsg * 1701bb76ff1Sjsg * Initialize a amdgpu_vm_pt_cursor to start a walk. 1711bb76ff1Sjsg */ 1721bb76ff1Sjsg static void amdgpu_vm_pt_start(struct amdgpu_device *adev, 1731bb76ff1Sjsg struct amdgpu_vm *vm, uint64_t start, 1741bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 1751bb76ff1Sjsg { 1761bb76ff1Sjsg cursor->pfn = start; 1771bb76ff1Sjsg cursor->parent = NULL; 1781bb76ff1Sjsg cursor->entry = &vm->root; 1791bb76ff1Sjsg cursor->level = adev->vm_manager.root_level; 1801bb76ff1Sjsg } 1811bb76ff1Sjsg 1821bb76ff1Sjsg /** 1831bb76ff1Sjsg * amdgpu_vm_pt_descendant - go to child node 1841bb76ff1Sjsg * 1851bb76ff1Sjsg * @adev: amdgpu_device pointer 1861bb76ff1Sjsg * @cursor: current state 1871bb76ff1Sjsg * 1881bb76ff1Sjsg * Walk to the child node of the current node. 1891bb76ff1Sjsg * Returns: 1901bb76ff1Sjsg * True if the walk was possible, false otherwise. 1911bb76ff1Sjsg */ 1921bb76ff1Sjsg static bool amdgpu_vm_pt_descendant(struct amdgpu_device *adev, 1931bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 1941bb76ff1Sjsg { 1951bb76ff1Sjsg unsigned int mask, shift, idx; 1961bb76ff1Sjsg 1971bb76ff1Sjsg if ((cursor->level == AMDGPU_VM_PTB) || !cursor->entry || 1981bb76ff1Sjsg !cursor->entry->bo) 1991bb76ff1Sjsg return false; 2001bb76ff1Sjsg 2011bb76ff1Sjsg mask = amdgpu_vm_pt_entries_mask(adev, cursor->level); 2021bb76ff1Sjsg shift = amdgpu_vm_pt_level_shift(adev, cursor->level); 2031bb76ff1Sjsg 2041bb76ff1Sjsg ++cursor->level; 2051bb76ff1Sjsg idx = (cursor->pfn >> shift) & mask; 2061bb76ff1Sjsg cursor->parent = cursor->entry; 2071bb76ff1Sjsg cursor->entry = &to_amdgpu_bo_vm(cursor->entry->bo)->entries[idx]; 2081bb76ff1Sjsg return true; 2091bb76ff1Sjsg } 2101bb76ff1Sjsg 2111bb76ff1Sjsg /** 2121bb76ff1Sjsg * amdgpu_vm_pt_sibling - go to sibling node 2131bb76ff1Sjsg * 2141bb76ff1Sjsg * @adev: amdgpu_device pointer 2151bb76ff1Sjsg * @cursor: current state 2161bb76ff1Sjsg * 2171bb76ff1Sjsg * Walk to the sibling node of the current node. 2181bb76ff1Sjsg * Returns: 2191bb76ff1Sjsg * True if the walk was possible, false otherwise. 2201bb76ff1Sjsg */ 2211bb76ff1Sjsg static bool amdgpu_vm_pt_sibling(struct amdgpu_device *adev, 2221bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 2231bb76ff1Sjsg { 2241bb76ff1Sjsg 2251bb76ff1Sjsg unsigned int shift, num_entries; 2261bb76ff1Sjsg struct amdgpu_bo_vm *parent; 2271bb76ff1Sjsg 2281bb76ff1Sjsg /* Root doesn't have a sibling */ 2291bb76ff1Sjsg if (!cursor->parent) 2301bb76ff1Sjsg return false; 2311bb76ff1Sjsg 2321bb76ff1Sjsg /* Go to our parents and see if we got a sibling */ 2331bb76ff1Sjsg shift = amdgpu_vm_pt_level_shift(adev, cursor->level - 1); 2341bb76ff1Sjsg num_entries = amdgpu_vm_pt_num_entries(adev, cursor->level - 1); 2351bb76ff1Sjsg parent = to_amdgpu_bo_vm(cursor->parent->bo); 2361bb76ff1Sjsg 2371bb76ff1Sjsg if (cursor->entry == &parent->entries[num_entries - 1]) 2381bb76ff1Sjsg return false; 2391bb76ff1Sjsg 2401bb76ff1Sjsg cursor->pfn += 1ULL << shift; 2411bb76ff1Sjsg cursor->pfn &= ~((1ULL << shift) - 1); 2421bb76ff1Sjsg ++cursor->entry; 2431bb76ff1Sjsg return true; 2441bb76ff1Sjsg } 2451bb76ff1Sjsg 2461bb76ff1Sjsg /** 2471bb76ff1Sjsg * amdgpu_vm_pt_ancestor - go to parent node 2481bb76ff1Sjsg * 2491bb76ff1Sjsg * @cursor: current state 2501bb76ff1Sjsg * 2511bb76ff1Sjsg * Walk to the parent node of the current node. 2521bb76ff1Sjsg * Returns: 2531bb76ff1Sjsg * True if the walk was possible, false otherwise. 2541bb76ff1Sjsg */ 2551bb76ff1Sjsg static bool amdgpu_vm_pt_ancestor(struct amdgpu_vm_pt_cursor *cursor) 2561bb76ff1Sjsg { 2571bb76ff1Sjsg if (!cursor->parent) 2581bb76ff1Sjsg return false; 2591bb76ff1Sjsg 2601bb76ff1Sjsg --cursor->level; 2611bb76ff1Sjsg cursor->entry = cursor->parent; 2621bb76ff1Sjsg cursor->parent = amdgpu_vm_pt_parent(cursor->parent); 2631bb76ff1Sjsg return true; 2641bb76ff1Sjsg } 2651bb76ff1Sjsg 2661bb76ff1Sjsg /** 2671bb76ff1Sjsg * amdgpu_vm_pt_next - get next PD/PT in hieratchy 2681bb76ff1Sjsg * 2691bb76ff1Sjsg * @adev: amdgpu_device pointer 2701bb76ff1Sjsg * @cursor: current state 2711bb76ff1Sjsg * 2721bb76ff1Sjsg * Walk the PD/PT tree to the next node. 2731bb76ff1Sjsg */ 2741bb76ff1Sjsg static void amdgpu_vm_pt_next(struct amdgpu_device *adev, 2751bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 2761bb76ff1Sjsg { 2771bb76ff1Sjsg /* First try a newborn child */ 2781bb76ff1Sjsg if (amdgpu_vm_pt_descendant(adev, cursor)) 2791bb76ff1Sjsg return; 2801bb76ff1Sjsg 2811bb76ff1Sjsg /* If that didn't worked try to find a sibling */ 2821bb76ff1Sjsg while (!amdgpu_vm_pt_sibling(adev, cursor)) { 2831bb76ff1Sjsg /* No sibling, go to our parents and grandparents */ 2841bb76ff1Sjsg if (!amdgpu_vm_pt_ancestor(cursor)) { 2851bb76ff1Sjsg cursor->pfn = ~0ll; 2861bb76ff1Sjsg return; 2871bb76ff1Sjsg } 2881bb76ff1Sjsg } 2891bb76ff1Sjsg } 2901bb76ff1Sjsg 2911bb76ff1Sjsg /** 2921bb76ff1Sjsg * amdgpu_vm_pt_first_dfs - start a deep first search 2931bb76ff1Sjsg * 2941bb76ff1Sjsg * @adev: amdgpu_device structure 2951bb76ff1Sjsg * @vm: amdgpu_vm structure 2961bb76ff1Sjsg * @start: optional cursor to start with 2971bb76ff1Sjsg * @cursor: state to initialize 2981bb76ff1Sjsg * 2991bb76ff1Sjsg * Starts a deep first traversal of the PD/PT tree. 3001bb76ff1Sjsg */ 3011bb76ff1Sjsg static void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev, 3021bb76ff1Sjsg struct amdgpu_vm *vm, 3031bb76ff1Sjsg struct amdgpu_vm_pt_cursor *start, 3041bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 3051bb76ff1Sjsg { 3061bb76ff1Sjsg if (start) 3071bb76ff1Sjsg *cursor = *start; 3081bb76ff1Sjsg else 3091bb76ff1Sjsg amdgpu_vm_pt_start(adev, vm, 0, cursor); 3101bb76ff1Sjsg 3111bb76ff1Sjsg while (amdgpu_vm_pt_descendant(adev, cursor)) 3121bb76ff1Sjsg ; 3131bb76ff1Sjsg } 3141bb76ff1Sjsg 3151bb76ff1Sjsg /** 3161bb76ff1Sjsg * amdgpu_vm_pt_continue_dfs - check if the deep first search should continue 3171bb76ff1Sjsg * 3181bb76ff1Sjsg * @start: starting point for the search 3191bb76ff1Sjsg * @entry: current entry 3201bb76ff1Sjsg * 3211bb76ff1Sjsg * Returns: 3221bb76ff1Sjsg * True when the search should continue, false otherwise. 3231bb76ff1Sjsg */ 3241bb76ff1Sjsg static bool amdgpu_vm_pt_continue_dfs(struct amdgpu_vm_pt_cursor *start, 3251bb76ff1Sjsg struct amdgpu_vm_bo_base *entry) 3261bb76ff1Sjsg { 3271bb76ff1Sjsg return entry && (!start || entry != start->entry); 3281bb76ff1Sjsg } 3291bb76ff1Sjsg 3301bb76ff1Sjsg /** 3311bb76ff1Sjsg * amdgpu_vm_pt_next_dfs - get the next node for a deep first search 3321bb76ff1Sjsg * 3331bb76ff1Sjsg * @adev: amdgpu_device structure 3341bb76ff1Sjsg * @cursor: current state 3351bb76ff1Sjsg * 3361bb76ff1Sjsg * Move the cursor to the next node in a deep first search. 3371bb76ff1Sjsg */ 3381bb76ff1Sjsg static void amdgpu_vm_pt_next_dfs(struct amdgpu_device *adev, 3391bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor) 3401bb76ff1Sjsg { 3411bb76ff1Sjsg if (!cursor->entry) 3421bb76ff1Sjsg return; 3431bb76ff1Sjsg 3441bb76ff1Sjsg if (!cursor->parent) 3451bb76ff1Sjsg cursor->entry = NULL; 3461bb76ff1Sjsg else if (amdgpu_vm_pt_sibling(adev, cursor)) 3471bb76ff1Sjsg while (amdgpu_vm_pt_descendant(adev, cursor)) 3481bb76ff1Sjsg ; 3491bb76ff1Sjsg else 3501bb76ff1Sjsg amdgpu_vm_pt_ancestor(cursor); 3511bb76ff1Sjsg } 3521bb76ff1Sjsg 3531bb76ff1Sjsg /* 3541bb76ff1Sjsg * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs 3551bb76ff1Sjsg */ 3561bb76ff1Sjsg #define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) \ 3571bb76ff1Sjsg for (amdgpu_vm_pt_first_dfs((adev), (vm), (start), &(cursor)), \ 3581bb76ff1Sjsg (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\ 3591bb76ff1Sjsg amdgpu_vm_pt_continue_dfs((start), (entry)); \ 3601bb76ff1Sjsg (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor))) 3611bb76ff1Sjsg 3621bb76ff1Sjsg /** 3631bb76ff1Sjsg * amdgpu_vm_pt_clear - initially clear the PDs/PTs 3641bb76ff1Sjsg * 3651bb76ff1Sjsg * @adev: amdgpu_device pointer 3661bb76ff1Sjsg * @vm: VM to clear BO from 3671bb76ff1Sjsg * @vmbo: BO to clear 3681bb76ff1Sjsg * @immediate: use an immediate update 3691bb76ff1Sjsg * 3701bb76ff1Sjsg * Root PD needs to be reserved when calling this. 3711bb76ff1Sjsg * 3721bb76ff1Sjsg * Returns: 3731bb76ff1Sjsg * 0 on success, errno otherwise. 3741bb76ff1Sjsg */ 3751bb76ff1Sjsg int amdgpu_vm_pt_clear(struct amdgpu_device *adev, struct amdgpu_vm *vm, 3761bb76ff1Sjsg struct amdgpu_bo_vm *vmbo, bool immediate) 3771bb76ff1Sjsg { 3781bb76ff1Sjsg unsigned int level = adev->vm_manager.root_level; 3791bb76ff1Sjsg struct ttm_operation_ctx ctx = { true, false }; 3801bb76ff1Sjsg struct amdgpu_vm_update_params params; 3811bb76ff1Sjsg struct amdgpu_bo *ancestor = &vmbo->bo; 3821bb76ff1Sjsg unsigned int entries, ats_entries; 3831bb76ff1Sjsg struct amdgpu_bo *bo = &vmbo->bo; 3841bb76ff1Sjsg uint64_t addr; 3851bb76ff1Sjsg int r, idx; 3861bb76ff1Sjsg 3871bb76ff1Sjsg /* Figure out our place in the hierarchy */ 3881bb76ff1Sjsg if (ancestor->parent) { 3891bb76ff1Sjsg ++level; 3901bb76ff1Sjsg while (ancestor->parent->parent) { 3911bb76ff1Sjsg ++level; 3921bb76ff1Sjsg ancestor = ancestor->parent; 3931bb76ff1Sjsg } 3941bb76ff1Sjsg } 3951bb76ff1Sjsg 3961bb76ff1Sjsg entries = amdgpu_bo_size(bo) / 8; 3971bb76ff1Sjsg if (!vm->pte_support_ats) { 3981bb76ff1Sjsg ats_entries = 0; 3991bb76ff1Sjsg 4001bb76ff1Sjsg } else if (!bo->parent) { 4011bb76ff1Sjsg ats_entries = amdgpu_vm_pt_num_ats_entries(adev); 4021bb76ff1Sjsg ats_entries = min(ats_entries, entries); 4031bb76ff1Sjsg entries -= ats_entries; 4041bb76ff1Sjsg 4051bb76ff1Sjsg } else { 4061bb76ff1Sjsg struct amdgpu_vm_bo_base *pt; 4071bb76ff1Sjsg 4081bb76ff1Sjsg pt = ancestor->vm_bo; 4091bb76ff1Sjsg ats_entries = amdgpu_vm_pt_num_ats_entries(adev); 4101bb76ff1Sjsg if ((pt - to_amdgpu_bo_vm(vm->root.bo)->entries) >= 4111bb76ff1Sjsg ats_entries) { 4121bb76ff1Sjsg ats_entries = 0; 4131bb76ff1Sjsg } else { 4141bb76ff1Sjsg ats_entries = entries; 4151bb76ff1Sjsg entries = 0; 4161bb76ff1Sjsg } 4171bb76ff1Sjsg } 4181bb76ff1Sjsg 4191bb76ff1Sjsg r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 4201bb76ff1Sjsg if (r) 4211bb76ff1Sjsg return r; 4221bb76ff1Sjsg 4231bb76ff1Sjsg if (vmbo->shadow) { 4241bb76ff1Sjsg struct amdgpu_bo *shadow = vmbo->shadow; 4251bb76ff1Sjsg 4261bb76ff1Sjsg r = ttm_bo_validate(&shadow->tbo, &shadow->placement, &ctx); 4271bb76ff1Sjsg if (r) 4281bb76ff1Sjsg return r; 4291bb76ff1Sjsg } 4301bb76ff1Sjsg 4311bb76ff1Sjsg if (!drm_dev_enter(adev_to_drm(adev), &idx)) 4321bb76ff1Sjsg return -ENODEV; 4331bb76ff1Sjsg 4341bb76ff1Sjsg r = vm->update_funcs->map_table(vmbo); 4351bb76ff1Sjsg if (r) 4361bb76ff1Sjsg goto exit; 4371bb76ff1Sjsg 4381bb76ff1Sjsg memset(¶ms, 0, sizeof(params)); 4391bb76ff1Sjsg params.adev = adev; 4401bb76ff1Sjsg params.vm = vm; 4411bb76ff1Sjsg params.immediate = immediate; 4421bb76ff1Sjsg 4431bb76ff1Sjsg r = vm->update_funcs->prepare(¶ms, NULL, AMDGPU_SYNC_EXPLICIT); 4441bb76ff1Sjsg if (r) 4451bb76ff1Sjsg goto exit; 4461bb76ff1Sjsg 4471bb76ff1Sjsg addr = 0; 4481bb76ff1Sjsg if (ats_entries) { 4491bb76ff1Sjsg uint64_t value = 0, flags; 4501bb76ff1Sjsg 4511bb76ff1Sjsg flags = AMDGPU_PTE_DEFAULT_ATC; 4521bb76ff1Sjsg if (level != AMDGPU_VM_PTB) { 4531bb76ff1Sjsg /* Handle leaf PDEs as PTEs */ 4541bb76ff1Sjsg flags |= AMDGPU_PDE_PTE; 4551bb76ff1Sjsg amdgpu_gmc_get_vm_pde(adev, level, &value, &flags); 4561bb76ff1Sjsg } 4571bb76ff1Sjsg 4581bb76ff1Sjsg r = vm->update_funcs->update(¶ms, vmbo, addr, 0, 4591bb76ff1Sjsg ats_entries, value, flags); 4601bb76ff1Sjsg if (r) 4611bb76ff1Sjsg goto exit; 4621bb76ff1Sjsg 4631bb76ff1Sjsg addr += ats_entries * 8; 4641bb76ff1Sjsg } 4651bb76ff1Sjsg 4661bb76ff1Sjsg if (entries) { 4671bb76ff1Sjsg uint64_t value = 0, flags = 0; 4681bb76ff1Sjsg 4691bb76ff1Sjsg if (adev->asic_type >= CHIP_VEGA10) { 4701bb76ff1Sjsg if (level != AMDGPU_VM_PTB) { 4711bb76ff1Sjsg /* Handle leaf PDEs as PTEs */ 4721bb76ff1Sjsg flags |= AMDGPU_PDE_PTE; 4731bb76ff1Sjsg amdgpu_gmc_get_vm_pde(adev, level, 4741bb76ff1Sjsg &value, &flags); 4751bb76ff1Sjsg } else { 4761bb76ff1Sjsg /* Workaround for fault priority problem on GMC9 */ 4771bb76ff1Sjsg flags = AMDGPU_PTE_EXECUTABLE; 4781bb76ff1Sjsg } 4791bb76ff1Sjsg } 4801bb76ff1Sjsg 4811bb76ff1Sjsg r = vm->update_funcs->update(¶ms, vmbo, addr, 0, entries, 4821bb76ff1Sjsg value, flags); 4831bb76ff1Sjsg if (r) 4841bb76ff1Sjsg goto exit; 4851bb76ff1Sjsg } 4861bb76ff1Sjsg 4871bb76ff1Sjsg r = vm->update_funcs->commit(¶ms, NULL); 4881bb76ff1Sjsg exit: 4891bb76ff1Sjsg drm_dev_exit(idx); 4901bb76ff1Sjsg return r; 4911bb76ff1Sjsg } 4921bb76ff1Sjsg 4931bb76ff1Sjsg /** 4941bb76ff1Sjsg * amdgpu_vm_pt_create - create bo for PD/PT 4951bb76ff1Sjsg * 4961bb76ff1Sjsg * @adev: amdgpu_device pointer 4971bb76ff1Sjsg * @vm: requesting vm 4981bb76ff1Sjsg * @level: the page table level 4991bb76ff1Sjsg * @immediate: use a immediate update 5001bb76ff1Sjsg * @vmbo: pointer to the buffer object pointer 501f005ef32Sjsg * @xcp_id: GPU partition id 5021bb76ff1Sjsg */ 5031bb76ff1Sjsg int amdgpu_vm_pt_create(struct amdgpu_device *adev, struct amdgpu_vm *vm, 504f005ef32Sjsg int level, bool immediate, struct amdgpu_bo_vm **vmbo, 505f005ef32Sjsg int32_t xcp_id) 5061bb76ff1Sjsg { 5071bb76ff1Sjsg struct amdgpu_bo_param bp; 5081bb76ff1Sjsg struct amdgpu_bo *bo; 5091bb76ff1Sjsg struct dma_resv *resv; 5101bb76ff1Sjsg unsigned int num_entries; 5111bb76ff1Sjsg int r; 5121bb76ff1Sjsg 5131bb76ff1Sjsg memset(&bp, 0, sizeof(bp)); 5141bb76ff1Sjsg 5151bb76ff1Sjsg bp.size = amdgpu_vm_pt_size(adev, level); 5161bb76ff1Sjsg bp.byte_align = AMDGPU_GPU_PAGE_SIZE; 517f005ef32Sjsg 518f005ef32Sjsg if (!adev->gmc.is_app_apu) 5191bb76ff1Sjsg bp.domain = AMDGPU_GEM_DOMAIN_VRAM; 520f005ef32Sjsg else 521f005ef32Sjsg bp.domain = AMDGPU_GEM_DOMAIN_GTT; 522f005ef32Sjsg 5231bb76ff1Sjsg bp.domain = amdgpu_bo_get_preferred_domain(adev, bp.domain); 5241bb76ff1Sjsg bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | 5251bb76ff1Sjsg AMDGPU_GEM_CREATE_CPU_GTT_USWC; 5261bb76ff1Sjsg 5271bb76ff1Sjsg if (level < AMDGPU_VM_PTB) 5281bb76ff1Sjsg num_entries = amdgpu_vm_pt_num_entries(adev, level); 5291bb76ff1Sjsg else 5301bb76ff1Sjsg num_entries = 0; 5311bb76ff1Sjsg 5321bb76ff1Sjsg bp.bo_ptr_size = struct_size((*vmbo), entries, num_entries); 5331bb76ff1Sjsg 5341bb76ff1Sjsg if (vm->use_cpu_for_update) 5351bb76ff1Sjsg bp.flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; 5361bb76ff1Sjsg 5371bb76ff1Sjsg bp.type = ttm_bo_type_kernel; 5381bb76ff1Sjsg bp.no_wait_gpu = immediate; 539f005ef32Sjsg bp.xcp_id_plus1 = xcp_id + 1; 540f005ef32Sjsg 5411bb76ff1Sjsg if (vm->root.bo) 5421bb76ff1Sjsg bp.resv = vm->root.bo->tbo.base.resv; 5431bb76ff1Sjsg 5441bb76ff1Sjsg r = amdgpu_bo_create_vm(adev, &bp, vmbo); 5451bb76ff1Sjsg if (r) 5461bb76ff1Sjsg return r; 5471bb76ff1Sjsg 5481bb76ff1Sjsg bo = &(*vmbo)->bo; 5491bb76ff1Sjsg if (vm->is_compute_context || (adev->flags & AMD_IS_APU)) { 5501bb76ff1Sjsg (*vmbo)->shadow = NULL; 5511bb76ff1Sjsg return 0; 5521bb76ff1Sjsg } 5531bb76ff1Sjsg 5541bb76ff1Sjsg if (!bp.resv) 5551bb76ff1Sjsg WARN_ON(dma_resv_lock(bo->tbo.base.resv, 5561bb76ff1Sjsg NULL)); 5571bb76ff1Sjsg resv = bp.resv; 5581bb76ff1Sjsg memset(&bp, 0, sizeof(bp)); 5591bb76ff1Sjsg bp.size = amdgpu_vm_pt_size(adev, level); 5601bb76ff1Sjsg bp.domain = AMDGPU_GEM_DOMAIN_GTT; 5611bb76ff1Sjsg bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC; 5621bb76ff1Sjsg bp.type = ttm_bo_type_kernel; 5631bb76ff1Sjsg bp.resv = bo->tbo.base.resv; 5641bb76ff1Sjsg bp.bo_ptr_size = sizeof(struct amdgpu_bo); 565f005ef32Sjsg bp.xcp_id_plus1 = xcp_id + 1; 5661bb76ff1Sjsg 5671bb76ff1Sjsg r = amdgpu_bo_create(adev, &bp, &(*vmbo)->shadow); 5681bb76ff1Sjsg 5691bb76ff1Sjsg if (!resv) 5701bb76ff1Sjsg dma_resv_unlock(bo->tbo.base.resv); 5711bb76ff1Sjsg 5721bb76ff1Sjsg if (r) { 5731bb76ff1Sjsg amdgpu_bo_unref(&bo); 5741bb76ff1Sjsg return r; 5751bb76ff1Sjsg } 5761bb76ff1Sjsg 5771bb76ff1Sjsg amdgpu_bo_add_to_shadow_list(*vmbo); 5781bb76ff1Sjsg 5791bb76ff1Sjsg return 0; 5801bb76ff1Sjsg } 5811bb76ff1Sjsg 5821bb76ff1Sjsg /** 5831bb76ff1Sjsg * amdgpu_vm_pt_alloc - Allocate a specific page table 5841bb76ff1Sjsg * 5851bb76ff1Sjsg * @adev: amdgpu_device pointer 5861bb76ff1Sjsg * @vm: VM to allocate page tables for 5871bb76ff1Sjsg * @cursor: Which page table to allocate 5881bb76ff1Sjsg * @immediate: use an immediate update 5891bb76ff1Sjsg * 5901bb76ff1Sjsg * Make sure a specific page table or directory is allocated. 5911bb76ff1Sjsg * 5921bb76ff1Sjsg * Returns: 5931bb76ff1Sjsg * 1 if page table needed to be allocated, 0 if page table was already 5941bb76ff1Sjsg * allocated, negative errno if an error occurred. 5951bb76ff1Sjsg */ 5961bb76ff1Sjsg static int amdgpu_vm_pt_alloc(struct amdgpu_device *adev, 5971bb76ff1Sjsg struct amdgpu_vm *vm, 5981bb76ff1Sjsg struct amdgpu_vm_pt_cursor *cursor, 5991bb76ff1Sjsg bool immediate) 6001bb76ff1Sjsg { 6011bb76ff1Sjsg struct amdgpu_vm_bo_base *entry = cursor->entry; 6021bb76ff1Sjsg struct amdgpu_bo *pt_bo; 6031bb76ff1Sjsg struct amdgpu_bo_vm *pt; 6041bb76ff1Sjsg int r; 6051bb76ff1Sjsg 6061bb76ff1Sjsg if (entry->bo) 6071bb76ff1Sjsg return 0; 6081bb76ff1Sjsg 6091bb76ff1Sjsg amdgpu_vm_eviction_unlock(vm); 610f005ef32Sjsg r = amdgpu_vm_pt_create(adev, vm, cursor->level, immediate, &pt, 611f005ef32Sjsg vm->root.bo->xcp_id); 6121bb76ff1Sjsg amdgpu_vm_eviction_lock(vm); 6131bb76ff1Sjsg if (r) 6141bb76ff1Sjsg return r; 6151bb76ff1Sjsg 6161bb76ff1Sjsg /* Keep a reference to the root directory to avoid 6171bb76ff1Sjsg * freeing them up in the wrong order. 6181bb76ff1Sjsg */ 6191bb76ff1Sjsg pt_bo = &pt->bo; 6201bb76ff1Sjsg pt_bo->parent = amdgpu_bo_ref(cursor->parent->bo); 6211bb76ff1Sjsg amdgpu_vm_bo_base_init(entry, vm, pt_bo); 6221bb76ff1Sjsg r = amdgpu_vm_pt_clear(adev, vm, pt, immediate); 6231bb76ff1Sjsg if (r) 6241bb76ff1Sjsg goto error_free_pt; 6251bb76ff1Sjsg 6261bb76ff1Sjsg return 0; 6271bb76ff1Sjsg 6281bb76ff1Sjsg error_free_pt: 6291bb76ff1Sjsg amdgpu_bo_unref(&pt->shadow); 6301bb76ff1Sjsg amdgpu_bo_unref(&pt_bo); 6311bb76ff1Sjsg return r; 6321bb76ff1Sjsg } 6331bb76ff1Sjsg 6341bb76ff1Sjsg /** 6351bb76ff1Sjsg * amdgpu_vm_pt_free - free one PD/PT 6361bb76ff1Sjsg * 6371bb76ff1Sjsg * @entry: PDE to free 6381bb76ff1Sjsg */ 6391bb76ff1Sjsg static void amdgpu_vm_pt_free(struct amdgpu_vm_bo_base *entry) 6401bb76ff1Sjsg { 6411bb76ff1Sjsg struct amdgpu_bo *shadow; 6421bb76ff1Sjsg 6431bb76ff1Sjsg if (!entry->bo) 6441bb76ff1Sjsg return; 645753b8a43Sjsg 646753b8a43Sjsg entry->bo->vm_bo = NULL; 6471bb76ff1Sjsg shadow = amdgpu_bo_shadowed(entry->bo); 6481bb76ff1Sjsg if (shadow) { 6491bb76ff1Sjsg ttm_bo_set_bulk_move(&shadow->tbo, NULL); 6501bb76ff1Sjsg amdgpu_bo_unref(&shadow); 6511bb76ff1Sjsg } 6521bb76ff1Sjsg ttm_bo_set_bulk_move(&entry->bo->tbo, NULL); 6531bb76ff1Sjsg 6541bb76ff1Sjsg spin_lock(&entry->vm->status_lock); 6551bb76ff1Sjsg list_del(&entry->vm_status); 6561bb76ff1Sjsg spin_unlock(&entry->vm->status_lock); 6571bb76ff1Sjsg amdgpu_bo_unref(&entry->bo); 6581bb76ff1Sjsg } 6591bb76ff1Sjsg 6601bb76ff1Sjsg void amdgpu_vm_pt_free_work(struct work_struct *work) 6611bb76ff1Sjsg { 6621bb76ff1Sjsg struct amdgpu_vm_bo_base *entry, *next; 6631bb76ff1Sjsg struct amdgpu_vm *vm; 6641bb76ff1Sjsg DRM_LIST_HEAD(pt_freed); 6651bb76ff1Sjsg 6661bb76ff1Sjsg vm = container_of(work, struct amdgpu_vm, pt_free_work); 6671bb76ff1Sjsg 6681bb76ff1Sjsg spin_lock(&vm->status_lock); 6691bb76ff1Sjsg list_splice_init(&vm->pt_freed, &pt_freed); 6701bb76ff1Sjsg spin_unlock(&vm->status_lock); 6711bb76ff1Sjsg 6721bb76ff1Sjsg /* flush_work in amdgpu_vm_fini ensure vm->root.bo is valid. */ 6731bb76ff1Sjsg amdgpu_bo_reserve(vm->root.bo, true); 6741bb76ff1Sjsg 6751bb76ff1Sjsg list_for_each_entry_safe(entry, next, &pt_freed, vm_status) 6761bb76ff1Sjsg amdgpu_vm_pt_free(entry); 6771bb76ff1Sjsg 6781bb76ff1Sjsg amdgpu_bo_unreserve(vm->root.bo); 6791bb76ff1Sjsg } 6801bb76ff1Sjsg 6811bb76ff1Sjsg /** 6821bb76ff1Sjsg * amdgpu_vm_pt_free_dfs - free PD/PT levels 6831bb76ff1Sjsg * 6841bb76ff1Sjsg * @adev: amdgpu device structure 6851bb76ff1Sjsg * @vm: amdgpu vm structure 6861bb76ff1Sjsg * @start: optional cursor where to start freeing PDs/PTs 687f005ef32Sjsg * @unlocked: vm resv unlock status 6881bb76ff1Sjsg * 6891bb76ff1Sjsg * Free the page directory or page table level and all sub levels. 6901bb76ff1Sjsg */ 6911bb76ff1Sjsg static void amdgpu_vm_pt_free_dfs(struct amdgpu_device *adev, 6921bb76ff1Sjsg struct amdgpu_vm *vm, 6931bb76ff1Sjsg struct amdgpu_vm_pt_cursor *start, 6941bb76ff1Sjsg bool unlocked) 6951bb76ff1Sjsg { 6961bb76ff1Sjsg struct amdgpu_vm_pt_cursor cursor; 6971bb76ff1Sjsg struct amdgpu_vm_bo_base *entry; 6981bb76ff1Sjsg 6991bb76ff1Sjsg if (unlocked) { 7001bb76ff1Sjsg spin_lock(&vm->status_lock); 7011bb76ff1Sjsg for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) 7021bb76ff1Sjsg list_move(&entry->vm_status, &vm->pt_freed); 7031bb76ff1Sjsg 7041bb76ff1Sjsg if (start) 7051bb76ff1Sjsg list_move(&start->entry->vm_status, &vm->pt_freed); 7061bb76ff1Sjsg spin_unlock(&vm->status_lock); 7071bb76ff1Sjsg schedule_work(&vm->pt_free_work); 7081bb76ff1Sjsg return; 7091bb76ff1Sjsg } 7101bb76ff1Sjsg 7111bb76ff1Sjsg for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry) 7121bb76ff1Sjsg amdgpu_vm_pt_free(entry); 7131bb76ff1Sjsg 7141bb76ff1Sjsg if (start) 7151bb76ff1Sjsg amdgpu_vm_pt_free(start->entry); 7161bb76ff1Sjsg } 7171bb76ff1Sjsg 7181bb76ff1Sjsg /** 7191bb76ff1Sjsg * amdgpu_vm_pt_free_root - free root PD 7201bb76ff1Sjsg * @adev: amdgpu device structure 7211bb76ff1Sjsg * @vm: amdgpu vm structure 7221bb76ff1Sjsg * 7231bb76ff1Sjsg * Free the root page directory and everything below it. 7241bb76ff1Sjsg */ 7251bb76ff1Sjsg void amdgpu_vm_pt_free_root(struct amdgpu_device *adev, struct amdgpu_vm *vm) 7261bb76ff1Sjsg { 7271bb76ff1Sjsg amdgpu_vm_pt_free_dfs(adev, vm, NULL, false); 7281bb76ff1Sjsg } 7291bb76ff1Sjsg 7301bb76ff1Sjsg /** 7311bb76ff1Sjsg * amdgpu_vm_pt_is_root_clean - check if a root PD is clean 7321bb76ff1Sjsg * 7331bb76ff1Sjsg * @adev: amdgpu_device pointer 7341bb76ff1Sjsg * @vm: the VM to check 7351bb76ff1Sjsg * 7361bb76ff1Sjsg * Check all entries of the root PD, if any subsequent PDs are allocated, 7371bb76ff1Sjsg * it means there are page table creating and filling, and is no a clean 7381bb76ff1Sjsg * VM 7391bb76ff1Sjsg * 7401bb76ff1Sjsg * Returns: 7411bb76ff1Sjsg * 0 if this VM is clean 7421bb76ff1Sjsg */ 7431bb76ff1Sjsg bool amdgpu_vm_pt_is_root_clean(struct amdgpu_device *adev, 7441bb76ff1Sjsg struct amdgpu_vm *vm) 7451bb76ff1Sjsg { 7461bb76ff1Sjsg enum amdgpu_vm_level root = adev->vm_manager.root_level; 7471bb76ff1Sjsg unsigned int entries = amdgpu_vm_pt_num_entries(adev, root); 7481bb76ff1Sjsg unsigned int i = 0; 7491bb76ff1Sjsg 7501bb76ff1Sjsg for (i = 0; i < entries; i++) { 7511bb76ff1Sjsg if (to_amdgpu_bo_vm(vm->root.bo)->entries[i].bo) 7521bb76ff1Sjsg return false; 7531bb76ff1Sjsg } 7541bb76ff1Sjsg return true; 7551bb76ff1Sjsg } 7561bb76ff1Sjsg 7571bb76ff1Sjsg /** 7581bb76ff1Sjsg * amdgpu_vm_pde_update - update a single level in the hierarchy 7591bb76ff1Sjsg * 7601bb76ff1Sjsg * @params: parameters for the update 7611bb76ff1Sjsg * @entry: entry to update 7621bb76ff1Sjsg * 7631bb76ff1Sjsg * Makes sure the requested entry in parent is up to date. 7641bb76ff1Sjsg */ 7651bb76ff1Sjsg int amdgpu_vm_pde_update(struct amdgpu_vm_update_params *params, 7661bb76ff1Sjsg struct amdgpu_vm_bo_base *entry) 7671bb76ff1Sjsg { 7681bb76ff1Sjsg struct amdgpu_vm_bo_base *parent = amdgpu_vm_pt_parent(entry); 769*523bdaadSjsg struct amdgpu_bo *bo, *pbo; 7701bb76ff1Sjsg struct amdgpu_vm *vm = params->vm; 7711bb76ff1Sjsg uint64_t pde, pt, flags; 7721bb76ff1Sjsg unsigned int level; 7731bb76ff1Sjsg 774*523bdaadSjsg if (WARN_ON(!parent)) 775*523bdaadSjsg return -EINVAL; 776*523bdaadSjsg 777*523bdaadSjsg bo = parent->bo; 7781bb76ff1Sjsg for (level = 0, pbo = bo->parent; pbo; ++level) 7791bb76ff1Sjsg pbo = pbo->parent; 7801bb76ff1Sjsg 7811bb76ff1Sjsg level += params->adev->vm_manager.root_level; 7821bb76ff1Sjsg amdgpu_gmc_get_pde_for_bo(entry->bo, level, &pt, &flags); 7831bb76ff1Sjsg pde = (entry - to_amdgpu_bo_vm(parent->bo)->entries) * 8; 7841bb76ff1Sjsg return vm->update_funcs->update(params, to_amdgpu_bo_vm(bo), pde, pt, 7851bb76ff1Sjsg 1, 0, flags); 7861bb76ff1Sjsg } 7871bb76ff1Sjsg 788f005ef32Sjsg /** 789f005ef32Sjsg * amdgpu_vm_pte_update_noretry_flags - Update PTE no-retry flags 790f005ef32Sjsg * 791f005ef32Sjsg * @adev: amdgpu_device pointer 792f005ef32Sjsg * @flags: pointer to PTE flags 793f005ef32Sjsg * 794f005ef32Sjsg * Update PTE no-retry flags when TF is enabled. 795f005ef32Sjsg */ 796f005ef32Sjsg static void amdgpu_vm_pte_update_noretry_flags(struct amdgpu_device *adev, 797f005ef32Sjsg uint64_t *flags) 798f005ef32Sjsg { 799f005ef32Sjsg /* 800f005ef32Sjsg * Update no-retry flags with the corresponding TF 801f005ef32Sjsg * no-retry combination. 802f005ef32Sjsg */ 803f005ef32Sjsg if ((*flags & AMDGPU_VM_NORETRY_FLAGS) == AMDGPU_VM_NORETRY_FLAGS) { 804f005ef32Sjsg *flags &= ~AMDGPU_VM_NORETRY_FLAGS; 805f005ef32Sjsg *flags |= adev->gmc.noretry_flags; 806f005ef32Sjsg } 807f005ef32Sjsg } 808f005ef32Sjsg 8091bb76ff1Sjsg /* 8101bb76ff1Sjsg * amdgpu_vm_pte_update_flags - figure out flags for PTE updates 8111bb76ff1Sjsg * 8121bb76ff1Sjsg * Make sure to set the right flags for the PTEs at the desired level. 8131bb76ff1Sjsg */ 8141bb76ff1Sjsg static void amdgpu_vm_pte_update_flags(struct amdgpu_vm_update_params *params, 8151bb76ff1Sjsg struct amdgpu_bo_vm *pt, 8161bb76ff1Sjsg unsigned int level, 8171bb76ff1Sjsg uint64_t pe, uint64_t addr, 8181bb76ff1Sjsg unsigned int count, uint32_t incr, 8191bb76ff1Sjsg uint64_t flags) 8201bb76ff1Sjsg { 821f005ef32Sjsg struct amdgpu_device *adev = params->adev; 822f005ef32Sjsg 8231bb76ff1Sjsg if (level != AMDGPU_VM_PTB) { 8241bb76ff1Sjsg flags |= AMDGPU_PDE_PTE; 825f005ef32Sjsg amdgpu_gmc_get_vm_pde(adev, level, &addr, &flags); 8261bb76ff1Sjsg 827f005ef32Sjsg } else if (adev->asic_type >= CHIP_VEGA10 && 8281bb76ff1Sjsg !(flags & AMDGPU_PTE_VALID) && 8291bb76ff1Sjsg !(flags & AMDGPU_PTE_PRT)) { 8301bb76ff1Sjsg 8311bb76ff1Sjsg /* Workaround for fault priority problem on GMC9 */ 8321bb76ff1Sjsg flags |= AMDGPU_PTE_EXECUTABLE; 8331bb76ff1Sjsg } 8341bb76ff1Sjsg 835f005ef32Sjsg /* 836f005ef32Sjsg * Update no-retry flags to use the no-retry flag combination 837f005ef32Sjsg * with TF enabled. The AMDGPU_VM_NORETRY_FLAGS flag combination 838f005ef32Sjsg * does not work when TF is enabled. So, replace them with 839f005ef32Sjsg * AMDGPU_VM_NORETRY_FLAGS_TF flag combination which works for 840f005ef32Sjsg * all cases. 841f005ef32Sjsg */ 842f005ef32Sjsg if (level == AMDGPU_VM_PTB) 843f005ef32Sjsg amdgpu_vm_pte_update_noretry_flags(adev, &flags); 844f005ef32Sjsg 845f005ef32Sjsg /* APUs mapping system memory may need different MTYPEs on different 846f005ef32Sjsg * NUMA nodes. Only do this for contiguous ranges that can be assumed 847f005ef32Sjsg * to be on the same NUMA node. 848f005ef32Sjsg */ 849f005ef32Sjsg if ((flags & AMDGPU_PTE_SYSTEM) && (adev->flags & AMD_IS_APU) && 850f005ef32Sjsg adev->gmc.gmc_funcs->override_vm_pte_flags && 851f005ef32Sjsg num_possible_nodes() > 1) { 852f005ef32Sjsg if (!params->pages_addr) 853f005ef32Sjsg amdgpu_gmc_override_vm_pte_flags(adev, params->vm, 854f005ef32Sjsg addr, &flags); 855f005ef32Sjsg else 856f005ef32Sjsg dev_dbg(adev->dev, 857f005ef32Sjsg "override_vm_pte_flags skipped: non-contiguous\n"); 858f005ef32Sjsg } 859f005ef32Sjsg 8601bb76ff1Sjsg params->vm->update_funcs->update(params, pt, pe, addr, count, incr, 8611bb76ff1Sjsg flags); 8621bb76ff1Sjsg } 8631bb76ff1Sjsg 8641bb76ff1Sjsg /** 8651bb76ff1Sjsg * amdgpu_vm_pte_fragment - get fragment for PTEs 8661bb76ff1Sjsg * 8671bb76ff1Sjsg * @params: see amdgpu_vm_update_params definition 8681bb76ff1Sjsg * @start: first PTE to handle 8691bb76ff1Sjsg * @end: last PTE to handle 8701bb76ff1Sjsg * @flags: hw mapping flags 8711bb76ff1Sjsg * @frag: resulting fragment size 8721bb76ff1Sjsg * @frag_end: end of this fragment 8731bb76ff1Sjsg * 8741bb76ff1Sjsg * Returns the first possible fragment for the start and end address. 8751bb76ff1Sjsg */ 8761bb76ff1Sjsg static void amdgpu_vm_pte_fragment(struct amdgpu_vm_update_params *params, 8771bb76ff1Sjsg uint64_t start, uint64_t end, uint64_t flags, 8781bb76ff1Sjsg unsigned int *frag, uint64_t *frag_end) 8791bb76ff1Sjsg { 8801bb76ff1Sjsg /** 8811bb76ff1Sjsg * The MC L1 TLB supports variable sized pages, based on a fragment 8821bb76ff1Sjsg * field in the PTE. When this field is set to a non-zero value, page 8831bb76ff1Sjsg * granularity is increased from 4KB to (1 << (12 + frag)). The PTE 8841bb76ff1Sjsg * flags are considered valid for all PTEs within the fragment range 8851bb76ff1Sjsg * and corresponding mappings are assumed to be physically contiguous. 8861bb76ff1Sjsg * 8871bb76ff1Sjsg * The L1 TLB can store a single PTE for the whole fragment, 8881bb76ff1Sjsg * significantly increasing the space available for translation 8891bb76ff1Sjsg * caching. This leads to large improvements in throughput when the 8901bb76ff1Sjsg * TLB is under pressure. 8911bb76ff1Sjsg * 8921bb76ff1Sjsg * The L2 TLB distributes small and large fragments into two 8931bb76ff1Sjsg * asymmetric partitions. The large fragment cache is significantly 8941bb76ff1Sjsg * larger. Thus, we try to use large fragments wherever possible. 8951bb76ff1Sjsg * Userspace can support this by aligning virtual base address and 8961bb76ff1Sjsg * allocation size to the fragment size. 8971bb76ff1Sjsg * 8981bb76ff1Sjsg * Starting with Vega10 the fragment size only controls the L1. The L2 8991bb76ff1Sjsg * is now directly feed with small/huge/giant pages from the walker. 9001bb76ff1Sjsg */ 9011bb76ff1Sjsg unsigned int max_frag; 9021bb76ff1Sjsg 9031bb76ff1Sjsg if (params->adev->asic_type < CHIP_VEGA10) 9041bb76ff1Sjsg max_frag = params->adev->vm_manager.fragment_size; 9051bb76ff1Sjsg else 9061bb76ff1Sjsg max_frag = 31; 9071bb76ff1Sjsg 9081bb76ff1Sjsg /* system pages are non continuously */ 9091bb76ff1Sjsg if (params->pages_addr) { 9101bb76ff1Sjsg *frag = 0; 9111bb76ff1Sjsg *frag_end = end; 9121bb76ff1Sjsg return; 9131bb76ff1Sjsg } 9141bb76ff1Sjsg 9151bb76ff1Sjsg /* This intentionally wraps around if no bit is set */ 9161bb76ff1Sjsg *frag = min_t(unsigned int, ffs(start) - 1, fls64(end - start) - 1); 9171bb76ff1Sjsg if (*frag >= max_frag) { 9181bb76ff1Sjsg *frag = max_frag; 9191bb76ff1Sjsg *frag_end = end & ~((1ULL << max_frag) - 1); 9201bb76ff1Sjsg } else { 9211bb76ff1Sjsg *frag_end = start + (1 << *frag); 9221bb76ff1Sjsg } 9231bb76ff1Sjsg } 9241bb76ff1Sjsg 9251bb76ff1Sjsg /** 9261bb76ff1Sjsg * amdgpu_vm_ptes_update - make sure that page tables are valid 9271bb76ff1Sjsg * 9281bb76ff1Sjsg * @params: see amdgpu_vm_update_params definition 9291bb76ff1Sjsg * @start: start of GPU address range 9301bb76ff1Sjsg * @end: end of GPU address range 9311bb76ff1Sjsg * @dst: destination address to map to, the next dst inside the function 9321bb76ff1Sjsg * @flags: mapping flags 9331bb76ff1Sjsg * 9341bb76ff1Sjsg * Update the page tables in the range @start - @end. 9351bb76ff1Sjsg * 9361bb76ff1Sjsg * Returns: 9371bb76ff1Sjsg * 0 for success, -EINVAL for failure. 9381bb76ff1Sjsg */ 9391bb76ff1Sjsg int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params, 9401bb76ff1Sjsg uint64_t start, uint64_t end, 9411bb76ff1Sjsg uint64_t dst, uint64_t flags) 9421bb76ff1Sjsg { 9431bb76ff1Sjsg struct amdgpu_device *adev = params->adev; 9441bb76ff1Sjsg struct amdgpu_vm_pt_cursor cursor; 9451bb76ff1Sjsg uint64_t frag_start = start, frag_end; 9461bb76ff1Sjsg unsigned int frag; 9471bb76ff1Sjsg int r; 9481bb76ff1Sjsg 9491bb76ff1Sjsg /* figure out the initial fragment */ 9501bb76ff1Sjsg amdgpu_vm_pte_fragment(params, frag_start, end, flags, &frag, 9511bb76ff1Sjsg &frag_end); 9521bb76ff1Sjsg 9531bb76ff1Sjsg /* walk over the address space and update the PTs */ 9541bb76ff1Sjsg amdgpu_vm_pt_start(adev, params->vm, start, &cursor); 9551bb76ff1Sjsg while (cursor.pfn < end) { 9561bb76ff1Sjsg unsigned int shift, parent_shift, mask; 9571bb76ff1Sjsg uint64_t incr, entry_end, pe_start; 9581bb76ff1Sjsg struct amdgpu_bo *pt; 9591bb76ff1Sjsg 9601bb76ff1Sjsg if (!params->unlocked) { 9611bb76ff1Sjsg /* make sure that the page tables covering the 9621bb76ff1Sjsg * address range are actually allocated 9631bb76ff1Sjsg */ 9641bb76ff1Sjsg r = amdgpu_vm_pt_alloc(params->adev, params->vm, 9651bb76ff1Sjsg &cursor, params->immediate); 9661bb76ff1Sjsg if (r) 9671bb76ff1Sjsg return r; 9681bb76ff1Sjsg } 9691bb76ff1Sjsg 9701bb76ff1Sjsg shift = amdgpu_vm_pt_level_shift(adev, cursor.level); 9711bb76ff1Sjsg parent_shift = amdgpu_vm_pt_level_shift(adev, cursor.level - 1); 9721bb76ff1Sjsg if (params->unlocked) { 9731bb76ff1Sjsg /* Unlocked updates are only allowed on the leaves */ 9741bb76ff1Sjsg if (amdgpu_vm_pt_descendant(adev, &cursor)) 9751bb76ff1Sjsg continue; 9761bb76ff1Sjsg } else if (adev->asic_type < CHIP_VEGA10 && 9771bb76ff1Sjsg (flags & AMDGPU_PTE_VALID)) { 9781bb76ff1Sjsg /* No huge page support before GMC v9 */ 9791bb76ff1Sjsg if (cursor.level != AMDGPU_VM_PTB) { 9801bb76ff1Sjsg if (!amdgpu_vm_pt_descendant(adev, &cursor)) 9811bb76ff1Sjsg return -ENOENT; 9821bb76ff1Sjsg continue; 9831bb76ff1Sjsg } 9841bb76ff1Sjsg } else if (frag < shift) { 9851bb76ff1Sjsg /* We can't use this level when the fragment size is 9861bb76ff1Sjsg * smaller than the address shift. Go to the next 9871bb76ff1Sjsg * child entry and try again. 9881bb76ff1Sjsg */ 9891bb76ff1Sjsg if (amdgpu_vm_pt_descendant(adev, &cursor)) 9901bb76ff1Sjsg continue; 9911bb76ff1Sjsg } else if (frag >= parent_shift) { 9921bb76ff1Sjsg /* If the fragment size is even larger than the parent 9931bb76ff1Sjsg * shift we should go up one level and check it again. 9941bb76ff1Sjsg */ 9951bb76ff1Sjsg if (!amdgpu_vm_pt_ancestor(&cursor)) 9961bb76ff1Sjsg return -EINVAL; 9971bb76ff1Sjsg continue; 9981bb76ff1Sjsg } 9991bb76ff1Sjsg 10001bb76ff1Sjsg pt = cursor.entry->bo; 10011bb76ff1Sjsg if (!pt) { 10021bb76ff1Sjsg /* We need all PDs and PTs for mapping something, */ 10031bb76ff1Sjsg if (flags & AMDGPU_PTE_VALID) 10041bb76ff1Sjsg return -ENOENT; 10051bb76ff1Sjsg 10061bb76ff1Sjsg /* but unmapping something can happen at a higher 10071bb76ff1Sjsg * level. 10081bb76ff1Sjsg */ 10091bb76ff1Sjsg if (!amdgpu_vm_pt_ancestor(&cursor)) 10101bb76ff1Sjsg return -EINVAL; 10111bb76ff1Sjsg 10121bb76ff1Sjsg pt = cursor.entry->bo; 10131bb76ff1Sjsg shift = parent_shift; 1014f005ef32Sjsg frag_end = max(frag_end, ALIGN(frag_start + 1, 10151bb76ff1Sjsg 1ULL << shift)); 10161bb76ff1Sjsg } 10171bb76ff1Sjsg 10181bb76ff1Sjsg /* Looks good so far, calculate parameters for the update */ 10191bb76ff1Sjsg incr = (uint64_t)AMDGPU_GPU_PAGE_SIZE << shift; 10201bb76ff1Sjsg mask = amdgpu_vm_pt_entries_mask(adev, cursor.level); 10211bb76ff1Sjsg pe_start = ((cursor.pfn >> shift) & mask) * 8; 10221bb76ff1Sjsg entry_end = ((uint64_t)mask + 1) << shift; 10231bb76ff1Sjsg entry_end += cursor.pfn & ~(entry_end - 1); 10241bb76ff1Sjsg entry_end = min(entry_end, end); 10251bb76ff1Sjsg 10261bb76ff1Sjsg do { 10271bb76ff1Sjsg struct amdgpu_vm *vm = params->vm; 10281bb76ff1Sjsg uint64_t upd_end = min(entry_end, frag_end); 10291bb76ff1Sjsg unsigned int nptes = (upd_end - frag_start) >> shift; 10301bb76ff1Sjsg uint64_t upd_flags = flags | AMDGPU_PTE_FRAG(frag); 10311bb76ff1Sjsg 10321bb76ff1Sjsg /* This can happen when we set higher level PDs to 10331bb76ff1Sjsg * silent to stop fault floods. 10341bb76ff1Sjsg */ 10351bb76ff1Sjsg nptes = max(nptes, 1u); 10361bb76ff1Sjsg 10371bb76ff1Sjsg trace_amdgpu_vm_update_ptes(params, frag_start, upd_end, 10381bb76ff1Sjsg min(nptes, 32u), dst, incr, 10391bb76ff1Sjsg upd_flags, 10404e1f8057Sjsg vm->task_info.tgid, 10411bb76ff1Sjsg vm->immediate.fence_context); 10421bb76ff1Sjsg amdgpu_vm_pte_update_flags(params, to_amdgpu_bo_vm(pt), 10431bb76ff1Sjsg cursor.level, pe_start, dst, 10441bb76ff1Sjsg nptes, incr, upd_flags); 10451bb76ff1Sjsg 10461bb76ff1Sjsg pe_start += nptes * 8; 10471bb76ff1Sjsg dst += nptes * incr; 10481bb76ff1Sjsg 10491bb76ff1Sjsg frag_start = upd_end; 10501bb76ff1Sjsg if (frag_start >= frag_end) { 10511bb76ff1Sjsg /* figure out the next fragment */ 10521bb76ff1Sjsg amdgpu_vm_pte_fragment(params, frag_start, end, 10531bb76ff1Sjsg flags, &frag, &frag_end); 10541bb76ff1Sjsg if (frag < shift) 10551bb76ff1Sjsg break; 10561bb76ff1Sjsg } 10571bb76ff1Sjsg } while (frag_start < entry_end); 10581bb76ff1Sjsg 10591bb76ff1Sjsg if (amdgpu_vm_pt_descendant(adev, &cursor)) { 10601bb76ff1Sjsg /* Free all child entries. 10611bb76ff1Sjsg * Update the tables with the flags and addresses and free up subsequent 10621bb76ff1Sjsg * tables in the case of huge pages or freed up areas. 10631bb76ff1Sjsg * This is the maximum you can free, because all other page tables are not 10641bb76ff1Sjsg * completely covered by the range and so potentially still in use. 10651bb76ff1Sjsg */ 10661bb76ff1Sjsg while (cursor.pfn < frag_start) { 10671bb76ff1Sjsg /* Make sure previous mapping is freed */ 10681bb76ff1Sjsg if (cursor.entry->bo) { 10691bb76ff1Sjsg params->table_freed = true; 10701bb76ff1Sjsg amdgpu_vm_pt_free_dfs(adev, params->vm, 10711bb76ff1Sjsg &cursor, 10721bb76ff1Sjsg params->unlocked); 10731bb76ff1Sjsg } 10741bb76ff1Sjsg amdgpu_vm_pt_next(adev, &cursor); 10751bb76ff1Sjsg } 10761bb76ff1Sjsg 10771bb76ff1Sjsg } else if (frag >= shift) { 10781bb76ff1Sjsg /* or just move on to the next on the same level. */ 10791bb76ff1Sjsg amdgpu_vm_pt_next(adev, &cursor); 10801bb76ff1Sjsg } 10811bb76ff1Sjsg } 10821bb76ff1Sjsg 10831bb76ff1Sjsg return 0; 10841bb76ff1Sjsg } 1085f005ef32Sjsg 1086f005ef32Sjsg /** 1087f005ef32Sjsg * amdgpu_vm_pt_map_tables - have bo of root PD cpu accessible 1088f005ef32Sjsg * @adev: amdgpu device structure 1089f005ef32Sjsg * @vm: amdgpu vm structure 1090f005ef32Sjsg * 1091f005ef32Sjsg * make root page directory and everything below it cpu accessible. 1092f005ef32Sjsg */ 1093f005ef32Sjsg int amdgpu_vm_pt_map_tables(struct amdgpu_device *adev, struct amdgpu_vm *vm) 1094f005ef32Sjsg { 1095f005ef32Sjsg struct amdgpu_vm_pt_cursor cursor; 1096f005ef32Sjsg struct amdgpu_vm_bo_base *entry; 1097f005ef32Sjsg 1098f005ef32Sjsg for_each_amdgpu_vm_pt_dfs_safe(adev, vm, NULL, cursor, entry) { 1099f005ef32Sjsg 1100f005ef32Sjsg struct amdgpu_bo_vm *bo; 1101f005ef32Sjsg int r; 1102f005ef32Sjsg 1103f005ef32Sjsg if (entry->bo) { 1104f005ef32Sjsg bo = to_amdgpu_bo_vm(entry->bo); 1105f005ef32Sjsg r = vm->update_funcs->map_table(bo); 1106f005ef32Sjsg if (r) 1107f005ef32Sjsg return r; 1108f005ef32Sjsg } 1109f005ef32Sjsg } 1110f005ef32Sjsg 1111f005ef32Sjsg return 0; 1112f005ef32Sjsg } 1113