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 drm_gem_free_mmap_offset(obj); 1562364839aSJoonyoung Shim 1572364839aSJoonyoung Shim /* release file pointer to gem object. */ 1581c248b7dSInki Dae drm_gem_object_release(obj); 1591c248b7dSInki Dae 1601c248b7dSInki Dae kfree(exynos_gem_obj); 1612364839aSJoonyoung Shim } 1622364839aSJoonyoung Shim 163a4f19aaaSInki Dae unsigned long exynos_drm_gem_get_size(struct drm_device *dev, 164a4f19aaaSInki Dae unsigned int gem_handle, 165a4f19aaaSInki Dae struct drm_file *file_priv) 166a4f19aaaSInki Dae { 167a4f19aaaSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 168a4f19aaaSInki Dae struct drm_gem_object *obj; 169a4f19aaaSInki Dae 170a4f19aaaSInki Dae obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 171a4f19aaaSInki Dae if (!obj) { 172a4f19aaaSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 173a4f19aaaSInki Dae return 0; 174a4f19aaaSInki Dae } 175a4f19aaaSInki Dae 176a4f19aaaSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 177a4f19aaaSInki Dae 178a4f19aaaSInki Dae drm_gem_object_unreference_unlocked(obj); 179a4f19aaaSInki Dae 1802a8cb489SJoonyoung Shim return exynos_gem_obj->size; 181a4f19aaaSInki Dae } 182a4f19aaaSInki Dae 183b319dc6aSJoonyoung Shim static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev, 1842364839aSJoonyoung Shim unsigned long size) 1852364839aSJoonyoung Shim { 1862364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1872364839aSJoonyoung Shim struct drm_gem_object *obj; 1882364839aSJoonyoung Shim int ret; 1892364839aSJoonyoung Shim 1902364839aSJoonyoung Shim exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 19138bb5253SSachin Kamat if (!exynos_gem_obj) 1925f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 1932364839aSJoonyoung Shim 1942b35892eSInki Dae exynos_gem_obj->size = size; 1952364839aSJoonyoung Shim obj = &exynos_gem_obj->base; 1962364839aSJoonyoung Shim 1972364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 1982364839aSJoonyoung Shim if (ret < 0) { 1992364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 2002364839aSJoonyoung Shim kfree(exynos_gem_obj); 2015f3f4266SJoonyoung Shim return ERR_PTR(ret); 2022364839aSJoonyoung Shim } 2032364839aSJoonyoung Shim 2042364839aSJoonyoung Shim DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 2052364839aSJoonyoung Shim 2062364839aSJoonyoung Shim return exynos_gem_obj; 2071c248b7dSInki Dae } 2081c248b7dSInki Dae 209f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 2102b35892eSInki Dae unsigned int flags, 211ee5e770eSJoonyoung Shim unsigned long size) 212f088d5a9SInki Dae { 2132364839aSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2142b35892eSInki Dae int ret; 215f088d5a9SInki Dae 216c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 217c4130bcdSJoonyoung Shim DRM_ERROR("invalid flags.\n"); 218c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 219c4130bcdSJoonyoung Shim } 220c4130bcdSJoonyoung Shim 221dcf9af82SInki Dae if (!size) { 222dcf9af82SInki Dae DRM_ERROR("invalid size.\n"); 223dcf9af82SInki Dae return ERR_PTR(-EINVAL); 224dcf9af82SInki Dae } 225f088d5a9SInki Dae 226eb57da88SJoonyoung Shim size = roundup(size, PAGE_SIZE); 227dcf9af82SInki Dae 2282364839aSJoonyoung Shim exynos_gem_obj = exynos_drm_gem_init(dev, size); 2292a8cb489SJoonyoung Shim if (IS_ERR(exynos_gem_obj)) 2302a8cb489SJoonyoung Shim return exynos_gem_obj; 2312b35892eSInki Dae 2322b35892eSInki Dae /* set memory type and cache attribute from user side. */ 2332b35892eSInki Dae exynos_gem_obj->flags = flags; 2342b35892eSInki Dae 2352a8cb489SJoonyoung Shim ret = exynos_drm_alloc_buf(exynos_gem_obj); 2362a8cb489SJoonyoung Shim if (ret < 0) { 237c58c1599SYoungJun Cho drm_gem_object_release(&exynos_gem_obj->base); 238c58c1599SYoungJun Cho kfree(exynos_gem_obj); 2392b35892eSInki Dae return ERR_PTR(ret); 240f088d5a9SInki Dae } 241f088d5a9SInki Dae 2422a8cb489SJoonyoung Shim return exynos_gem_obj; 2432a8cb489SJoonyoung Shim } 2442a8cb489SJoonyoung Shim 2451c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 2461c248b7dSInki Dae struct drm_file *file_priv) 2471c248b7dSInki Dae { 2481c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 249ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 2502364839aSJoonyoung Shim int ret; 2511c248b7dSInki Dae 2522b35892eSInki Dae exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); 2531c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 2541c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 2551c248b7dSInki Dae 2562364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 2572364839aSJoonyoung Shim &args->handle); 2582364839aSJoonyoung Shim if (ret) { 2592364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 2602364839aSJoonyoung Shim return ret; 2612364839aSJoonyoung Shim } 2622364839aSJoonyoung Shim 2631c248b7dSInki Dae return 0; 2641c248b7dSInki Dae } 2651c248b7dSInki Dae 266d87342c1SInki Dae dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, 267f0b1bda7SInki Dae unsigned int gem_handle, 268d87342c1SInki Dae struct drm_file *filp) 269f0b1bda7SInki Dae { 270f0b1bda7SInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 271f0b1bda7SInki Dae struct drm_gem_object *obj; 272f0b1bda7SInki Dae 273d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 274f0b1bda7SInki Dae if (!obj) { 275f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 276f0b1bda7SInki Dae return ERR_PTR(-EINVAL); 277f0b1bda7SInki Dae } 278f0b1bda7SInki Dae 279f0b1bda7SInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 280f0b1bda7SInki Dae 2812a8cb489SJoonyoung Shim return &exynos_gem_obj->dma_addr; 282f0b1bda7SInki Dae } 283f0b1bda7SInki Dae 284f0b1bda7SInki Dae void exynos_drm_gem_put_dma_addr(struct drm_device *dev, 285f0b1bda7SInki Dae unsigned int gem_handle, 286d87342c1SInki Dae struct drm_file *filp) 287f0b1bda7SInki Dae { 288f0b1bda7SInki Dae struct drm_gem_object *obj; 289f0b1bda7SInki Dae 290d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 291f0b1bda7SInki Dae if (!obj) { 292f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 293f0b1bda7SInki Dae return; 294f0b1bda7SInki Dae } 295f0b1bda7SInki Dae 296f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 297f0b1bda7SInki Dae 298f0b1bda7SInki Dae /* 299f0b1bda7SInki Dae * decrease obj->refcount one more time because we has already 300f0b1bda7SInki Dae * increased it at exynos_drm_gem_get_dma_addr(). 301f0b1bda7SInki Dae */ 302f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 303f0b1bda7SInki Dae } 304f0b1bda7SInki Dae 305832316c7SInki Dae int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj, 3061c248b7dSInki Dae struct vm_area_struct *vma) 3071c248b7dSInki Dae { 308832316c7SInki Dae struct drm_device *drm_dev = exynos_gem_obj->base.dev; 3090519f9a1SInki Dae unsigned long vm_size; 3105b07c660SInki Dae int ret; 3111c248b7dSInki Dae 312832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 313832316c7SInki Dae vma->vm_pgoff = 0; 3141c248b7dSInki Dae 3150519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 3162b35892eSInki Dae 3171c248b7dSInki Dae /* check if user-requested size is valid. */ 3182a8cb489SJoonyoung Shim if (vm_size > exynos_gem_obj->size) 3191c248b7dSInki Dae return -EINVAL; 3201c248b7dSInki Dae 3212a8cb489SJoonyoung Shim ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages, 3222a8cb489SJoonyoung Shim exynos_gem_obj->dma_addr, exynos_gem_obj->size, 3232a8cb489SJoonyoung Shim &exynos_gem_obj->dma_attrs); 3245b07c660SInki Dae if (ret < 0) { 3255b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 3265b07c660SInki Dae return ret; 3275b07c660SInki Dae } 3285b07c660SInki Dae 3291c248b7dSInki Dae return 0; 3301c248b7dSInki Dae } 3311c248b7dSInki Dae 33240cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 33340cd7e0cSInki Dae struct drm_file *file_priv) 33440cd7e0cSInki Dae { struct exynos_drm_gem_obj *exynos_gem_obj; 33540cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 33640cd7e0cSInki Dae struct drm_gem_object *obj; 33740cd7e0cSInki Dae 33840cd7e0cSInki Dae mutex_lock(&dev->struct_mutex); 33940cd7e0cSInki Dae 34040cd7e0cSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 34140cd7e0cSInki Dae if (!obj) { 34240cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 34340cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 34440cd7e0cSInki Dae return -EINVAL; 34540cd7e0cSInki Dae } 34640cd7e0cSInki Dae 34740cd7e0cSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 34840cd7e0cSInki Dae 34940cd7e0cSInki Dae args->flags = exynos_gem_obj->flags; 35040cd7e0cSInki Dae args->size = exynos_gem_obj->size; 35140cd7e0cSInki Dae 35240cd7e0cSInki Dae drm_gem_object_unreference(obj); 35340cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 35440cd7e0cSInki Dae 35540cd7e0cSInki Dae return 0; 35640cd7e0cSInki Dae } 35740cd7e0cSInki Dae 3582a3098ffSInki Dae int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, 3592a3098ffSInki Dae struct sg_table *sgt, 3602a3098ffSInki Dae enum dma_data_direction dir) 3612a3098ffSInki Dae { 3622a3098ffSInki Dae int nents; 3632a3098ffSInki Dae 3642a3098ffSInki Dae mutex_lock(&drm_dev->struct_mutex); 3652a3098ffSInki Dae 3662a3098ffSInki Dae nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3672a3098ffSInki Dae if (!nents) { 3682a3098ffSInki Dae DRM_ERROR("failed to map sgl with dma.\n"); 3692a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3702a3098ffSInki Dae return nents; 3712a3098ffSInki Dae } 3722a3098ffSInki Dae 3732a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3742a3098ffSInki Dae return 0; 3752a3098ffSInki Dae } 3762a3098ffSInki Dae 3772a3098ffSInki Dae void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, 3782a3098ffSInki Dae struct sg_table *sgt, 3792a3098ffSInki Dae enum dma_data_direction dir) 3802a3098ffSInki Dae { 3812a3098ffSInki Dae dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir); 3822a3098ffSInki Dae } 3832a3098ffSInki Dae 384ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 3851c248b7dSInki Dae { 3862364839aSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem_obj(obj)); 3871c248b7dSInki Dae } 3881c248b7dSInki Dae 3891c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 390ee5e770eSJoonyoung Shim struct drm_device *dev, 391ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 3921c248b7dSInki Dae { 3931c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 394333e8e58SJoonyoung Shim unsigned int flags; 3952364839aSJoonyoung Shim int ret; 3961c248b7dSInki Dae 3971c248b7dSInki Dae /* 398c6b78bc8SMasanari Iida * allocate memory to be used for framebuffer. 3991c248b7dSInki Dae * - this callback would be called by user application 4001c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 4011c248b7dSInki Dae */ 4021c248b7dSInki Dae 4033fd6b694SCooper Yuan args->pitch = args->width * ((args->bpp + 7) / 8); 4047da5907cSInki Dae args->size = args->pitch * args->height; 4051c248b7dSInki Dae 406333e8e58SJoonyoung Shim if (is_drm_iommu_supported(dev)) 407333e8e58SJoonyoung Shim flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC; 408333e8e58SJoonyoung Shim else 409333e8e58SJoonyoung Shim flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; 4103fec4532SVikas Sajjan 411333e8e58SJoonyoung Shim exynos_gem_obj = exynos_drm_gem_create(dev, flags, args->size); 412122beea8SRahul Sharma if (IS_ERR(exynos_gem_obj)) { 413122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 4141c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 415122beea8SRahul Sharma } 4161c248b7dSInki Dae 4172364839aSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv, 4182364839aSJoonyoung Shim &args->handle); 4192364839aSJoonyoung Shim if (ret) { 4202364839aSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem_obj); 4212364839aSJoonyoung Shim return ret; 4222364839aSJoonyoung Shim } 4232364839aSJoonyoung Shim 4241c248b7dSInki Dae return 0; 4251c248b7dSInki Dae } 4261c248b7dSInki Dae 4271c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 428ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 429ee5e770eSJoonyoung Shim uint64_t *offset) 4301c248b7dSInki Dae { 4311c248b7dSInki Dae struct drm_gem_object *obj; 4322d91cf17SJoonyoung Shim int ret = 0; 4331c248b7dSInki Dae 4341c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 4351c248b7dSInki Dae 4361c248b7dSInki Dae /* 4371c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 4381c248b7dSInki Dae * - this callback would be called by user application 4391c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 4401c248b7dSInki Dae */ 4411c248b7dSInki Dae 4421c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 4431c248b7dSInki Dae if (!obj) { 4441c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 4452d91cf17SJoonyoung Shim ret = -EINVAL; 4462d91cf17SJoonyoung Shim goto unlock; 4471c248b7dSInki Dae } 4481c248b7dSInki Dae 4496037bafaSLaurent Pinchart ret = drm_gem_create_mmap_offset(obj); 4502d91cf17SJoonyoung Shim if (ret) 4512d91cf17SJoonyoung Shim goto out; 4521c248b7dSInki Dae 4530de23977SDavid Herrmann *offset = drm_vma_node_offset_addr(&obj->vma_node); 4541c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 4551c248b7dSInki Dae 4562d91cf17SJoonyoung Shim out: 4572d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 4582d91cf17SJoonyoung Shim unlock: 4591c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 4602d91cf17SJoonyoung Shim return ret; 4611c248b7dSInki Dae } 4621c248b7dSInki Dae 4631c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 4641c248b7dSInki Dae { 4651c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 4660e9a2ee3SJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 4670e9a2ee3SJoonyoung Shim unsigned long pfn; 4681c248b7dSInki Dae pgoff_t page_offset; 4691c248b7dSInki Dae int ret; 4701c248b7dSInki Dae 4711c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 4721c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 4731c248b7dSInki Dae 4742a8cb489SJoonyoung Shim if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) { 4750e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 4760e9a2ee3SJoonyoung Shim ret = -EINVAL; 4770e9a2ee3SJoonyoung Shim goto out; 4780e9a2ee3SJoonyoung Shim } 4791c248b7dSInki Dae 4802a8cb489SJoonyoung Shim pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]); 4810e9a2ee3SJoonyoung Shim ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 4820e9a2ee3SJoonyoung Shim 4830e9a2ee3SJoonyoung Shim out: 48423597e26SJoonyoung Shim switch (ret) { 48523597e26SJoonyoung Shim case 0: 48623597e26SJoonyoung Shim case -ERESTARTSYS: 48723597e26SJoonyoung Shim case -EINTR: 48823597e26SJoonyoung Shim return VM_FAULT_NOPAGE; 48923597e26SJoonyoung Shim case -ENOMEM: 49023597e26SJoonyoung Shim return VM_FAULT_OOM; 49123597e26SJoonyoung Shim default: 49223597e26SJoonyoung Shim return VM_FAULT_SIGBUS; 49323597e26SJoonyoung Shim } 4941c248b7dSInki Dae } 4951c248b7dSInki Dae 4961c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 4971c248b7dSInki Dae { 498c01d73faSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 499c01d73faSInki Dae struct drm_gem_object *obj; 5001c248b7dSInki Dae int ret; 5011c248b7dSInki Dae 5021c248b7dSInki Dae /* set vm_area_struct. */ 5031c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 5041c248b7dSInki Dae if (ret < 0) { 5051c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 5061c248b7dSInki Dae return ret; 5071c248b7dSInki Dae } 5081c248b7dSInki Dae 509c01d73faSInki Dae obj = vma->vm_private_data; 510c01d73faSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 511c01d73faSInki Dae 512211b8878SJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags); 513211b8878SJoonyoung Shim 514211b8878SJoonyoung Shim /* non-cachable as default. */ 515211b8878SJoonyoung Shim if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE) 516211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 517211b8878SJoonyoung Shim else if (exynos_gem_obj->flags & EXYNOS_BO_WC) 518211b8878SJoonyoung Shim vma->vm_page_prot = 519211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 520211b8878SJoonyoung Shim else 521211b8878SJoonyoung Shim vma->vm_page_prot = 522211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 523c01d73faSInki Dae 524832316c7SInki Dae ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma); 525832316c7SInki Dae if (ret) 526832316c7SInki Dae goto err_close_vm; 527832316c7SInki Dae 528832316c7SInki Dae return ret; 529832316c7SInki Dae 530832316c7SInki Dae err_close_vm: 531832316c7SInki Dae drm_gem_vm_close(vma); 532832316c7SInki Dae drm_gem_free_mmap_offset(obj); 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