diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 4a94f58e7f23..4ee75b9bcd94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -316,6 +316,53 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, return 0; } +int +nvkm_vm_get_fix(struct nvkm_vm *vm, u64 offset, u64 size, u32 page_shift, + u32 access, struct nvkm_vma *vma) +{ + struct nvkm_mmu *mmu = vm->mmu; + u64 moffset = offset >> 12; + u64 msize = size >> 12; + u32 fpde, lpde, pde; + int ret; + + mutex_lock(&vm->mutex); + ret = nvkm_mm_fix(&vm->mm, page_shift, moffset, msize, &vma->node); + if (unlikely(ret != 0)) { + mutex_unlock(&vm->mutex); + return ret; + } + + fpde = (vma->node->offset >> mmu->func->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> mmu->func->pgt_bits; + + for (pde = fpde; pde <= lpde; pde++) { + struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + int big = (vma->node->type != mmu->func->spg_shift); + + if (likely(vpgt->refcount[big])) { + vpgt->refcount[big]++; + continue; + } + + ret = nvkm_vm_map_pgt(vm, pde, vma->node->type); + if (ret) { + if (pde != fpde) + nvkm_vm_unmap_pgt(vm, big, fpde, pde - 1); + nvkm_mm_free(&vm->mm, &vma->node); + mutex_unlock(&vm->mutex); + return ret; + } + } + mutex_unlock(&vm->mutex); + + vma->vm = NULL; + nvkm_vm_ref(vm, &vma->vm, NULL); + vma->offset = (u64)vma->node->offset << 12; + vma->access = access; + return 0; +} + void nvkm_vm_put(struct nvkm_vma *vma) { |