11c248b7dSInki Dae /* exynos_drm_gem.c 21c248b7dSInki Dae * 31c248b7dSInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd. 41c248b7dSInki Dae * Author: Inki Dae <inki.dae@samsung.com> 51c248b7dSInki Dae * 6d81aecb5SInki Dae * This program is free software; you can redistribute it and/or modify it 7d81aecb5SInki Dae * under the terms of the GNU General Public License as published by the 8d81aecb5SInki Dae * Free Software Foundation; either version 2 of the License, or (at your 9d81aecb5SInki Dae * option) any later version. 101c248b7dSInki Dae */ 111c248b7dSInki Dae 12760285e7SDavid Howells #include <drm/drmP.h> 130de23977SDavid Herrmann #include <drm/drm_vma_manager.h> 141c248b7dSInki Dae 152b35892eSInki Dae #include <linux/shmem_fs.h> 161c248b7dSInki Dae #include <drm/exynos_drm.h> 171c248b7dSInki Dae 181c248b7dSInki Dae #include "exynos_drm_drv.h" 191c248b7dSInki Dae #include "exynos_drm_gem.h" 201c248b7dSInki Dae #include "exynos_drm_buf.h" 213fec4532SVikas Sajjan #include "exynos_drm_iommu.h" 221c248b7dSInki Dae 23dcf9af82SInki Dae static unsigned long roundup_gem_size(unsigned long size, unsigned int flags) 24dcf9af82SInki Dae { 250519f9a1SInki Dae /* TODO */ 260519f9a1SInki Dae 27dcf9af82SInki Dae return roundup(size, PAGE_SIZE); 282b35892eSInki Dae } 292b35892eSInki Dae 302364839aSJoonyoung Shim static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 312364839aSJoonyoung Shim struct drm_file *file_priv, 322364839aSJoonyoung Shim unsigned int *handle) 331c248b7dSInki Dae { 341c248b7dSInki Dae int ret; 351c248b7dSInki Dae 361c248b7dSInki Dae /* 371c248b7dSInki Dae * allocate a id of idr table where the obj is registered 381c248b7dSInki Dae * and handle has the id what user can see. 391c248b7dSInki Dae */ 401c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 411c248b7dSInki Dae if (ret) 422364839aSJoonyoung Shim return ret; 431c248b7dSInki Dae 441c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 451c248b7dSInki Dae 461c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 471c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 481c248b7dSInki Dae 492364839aSJoonyoung Shim return 0; 502364839aSJoonyoung Shim } 511c248b7dSInki Dae 522364839aSJoonyoung Shim void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) 532364839aSJoonyoung Shim { 542364839aSJoonyoung Shim struct drm_gem_object *obj; 55c01d73faSInki Dae struct exynos_drm_gem_buf *buf; 562364839aSJoonyoung Shim 572364839aSJoonyoung Shim obj = &exynos_gem_obj->base; 58c01d73faSInki Dae buf = exynos_gem_obj->buffer; 592364839aSJoonyoung Shim 60a8e11d1cSDaniel Vetter DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); 612364839aSJoonyoung Shim 62c374e731SInki Dae /* 63c374e731SInki Dae * do not release memory region from exporter. 64c374e731SInki Dae * 65c374e731SInki Dae * the region will be released by exporter 66c374e731SInki Dae * once dmabuf's refcount becomes 0. 67c374e731SInki Dae */ 68c374e731SInki Dae if (obj->import_attach) 69c374e731SInki Dae goto out; 70c374e731SInki Dae 71c01d73faSInki Dae exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf); 722b35892eSInki Dae 73c374e731SInki Dae out: 74c01d73faSInki Dae exynos_drm_fini_buf(obj->dev, buf); 752b35892eSInki Dae exynos_gem_obj->buffer = NULL; 762364839aSJoonyoung Shim 772364839aSJoonyoung Shim drm_gem_free_mmap_offset(obj); 782364839aSJoonyoung Shim 792364839aSJoonyoung Shim /* release file pointer to gem object. */ 801c248b7dSInki Dae drm_gem_object_release(obj); 811c248b7dSInki Dae 821c248b7dSInki Dae kfree(exynos_gem_obj); 832b35892eSInki Dae exynos_gem_obj = NULL; 842364839aSJoonyoung Shim } 852364839aSJoonyoung Shim 86a4f19aaaSInki Dae unsigned long exynos_drm_gem_get_size(struct drm_device *dev, 87a4f19aaaSInki Dae unsigned int gem_handle, 88a4f19aaaSInki Dae struct drm_file *file_priv) 89a4f19aaaSInki Dae { 90a4f19aaaSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 91a4f19aaaSInki Dae struct drm_gem_object *obj; 92a4f19aaaSInki Dae 93a4f19aaaSInki Dae obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 94a4f19aaaSInki Dae if (!obj) { 95a4f19aaaSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 96a4f19aaaSInki Dae return 0; 97a4f19aaaSInki Dae } 98a4f19aaaSInki Dae 99a4f19aaaSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 100a4f19aaaSInki Dae 101a4f19aaaSInki Dae drm_gem_object_unreference_unlocked(obj); 102a4f19aaaSInki Dae 103a4f19aaaSInki Dae return exynos_gem_obj->buffer->size; 104a4f19aaaSInki Dae } 105a4f19aaaSInki Dae 106a4f19aaaSInki Dae 107b2df26c1SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, 1082364839aSJoonyoung Shim unsigned long size) 1092364839aSJoonyoung Shim { 1102364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1112364839aSJoonyoung Shim struct drm_gem_object *obj; 1122364839aSJoonyoung Shim int ret; 1132364839aSJoonyoung Shim 1142364839aSJoonyoung Shim exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 11538bb5253SSachin Kamat if (!exynos_gem_obj) 1165f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 1172364839aSJoonyoung Shim 1182b35892eSInki Dae exynos_gem_obj->size = size; 1192364839aSJoonyoung Shim obj = &exynos_gem_obj->base; 1202364839aSJoonyoung Shim 1212364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 1222364839aSJoonyoung Shim if (ret < 0) { 1232364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 1242364839aSJoonyoung Shim kfree(exynos_gem_obj); 1255f3f4266SJoonyoung Shim return ERR_PTR(ret); 1262364839aSJoonyoung Shim } 1272364839aSJoonyoung Shim 1282364839aSJoonyoung Shim DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 1292364839aSJoonyoung Shim 1302364839aSJoonyoung Shim return exynos_gem_obj; 1311c248b7dSInki Dae } 1321c248b7dSInki Dae 133f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 1342b35892eSInki Dae unsigned int flags, 135ee5e770eSJoonyoung Shim unsigned long size) 136f088d5a9SInki Dae { 1372364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1382b35892eSInki Dae struct exynos_drm_gem_buf *buf; 1392b35892eSInki Dae int ret; 140f088d5a9SInki Dae 141c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 142c4130bcdSJoonyoung Shim DRM_ERROR("invalid flags.\n"); 143c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 144c4130bcdSJoonyoung Shim } 145c4130bcdSJoonyoung Shim 146dcf9af82SInki Dae if (!size) { 147dcf9af82SInki Dae DRM_ERROR("invalid size.\n"); 148dcf9af82SInki Dae return ERR_PTR(-EINVAL); 149dcf9af82SInki Dae } 150f088d5a9SInki Dae 151dcf9af82SInki Dae size = roundup_gem_size(size, flags); 152dcf9af82SInki Dae 1532b35892eSInki Dae buf = exynos_drm_init_buf(dev, size); 1542b35892eSInki Dae if (!buf) 155ee5e770eSJoonyoung Shim return ERR_PTR(-ENOMEM); 156f088d5a9SInki Dae 1572364839aSJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, size); 1585f3f4266SJoonyoung Shim if (IS_ERR(exynos_gem_obj)) { 1595f3f4266SJoonyoung Shim ret = PTR_ERR(exynos_gem_obj); 160dcf9af82SInki Dae goto err_fini_buf; 161f088d5a9SInki Dae } 162f088d5a9SInki Dae 1632b35892eSInki Dae exynos_gem_obj->buffer = buf; 1642b35892eSInki Dae 1652b35892eSInki Dae /* set memory type and cache attribute from user side. */ 1662b35892eSInki Dae exynos_gem_obj->flags = flags; 1672b35892eSInki Dae 1682b35892eSInki Dae ret = exynos_drm_alloc_buf(dev, buf, flags); 169c58c1599SYoungJun Cho if (ret < 0) 170c58c1599SYoungJun Cho goto err_gem_fini; 171f088d5a9SInki Dae 172f088d5a9SInki Dae return exynos_gem_obj; 173dcf9af82SInki Dae 174c58c1599SYoungJun Cho err_gem_fini: 175c58c1599SYoungJun Cho drm_gem_object_release(&exynos_gem_obj->base); 176c58c1599SYoungJun Cho kfree(exynos_gem_obj); 177dcf9af82SInki Dae err_fini_buf: 1782b35892eSInki Dae exynos_drm_fini_buf(dev, buf); 1792b35892eSInki Dae return ERR_PTR(ret); 180f088d5a9SInki Dae } 181f088d5a9SInki Dae 1821c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 1831c248b7dSInki Dae struct drm_file *file_priv) 1841c248b7dSInki Dae { 1851c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 186ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1872364839aSJoonyoung Shim int ret; 1881c248b7dSInki Dae 1892b35892eSInki Dae exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); 1901c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 1911c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 1921c248b7dSInki Dae 1932364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 1942364839aSJoonyoung Shim &args->handle); 1952364839aSJoonyoung Shim if (ret) { 1962364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 1972364839aSJoonyoung Shim return ret; 1982364839aSJoonyoung Shim } 1992364839aSJoonyoung Shim 2001c248b7dSInki Dae return 0; 2011c248b7dSInki Dae } 2021c248b7dSInki Dae 203d87342c1SInki Dae dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, 204f0b1bda7SInki Dae unsigned int gem_handle, 205d87342c1SInki Dae struct drm_file *filp) 206f0b1bda7SInki Dae { 207f0b1bda7SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 208f0b1bda7SInki Dae struct drm_gem_object *obj; 209f0b1bda7SInki Dae 210d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 211f0b1bda7SInki Dae if (!obj) { 212f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 213f0b1bda7SInki Dae return ERR_PTR(-EINVAL); 214f0b1bda7SInki Dae } 215f0b1bda7SInki Dae 216f0b1bda7SInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 217f0b1bda7SInki Dae 218f0b1bda7SInki Dae return &exynos_gem_obj->buffer->dma_addr; 219f0b1bda7SInki Dae } 220f0b1bda7SInki Dae 221f0b1bda7SInki Dae void exynos_drm_gem_put_dma_addr(struct drm_device *dev, 222f0b1bda7SInki Dae unsigned int gem_handle, 223d87342c1SInki Dae struct drm_file *filp) 224f0b1bda7SInki Dae { 225f0b1bda7SInki Dae struct drm_gem_object *obj; 226f0b1bda7SInki Dae 227d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 228f0b1bda7SInki Dae if (!obj) { 229f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 230f0b1bda7SInki Dae return; 231f0b1bda7SInki Dae } 232f0b1bda7SInki Dae 233f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 234f0b1bda7SInki Dae 235f0b1bda7SInki Dae /* 236f0b1bda7SInki Dae * decrease obj->refcount one more time because we has already 237f0b1bda7SInki Dae * increased it at exynos_drm_gem_get_dma_addr(). 238f0b1bda7SInki Dae */ 239f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 240f0b1bda7SInki Dae } 241f0b1bda7SInki Dae 242832316c7SInki Dae int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, 2431c248b7dSInki Dae struct vm_area_struct *vma) 2441c248b7dSInki Dae { 245832316c7SInki Dae struct drm_device *drm_dev = exynos_gem_obj->base.dev; 2462c871127SInki Dae struct exynos_drm_gem_buf *buffer; 2470519f9a1SInki Dae unsigned long vm_size; 2485b07c660SInki Dae int ret; 2491c248b7dSInki Dae 250832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 251832316c7SInki Dae vma->vm_pgoff = 0; 2521c248b7dSInki Dae 2530519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 2542b35892eSInki Dae 2551c248b7dSInki Dae /* 2562c871127SInki Dae * a buffer contains information to physically continuous memory 2571c248b7dSInki Dae * allocated by user request or at framebuffer creation. 2581c248b7dSInki Dae */ 2592c871127SInki Dae buffer = exynos_gem_obj->buffer; 2601c248b7dSInki Dae 2611c248b7dSInki Dae /* check if user-requested size is valid. */ 2622c871127SInki Dae if (vm_size > buffer->size) 2631c248b7dSInki Dae return -EINVAL; 2641c248b7dSInki Dae 2654744ad24SInki Dae ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages, 2660519f9a1SInki Dae buffer->dma_addr, buffer->size, 2670519f9a1SInki Dae &buffer->dma_attrs); 2685b07c660SInki Dae if (ret < 0) { 2695b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 2705b07c660SInki Dae return ret; 2715b07c660SInki Dae } 2725b07c660SInki Dae 2731c248b7dSInki Dae return 0; 2741c248b7dSInki Dae } 2751c248b7dSInki Dae 27640cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 27740cd7e0cSInki Dae struct drm_file *file_priv) 27840cd7e0cSInki Dae { struct exynos_drm_gem_obj *exynos_gem_obj; 27940cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 28040cd7e0cSInki Dae struct drm_gem_object *obj; 28140cd7e0cSInki Dae 28240cd7e0cSInki Dae mutex_lock(&dev->struct_mutex); 28340cd7e0cSInki Dae 28440cd7e0cSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 28540cd7e0cSInki Dae if (!obj) { 28640cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 28740cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 28840cd7e0cSInki Dae return -EINVAL; 28940cd7e0cSInki Dae } 29040cd7e0cSInki Dae 29140cd7e0cSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 29240cd7e0cSInki Dae 29340cd7e0cSInki Dae args->flags = exynos_gem_obj->flags; 29440cd7e0cSInki Dae args->size = exynos_gem_obj->size; 29540cd7e0cSInki Dae 29640cd7e0cSInki Dae drm_gem_object_unreference(obj); 29740cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 29840cd7e0cSInki Dae 29940cd7e0cSInki Dae return 0; 30040cd7e0cSInki Dae } 30140cd7e0cSInki Dae 3022a3098ffSInki Dae struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma) 3032a3098ffSInki Dae { 3042a3098ffSInki Dae struct vm_area_struct *vma_copy; 3052a3098ffSInki Dae 3062a3098ffSInki Dae vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL); 3072a3098ffSInki Dae if (!vma_copy) 3082a3098ffSInki Dae return NULL; 3092a3098ffSInki Dae 3102a3098ffSInki Dae if (vma->vm_ops && vma->vm_ops->open) 3112a3098ffSInki Dae vma->vm_ops->open(vma); 3122a3098ffSInki Dae 3132a3098ffSInki Dae if (vma->vm_file) 3142a3098ffSInki Dae get_file(vma->vm_file); 3152a3098ffSInki Dae 3162a3098ffSInki Dae memcpy(vma_copy, vma, sizeof(*vma)); 3172a3098ffSInki Dae 3182a3098ffSInki Dae vma_copy->vm_mm = NULL; 3192a3098ffSInki Dae vma_copy->vm_next = NULL; 3202a3098ffSInki Dae vma_copy->vm_prev = NULL; 3212a3098ffSInki Dae 3222a3098ffSInki Dae return vma_copy; 3232a3098ffSInki Dae } 3242a3098ffSInki Dae 3252a3098ffSInki Dae void exynos_gem_put_vma(struct vm_area_struct *vma) 3262a3098ffSInki Dae { 3272a3098ffSInki Dae if (!vma) 3282a3098ffSInki Dae return; 3292a3098ffSInki Dae 3302a3098ffSInki Dae if (vma->vm_ops && vma->vm_ops->close) 3312a3098ffSInki Dae vma->vm_ops->close(vma); 3322a3098ffSInki Dae 3332a3098ffSInki Dae if (vma->vm_file) 3342a3098ffSInki Dae fput(vma->vm_file); 3352a3098ffSInki Dae 3362a3098ffSInki Dae kfree(vma); 3372a3098ffSInki Dae } 3382a3098ffSInki Dae 3392a3098ffSInki Dae int exynos_gem_get_pages_from_userptr(unsigned long start, 3402a3098ffSInki Dae unsigned int npages, 3412a3098ffSInki Dae struct page **pages, 3422a3098ffSInki Dae struct vm_area_struct *vma) 3432a3098ffSInki Dae { 3442a3098ffSInki Dae int get_npages; 3452a3098ffSInki Dae 3462a3098ffSInki Dae /* the memory region mmaped with VM_PFNMAP. */ 3472a3098ffSInki Dae if (vma_is_io(vma)) { 3482a3098ffSInki Dae unsigned int i; 3492a3098ffSInki Dae 3502a3098ffSInki Dae for (i = 0; i < npages; ++i, start += PAGE_SIZE) { 3512a3098ffSInki Dae unsigned long pfn; 3522a3098ffSInki Dae int ret = follow_pfn(vma, start, &pfn); 3532a3098ffSInki Dae if (ret) 3542a3098ffSInki Dae return ret; 3552a3098ffSInki Dae 3562a3098ffSInki Dae pages[i] = pfn_to_page(pfn); 3572a3098ffSInki Dae } 3582a3098ffSInki Dae 3592a3098ffSInki Dae if (i != npages) { 3602a3098ffSInki Dae DRM_ERROR("failed to get user_pages.\n"); 3612a3098ffSInki Dae return -EINVAL; 3622a3098ffSInki Dae } 3632a3098ffSInki Dae 3642a3098ffSInki Dae return 0; 3652a3098ffSInki Dae } 3662a3098ffSInki Dae 3672a3098ffSInki Dae get_npages = get_user_pages(current, current->mm, start, 3682a3098ffSInki Dae npages, 1, 1, pages, NULL); 3692a3098ffSInki Dae get_npages = max(get_npages, 0); 3702a3098ffSInki Dae if (get_npages != npages) { 3712a3098ffSInki Dae DRM_ERROR("failed to get user_pages.\n"); 3722a3098ffSInki Dae while (get_npages) 3732a3098ffSInki Dae put_page(pages[--get_npages]); 3742a3098ffSInki Dae return -EFAULT; 3752a3098ffSInki Dae } 3762a3098ffSInki Dae 3772a3098ffSInki Dae return 0; 3782a3098ffSInki Dae } 3792a3098ffSInki Dae 3802a3098ffSInki Dae void exynos_gem_put_pages_to_userptr(struct page **pages, 3812a3098ffSInki Dae unsigned int npages, 3822a3098ffSInki Dae struct vm_area_struct *vma) 3832a3098ffSInki Dae { 3842a3098ffSInki Dae if (!vma_is_io(vma)) { 3852a3098ffSInki Dae unsigned int i; 3862a3098ffSInki Dae 3872a3098ffSInki Dae for (i = 0; i < npages; i++) { 3882a3098ffSInki Dae set_page_dirty_lock(pages[i]); 3892a3098ffSInki Dae 3902a3098ffSInki Dae /* 3912a3098ffSInki Dae * undo the reference we took when populating 3922a3098ffSInki Dae * the table. 3932a3098ffSInki Dae */ 3942a3098ffSInki Dae put_page(pages[i]); 3952a3098ffSInki Dae } 3962a3098ffSInki Dae } 3972a3098ffSInki Dae } 3982a3098ffSInki Dae 3992a3098ffSInki Dae int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, 4002a3098ffSInki Dae struct sg_table *sgt, 4012a3098ffSInki Dae enum dma_data_direction dir) 4022a3098ffSInki Dae { 4032a3098ffSInki Dae int nents; 4042a3098ffSInki Dae 4052a3098ffSInki Dae mutex_lock(&drm_dev->struct_mutex); 4062a3098ffSInki Dae 4072a3098ffSInki Dae nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 4082a3098ffSInki Dae if (!nents) { 4092a3098ffSInki Dae DRM_ERROR("failed to map sgl with dma.\n"); 4102a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 4112a3098ffSInki Dae return nents; 4122a3098ffSInki Dae } 4132a3098ffSInki Dae 4142a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 4152a3098ffSInki Dae return 0; 4162a3098ffSInki Dae } 4172a3098ffSInki Dae 4182a3098ffSInki Dae void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, 4192a3098ffSInki Dae struct sg_table *sgt, 4202a3098ffSInki Dae enum dma_data_direction dir) 4212a3098ffSInki Dae { 4222a3098ffSInki Dae dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 4232a3098ffSInki Dae } 4242a3098ffSInki Dae 425ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 4261c248b7dSInki Dae { 427b2df26c1SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 428b2df26c1SInki Dae struct exynos_drm_gem_buf *buf; 429b2df26c1SInki Dae 430b2df26c1SInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 431b2df26c1SInki Dae buf = exynos_gem_obj->buffer; 432b2df26c1SInki Dae 4332364839aSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); 4341c248b7dSInki Dae } 4351c248b7dSInki Dae 4361c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 437ee5e770eSJoonyoung Shim struct drm_device *dev, 438ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 4391c248b7dSInki Dae { 4401c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 4412364839aSJoonyoung Shim int ret; 4421c248b7dSInki Dae 4431c248b7dSInki Dae /* 444c6b78bc8SMasanari Iida * allocate memory to be used for framebuffer. 4451c248b7dSInki Dae * - this callback would be called by user application 4461c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 4471c248b7dSInki Dae */ 4481c248b7dSInki Dae 4493fd6b694SCooper Yuan args->pitch = args->width * ((args->bpp + 7) / 8); 4507da5907cSInki Dae args->size = args->pitch * args->height; 4511c248b7dSInki Dae 452122beea8SRahul Sharma if (is_drm_iommu_supported(dev)) { 4533fec4532SVikas Sajjan exynos_gem_obj = exynos_drm_gem_create(dev, 4543fec4532SVikas Sajjan EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC, 4553fec4532SVikas Sajjan args->size); 456122beea8SRahul Sharma } else { 457122beea8SRahul Sharma exynos_gem_obj = exynos_drm_gem_create(dev, 458122beea8SRahul Sharma EXYNOS_BO_CONTIG | EXYNOS_BO_WC, 459122beea8SRahul Sharma args->size); 4603fec4532SVikas Sajjan } 4613fec4532SVikas Sajjan 462122beea8SRahul Sharma if (IS_ERR(exynos_gem_obj)) { 463122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 4641c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 465122beea8SRahul Sharma } 4661c248b7dSInki Dae 4672364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 4682364839aSJoonyoung Shim &args->handle); 4692364839aSJoonyoung Shim if (ret) { 4702364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 4712364839aSJoonyoung Shim return ret; 4722364839aSJoonyoung Shim } 4732364839aSJoonyoung Shim 4741c248b7dSInki Dae return 0; 4751c248b7dSInki Dae } 4761c248b7dSInki Dae 4771c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 478ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 479ee5e770eSJoonyoung Shim uint64_t *offset) 4801c248b7dSInki Dae { 4811c248b7dSInki Dae struct drm_gem_object *obj; 4822d91cf17SJoonyoung Shim int ret = 0; 4831c248b7dSInki Dae 4841c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 4851c248b7dSInki Dae 4861c248b7dSInki Dae /* 4871c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 4881c248b7dSInki Dae * - this callback would be called by user application 4891c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 4901c248b7dSInki Dae */ 4911c248b7dSInki Dae 4921c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 4931c248b7dSInki Dae if (!obj) { 4941c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 4952d91cf17SJoonyoung Shim ret = -EINVAL; 4962d91cf17SJoonyoung Shim goto unlock; 4971c248b7dSInki Dae } 4981c248b7dSInki Dae 4996037bafaSLaurent Pinchart ret = drm_gem_create_mmap_offset(obj); 5002d91cf17SJoonyoung Shim if (ret) 5012d91cf17SJoonyoung Shim goto out; 5021c248b7dSInki Dae 5030de23977SDavid Herrmann *offset = drm_vma_node_offset_addr(&obj->vma_node); 5041c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 5051c248b7dSInki Dae 5062d91cf17SJoonyoung Shim out: 5072d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 5082d91cf17SJoonyoung Shim unlock: 5091c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 5102d91cf17SJoonyoung Shim return ret; 5111c248b7dSInki Dae } 5121c248b7dSInki Dae 5131c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 5141c248b7dSInki Dae { 5151c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 5160e9a2ee3SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 5170e9a2ee3SJoonyoung Shim struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer; 5180e9a2ee3SJoonyoung Shim unsigned long pfn; 5191c248b7dSInki Dae pgoff_t page_offset; 5201c248b7dSInki Dae int ret; 5211c248b7dSInki Dae 5221c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 5231c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 5241c248b7dSInki Dae 5250e9a2ee3SJoonyoung Shim if (page_offset >= (buf->size >> PAGE_SHIFT)) { 5260e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 5270e9a2ee3SJoonyoung Shim ret = -EINVAL; 5280e9a2ee3SJoonyoung Shim goto out; 5290e9a2ee3SJoonyoung Shim } 5301c248b7dSInki Dae 5310e9a2ee3SJoonyoung Shim pfn = page_to_pfn(buf->pages[page_offset]); 5320e9a2ee3SJoonyoung Shim ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 5330e9a2ee3SJoonyoung Shim 5340e9a2ee3SJoonyoung Shim out: 53523597e26SJoonyoung Shim switch (ret) { 53623597e26SJoonyoung Shim case 0: 53723597e26SJoonyoung Shim case -ERESTARTSYS: 53823597e26SJoonyoung Shim case -EINTR: 53923597e26SJoonyoung Shim return VM_FAULT_NOPAGE; 54023597e26SJoonyoung Shim case -ENOMEM: 54123597e26SJoonyoung Shim return VM_FAULT_OOM; 54223597e26SJoonyoung Shim default: 54323597e26SJoonyoung Shim return VM_FAULT_SIGBUS; 54423597e26SJoonyoung Shim } 5451c248b7dSInki Dae } 5461c248b7dSInki Dae 5471c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 5481c248b7dSInki Dae { 549c01d73faSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 550c01d73faSInki Dae struct drm_gem_object *obj; 5511c248b7dSInki Dae int ret; 5521c248b7dSInki Dae 5531c248b7dSInki Dae /* set vm_area_struct. */ 5541c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 5551c248b7dSInki Dae if (ret < 0) { 5561c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 5571c248b7dSInki Dae return ret; 5581c248b7dSInki Dae } 5591c248b7dSInki Dae 560c01d73faSInki Dae obj = vma->vm_private_data; 561c01d73faSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 562c01d73faSInki Dae 563211b8878SJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); 564211b8878SJoonyoung Shim 565211b8878SJoonyoung Shim /* non-cachable as default. */ 566211b8878SJoonyoung Shim if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) 567211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 568211b8878SJoonyoung Shim else if (exynos_gem_obj->flags & EXYNOS_BO_WC) 569211b8878SJoonyoung Shim vma->vm_page_prot = 570211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 571211b8878SJoonyoung Shim else 572211b8878SJoonyoung Shim vma->vm_page_prot = 573211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 574c01d73faSInki Dae 575832316c7SInki Dae ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); 576832316c7SInki Dae if (ret) 577832316c7SInki Dae goto err_close_vm; 578832316c7SInki Dae 579832316c7SInki Dae return ret; 580832316c7SInki Dae 581832316c7SInki Dae err_close_vm: 582832316c7SInki Dae drm_gem_vm_close(vma); 583832316c7SInki Dae drm_gem_free_mmap_offset(obj); 584832316c7SInki Dae 5851c248b7dSInki Dae return ret; 5861c248b7dSInki Dae } 587