1*6dd09027SChristian König /* 2*6dd09027SChristian König * Copyright 2019 Advanced Micro Devices, Inc. 3*6dd09027SChristian König * 4*6dd09027SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 5*6dd09027SChristian König * copy of this software and associated documentation files (the "Software"), 6*6dd09027SChristian König * to deal in the Software without restriction, including without limitation 7*6dd09027SChristian König * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*6dd09027SChristian König * and/or sell copies of the Software, and to permit persons to whom the 9*6dd09027SChristian König * Software is furnished to do so, subject to the following conditions: 10*6dd09027SChristian König * 11*6dd09027SChristian König * The above copyright notice and this permission notice shall be included in 12*6dd09027SChristian König * all copies or substantial portions of the Software. 13*6dd09027SChristian König * 14*6dd09027SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*6dd09027SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*6dd09027SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17*6dd09027SChristian König * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18*6dd09027SChristian König * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19*6dd09027SChristian König * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20*6dd09027SChristian König * OTHER DEALINGS IN THE SOFTWARE. 21*6dd09027SChristian König */ 22*6dd09027SChristian König 23*6dd09027SChristian König #include "amdgpu_vm.h" 24*6dd09027SChristian König #include "amdgpu_job.h" 25*6dd09027SChristian König #include "amdgpu_object.h" 26*6dd09027SChristian König #include "amdgpu_trace.h" 27*6dd09027SChristian König 28*6dd09027SChristian König #define AMDGPU_VM_SDMA_MIN_NUM_DW 256u 29*6dd09027SChristian König #define AMDGPU_VM_SDMA_MAX_NUM_DW (16u * 1024u) 30*6dd09027SChristian König 31*6dd09027SChristian König /** 32*6dd09027SChristian König * amdgpu_vm_sdma_prepare - prepare SDMA command submission 33*6dd09027SChristian König * 34*6dd09027SChristian König * @p: see amdgpu_vm_update_params definition 35*6dd09027SChristian König * @owner: owner we need to sync to 36*6dd09027SChristian König * @exclusive: exclusive move fence we need to sync to 37*6dd09027SChristian König * 38*6dd09027SChristian König * Returns: 39*6dd09027SChristian König * Negativ errno, 0 for success. 40*6dd09027SChristian König */ 41*6dd09027SChristian König static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, 42*6dd09027SChristian König void *owner, struct dma_fence *exclusive) 43*6dd09027SChristian König { 44*6dd09027SChristian König struct amdgpu_bo *root = p->vm->root.base.bo; 45*6dd09027SChristian König unsigned int ndw = AMDGPU_VM_SDMA_MIN_NUM_DW; 46*6dd09027SChristian König int r; 47*6dd09027SChristian König 48*6dd09027SChristian König r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, &p->job); 49*6dd09027SChristian König if (r) 50*6dd09027SChristian König return r; 51*6dd09027SChristian König 52*6dd09027SChristian König r = amdgpu_sync_fence(p->adev, &p->job->sync, exclusive, false); 53*6dd09027SChristian König if (r) 54*6dd09027SChristian König return r; 55*6dd09027SChristian König 56*6dd09027SChristian König r = amdgpu_sync_resv(p->adev, &p->job->sync, root->tbo.resv, 57*6dd09027SChristian König owner, false); 58*6dd09027SChristian König if (r) 59*6dd09027SChristian König return r; 60*6dd09027SChristian König 61*6dd09027SChristian König p->num_dw_left = ndw; 62*6dd09027SChristian König p->ib = &p->job->ibs[0]; 63*6dd09027SChristian König return 0; 64*6dd09027SChristian König } 65*6dd09027SChristian König 66*6dd09027SChristian König /** 67*6dd09027SChristian König * amdgpu_vm_sdma_commit - commit SDMA command submission 68*6dd09027SChristian König * 69*6dd09027SChristian König * @p: see amdgpu_vm_update_params definition 70*6dd09027SChristian König * @fence: resulting fence 71*6dd09027SChristian König * 72*6dd09027SChristian König * Returns: 73*6dd09027SChristian König * Negativ errno, 0 for success. 74*6dd09027SChristian König */ 75*6dd09027SChristian König static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p, 76*6dd09027SChristian König struct dma_fence **fence) 77*6dd09027SChristian König { 78*6dd09027SChristian König struct amdgpu_bo *root = p->vm->root.base.bo; 79*6dd09027SChristian König struct amdgpu_ring *ring; 80*6dd09027SChristian König struct dma_fence *f; 81*6dd09027SChristian König int r; 82*6dd09027SChristian König 83*6dd09027SChristian König ring = container_of(p->vm->entity.rq->sched, struct amdgpu_ring, sched); 84*6dd09027SChristian König 85*6dd09027SChristian König WARN_ON(p->ib->length_dw == 0); 86*6dd09027SChristian König amdgpu_ring_pad_ib(ring, p->ib); 87*6dd09027SChristian König WARN_ON(p->ib->length_dw > p->num_dw_left); 88*6dd09027SChristian König r = amdgpu_job_submit(p->job, &p->vm->entity, 89*6dd09027SChristian König AMDGPU_FENCE_OWNER_VM, &f); 90*6dd09027SChristian König if (r) 91*6dd09027SChristian König goto error; 92*6dd09027SChristian König 93*6dd09027SChristian König amdgpu_bo_fence(root, f, true); 94*6dd09027SChristian König if (fence) 95*6dd09027SChristian König swap(*fence, f); 96*6dd09027SChristian König dma_fence_put(f); 97*6dd09027SChristian König return 0; 98*6dd09027SChristian König 99*6dd09027SChristian König error: 100*6dd09027SChristian König amdgpu_job_free(p->job); 101*6dd09027SChristian König return r; 102*6dd09027SChristian König } 103*6dd09027SChristian König 104*6dd09027SChristian König 105*6dd09027SChristian König /** 106*6dd09027SChristian König * amdgpu_vm_sdma_copy_ptes - copy the PTEs from mapping 107*6dd09027SChristian König * 108*6dd09027SChristian König * @p: see amdgpu_vm_update_params definition 109*6dd09027SChristian König * @bo: PD/PT to update 110*6dd09027SChristian König * @pe: addr of the page entry 111*6dd09027SChristian König * @count: number of page entries to copy 112*6dd09027SChristian König * 113*6dd09027SChristian König * Traces the parameters and calls the DMA function to copy the PTEs. 114*6dd09027SChristian König */ 115*6dd09027SChristian König static void amdgpu_vm_sdma_copy_ptes(struct amdgpu_vm_update_params *p, 116*6dd09027SChristian König struct amdgpu_bo *bo, uint64_t pe, 117*6dd09027SChristian König unsigned count) 118*6dd09027SChristian König { 119*6dd09027SChristian König uint64_t src = p->ib->gpu_addr; 120*6dd09027SChristian König 121*6dd09027SChristian König src += p->num_dw_left * 4; 122*6dd09027SChristian König 123*6dd09027SChristian König pe += amdgpu_bo_gpu_offset(bo); 124*6dd09027SChristian König trace_amdgpu_vm_copy_ptes(pe, src, count); 125*6dd09027SChristian König 126*6dd09027SChristian König amdgpu_vm_copy_pte(p->adev, p->ib, pe, src, count); 127*6dd09027SChristian König } 128*6dd09027SChristian König 129*6dd09027SChristian König /** 130*6dd09027SChristian König * amdgpu_vm_sdma_set_ptes - helper to call the right asic function 131*6dd09027SChristian König * 132*6dd09027SChristian König * @p: see amdgpu_vm_update_params definition 133*6dd09027SChristian König * @bo: PD/PT to update 134*6dd09027SChristian König * @pe: addr of the page entry 135*6dd09027SChristian König * @addr: dst addr to write into pe 136*6dd09027SChristian König * @count: number of page entries to update 137*6dd09027SChristian König * @incr: increase next addr by incr bytes 138*6dd09027SChristian König * @flags: hw access flags 139*6dd09027SChristian König * 140*6dd09027SChristian König * Traces the parameters and calls the right asic functions 141*6dd09027SChristian König * to setup the page table using the DMA. 142*6dd09027SChristian König */ 143*6dd09027SChristian König static void amdgpu_vm_sdma_set_ptes(struct amdgpu_vm_update_params *p, 144*6dd09027SChristian König struct amdgpu_bo *bo, uint64_t pe, 145*6dd09027SChristian König uint64_t addr, unsigned count, 146*6dd09027SChristian König uint32_t incr, uint64_t flags) 147*6dd09027SChristian König { 148*6dd09027SChristian König pe += amdgpu_bo_gpu_offset(bo); 149*6dd09027SChristian König trace_amdgpu_vm_set_ptes(pe, addr, count, incr, flags); 150*6dd09027SChristian König if (count < 3) { 151*6dd09027SChristian König amdgpu_vm_write_pte(p->adev, p->ib, pe, addr | flags, 152*6dd09027SChristian König count, incr); 153*6dd09027SChristian König } else { 154*6dd09027SChristian König amdgpu_vm_set_pte_pde(p->adev, p->ib, pe, addr, 155*6dd09027SChristian König count, incr, flags); 156*6dd09027SChristian König } 157*6dd09027SChristian König } 158*6dd09027SChristian König 159*6dd09027SChristian König /** 160*6dd09027SChristian König * amdgpu_vm_sdma_update - execute VM update 161*6dd09027SChristian König * 162*6dd09027SChristian König * @p: see amdgpu_vm_update_params definition 163*6dd09027SChristian König * @bo: PD/PT to update 164*6dd09027SChristian König * @pe: addr of the page entry 165*6dd09027SChristian König * @addr: dst addr to write into pe 166*6dd09027SChristian König * @count: number of page entries to update 167*6dd09027SChristian König * @incr: increase next addr by incr bytes 168*6dd09027SChristian König * @flags: hw access flags 169*6dd09027SChristian König * 170*6dd09027SChristian König * Reserve space in the IB, setup mapping buffer on demand and write commands to 171*6dd09027SChristian König * the IB. 172*6dd09027SChristian König */ 173*6dd09027SChristian König static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, 174*6dd09027SChristian König struct amdgpu_bo *bo, uint64_t pe, 175*6dd09027SChristian König uint64_t addr, unsigned count, uint32_t incr, 176*6dd09027SChristian König uint64_t flags) 177*6dd09027SChristian König { 178*6dd09027SChristian König unsigned int i, ndw, nptes; 179*6dd09027SChristian König uint64_t *pte; 180*6dd09027SChristian König int r; 181*6dd09027SChristian König 182*6dd09027SChristian König do { 183*6dd09027SChristian König ndw = p->num_dw_left; 184*6dd09027SChristian König ndw -= p->ib->length_dw; 185*6dd09027SChristian König 186*6dd09027SChristian König if (ndw < 32) { 187*6dd09027SChristian König r = amdgpu_vm_sdma_commit(p, NULL); 188*6dd09027SChristian König if (r) 189*6dd09027SChristian König return r; 190*6dd09027SChristian König 191*6dd09027SChristian König /* estimate how many dw we need */ 192*6dd09027SChristian König ndw = 32; 193*6dd09027SChristian König if (p->pages_addr) 194*6dd09027SChristian König ndw += count * 2; 195*6dd09027SChristian König ndw = max(ndw, AMDGPU_VM_SDMA_MIN_NUM_DW); 196*6dd09027SChristian König ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW); 197*6dd09027SChristian König 198*6dd09027SChristian König r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, &p->job); 199*6dd09027SChristian König if (r) 200*6dd09027SChristian König return r; 201*6dd09027SChristian König 202*6dd09027SChristian König p->num_dw_left = ndw; 203*6dd09027SChristian König p->ib = &p->job->ibs[0]; 204*6dd09027SChristian König } 205*6dd09027SChristian König 206*6dd09027SChristian König if (!p->pages_addr) { 207*6dd09027SChristian König /* set page commands needed */ 208*6dd09027SChristian König if (bo->shadow) 209*6dd09027SChristian König amdgpu_vm_sdma_set_ptes(p, bo->shadow, pe, addr, 210*6dd09027SChristian König count, incr, flags); 211*6dd09027SChristian König amdgpu_vm_sdma_set_ptes(p, bo, pe, addr, count, 212*6dd09027SChristian König incr, flags); 213*6dd09027SChristian König return 0; 214*6dd09027SChristian König } 215*6dd09027SChristian König 216*6dd09027SChristian König /* copy commands needed */ 217*6dd09027SChristian König ndw -= p->adev->vm_manager.vm_pte_funcs->copy_pte_num_dw * 218*6dd09027SChristian König (bo->shadow ? 2 : 1); 219*6dd09027SChristian König 220*6dd09027SChristian König /* for padding */ 221*6dd09027SChristian König ndw -= 7; 222*6dd09027SChristian König 223*6dd09027SChristian König nptes = min(count, ndw / 2); 224*6dd09027SChristian König 225*6dd09027SChristian König /* Put the PTEs at the end of the IB. */ 226*6dd09027SChristian König p->num_dw_left -= nptes * 2; 227*6dd09027SChristian König pte = (uint64_t *)&(p->ib->ptr[p->num_dw_left]); 228*6dd09027SChristian König for (i = 0; i < nptes; ++i, addr += incr) { 229*6dd09027SChristian König pte[i] = amdgpu_vm_map_gart(p->pages_addr, addr); 230*6dd09027SChristian König pte[i] |= flags; 231*6dd09027SChristian König } 232*6dd09027SChristian König 233*6dd09027SChristian König if (bo->shadow) 234*6dd09027SChristian König amdgpu_vm_sdma_copy_ptes(p, bo->shadow, pe, nptes); 235*6dd09027SChristian König amdgpu_vm_sdma_copy_ptes(p, bo, pe, nptes); 236*6dd09027SChristian König 237*6dd09027SChristian König pe += nptes * 8; 238*6dd09027SChristian König count -= nptes; 239*6dd09027SChristian König } while (count); 240*6dd09027SChristian König 241*6dd09027SChristian König return 0; 242*6dd09027SChristian König } 243*6dd09027SChristian König 244*6dd09027SChristian König const struct amdgpu_vm_update_funcs amdgpu_vm_sdma_funcs = { 245*6dd09027SChristian König .prepare = amdgpu_vm_sdma_prepare, 246*6dd09027SChristian König .update = amdgpu_vm_sdma_update, 247*6dd09027SChristian König .commit = amdgpu_vm_sdma_commit 248*6dd09027SChristian König }; 249