diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_gem.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_gem.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 5fdfb8f51a41..2cc6b3ae4e07 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -448,6 +448,129 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, return 0; } +struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma) +{ + struct vm_area_struct *vma_copy; + + vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL); + if (!vma_copy) + return NULL; + + if (vma->vm_ops && vma->vm_ops->open) + vma->vm_ops->open(vma); + + if (vma->vm_file) + get_file(vma->vm_file); + + memcpy(vma_copy, vma, sizeof(*vma)); + + vma_copy->vm_mm = NULL; + vma_copy->vm_next = NULL; + vma_copy->vm_prev = NULL; + + return vma_copy; +} + +void exynos_gem_put_vma(struct vm_area_struct *vma) +{ + if (!vma) + return; + + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + + if (vma->vm_file) + fput(vma->vm_file); + + kfree(vma); +} + +int exynos_gem_get_pages_from_userptr(unsigned long start, + unsigned int npages, + struct page **pages, + struct vm_area_struct *vma) +{ + int get_npages; + + /* the memory region mmaped with VM_PFNMAP. */ + if (vma_is_io(vma)) { + unsigned int i; + + for (i = 0; i < npages; ++i, start += PAGE_SIZE) { + unsigned long pfn; + int ret = follow_pfn(vma, start, &pfn); + if (ret) + return ret; + + pages[i] = pfn_to_page(pfn); + } + + if (i != npages) { + DRM_ERROR("failed to get user_pages.\n"); + return -EINVAL; + } + + return 0; + } + + get_npages = get_user_pages(current, current->mm, start, + npages, 1, 1, pages, NULL); + get_npages = max(get_npages, 0); + if (get_npages != npages) { + DRM_ERROR("failed to get user_pages.\n"); + while (get_npages) + put_page(pages[--get_npages]); + return -EFAULT; + } + + return 0; +} + +void exynos_gem_put_pages_to_userptr(struct page **pages, + unsigned int npages, + struct vm_area_struct *vma) +{ + if (!vma_is_io(vma)) { + unsigned int i; + + for (i = 0; i < npages; i++) { + set_page_dirty_lock(pages[i]); + + /* + * undo the reference we took when populating + * the table. + */ + put_page(pages[i]); + } + } +} + +int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + int nents; + + mutex_lock(&drm_dev->struct_mutex); + + nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); + if (!nents) { + DRM_ERROR("failed to map sgl with dma.\n"); + mutex_unlock(&drm_dev->struct_mutex); + return nents; + } + + mutex_unlock(&drm_dev->struct_mutex); + return 0; +} + +void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); +} + int exynos_drm_gem_init_object(struct drm_gem_object *obj) { DRM_DEBUG_KMS("%s\n", __FILE__); |