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 dma_addr_t start_addr; 602a8cb489SJoonyoung Shim unsigned int i = 0; 612a8cb489SJoonyoung Shim 622a8cb489SJoonyoung Shim obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); 632a8cb489SJoonyoung Shim if (!obj->pages) { 642a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate pages.\n"); 652a8cb489SJoonyoung Shim return -ENOMEM; 662a8cb489SJoonyoung Shim } 672a8cb489SJoonyoung Shim 682a8cb489SJoonyoung Shim obj->cookie = dma_alloc_attrs(dev->dev, 692a8cb489SJoonyoung Shim obj->size, 702a8cb489SJoonyoung Shim &obj->dma_addr, GFP_KERNEL, 712a8cb489SJoonyoung Shim &obj->dma_attrs); 722a8cb489SJoonyoung Shim if (!obj->cookie) { 732a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate buffer.\n"); 742a8cb489SJoonyoung Shim drm_free_large(obj->pages); 752a8cb489SJoonyoung Shim return -ENOMEM; 762a8cb489SJoonyoung Shim } 772a8cb489SJoonyoung Shim 782a8cb489SJoonyoung Shim start_addr = obj->dma_addr; 792a8cb489SJoonyoung Shim while (i < nr_pages) { 805e0fb1f9SJoonyoung Shim obj->pages[i] = pfn_to_page(dma_to_pfn(dev->dev, 815e0fb1f9SJoonyoung Shim start_addr)); 822a8cb489SJoonyoung Shim start_addr += PAGE_SIZE; 832a8cb489SJoonyoung Shim i++; 842a8cb489SJoonyoung Shim } 852a8cb489SJoonyoung Shim } else { 862a8cb489SJoonyoung Shim obj->pages = dma_alloc_attrs(dev->dev, obj->size, 872a8cb489SJoonyoung Shim &obj->dma_addr, GFP_KERNEL, 882a8cb489SJoonyoung Shim &obj->dma_attrs); 892a8cb489SJoonyoung Shim if (!obj->pages) { 902a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate buffer.\n"); 912a8cb489SJoonyoung Shim return -ENOMEM; 922a8cb489SJoonyoung Shim } 932a8cb489SJoonyoung Shim } 942a8cb489SJoonyoung Shim 952a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 962a8cb489SJoonyoung Shim (unsigned long)obj->dma_addr, 972a8cb489SJoonyoung Shim obj->size); 982a8cb489SJoonyoung Shim 992a8cb489SJoonyoung Shim return 0; 1002a8cb489SJoonyoung Shim } 1012a8cb489SJoonyoung Shim 1022a8cb489SJoonyoung Shim static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj) 1032a8cb489SJoonyoung Shim { 1042a8cb489SJoonyoung Shim struct drm_device *dev = obj->base.dev; 1052a8cb489SJoonyoung Shim 1062a8cb489SJoonyoung Shim if (!obj->dma_addr) { 1072a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr is invalid.\n"); 1082a8cb489SJoonyoung Shim return; 1092a8cb489SJoonyoung Shim } 1102a8cb489SJoonyoung Shim 1112a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 1122a8cb489SJoonyoung Shim (unsigned long)obj->dma_addr, obj->size); 1132a8cb489SJoonyoung Shim 1142a8cb489SJoonyoung Shim if (!is_drm_iommu_supported(dev)) { 1152a8cb489SJoonyoung Shim dma_free_attrs(dev->dev, obj->size, obj->cookie, 1162a8cb489SJoonyoung Shim (dma_addr_t)obj->dma_addr, &obj->dma_attrs); 1172a8cb489SJoonyoung Shim drm_free_large(obj->pages); 1182a8cb489SJoonyoung Shim } else 1192a8cb489SJoonyoung Shim dma_free_attrs(dev->dev, obj->size, obj->pages, 1202a8cb489SJoonyoung Shim (dma_addr_t)obj->dma_addr, &obj->dma_attrs); 1212a8cb489SJoonyoung Shim } 1222a8cb489SJoonyoung Shim 1232364839aSJoonyoung Shim static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 1242364839aSJoonyoung Shim struct drm_file *file_priv, 1252364839aSJoonyoung Shim unsigned int *handle) 1261c248b7dSInki Dae { 1271c248b7dSInki Dae int ret; 1281c248b7dSInki Dae 1291c248b7dSInki Dae /* 1301c248b7dSInki Dae * allocate a id of idr table where the obj is registered 1311c248b7dSInki Dae * and handle has the id what user can see. 1321c248b7dSInki Dae */ 1331c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 1341c248b7dSInki Dae if (ret) 1352364839aSJoonyoung Shim return ret; 1361c248b7dSInki Dae 1371c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 1381c248b7dSInki Dae 1391c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 1401c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 1411c248b7dSInki Dae 1422364839aSJoonyoung Shim return 0; 1432364839aSJoonyoung Shim } 1441c248b7dSInki Dae 1452364839aSJoonyoung Shim void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj) 1462364839aSJoonyoung Shim { 1472a8cb489SJoonyoung Shim struct drm_gem_object *obj = &exynos_gem_obj->base; 1482364839aSJoonyoung Shim 149a8e11d1cSDaniel Vetter DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); 1502364839aSJoonyoung Shim 151c374e731SInki Dae /* 152c374e731SInki Dae * do not release memory region from exporter. 153c374e731SInki Dae * 154c374e731SInki Dae * the region will be released by exporter 155c374e731SInki Dae * once dmabuf's refcount becomes 0. 156c374e731SInki Dae */ 157c374e731SInki Dae if (obj->import_attach) 1587c93537aSJoonyoung Shim drm_prime_gem_destroy(obj, exynos_gem_obj->sgt); 1597c93537aSJoonyoung Shim else 1602a8cb489SJoonyoung Shim exynos_drm_free_buf(exynos_gem_obj); 1612b35892eSInki Dae 1622364839aSJoonyoung Shim drm_gem_free_mmap_offset(obj); 1632364839aSJoonyoung Shim 1642364839aSJoonyoung Shim /* release file pointer to gem object. */ 1651c248b7dSInki Dae drm_gem_object_release(obj); 1661c248b7dSInki Dae 1671c248b7dSInki Dae kfree(exynos_gem_obj); 1682364839aSJoonyoung Shim } 1692364839aSJoonyoung Shim 170a4f19aaaSInki Dae unsigned long exynos_drm_gem_get_size(struct drm_device *dev, 171a4f19aaaSInki Dae unsigned int gem_handle, 172a4f19aaaSInki Dae struct drm_file *file_priv) 173a4f19aaaSInki Dae { 174a4f19aaaSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 175a4f19aaaSInki Dae struct drm_gem_object *obj; 176a4f19aaaSInki Dae 177a4f19aaaSInki Dae obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 178a4f19aaaSInki Dae if (!obj) { 179a4f19aaaSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 180a4f19aaaSInki Dae return 0; 181a4f19aaaSInki Dae } 182a4f19aaaSInki Dae 183a4f19aaaSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 184a4f19aaaSInki Dae 185a4f19aaaSInki Dae drm_gem_object_unreference_unlocked(obj); 186a4f19aaaSInki Dae 1872a8cb489SJoonyoung Shim return exynos_gem_obj->size; 188a4f19aaaSInki Dae } 189a4f19aaaSInki Dae 190b319dc6aSJoonyoung Shim static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, 1912364839aSJoonyoung Shim unsigned long size) 1922364839aSJoonyoung Shim { 1932364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1942364839aSJoonyoung Shim struct drm_gem_object *obj; 1952364839aSJoonyoung Shim int ret; 1962364839aSJoonyoung Shim 1972364839aSJoonyoung Shim exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 19838bb5253SSachin Kamat if (!exynos_gem_obj) 1995f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 2002364839aSJoonyoung Shim 2012b35892eSInki Dae exynos_gem_obj->size = size; 2022364839aSJoonyoung Shim obj = &exynos_gem_obj->base; 2032364839aSJoonyoung Shim 2042364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 2052364839aSJoonyoung Shim if (ret < 0) { 2062364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 2072364839aSJoonyoung Shim kfree(exynos_gem_obj); 2085f3f4266SJoonyoung Shim return ERR_PTR(ret); 2092364839aSJoonyoung Shim } 2102364839aSJoonyoung Shim 2112364839aSJoonyoung Shim DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 2122364839aSJoonyoung Shim 2132364839aSJoonyoung Shim return exynos_gem_obj; 2141c248b7dSInki Dae } 2151c248b7dSInki Dae 216f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 2172b35892eSInki Dae unsigned int flags, 218ee5e770eSJoonyoung Shim unsigned long size) 219f088d5a9SInki Dae { 2202364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2212b35892eSInki Dae int ret; 222f088d5a9SInki Dae 223c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 224c4130bcdSJoonyoung Shim DRM_ERROR("invalid flags.\n"); 225c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 226c4130bcdSJoonyoung Shim } 227c4130bcdSJoonyoung Shim 228dcf9af82SInki Dae if (!size) { 229dcf9af82SInki Dae DRM_ERROR("invalid size.\n"); 230dcf9af82SInki Dae return ERR_PTR(-EINVAL); 231dcf9af82SInki Dae } 232f088d5a9SInki Dae 233eb57da88SJoonyoung Shim size = roundup(size, PAGE_SIZE); 234dcf9af82SInki Dae 2352364839aSJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, size); 2362a8cb489SJoonyoung Shim if (IS_ERR(exynos_gem_obj)) 2372a8cb489SJoonyoung Shim return exynos_gem_obj; 2382b35892eSInki Dae 2392b35892eSInki Dae /* set memory type and cache attribute from user side. */ 2402b35892eSInki Dae exynos_gem_obj->flags = flags; 2412b35892eSInki Dae 2422a8cb489SJoonyoung Shim ret = exynos_drm_alloc_buf(exynos_gem_obj); 2432a8cb489SJoonyoung Shim if (ret < 0) { 244c58c1599SYoungJun Cho drm_gem_object_release(&exynos_gem_obj->base); 245c58c1599SYoungJun Cho kfree(exynos_gem_obj); 2462b35892eSInki Dae return ERR_PTR(ret); 247f088d5a9SInki Dae } 248f088d5a9SInki Dae 2492a8cb489SJoonyoung Shim return exynos_gem_obj; 2502a8cb489SJoonyoung Shim } 2512a8cb489SJoonyoung Shim 2521c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 2531c248b7dSInki Dae struct drm_file *file_priv) 2541c248b7dSInki Dae { 2551c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 256ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2572364839aSJoonyoung Shim int ret; 2581c248b7dSInki Dae 2592b35892eSInki Dae exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); 2601c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 2611c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 2621c248b7dSInki Dae 2632364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 2642364839aSJoonyoung Shim &args->handle); 2652364839aSJoonyoung Shim if (ret) { 2662364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 2672364839aSJoonyoung Shim return ret; 2682364839aSJoonyoung Shim } 2692364839aSJoonyoung Shim 2701c248b7dSInki Dae return 0; 2711c248b7dSInki Dae } 2721c248b7dSInki Dae 273d87342c1SInki Dae dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, 274f0b1bda7SInki Dae unsigned int gem_handle, 275d87342c1SInki Dae struct drm_file *filp) 276f0b1bda7SInki Dae { 277f0b1bda7SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 278f0b1bda7SInki Dae struct drm_gem_object *obj; 279f0b1bda7SInki Dae 280d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 281f0b1bda7SInki Dae if (!obj) { 282f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 283f0b1bda7SInki Dae return ERR_PTR(-EINVAL); 284f0b1bda7SInki Dae } 285f0b1bda7SInki Dae 286f0b1bda7SInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 287f0b1bda7SInki Dae 2882a8cb489SJoonyoung Shim return &exynos_gem_obj->dma_addr; 289f0b1bda7SInki Dae } 290f0b1bda7SInki Dae 291f0b1bda7SInki Dae void exynos_drm_gem_put_dma_addr(struct drm_device *dev, 292f0b1bda7SInki Dae unsigned int gem_handle, 293d87342c1SInki Dae struct drm_file *filp) 294f0b1bda7SInki Dae { 295f0b1bda7SInki Dae struct drm_gem_object *obj; 296f0b1bda7SInki Dae 297d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 298f0b1bda7SInki Dae if (!obj) { 299f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 300f0b1bda7SInki Dae return; 301f0b1bda7SInki Dae } 302f0b1bda7SInki Dae 303f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 304f0b1bda7SInki Dae 305f0b1bda7SInki Dae /* 306f0b1bda7SInki Dae * decrease obj->refcount one more time because we has already 307f0b1bda7SInki Dae * increased it at exynos_drm_gem_get_dma_addr(). 308f0b1bda7SInki Dae */ 309f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 310f0b1bda7SInki Dae } 311f0b1bda7SInki Dae 312832316c7SInki Dae int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, 3131c248b7dSInki Dae struct vm_area_struct *vma) 3141c248b7dSInki Dae { 315832316c7SInki Dae struct drm_device *drm_dev = exynos_gem_obj->base.dev; 3160519f9a1SInki Dae unsigned long vm_size; 3175b07c660SInki Dae int ret; 3181c248b7dSInki Dae 319832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 320832316c7SInki Dae vma->vm_pgoff = 0; 3211c248b7dSInki Dae 3220519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 3232b35892eSInki Dae 3241c248b7dSInki Dae /* check if user-requested size is valid. */ 3252a8cb489SJoonyoung Shim if (vm_size > exynos_gem_obj->size) 3261c248b7dSInki Dae return -EINVAL; 3271c248b7dSInki Dae 3282a8cb489SJoonyoung Shim ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, 3292a8cb489SJoonyoung Shim exynos_gem_obj->dma_addr, exynos_gem_obj->size, 3302a8cb489SJoonyoung Shim &exynos_gem_obj->dma_attrs); 3315b07c660SInki Dae if (ret < 0) { 3325b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 3335b07c660SInki Dae return ret; 3345b07c660SInki Dae } 3355b07c660SInki Dae 3361c248b7dSInki Dae return 0; 3371c248b7dSInki Dae } 3381c248b7dSInki Dae 33940cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 34040cd7e0cSInki Dae struct drm_file *file_priv) 34140cd7e0cSInki Dae { struct exynos_drm_gem_obj *exynos_gem_obj; 34240cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 34340cd7e0cSInki Dae struct drm_gem_object *obj; 34440cd7e0cSInki Dae 34540cd7e0cSInki Dae mutex_lock(&dev->struct_mutex); 34640cd7e0cSInki Dae 34740cd7e0cSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 34840cd7e0cSInki Dae if (!obj) { 34940cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 35040cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 35140cd7e0cSInki Dae return -EINVAL; 35240cd7e0cSInki Dae } 35340cd7e0cSInki Dae 35440cd7e0cSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 35540cd7e0cSInki Dae 35640cd7e0cSInki Dae args->flags = exynos_gem_obj->flags; 35740cd7e0cSInki Dae args->size = exynos_gem_obj->size; 35840cd7e0cSInki Dae 35940cd7e0cSInki Dae drm_gem_object_unreference(obj); 36040cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 36140cd7e0cSInki Dae 36240cd7e0cSInki Dae return 0; 36340cd7e0cSInki Dae } 36440cd7e0cSInki Dae 3652a3098ffSInki Dae int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, 3662a3098ffSInki Dae struct sg_table *sgt, 3672a3098ffSInki Dae enum dma_data_direction dir) 3682a3098ffSInki Dae { 3692a3098ffSInki Dae int nents; 3702a3098ffSInki Dae 3712a3098ffSInki Dae mutex_lock(&drm_dev->struct_mutex); 3722a3098ffSInki Dae 3732a3098ffSInki Dae nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3742a3098ffSInki Dae if (!nents) { 3752a3098ffSInki Dae DRM_ERROR("failed to map sgl with dma.\n"); 3762a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3772a3098ffSInki Dae return nents; 3782a3098ffSInki Dae } 3792a3098ffSInki Dae 3802a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3812a3098ffSInki Dae return 0; 3822a3098ffSInki Dae } 3832a3098ffSInki Dae 3842a3098ffSInki Dae void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, 3852a3098ffSInki Dae struct sg_table *sgt, 3862a3098ffSInki Dae enum dma_data_direction dir) 3872a3098ffSInki Dae { 3882a3098ffSInki Dae dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3892a3098ffSInki Dae } 3902a3098ffSInki Dae 391ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 3921c248b7dSInki Dae { 3932364839aSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); 3941c248b7dSInki Dae } 3951c248b7dSInki Dae 3961c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 397ee5e770eSJoonyoung Shim struct drm_device *dev, 398ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 3991c248b7dSInki Dae { 4001c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 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 412122beea8SRahul Sharma if (is_drm_iommu_supported(dev)) { 4133fec4532SVikas Sajjan exynos_gem_obj = exynos_drm_gem_create(dev, 4143fec4532SVikas Sajjan EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC, 4153fec4532SVikas Sajjan args->size); 416122beea8SRahul Sharma } else { 417122beea8SRahul Sharma exynos_gem_obj = exynos_drm_gem_create(dev, 418122beea8SRahul Sharma EXYNOS_BO_CONTIG | EXYNOS_BO_WC, 419122beea8SRahul Sharma args->size); 4203fec4532SVikas Sajjan } 4213fec4532SVikas Sajjan 422122beea8SRahul Sharma if (IS_ERR(exynos_gem_obj)) { 423122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 4241c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 425122beea8SRahul Sharma } 4261c248b7dSInki Dae 4272364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 4282364839aSJoonyoung Shim &args->handle); 4292364839aSJoonyoung Shim if (ret) { 4302364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 4312364839aSJoonyoung Shim return ret; 4322364839aSJoonyoung Shim } 4332364839aSJoonyoung Shim 4341c248b7dSInki Dae return 0; 4351c248b7dSInki Dae } 4361c248b7dSInki Dae 4371c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 438ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 439ee5e770eSJoonyoung Shim uint64_t *offset) 4401c248b7dSInki Dae { 4411c248b7dSInki Dae struct drm_gem_object *obj; 4422d91cf17SJoonyoung Shim int ret = 0; 4431c248b7dSInki Dae 4441c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 4451c248b7dSInki Dae 4461c248b7dSInki Dae /* 4471c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 4481c248b7dSInki Dae * - this callback would be called by user application 4491c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 4501c248b7dSInki Dae */ 4511c248b7dSInki Dae 4521c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 4531c248b7dSInki Dae if (!obj) { 4541c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 4552d91cf17SJoonyoung Shim ret = -EINVAL; 4562d91cf17SJoonyoung Shim goto unlock; 4571c248b7dSInki Dae } 4581c248b7dSInki Dae 4596037bafaSLaurent Pinchart ret = drm_gem_create_mmap_offset(obj); 4602d91cf17SJoonyoung Shim if (ret) 4612d91cf17SJoonyoung Shim goto out; 4621c248b7dSInki Dae 4630de23977SDavid Herrmann *offset = drm_vma_node_offset_addr(&obj->vma_node); 4641c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 4651c248b7dSInki Dae 4662d91cf17SJoonyoung Shim out: 4672d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 4682d91cf17SJoonyoung Shim unlock: 4691c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 4702d91cf17SJoonyoung Shim return ret; 4711c248b7dSInki Dae } 4721c248b7dSInki Dae 4731c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 4741c248b7dSInki Dae { 4751c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 4760e9a2ee3SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 4770e9a2ee3SJoonyoung Shim unsigned long pfn; 4781c248b7dSInki Dae pgoff_t page_offset; 4791c248b7dSInki Dae int ret; 4801c248b7dSInki Dae 4811c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 4821c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 4831c248b7dSInki Dae 4842a8cb489SJoonyoung Shim if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) { 4850e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 4860e9a2ee3SJoonyoung Shim ret = -EINVAL; 4870e9a2ee3SJoonyoung Shim goto out; 4880e9a2ee3SJoonyoung Shim } 4891c248b7dSInki Dae 4902a8cb489SJoonyoung Shim pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]); 4910e9a2ee3SJoonyoung Shim ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 4920e9a2ee3SJoonyoung Shim 4930e9a2ee3SJoonyoung Shim out: 49423597e26SJoonyoung Shim switch (ret) { 49523597e26SJoonyoung Shim case 0: 49623597e26SJoonyoung Shim case -ERESTARTSYS: 49723597e26SJoonyoung Shim case -EINTR: 49823597e26SJoonyoung Shim return VM_FAULT_NOPAGE; 49923597e26SJoonyoung Shim case -ENOMEM: 50023597e26SJoonyoung Shim return VM_FAULT_OOM; 50123597e26SJoonyoung Shim default: 50223597e26SJoonyoung Shim return VM_FAULT_SIGBUS; 50323597e26SJoonyoung Shim } 5041c248b7dSInki Dae } 5051c248b7dSInki Dae 5061c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 5071c248b7dSInki Dae { 508c01d73faSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 509c01d73faSInki Dae struct drm_gem_object *obj; 5101c248b7dSInki Dae int ret; 5111c248b7dSInki Dae 5121c248b7dSInki Dae /* set vm_area_struct. */ 5131c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 5141c248b7dSInki Dae if (ret < 0) { 5151c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 5161c248b7dSInki Dae return ret; 5171c248b7dSInki Dae } 5181c248b7dSInki Dae 519c01d73faSInki Dae obj = vma->vm_private_data; 520c01d73faSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 521c01d73faSInki Dae 522211b8878SJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); 523211b8878SJoonyoung Shim 524211b8878SJoonyoung Shim /* non-cachable as default. */ 525211b8878SJoonyoung Shim if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) 526211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 527211b8878SJoonyoung Shim else if (exynos_gem_obj->flags & EXYNOS_BO_WC) 528211b8878SJoonyoung Shim vma->vm_page_prot = 529211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 530211b8878SJoonyoung Shim else 531211b8878SJoonyoung Shim vma->vm_page_prot = 532211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 533c01d73faSInki Dae 534832316c7SInki Dae ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); 535832316c7SInki Dae if (ret) 536832316c7SInki Dae goto err_close_vm; 537832316c7SInki Dae 538832316c7SInki Dae return ret; 539832316c7SInki Dae 540832316c7SInki Dae err_close_vm: 541832316c7SInki Dae drm_gem_vm_close(vma); 542832316c7SInki Dae drm_gem_free_mmap_offset(obj); 543832316c7SInki Dae 5441c248b7dSInki Dae return ret; 5451c248b7dSInki Dae } 54601ed50ddSJoonyoung Shim 54701ed50ddSJoonyoung Shim /* low-level interface prime helpers */ 54801ed50ddSJoonyoung Shim struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 54901ed50ddSJoonyoung Shim { 55001ed50ddSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 55101ed50ddSJoonyoung Shim int npages; 55201ed50ddSJoonyoung Shim 5532a8cb489SJoonyoung Shim npages = exynos_gem_obj->size >> PAGE_SHIFT; 55401ed50ddSJoonyoung Shim 5552a8cb489SJoonyoung Shim return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages); 55601ed50ddSJoonyoung Shim } 55701ed50ddSJoonyoung Shim 55801ed50ddSJoonyoung Shim struct drm_gem_object * 55901ed50ddSJoonyoung Shim exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, 56001ed50ddSJoonyoung Shim struct dma_buf_attachment *attach, 56101ed50ddSJoonyoung Shim struct sg_table *sgt) 56201ed50ddSJoonyoung Shim { 56301ed50ddSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 56401ed50ddSJoonyoung Shim int npages; 56501ed50ddSJoonyoung Shim int ret; 56601ed50ddSJoonyoung Shim 5672a8cb489SJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); 56801ed50ddSJoonyoung Shim if (IS_ERR(exynos_gem_obj)) { 56901ed50ddSJoonyoung Shim ret = PTR_ERR(exynos_gem_obj); 57050002d4cSInki Dae return ERR_PTR(ret); 57101ed50ddSJoonyoung Shim } 57201ed50ddSJoonyoung Shim 5732a8cb489SJoonyoung Shim exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); 5742a8cb489SJoonyoung Shim 5752a8cb489SJoonyoung Shim npages = exynos_gem_obj->size >> PAGE_SHIFT; 5762a8cb489SJoonyoung Shim exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); 5772a8cb489SJoonyoung Shim if (!exynos_gem_obj->pages) { 5782a8cb489SJoonyoung Shim ret = -ENOMEM; 5792a8cb489SJoonyoung Shim goto err; 5802a8cb489SJoonyoung Shim } 5812a8cb489SJoonyoung Shim 5822a8cb489SJoonyoung Shim ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL, 5832a8cb489SJoonyoung Shim npages); 5842a8cb489SJoonyoung Shim if (ret < 0) 5852a8cb489SJoonyoung Shim goto err_free_large; 5862a8cb489SJoonyoung Shim 5877c93537aSJoonyoung Shim exynos_gem_obj->sgt = sgt; 5887c93537aSJoonyoung Shim 58901ed50ddSJoonyoung Shim if (sgt->nents == 1) { 59001ed50ddSJoonyoung Shim /* always physically continuous memory if sgt->nents is 1. */ 59101ed50ddSJoonyoung Shim exynos_gem_obj->flags |= EXYNOS_BO_CONTIG; 59201ed50ddSJoonyoung Shim } else { 59301ed50ddSJoonyoung Shim /* 59401ed50ddSJoonyoung Shim * this case could be CONTIG or NONCONTIG type but for now 59501ed50ddSJoonyoung Shim * sets NONCONTIG. 59601ed50ddSJoonyoung Shim * TODO. we have to find a way that exporter can notify 59701ed50ddSJoonyoung Shim * the type of its own buffer to importer. 59801ed50ddSJoonyoung Shim */ 59901ed50ddSJoonyoung Shim exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG; 60001ed50ddSJoonyoung Shim } 60101ed50ddSJoonyoung Shim 60201ed50ddSJoonyoung Shim return &exynos_gem_obj->base; 60301ed50ddSJoonyoung Shim 60401ed50ddSJoonyoung Shim err_free_large: 6052a8cb489SJoonyoung Shim drm_free_large(exynos_gem_obj->pages); 60601ed50ddSJoonyoung Shim err: 6072a8cb489SJoonyoung Shim drm_gem_object_release(&exynos_gem_obj->base); 6082a8cb489SJoonyoung Shim kfree(exynos_gem_obj); 60901ed50ddSJoonyoung Shim return ERR_PTR(ret); 61001ed50ddSJoonyoung Shim } 61101ed50ddSJoonyoung Shim 61201ed50ddSJoonyoung Shim void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj) 61301ed50ddSJoonyoung Shim { 61401ed50ddSJoonyoung Shim return NULL; 61501ed50ddSJoonyoung Shim } 61601ed50ddSJoonyoung Shim 61701ed50ddSJoonyoung Shim void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) 61801ed50ddSJoonyoung Shim { 61901ed50ddSJoonyoung Shim /* Nothing to do */ 62001ed50ddSJoonyoung Shim } 621