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> 1601ed50ddSJoonyoung Shim #include <linux/dma-buf.h> 171c248b7dSInki Dae #include <drm/exynos_drm.h> 181c248b7dSInki Dae 191c248b7dSInki Dae #include "exynos_drm_drv.h" 201c248b7dSInki Dae #include "exynos_drm_gem.h" 213fec4532SVikas Sajjan #include "exynos_drm_iommu.h" 221c248b7dSInki Dae 232a8cb489SJoonyoung Shim static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj) 242a8cb489SJoonyoung Shim { 252a8cb489SJoonyoung Shim struct drm_device *dev = obj->base.dev; 262a8cb489SJoonyoung Shim enum dma_attr attr; 272a8cb489SJoonyoung Shim unsigned int nr_pages; 282a8cb489SJoonyoung Shim 292a8cb489SJoonyoung Shim if (obj->dma_addr) { 302a8cb489SJoonyoung Shim DRM_DEBUG_KMS("already allocated.\n"); 312a8cb489SJoonyoung Shim return 0; 322a8cb489SJoonyoung Shim } 332a8cb489SJoonyoung Shim 342a8cb489SJoonyoung Shim init_dma_attrs(&obj->dma_attrs); 352a8cb489SJoonyoung Shim 362a8cb489SJoonyoung Shim /* 372a8cb489SJoonyoung Shim * if EXYNOS_BO_CONTIG, fully physically contiguous memory 382a8cb489SJoonyoung Shim * region will be allocated else physically contiguous 392a8cb489SJoonyoung Shim * as possible. 402a8cb489SJoonyoung Shim */ 412a8cb489SJoonyoung Shim if (!(obj->flags & EXYNOS_BO_NONCONTIG)) 422a8cb489SJoonyoung Shim dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs); 432a8cb489SJoonyoung Shim 442a8cb489SJoonyoung Shim /* 452a8cb489SJoonyoung Shim * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping 462a8cb489SJoonyoung Shim * else cachable mapping. 472a8cb489SJoonyoung Shim */ 482a8cb489SJoonyoung Shim if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE)) 492a8cb489SJoonyoung Shim attr = DMA_ATTR_WRITE_COMBINE; 502a8cb489SJoonyoung Shim else 512a8cb489SJoonyoung Shim attr = DMA_ATTR_NON_CONSISTENT; 522a8cb489SJoonyoung Shim 532a8cb489SJoonyoung Shim dma_set_attr(attr, &obj->dma_attrs); 542a8cb489SJoonyoung Shim dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs); 552a8cb489SJoonyoung Shim 562a8cb489SJoonyoung Shim nr_pages = obj->size >> PAGE_SHIFT; 572a8cb489SJoonyoung Shim 582a8cb489SJoonyoung Shim if (!is_drm_iommu_supported(dev)) { 592a8cb489SJoonyoung Shim obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); 602a8cb489SJoonyoung Shim if (!obj->pages) { 612a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate pages.\n"); 622a8cb489SJoonyoung Shim return -ENOMEM; 632a8cb489SJoonyoung Shim } 64333e8e58SJoonyoung Shim } 652a8cb489SJoonyoung Shim 66333e8e58SJoonyoung Shim obj->cookie = dma_alloc_attrs(dev->dev, obj->size, &obj->dma_addr, 67333e8e58SJoonyoung Shim GFP_KERNEL, &obj->dma_attrs); 682a8cb489SJoonyoung Shim if (!obj->cookie) { 692a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate buffer.\n"); 70333e8e58SJoonyoung Shim if (obj->pages) 712a8cb489SJoonyoung Shim drm_free_large(obj->pages); 722a8cb489SJoonyoung Shim return -ENOMEM; 732a8cb489SJoonyoung Shim } 742a8cb489SJoonyoung Shim 75333e8e58SJoonyoung Shim if (obj->pages) { 76333e8e58SJoonyoung Shim dma_addr_t start_addr; 77333e8e58SJoonyoung Shim unsigned int i = 0; 78333e8e58SJoonyoung Shim 792a8cb489SJoonyoung Shim start_addr = obj->dma_addr; 802a8cb489SJoonyoung Shim while (i < nr_pages) { 815e0fb1f9SJoonyoung Shim obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev, 825e0fb1f9SJoonyoung Shim start_addr)); 832a8cb489SJoonyoung Shim start_addr += PAGE_SIZE; 842a8cb489SJoonyoung Shim i++; 852a8cb489SJoonyoung Shim } 862a8cb489SJoonyoung Shim } else { 87333e8e58SJoonyoung Shim obj->pages = obj->cookie; 882a8cb489SJoonyoung Shim } 892a8cb489SJoonyoung Shim 902a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 912a8cb489SJoonyoung Shim (unsigned long)obj->dma_addr, 922a8cb489SJoonyoung Shim obj->size); 932a8cb489SJoonyoung Shim 942a8cb489SJoonyoung Shim return 0; 952a8cb489SJoonyoung Shim } 962a8cb489SJoonyoung Shim 972a8cb489SJoonyoung Shim static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj) 982a8cb489SJoonyoung Shim { 992a8cb489SJoonyoung Shim struct drm_device *dev = obj->base.dev; 1002a8cb489SJoonyoung Shim 1012a8cb489SJoonyoung Shim if (!obj->dma_addr) { 1022a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr is invalid.\n"); 1032a8cb489SJoonyoung Shim return; 1042a8cb489SJoonyoung Shim } 1052a8cb489SJoonyoung Shim 1062a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 1072a8cb489SJoonyoung Shim (unsigned long)obj->dma_addr, obj->size); 1082a8cb489SJoonyoung Shim 1092a8cb489SJoonyoung Shim dma_free_attrs(dev->dev, obj->size, obj->cookie, 1102a8cb489SJoonyoung Shim (dma_addr_t)obj->dma_addr, &obj->dma_attrs); 111333e8e58SJoonyoung Shim 112333e8e58SJoonyoung Shim if (!is_drm_iommu_supported(dev)) 1132a8cb489SJoonyoung Shim drm_free_large(obj->pages); 1142a8cb489SJoonyoung Shim } 1152a8cb489SJoonyoung Shim 1162364839aSJoonyoung Shim static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 1172364839aSJoonyoung Shim struct drm_file *file_priv, 1182364839aSJoonyoung Shim unsigned int *handle) 1191c248b7dSInki Dae { 1201c248b7dSInki Dae int ret; 1211c248b7dSInki Dae 1221c248b7dSInki Dae /* 1231c248b7dSInki Dae * allocate a id of idr table where the obj is registered 1241c248b7dSInki Dae * and handle has the id what user can see. 1251c248b7dSInki Dae */ 1261c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 1271c248b7dSInki Dae if (ret) 1282364839aSJoonyoung Shim return ret; 1291c248b7dSInki Dae 1301c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 1311c248b7dSInki Dae 1321c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 1331c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 1341c248b7dSInki Dae 1352364839aSJoonyoung Shim return 0; 1362364839aSJoonyoung Shim } 1371c248b7dSInki Dae 1382364839aSJoonyoung Shim void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) 1392364839aSJoonyoung Shim { 1402a8cb489SJoonyoung Shim struct drm_gem_object *obj = &exynos_gem_obj->base; 1412364839aSJoonyoung Shim 142a8e11d1cSDaniel Vetter DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); 1432364839aSJoonyoung Shim 144c374e731SInki Dae /* 145c374e731SInki Dae * do not release memory region from exporter. 146c374e731SInki Dae * 147c374e731SInki Dae * the region will be released by exporter 148c374e731SInki Dae * once dmabuf's refcount becomes 0. 149c374e731SInki Dae */ 150c374e731SInki Dae if (obj->import_attach) 1517c93537aSJoonyoung Shim drm_prime_gem_destroy(obj, exynos_gem_obj->sgt); 1527c93537aSJoonyoung Shim else 1532a8cb489SJoonyoung Shim exynos_drm_free_buf(exynos_gem_obj); 1542b35892eSInki Dae 1552364839aSJoonyoung Shim /* release file pointer to gem object. */ 1561c248b7dSInki Dae drm_gem_object_release(obj); 1571c248b7dSInki Dae 1581c248b7dSInki Dae kfree(exynos_gem_obj); 1592364839aSJoonyoung Shim } 1602364839aSJoonyoung Shim 161a4f19aaaSInki Dae unsigned long exynos_drm_gem_get_size(struct drm_device *dev, 162a4f19aaaSInki Dae unsigned int gem_handle, 163a4f19aaaSInki Dae struct drm_file *file_priv) 164a4f19aaaSInki Dae { 165a4f19aaaSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 166a4f19aaaSInki Dae struct drm_gem_object *obj; 167a4f19aaaSInki Dae 168a4f19aaaSInki Dae obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 169a4f19aaaSInki Dae if (!obj) { 170a4f19aaaSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 171a4f19aaaSInki Dae return 0; 172a4f19aaaSInki Dae } 173a4f19aaaSInki Dae 174a4f19aaaSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 175a4f19aaaSInki Dae 176a4f19aaaSInki Dae drm_gem_object_unreference_unlocked(obj); 177a4f19aaaSInki Dae 1782a8cb489SJoonyoung Shim return exynos_gem_obj->size; 179a4f19aaaSInki Dae } 180a4f19aaaSInki Dae 181b319dc6aSJoonyoung Shim static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, 1822364839aSJoonyoung Shim unsigned long size) 1832364839aSJoonyoung Shim { 1842364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1852364839aSJoonyoung Shim struct drm_gem_object *obj; 1862364839aSJoonyoung Shim int ret; 1872364839aSJoonyoung Shim 1882364839aSJoonyoung Shim exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 18938bb5253SSachin Kamat if (!exynos_gem_obj) 1905f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 1912364839aSJoonyoung Shim 1922b35892eSInki Dae exynos_gem_obj->size = size; 1932364839aSJoonyoung Shim obj = &exynos_gem_obj->base; 1942364839aSJoonyoung Shim 1952364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 1962364839aSJoonyoung Shim if (ret < 0) { 1972364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 1982364839aSJoonyoung Shim kfree(exynos_gem_obj); 1995f3f4266SJoonyoung Shim return ERR_PTR(ret); 2002364839aSJoonyoung Shim } 2012364839aSJoonyoung Shim 20248cf53f4SJoonyoung Shim ret = drm_gem_create_mmap_offset(obj); 20348cf53f4SJoonyoung Shim if (ret < 0) { 20448cf53f4SJoonyoung Shim drm_gem_object_release(obj); 20548cf53f4SJoonyoung Shim kfree(exynos_gem_obj); 20648cf53f4SJoonyoung Shim return ERR_PTR(ret); 20748cf53f4SJoonyoung Shim } 20848cf53f4SJoonyoung Shim 2092364839aSJoonyoung Shim DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 2102364839aSJoonyoung Shim 2112364839aSJoonyoung Shim return exynos_gem_obj; 2121c248b7dSInki Dae } 2131c248b7dSInki Dae 214f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 2152b35892eSInki Dae unsigned int flags, 216ee5e770eSJoonyoung Shim unsigned long size) 217f088d5a9SInki Dae { 2182364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2192b35892eSInki Dae int ret; 220f088d5a9SInki Dae 221c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 222c4130bcdSJoonyoung Shim DRM_ERROR("invalid flags.\n"); 223c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 224c4130bcdSJoonyoung Shim } 225c4130bcdSJoonyoung Shim 226dcf9af82SInki Dae if (!size) { 227dcf9af82SInki Dae DRM_ERROR("invalid size.\n"); 228dcf9af82SInki Dae return ERR_PTR(-EINVAL); 229dcf9af82SInki Dae } 230f088d5a9SInki Dae 231eb57da88SJoonyoung Shim size = roundup(size, PAGE_SIZE); 232dcf9af82SInki Dae 2332364839aSJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, size); 2342a8cb489SJoonyoung Shim if (IS_ERR(exynos_gem_obj)) 2352a8cb489SJoonyoung Shim return exynos_gem_obj; 2362b35892eSInki Dae 2372b35892eSInki Dae /* set memory type and cache attribute from user side. */ 2382b35892eSInki Dae exynos_gem_obj->flags = flags; 2392b35892eSInki Dae 2402a8cb489SJoonyoung Shim ret = exynos_drm_alloc_buf(exynos_gem_obj); 2412a8cb489SJoonyoung Shim if (ret < 0) { 242c58c1599SYoungJun Cho drm_gem_object_release(&exynos_gem_obj->base); 243c58c1599SYoungJun Cho kfree(exynos_gem_obj); 2442b35892eSInki Dae return ERR_PTR(ret); 245f088d5a9SInki Dae } 246f088d5a9SInki Dae 2472a8cb489SJoonyoung Shim return exynos_gem_obj; 2482a8cb489SJoonyoung Shim } 2492a8cb489SJoonyoung Shim 2501c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 2511c248b7dSInki Dae struct drm_file *file_priv) 2521c248b7dSInki Dae { 2531c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 254ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2552364839aSJoonyoung Shim int ret; 2561c248b7dSInki Dae 2572b35892eSInki Dae exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); 2581c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 2591c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 2601c248b7dSInki Dae 2612364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 2622364839aSJoonyoung Shim &args->handle); 2632364839aSJoonyoung Shim if (ret) { 2642364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 2652364839aSJoonyoung Shim return ret; 2662364839aSJoonyoung Shim } 2672364839aSJoonyoung Shim 2681c248b7dSInki Dae return 0; 2691c248b7dSInki Dae } 2701c248b7dSInki Dae 271d87342c1SInki Dae dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, 272f0b1bda7SInki Dae unsigned int gem_handle, 273d87342c1SInki Dae struct drm_file *filp) 274f0b1bda7SInki Dae { 275f0b1bda7SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 276f0b1bda7SInki Dae struct drm_gem_object *obj; 277f0b1bda7SInki Dae 278d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 279f0b1bda7SInki Dae if (!obj) { 280f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 281f0b1bda7SInki Dae return ERR_PTR(-EINVAL); 282f0b1bda7SInki Dae } 283f0b1bda7SInki Dae 284f0b1bda7SInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 285f0b1bda7SInki Dae 2862a8cb489SJoonyoung Shim return &exynos_gem_obj->dma_addr; 287f0b1bda7SInki Dae } 288f0b1bda7SInki Dae 289f0b1bda7SInki Dae void exynos_drm_gem_put_dma_addr(struct drm_device *dev, 290f0b1bda7SInki Dae unsigned int gem_handle, 291d87342c1SInki Dae struct drm_file *filp) 292f0b1bda7SInki Dae { 293f0b1bda7SInki Dae struct drm_gem_object *obj; 294f0b1bda7SInki Dae 295d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 296f0b1bda7SInki Dae if (!obj) { 297f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 298f0b1bda7SInki Dae return; 299f0b1bda7SInki Dae } 300f0b1bda7SInki Dae 301f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 302f0b1bda7SInki Dae 303f0b1bda7SInki Dae /* 304f0b1bda7SInki Dae * decrease obj->refcount one more time because we has already 305f0b1bda7SInki Dae * increased it at exynos_drm_gem_get_dma_addr(). 306f0b1bda7SInki Dae */ 307f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 308f0b1bda7SInki Dae } 309f0b1bda7SInki Dae 310832316c7SInki Dae int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, 3111c248b7dSInki Dae struct vm_area_struct *vma) 3121c248b7dSInki Dae { 313832316c7SInki Dae struct drm_device *drm_dev = exynos_gem_obj->base.dev; 3140519f9a1SInki Dae unsigned long vm_size; 3155b07c660SInki Dae int ret; 3161c248b7dSInki Dae 317832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 318832316c7SInki Dae vma->vm_pgoff = 0; 3191c248b7dSInki Dae 3200519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 3212b35892eSInki Dae 3221c248b7dSInki Dae /* check if user-requested size is valid. */ 3232a8cb489SJoonyoung Shim if (vm_size > exynos_gem_obj->size) 3241c248b7dSInki Dae return -EINVAL; 3251c248b7dSInki Dae 3262a8cb489SJoonyoung Shim ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, 3272a8cb489SJoonyoung Shim exynos_gem_obj->dma_addr, exynos_gem_obj->size, 3282a8cb489SJoonyoung Shim &exynos_gem_obj->dma_attrs); 3295b07c660SInki Dae if (ret < 0) { 3305b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 3315b07c660SInki Dae return ret; 3325b07c660SInki Dae } 3335b07c660SInki Dae 3341c248b7dSInki Dae return 0; 3351c248b7dSInki Dae } 3361c248b7dSInki Dae 33740cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 33840cd7e0cSInki Dae struct drm_file *file_priv) 339b4cfd4ddSJoonyoung Shim { 340b4cfd4ddSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 34140cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 34240cd7e0cSInki Dae struct drm_gem_object *obj; 34340cd7e0cSInki Dae 34440cd7e0cSInki Dae mutex_lock(&dev->struct_mutex); 34540cd7e0cSInki Dae 34640cd7e0cSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 34740cd7e0cSInki Dae if (!obj) { 34840cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 34940cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 35040cd7e0cSInki Dae return -EINVAL; 35140cd7e0cSInki Dae } 35240cd7e0cSInki Dae 35340cd7e0cSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 35440cd7e0cSInki Dae 35540cd7e0cSInki Dae args->flags = exynos_gem_obj->flags; 35640cd7e0cSInki Dae args->size = exynos_gem_obj->size; 35740cd7e0cSInki Dae 35840cd7e0cSInki Dae drm_gem_object_unreference(obj); 35940cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 36040cd7e0cSInki Dae 36140cd7e0cSInki Dae return 0; 36240cd7e0cSInki Dae } 36340cd7e0cSInki Dae 3642a3098ffSInki Dae int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, 3652a3098ffSInki Dae struct sg_table *sgt, 3662a3098ffSInki Dae enum dma_data_direction dir) 3672a3098ffSInki Dae { 3682a3098ffSInki Dae int nents; 3692a3098ffSInki Dae 3702a3098ffSInki Dae mutex_lock(&drm_dev->struct_mutex); 3712a3098ffSInki Dae 3722a3098ffSInki Dae nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3732a3098ffSInki Dae if (!nents) { 3742a3098ffSInki Dae DRM_ERROR("failed to map sgl with dma.\n"); 3752a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3762a3098ffSInki Dae return nents; 3772a3098ffSInki Dae } 3782a3098ffSInki Dae 3792a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3802a3098ffSInki Dae return 0; 3812a3098ffSInki Dae } 3822a3098ffSInki Dae 3832a3098ffSInki Dae void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, 3842a3098ffSInki Dae struct sg_table *sgt, 3852a3098ffSInki Dae enum dma_data_direction dir) 3862a3098ffSInki Dae { 3872a3098ffSInki Dae dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3882a3098ffSInki Dae } 3892a3098ffSInki Dae 390ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 3911c248b7dSInki Dae { 3922364839aSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); 3931c248b7dSInki Dae } 3941c248b7dSInki Dae 3951c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 396ee5e770eSJoonyoung Shim struct drm_device *dev, 397ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 3981c248b7dSInki Dae { 3991c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 400333e8e58SJoonyoung Shim unsigned int flags; 4012364839aSJoonyoung Shim int ret; 4021c248b7dSInki Dae 4031c248b7dSInki Dae /* 404c6b78bc8SMasanari Iida * allocate memory to be used for framebuffer. 4051c248b7dSInki Dae * - this callback would be called by user application 4061c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 4071c248b7dSInki Dae */ 4081c248b7dSInki Dae 4093fd6b694SCooper Yuan args->pitch = args->width * ((args->bpp + 7) / 8); 4107da5907cSInki Dae args->size = args->pitch * args->height; 4111c248b7dSInki Dae 412333e8e58SJoonyoung Shim if (is_drm_iommu_supported(dev)) 413333e8e58SJoonyoung Shim flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC; 414333e8e58SJoonyoung Shim else 415333e8e58SJoonyoung Shim flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; 4163fec4532SVikas Sajjan 417333e8e58SJoonyoung Shim exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size); 418122beea8SRahul Sharma if (IS_ERR(exynos_gem_obj)) { 419122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 4201c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 421122beea8SRahul Sharma } 4221c248b7dSInki Dae 4232364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 4242364839aSJoonyoung Shim &args->handle); 4252364839aSJoonyoung Shim if (ret) { 4262364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 4272364839aSJoonyoung Shim return ret; 4282364839aSJoonyoung Shim } 4292364839aSJoonyoung Shim 4301c248b7dSInki Dae return 0; 4311c248b7dSInki Dae } 4321c248b7dSInki Dae 4331c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 434ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 435ee5e770eSJoonyoung Shim uint64_t *offset) 4361c248b7dSInki Dae { 4371c248b7dSInki Dae struct drm_gem_object *obj; 4382d91cf17SJoonyoung Shim int ret = 0; 4391c248b7dSInki Dae 4401c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 4411c248b7dSInki Dae 4421c248b7dSInki Dae /* 4431c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 4441c248b7dSInki Dae * - this callback would be called by user application 4451c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 4461c248b7dSInki Dae */ 4471c248b7dSInki Dae 4481c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 4491c248b7dSInki Dae if (!obj) { 4501c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 4512d91cf17SJoonyoung Shim ret = -EINVAL; 4522d91cf17SJoonyoung Shim goto unlock; 4531c248b7dSInki Dae } 4541c248b7dSInki Dae 4550de23977SDavid Herrmann *offset = drm_vma_node_offset_addr(&obj->vma_node); 4561c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 4571c248b7dSInki Dae 4582d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 4592d91cf17SJoonyoung Shim unlock: 4601c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 4612d91cf17SJoonyoung Shim return ret; 4621c248b7dSInki Dae } 4631c248b7dSInki Dae 4641c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 4651c248b7dSInki Dae { 4661c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 4670e9a2ee3SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 4680e9a2ee3SJoonyoung Shim unsigned long pfn; 4691c248b7dSInki Dae pgoff_t page_offset; 4701c248b7dSInki Dae int ret; 4711c248b7dSInki Dae 4721c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 4731c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 4741c248b7dSInki Dae 4752a8cb489SJoonyoung Shim if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) { 4760e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 4770e9a2ee3SJoonyoung Shim ret = -EINVAL; 4780e9a2ee3SJoonyoung Shim goto out; 4790e9a2ee3SJoonyoung Shim } 4801c248b7dSInki Dae 4812a8cb489SJoonyoung Shim pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]); 4820e9a2ee3SJoonyoung Shim ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 4830e9a2ee3SJoonyoung Shim 4840e9a2ee3SJoonyoung Shim out: 48523597e26SJoonyoung Shim switch (ret) { 48623597e26SJoonyoung Shim case 0: 48723597e26SJoonyoung Shim case -ERESTARTSYS: 48823597e26SJoonyoung Shim case -EINTR: 48923597e26SJoonyoung Shim return VM_FAULT_NOPAGE; 49023597e26SJoonyoung Shim case -ENOMEM: 49123597e26SJoonyoung Shim return VM_FAULT_OOM; 49223597e26SJoonyoung Shim default: 49323597e26SJoonyoung Shim return VM_FAULT_SIGBUS; 49423597e26SJoonyoung Shim } 4951c248b7dSInki Dae } 4961c248b7dSInki Dae 4971c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 4981c248b7dSInki Dae { 499c01d73faSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 500c01d73faSInki Dae struct drm_gem_object *obj; 5011c248b7dSInki Dae int ret; 5021c248b7dSInki Dae 5031c248b7dSInki Dae /* set vm_area_struct. */ 5041c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 5051c248b7dSInki Dae if (ret < 0) { 5061c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 5071c248b7dSInki Dae return ret; 5081c248b7dSInki Dae } 5091c248b7dSInki Dae 510c01d73faSInki Dae obj = vma->vm_private_data; 511c01d73faSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 512c01d73faSInki Dae 513211b8878SJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); 514211b8878SJoonyoung Shim 515211b8878SJoonyoung Shim /* non-cachable as default. */ 516211b8878SJoonyoung Shim if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) 517211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 518211b8878SJoonyoung Shim else if (exynos_gem_obj->flags & EXYNOS_BO_WC) 519211b8878SJoonyoung Shim vma->vm_page_prot = 520211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 521211b8878SJoonyoung Shim else 522211b8878SJoonyoung Shim vma->vm_page_prot = 523211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 524c01d73faSInki Dae 525832316c7SInki Dae ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); 526832316c7SInki Dae if (ret) 527832316c7SInki Dae goto err_close_vm; 528832316c7SInki Dae 529832316c7SInki Dae return ret; 530832316c7SInki Dae 531832316c7SInki Dae err_close_vm: 532832316c7SInki Dae drm_gem_vm_close(vma); 533832316c7SInki Dae 5341c248b7dSInki Dae return ret; 5351c248b7dSInki Dae } 53601ed50ddSJoonyoung Shim 53701ed50ddSJoonyoung Shim /* low-level interface prime helpers */ 53801ed50ddSJoonyoung Shim struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 53901ed50ddSJoonyoung Shim { 54001ed50ddSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 54101ed50ddSJoonyoung Shim int npages; 54201ed50ddSJoonyoung Shim 5432a8cb489SJoonyoung Shim npages = exynos_gem_obj->size >> PAGE_SHIFT; 54401ed50ddSJoonyoung Shim 5452a8cb489SJoonyoung Shim return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages); 54601ed50ddSJoonyoung Shim } 54701ed50ddSJoonyoung Shim 54801ed50ddSJoonyoung Shim struct drm_gem_object * 54901ed50ddSJoonyoung Shim exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, 55001ed50ddSJoonyoung Shim struct dma_buf_attachment *attach, 55101ed50ddSJoonyoung Shim struct sg_table *sgt) 55201ed50ddSJoonyoung Shim { 55301ed50ddSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 55401ed50ddSJoonyoung Shim int npages; 55501ed50ddSJoonyoung Shim int ret; 55601ed50ddSJoonyoung Shim 5572a8cb489SJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); 55801ed50ddSJoonyoung Shim if (IS_ERR(exynos_gem_obj)) { 55901ed50ddSJoonyoung Shim ret = PTR_ERR(exynos_gem_obj); 56050002d4cSInki Dae return ERR_PTR(ret); 56101ed50ddSJoonyoung Shim } 56201ed50ddSJoonyoung Shim 5632a8cb489SJoonyoung Shim exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); 5642a8cb489SJoonyoung Shim 5652a8cb489SJoonyoung Shim npages = exynos_gem_obj->size >> PAGE_SHIFT; 5662a8cb489SJoonyoung Shim exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); 5672a8cb489SJoonyoung Shim if (!exynos_gem_obj->pages) { 5682a8cb489SJoonyoung Shim ret = -ENOMEM; 5692a8cb489SJoonyoung Shim goto err; 5702a8cb489SJoonyoung Shim } 5712a8cb489SJoonyoung Shim 5722a8cb489SJoonyoung Shim ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL, 5732a8cb489SJoonyoung Shim npages); 5742a8cb489SJoonyoung Shim if (ret < 0) 5752a8cb489SJoonyoung Shim goto err_free_large; 5762a8cb489SJoonyoung Shim 5777c93537aSJoonyoung Shim exynos_gem_obj->sgt = sgt; 5787c93537aSJoonyoung Shim 57901ed50ddSJoonyoung Shim if (sgt->nents == 1) { 58001ed50ddSJoonyoung Shim /* always physically continuous memory if sgt->nents is 1. */ 58101ed50ddSJoonyoung Shim exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; 58201ed50ddSJoonyoung Shim } else { 58301ed50ddSJoonyoung Shim /* 58401ed50ddSJoonyoung Shim * this case could be CONTIG or NONCONTIG type but for now 58501ed50ddSJoonyoung Shim * sets NONCONTIG. 58601ed50ddSJoonyoung Shim * TODO. we have to find a way that exporter can notify 58701ed50ddSJoonyoung Shim * the type of its own buffer to importer. 58801ed50ddSJoonyoung Shim */ 58901ed50ddSJoonyoung Shim exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG; 59001ed50ddSJoonyoung Shim } 59101ed50ddSJoonyoung Shim 59201ed50ddSJoonyoung Shim return &exynos_gem_obj->base; 59301ed50ddSJoonyoung Shim 59401ed50ddSJoonyoung Shim err_free_large: 5952a8cb489SJoonyoung Shim drm_free_large(exynos_gem_obj->pages); 59601ed50ddSJoonyoung Shim err: 5972a8cb489SJoonyoung Shim drm_gem_object_release(&exynos_gem_obj->base); 5982a8cb489SJoonyoung Shim kfree(exynos_gem_obj); 59901ed50ddSJoonyoung Shim return ERR_PTR(ret); 60001ed50ddSJoonyoung Shim } 60101ed50ddSJoonyoung Shim 60201ed50ddSJoonyoung Shim void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj) 60301ed50ddSJoonyoung Shim { 60401ed50ddSJoonyoung Shim return NULL; 60501ed50ddSJoonyoung Shim } 60601ed50ddSJoonyoung Shim 60701ed50ddSJoonyoung Shim void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) 60801ed50ddSJoonyoung Shim { 60901ed50ddSJoonyoung Shim /* Nothing to do */ 61001ed50ddSJoonyoung Shim } 611