diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/compote/compote-memory.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/compote/compote-memory.c | 90 |
1 files changed, 88 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/compote/compote-memory.c b/drivers/gpu/drm/nouveau/compote/compote-memory.c index 55fca9092846..8435ec0a8d03 100644 --- a/drivers/gpu/drm/nouveau/compote/compote-memory.c +++ b/drivers/gpu/drm/nouveau/compote/compote-memory.c @@ -33,11 +33,12 @@ static struct compote_mo *compote_file_mo_find(struct compote_file *cfile, uint64_t foffset) { struct ttm_bo_device *bdev = &cfile->cdevice->nvdrm->ttm.bdev; + unsigned long pgoffset = foffset >> PAGE_SHIFT; struct drm_vma_offset_node *node; struct compote_mo *mo = NULL; drm_vma_offset_lock_lookup(&bdev->vma_manager); - node = drm_vma_offset_lookup_locked(&bdev->vma_manager, foffset, 1); + node = drm_vma_offset_lookup_locked(&bdev->vma_manager, pgoffset, 1); if (likely(node)) { struct ttm_buffer_object *bo; struct nouveau_bo *nvbo; @@ -66,7 +67,6 @@ static int compote_mo_new(struct compote_mo **mop, if (mo == NULL) return -ENOMEM; - align = 0; tile_mode = 0; tile_flags = 0; @@ -79,6 +79,7 @@ static int compote_mo_new(struct compote_mo **mop, mo->cfile = cfile; mo->nvbo->mo = mo; kref_init(&mo->kref); + INIT_LIST_HEAD(&mo->vas); mo->npages = PAGE_ALIGN(nbytes); mo->foffset = drm_vma_node_offset_addr(&mo->nvbo->bo.vma_node); @@ -150,3 +151,88 @@ long compote_ioctl_mem_free(struct compote_file *cfile, void __user *uarg) compote_mo_unref(mo); return 0; } + +static int compote_vm_fault(struct vm_fault *vmf) +{ + struct compote_mo_va *mo_va = vmf->vma->vm_private_data; + struct ttm_buffer_object *bo; + int ret; + + bo = &mo_va->mo->nvbo->bo; + vmf->vma->vm_private_data = bo; + ret = mo_va->ttm_vm_ops->fault(vmf); + vmf->vma->vm_private_data = mo_va; + + return ret; +} + +static void compote_vm_open(struct vm_area_struct *vma) +{ + struct compote_mo_va *mo_va = vma->vm_private_data; + struct ttm_buffer_object *bo; + + compote_mo_ref(mo_va->mo); + + bo = &mo_va->mo->nvbo->bo; + vma->vm_private_data = bo; + mo_va->ttm_vm_ops->open(vma); + vma->vm_private_data = mo_va; +} + +static void compote_vm_close(struct vm_area_struct *vma) +{ + struct compote_mo_va *mo_va = vma->vm_private_data; + struct ttm_buffer_object *bo; + + bo = &mo_va->mo->nvbo->bo; + vma->vm_private_data = bo; + mo_va->ttm_vm_ops->close(vma); + + list_del_init(&mo_va->list); + vma->vm_private_data = NULL; + compote_mo_unref(mo_va->mo); + kfree(mo_va); +} + +static const struct vm_operations_struct compote_vm_ops = { + .fault = compote_vm_fault, + .open = compote_vm_open, + .close = compote_vm_close +}; + +int compote_mo_mmap(struct compote_file *cfile, + struct vm_area_struct *vma, + struct file *file) +{ + struct ttm_bo_device *bdev = &cfile->cdevice->nvdrm->ttm.bdev; + struct compote_mo_va *mo_va; + struct compote_mo *mo; + int ret; + + mo = compote_file_mo_find(cfile, vma->vm_pgoff << PAGE_SHIFT); + if (mo == NULL) + return -EINVAL; + + mo_va = kzalloc(sizeof(*mo_va), GFP_KERNEL); + if (mo_va == NULL) + return -ENOMEM; + + mo_va->mo = mo; + mo_va->start = vma->vm_start; + mo_va->end = vma->vm_end; + mo_va->pgoffset = vma->vm_pgoff - (mo->foffset >> PAGE_SHIFT); + + ret = ttm_bo_mmap(file, vma, bdev); + if (unlikely(ret != 0)) { + compote_mo_unref(mo); + kfree(mo_va); + return ret; + } + + list_add_tail(&mo_va->list, &mo->vas); + mo_va->ttm_vm_ops = vma->vm_ops; + vma->vm_ops = &compote_vm_ops; + vma->vm_private_data = mo_va; + + return 0; +} |