Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan at amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 82 +++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 63f0572..63b4696 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -79,6 +79,12 @@ struct amdgpu_pte_update_params { uint64_t flags); /* indicate update pt or its shadow */ bool shadow; + /* The next two are used during VM update by CPU + * DMA addresses to use for mapping + * Kernel pointer of PD/PT BO that needs to be updated + */ + dma_addr_t *pages_addr; + void *kptr; }; /* Helper to disable partial resident texture feature from a fence callback */ @@ -975,10 +981,14 @@ static void amdgpu_vm_cpu_set_ptes(struct amdgpu_pte_update_params *params, uint64_t flags) { unsigned int i; + uint64_t value; for (i = 0; i < count; i++) { + value = params->pages_addr ? + amdgpu_vm_map_gart(params->pages_addr, addr) : + addr; amdgpu_gart_set_pte_pde(params->adev, (void *)pe, - i, addr, flags); + i, value, flags); addr += incr; } @@ -1211,6 +1221,59 @@ static struct amdgpu_bo *amdgpu_vm_get_pt(struct amdgpu_pte_update_params *p, } /** + * amdgpu_vm_update_ptes_cpu - Update the page tables in the range + * start - @end using CPU. + * See amdgpu_vm_update_ptes for parameter description. + * + */ +static int amdgpu_vm_update_ptes_cpu(struct amdgpu_pte_update_params *params, + uint64_t start, uint64_t end, + uint64_t dst, uint64_t flags) +{ + struct amdgpu_device *adev = params->adev; + const uint64_t mask = AMDGPU_VM_PTE_COUNT(adev) - 1; + void *pe_ptr; + uint64_t addr; + struct amdgpu_bo *pt; + unsigned int nptes; + int r; + + /* initialize the variables */ + addr = start; + + /* walk over the address space and update the page tables */ + while (addr < end) { + pt = amdgpu_vm_get_pt(params, addr); + if (!pt) { + pr_err("PT not found, aborting update_ptes\n"); + return -EINVAL; + } + + WARN_ON(params->shadow); + + r = amdgpu_bo_kmap(pt, &pe_ptr); + if (r) + return r; + + pe_ptr += (addr & mask) * 8; + + if ((addr & ~mask) == (end & ~mask)) + nptes = end - addr; + else + nptes = AMDGPU_VM_PTE_COUNT(adev) - (addr & mask); + + params->func(params, (uint64_t)pe_ptr, dst, nptes, + AMDGPU_GPU_PAGE_SIZE, flags); + + amdgpu_bo_kunmap(pt); + addr += nptes; + dst += nptes * AMDGPU_GPU_PAGE_SIZE; + } + + return 0; +} + +/** * amdgpu_vm_update_ptes - make sure that page tables are valid * * @params: see amdgpu_pte_update_params definition @@ -1236,6 +1299,10 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, unsigned nptes; /* next number of ptes to be updated */ uint64_t next_pe_start; + if (params->func == amdgpu_vm_cpu_set_ptes) + return amdgpu_vm_update_ptes_cpu(params, start, end, + dst, flags); + /* initialize the variables */ addr = start; pt = amdgpu_vm_get_pt(params, addr); @@ -1422,6 +1489,19 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, params.vm = vm; params.src = src; + if (vm->is_vm_update_mode_cpu) { + /* params.src is used as flag to indicate system Memory */ + if (pages_addr) + params.src = ~0; + + params.func = amdgpu_vm_cpu_set_ptes; + params.pages_addr = pages_addr; + params.shadow = false; + r = amdgpu_vm_frag_ptes(¶ms, start, last + 1, addr, flags); + if (!r) + return r; + } + ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); /* sync to everything on unmapping */ -- 1.9.1