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> 1701c8f1c4SDan Williams #include <linux/pfn_t.h> 181c248b7dSInki Dae #include <drm/exynos_drm.h> 191c248b7dSInki Dae 201c248b7dSInki Dae #include "exynos_drm_drv.h" 211c248b7dSInki Dae #include "exynos_drm_gem.h" 223fec4532SVikas Sajjan #include "exynos_drm_iommu.h" 231c248b7dSInki Dae 24813fd67bSJoonyoung Shim static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem) 252a8cb489SJoonyoung Shim { 26813fd67bSJoonyoung Shim struct drm_device *dev = exynos_gem->base.dev; 2700085f1eSKrzysztof Kozlowski unsigned long attr; 282a8cb489SJoonyoung Shim unsigned int nr_pages; 29df547bf7SMarek Szyprowski struct sg_table sgt; 30df547bf7SMarek Szyprowski int ret = -ENOMEM; 312a8cb489SJoonyoung Shim 32813fd67bSJoonyoung Shim if (exynos_gem->dma_addr) { 332a8cb489SJoonyoung Shim DRM_DEBUG_KMS("already allocated.\n"); 342a8cb489SJoonyoung Shim return 0; 352a8cb489SJoonyoung Shim } 362a8cb489SJoonyoung Shim 3700085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs = 0; 382a8cb489SJoonyoung Shim 392a8cb489SJoonyoung Shim /* 402a8cb489SJoonyoung Shim * if EXYNOS_BO_CONTIG, fully physically contiguous memory 412a8cb489SJoonyoung Shim * region will be allocated else physically contiguous 422a8cb489SJoonyoung Shim * as possible. 432a8cb489SJoonyoung Shim */ 44813fd67bSJoonyoung Shim if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG)) 4500085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS; 462a8cb489SJoonyoung Shim 472a8cb489SJoonyoung Shim /* 482a8cb489SJoonyoung Shim * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping 492a8cb489SJoonyoung Shim * else cachable mapping. 502a8cb489SJoonyoung Shim */ 51813fd67bSJoonyoung Shim if (exynos_gem->flags & EXYNOS_BO_WC || 52813fd67bSJoonyoung Shim !(exynos_gem->flags & EXYNOS_BO_CACHABLE)) 532a8cb489SJoonyoung Shim attr = DMA_ATTR_WRITE_COMBINE; 542a8cb489SJoonyoung Shim else 552a8cb489SJoonyoung Shim attr = DMA_ATTR_NON_CONSISTENT; 562a8cb489SJoonyoung Shim 5700085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs |= attr; 5800085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; 592a8cb489SJoonyoung Shim 60813fd67bSJoonyoung Shim nr_pages = exynos_gem->size >> PAGE_SHIFT; 612a8cb489SJoonyoung Shim 622098105eSMichal Hocko exynos_gem->pages = kvmalloc_array(nr_pages, sizeof(struct page *), 632098105eSMichal Hocko GFP_KERNEL | __GFP_ZERO); 64813fd67bSJoonyoung Shim if (!exynos_gem->pages) { 652a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate pages.\n"); 662a8cb489SJoonyoung Shim return -ENOMEM; 672a8cb489SJoonyoung Shim } 682a8cb489SJoonyoung Shim 69f43c3596SMarek Szyprowski exynos_gem->cookie = dma_alloc_attrs(to_dma_dev(dev), exynos_gem->size, 70813fd67bSJoonyoung Shim &exynos_gem->dma_addr, GFP_KERNEL, 7100085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs); 72813fd67bSJoonyoung Shim if (!exynos_gem->cookie) { 732a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate buffer.\n"); 74df547bf7SMarek Szyprowski goto err_free; 752a8cb489SJoonyoung Shim } 762a8cb489SJoonyoung Shim 77f43c3596SMarek Szyprowski ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt, exynos_gem->cookie, 78df547bf7SMarek Szyprowski exynos_gem->dma_addr, exynos_gem->size, 7900085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs); 80df547bf7SMarek Szyprowski if (ret < 0) { 81df547bf7SMarek Szyprowski DRM_ERROR("failed to get sgtable.\n"); 82df547bf7SMarek Szyprowski goto err_dma_free; 83df547bf7SMarek Szyprowski } 84333e8e58SJoonyoung Shim 85df547bf7SMarek Szyprowski if (drm_prime_sg_to_page_addr_arrays(&sgt, exynos_gem->pages, NULL, 86df547bf7SMarek Szyprowski nr_pages)) { 87df547bf7SMarek Szyprowski DRM_ERROR("invalid sgtable.\n"); 88df547bf7SMarek Szyprowski ret = -EINVAL; 89df547bf7SMarek Szyprowski goto err_sgt_free; 902a8cb489SJoonyoung Shim } 91df547bf7SMarek Szyprowski 92df547bf7SMarek Szyprowski sg_free_table(&sgt); 932a8cb489SJoonyoung Shim 942a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 95813fd67bSJoonyoung Shim (unsigned long)exynos_gem->dma_addr, exynos_gem->size); 962a8cb489SJoonyoung Shim 972a8cb489SJoonyoung Shim return 0; 98df547bf7SMarek Szyprowski 99df547bf7SMarek Szyprowski err_sgt_free: 100df547bf7SMarek Szyprowski sg_free_table(&sgt); 101df547bf7SMarek Szyprowski err_dma_free: 102f43c3596SMarek Szyprowski dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, 10300085f1eSKrzysztof Kozlowski exynos_gem->dma_addr, exynos_gem->dma_attrs); 104df547bf7SMarek Szyprowski err_free: 1052098105eSMichal Hocko kvfree(exynos_gem->pages); 106df547bf7SMarek Szyprowski 107df547bf7SMarek Szyprowski return ret; 1082a8cb489SJoonyoung Shim } 1092a8cb489SJoonyoung Shim 110813fd67bSJoonyoung Shim static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) 1112a8cb489SJoonyoung Shim { 112813fd67bSJoonyoung Shim struct drm_device *dev = exynos_gem->base.dev; 1132a8cb489SJoonyoung Shim 114813fd67bSJoonyoung Shim if (!exynos_gem->dma_addr) { 1152a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr is invalid.\n"); 1162a8cb489SJoonyoung Shim return; 1172a8cb489SJoonyoung Shim } 1182a8cb489SJoonyoung Shim 1192a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 120813fd67bSJoonyoung Shim (unsigned long)exynos_gem->dma_addr, exynos_gem->size); 1212a8cb489SJoonyoung Shim 122f43c3596SMarek Szyprowski dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, 123813fd67bSJoonyoung Shim (dma_addr_t)exynos_gem->dma_addr, 12400085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs); 125333e8e58SJoonyoung Shim 1262098105eSMichal Hocko kvfree(exynos_gem->pages); 1272a8cb489SJoonyoung Shim } 1282a8cb489SJoonyoung Shim 1292364839aSJoonyoung Shim static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 1302364839aSJoonyoung Shim struct drm_file *file_priv, 1312364839aSJoonyoung Shim unsigned int *handle) 1321c248b7dSInki Dae { 1331c248b7dSInki Dae int ret; 1341c248b7dSInki Dae 1351c248b7dSInki Dae /* 1361c248b7dSInki Dae * allocate a id of idr table where the obj is registered 1371c248b7dSInki Dae * and handle has the id what user can see. 1381c248b7dSInki Dae */ 1391c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 1401c248b7dSInki Dae if (ret) 1412364839aSJoonyoung Shim return ret; 1421c248b7dSInki Dae 1431c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 1441c248b7dSInki Dae 1451c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 146af7d9101SThomas Zimmermann drm_gem_object_put_unlocked(obj); 1471c248b7dSInki Dae 1482364839aSJoonyoung Shim return 0; 1492364839aSJoonyoung Shim } 1501c248b7dSInki Dae 151813fd67bSJoonyoung Shim void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) 1522364839aSJoonyoung Shim { 153813fd67bSJoonyoung Shim struct drm_gem_object *obj = &exynos_gem->base; 1542364839aSJoonyoung Shim 155a8e11d1cSDaniel Vetter DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); 1562364839aSJoonyoung Shim 157c374e731SInki Dae /* 158c374e731SInki Dae * do not release memory region from exporter. 159c374e731SInki Dae * 160c374e731SInki Dae * the region will be released by exporter 161c374e731SInki Dae * once dmabuf's refcount becomes 0. 162c374e731SInki Dae */ 163c374e731SInki Dae if (obj->import_attach) 164813fd67bSJoonyoung Shim drm_prime_gem_destroy(obj, exynos_gem->sgt); 1657c93537aSJoonyoung Shim else 166813fd67bSJoonyoung Shim exynos_drm_free_buf(exynos_gem); 1672b35892eSInki Dae 1682364839aSJoonyoung Shim /* release file pointer to gem object. */ 1691c248b7dSInki Dae drm_gem_object_release(obj); 1701c248b7dSInki Dae 171813fd67bSJoonyoung Shim kfree(exynos_gem); 1722364839aSJoonyoung Shim } 1732364839aSJoonyoung Shim 174813fd67bSJoonyoung Shim static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, 1752364839aSJoonyoung Shim unsigned long size) 1762364839aSJoonyoung Shim { 177813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 1782364839aSJoonyoung Shim struct drm_gem_object *obj; 1792364839aSJoonyoung Shim int ret; 1802364839aSJoonyoung Shim 181813fd67bSJoonyoung Shim exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL); 182813fd67bSJoonyoung Shim if (!exynos_gem) 1835f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 1842364839aSJoonyoung Shim 185813fd67bSJoonyoung Shim exynos_gem->size = size; 186813fd67bSJoonyoung Shim obj = &exynos_gem->base; 1872364839aSJoonyoung Shim 1882364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 1892364839aSJoonyoung Shim if (ret < 0) { 1902364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 191813fd67bSJoonyoung Shim kfree(exynos_gem); 1925f3f4266SJoonyoung Shim return ERR_PTR(ret); 1932364839aSJoonyoung Shim } 1942364839aSJoonyoung Shim 19548cf53f4SJoonyoung Shim ret = drm_gem_create_mmap_offset(obj); 19648cf53f4SJoonyoung Shim if (ret < 0) { 19748cf53f4SJoonyoung Shim drm_gem_object_release(obj); 198813fd67bSJoonyoung Shim kfree(exynos_gem); 19948cf53f4SJoonyoung Shim return ERR_PTR(ret); 20048cf53f4SJoonyoung Shim } 20148cf53f4SJoonyoung Shim 2029cdf0ed2SKrzysztof Kozlowski DRM_DEBUG_KMS("created file object = %pK\n", obj->filp); 2032364839aSJoonyoung Shim 204813fd67bSJoonyoung Shim return exynos_gem; 2051c248b7dSInki Dae } 2061c248b7dSInki Dae 207813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, 2082b35892eSInki Dae unsigned int flags, 209ee5e770eSJoonyoung Shim unsigned long size) 210f088d5a9SInki Dae { 211813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 2122b35892eSInki Dae int ret; 213f088d5a9SInki Dae 214c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 21563eb0a12SShuah Khan DRM_ERROR("invalid GEM buffer flags: %u\n", flags); 216c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 217c4130bcdSJoonyoung Shim } 218c4130bcdSJoonyoung Shim 219dcf9af82SInki Dae if (!size) { 22063eb0a12SShuah Khan DRM_ERROR("invalid GEM buffer size: %lu\n", size); 221dcf9af82SInki Dae return ERR_PTR(-EINVAL); 222dcf9af82SInki Dae } 223f088d5a9SInki Dae 224eb57da88SJoonyoung Shim size = roundup(size, PAGE_SIZE); 225dcf9af82SInki Dae 226813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_init(dev, size); 227813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) 228813fd67bSJoonyoung Shim return exynos_gem; 2292b35892eSInki Dae 230120a264fSMarek Szyprowski if (!is_drm_iommu_supported(dev) && (flags & EXYNOS_BO_NONCONTIG)) { 231120a264fSMarek Szyprowski /* 232120a264fSMarek Szyprowski * when no IOMMU is available, all allocated buffers are 233120a264fSMarek Szyprowski * contiguous anyway, so drop EXYNOS_BO_NONCONTIG flag 234120a264fSMarek Szyprowski */ 235120a264fSMarek Szyprowski flags &= ~EXYNOS_BO_NONCONTIG; 236120a264fSMarek Szyprowski DRM_WARN("Non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n"); 237120a264fSMarek Szyprowski } 238120a264fSMarek Szyprowski 2392b35892eSInki Dae /* set memory type and cache attribute from user side. */ 240813fd67bSJoonyoung Shim exynos_gem->flags = flags; 2412b35892eSInki Dae 242813fd67bSJoonyoung Shim ret = exynos_drm_alloc_buf(exynos_gem); 2432a8cb489SJoonyoung Shim if (ret < 0) { 244813fd67bSJoonyoung Shim drm_gem_object_release(&exynos_gem->base); 245813fd67bSJoonyoung Shim kfree(exynos_gem); 2462b35892eSInki Dae return ERR_PTR(ret); 247f088d5a9SInki Dae } 248f088d5a9SInki Dae 249813fd67bSJoonyoung Shim return exynos_gem; 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; 256813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 2572364839aSJoonyoung Shim int ret; 2581c248b7dSInki Dae 259813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size); 260813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) 261813fd67bSJoonyoung Shim return PTR_ERR(exynos_gem); 2621c248b7dSInki Dae 263813fd67bSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, 2642364839aSJoonyoung Shim &args->handle); 2652364839aSJoonyoung Shim if (ret) { 266813fd67bSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem); 2672364839aSJoonyoung Shim return ret; 2682364839aSJoonyoung Shim } 2692364839aSJoonyoung Shim 2701c248b7dSInki Dae return 0; 2711c248b7dSInki Dae } 2721c248b7dSInki Dae 2736564c65fSJoonyoung Shim int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, 2746564c65fSJoonyoung Shim struct drm_file *file_priv) 2756564c65fSJoonyoung Shim { 2766564c65fSJoonyoung Shim struct drm_exynos_gem_map *args = data; 2776564c65fSJoonyoung Shim 2784d12c233SNoralf Trønnes return drm_gem_dumb_map_offset(file_priv, dev, args->handle, 2796564c65fSJoonyoung Shim &args->offset); 2806564c65fSJoonyoung Shim } 2816564c65fSJoonyoung Shim 2823aa2a5c1SMarek Szyprowski struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, 2833aa2a5c1SMarek Szyprowski unsigned int gem_handle) 284f0b1bda7SInki Dae { 285f0b1bda7SInki Dae struct drm_gem_object *obj; 286f0b1bda7SInki Dae 287a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(filp, gem_handle); 2883aa2a5c1SMarek Szyprowski if (!obj) 2893aa2a5c1SMarek Szyprowski return NULL; 2903aa2a5c1SMarek Szyprowski return to_exynos_gem(obj); 291f0b1bda7SInki Dae } 292f0b1bda7SInki Dae 293813fd67bSJoonyoung Shim static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, 2941c248b7dSInki Dae struct vm_area_struct *vma) 2951c248b7dSInki Dae { 296813fd67bSJoonyoung Shim struct drm_device *drm_dev = exynos_gem->base.dev; 2970519f9a1SInki Dae unsigned long vm_size; 2985b07c660SInki Dae int ret; 2991c248b7dSInki Dae 300832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 301832316c7SInki Dae vma->vm_pgoff = 0; 3021c248b7dSInki Dae 3030519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 3042b35892eSInki Dae 3051c248b7dSInki Dae /* check if user-requested size is valid. */ 306813fd67bSJoonyoung Shim if (vm_size > exynos_gem->size) 3071c248b7dSInki Dae return -EINVAL; 3081c248b7dSInki Dae 309f43c3596SMarek Szyprowski ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, exynos_gem->cookie, 310813fd67bSJoonyoung Shim exynos_gem->dma_addr, exynos_gem->size, 31100085f1eSKrzysztof Kozlowski exynos_gem->dma_attrs); 3125b07c660SInki Dae if (ret < 0) { 3135b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 3145b07c660SInki Dae return ret; 3155b07c660SInki Dae } 3165b07c660SInki Dae 3171c248b7dSInki Dae return 0; 3181c248b7dSInki Dae } 3191c248b7dSInki Dae 32040cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 32140cd7e0cSInki Dae struct drm_file *file_priv) 322b4cfd4ddSJoonyoung Shim { 323813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 32440cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 32540cd7e0cSInki Dae struct drm_gem_object *obj; 32640cd7e0cSInki Dae 327a8ad0bd8SChris Wilson obj = drm_gem_object_lookup(file_priv, args->handle); 32840cd7e0cSInki Dae if (!obj) { 32940cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 33040cd7e0cSInki Dae return -EINVAL; 33140cd7e0cSInki Dae } 33240cd7e0cSInki Dae 333813fd67bSJoonyoung Shim exynos_gem = to_exynos_gem(obj); 33440cd7e0cSInki Dae 335813fd67bSJoonyoung Shim args->flags = exynos_gem->flags; 336813fd67bSJoonyoung Shim args->size = exynos_gem->size; 33740cd7e0cSInki Dae 338af7d9101SThomas Zimmermann drm_gem_object_put_unlocked(obj); 33940cd7e0cSInki Dae 34040cd7e0cSInki Dae return 0; 34140cd7e0cSInki Dae } 34240cd7e0cSInki Dae 343ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 3441c248b7dSInki Dae { 345813fd67bSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem(obj)); 3461c248b7dSInki Dae } 3471c248b7dSInki Dae 3481c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 349ee5e770eSJoonyoung Shim struct drm_device *dev, 350ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 3511c248b7dSInki Dae { 352813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 353333e8e58SJoonyoung Shim unsigned int flags; 3542364839aSJoonyoung Shim int ret; 3551c248b7dSInki Dae 3561c248b7dSInki Dae /* 357c6b78bc8SMasanari Iida * allocate memory to be used for framebuffer. 3581c248b7dSInki Dae * - this callback would be called by user application 3591c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 3601c248b7dSInki Dae */ 3611c248b7dSInki Dae 3623fd6b694SCooper Yuan args->pitch = args->width * ((args->bpp + 7) / 8); 3637da5907cSInki Dae args->size = args->pitch * args->height; 3641c248b7dSInki Dae 365333e8e58SJoonyoung Shim if (is_drm_iommu_supported(dev)) 366333e8e58SJoonyoung Shim flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC; 367333e8e58SJoonyoung Shim else 368333e8e58SJoonyoung Shim flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; 3693fec4532SVikas Sajjan 370813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_create(dev, flags, args->size); 371813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) { 372122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 373813fd67bSJoonyoung Shim return PTR_ERR(exynos_gem); 374122beea8SRahul Sharma } 3751c248b7dSInki Dae 376813fd67bSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, 3772364839aSJoonyoung Shim &args->handle); 3782364839aSJoonyoung Shim if (ret) { 379813fd67bSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem); 3802364839aSJoonyoung Shim return ret; 3812364839aSJoonyoung Shim } 3822364839aSJoonyoung Shim 3831c248b7dSInki Dae return 0; 3841c248b7dSInki Dae } 3851c248b7dSInki Dae 3868a8d9b2cSSouptick Joarder vm_fault_t exynos_drm_gem_fault(struct vm_fault *vmf) 3871c248b7dSInki Dae { 38811bac800SDave Jiang struct vm_area_struct *vma = vmf->vma; 3891c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 390813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); 3910e9a2ee3SJoonyoung Shim unsigned long pfn; 3921c248b7dSInki Dae pgoff_t page_offset; 3931c248b7dSInki Dae 3941a29d85eSJan Kara page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 3951c248b7dSInki Dae 396813fd67bSJoonyoung Shim if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) { 3970e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 3988a8d9b2cSSouptick Joarder return VM_FAULT_SIGBUS; 3990e9a2ee3SJoonyoung Shim } 4001c248b7dSInki Dae 401813fd67bSJoonyoung Shim pfn = page_to_pfn(exynos_gem->pages[page_offset]); 4028a8d9b2cSSouptick Joarder return vmf_insert_mixed(vma, vmf->address, 4038a8d9b2cSSouptick Joarder __pfn_to_pfn_t(pfn, PFN_DEV)); 4041c248b7dSInki Dae } 4051c248b7dSInki Dae 4065a0202f7SJoonyoung Shim static int exynos_drm_gem_mmap_obj(struct drm_gem_object *obj, 4075a0202f7SJoonyoung Shim struct vm_area_struct *vma) 4081c248b7dSInki Dae { 4095a0202f7SJoonyoung Shim struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); 4101c248b7dSInki Dae int ret; 4111c248b7dSInki Dae 412813fd67bSJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags); 413211b8878SJoonyoung Shim 414211b8878SJoonyoung Shim /* non-cachable as default. */ 415813fd67bSJoonyoung Shim if (exynos_gem->flags & EXYNOS_BO_CACHABLE) 416211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 417813fd67bSJoonyoung Shim else if (exynos_gem->flags & EXYNOS_BO_WC) 418211b8878SJoonyoung Shim vma->vm_page_prot = 419211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 420211b8878SJoonyoung Shim else 421211b8878SJoonyoung Shim vma->vm_page_prot = 422211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 423c01d73faSInki Dae 424813fd67bSJoonyoung Shim ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma); 425832316c7SInki Dae if (ret) 426832316c7SInki Dae goto err_close_vm; 427832316c7SInki Dae 428832316c7SInki Dae return ret; 429832316c7SInki Dae 430832316c7SInki Dae err_close_vm: 431832316c7SInki Dae drm_gem_vm_close(vma); 432832316c7SInki Dae 4331c248b7dSInki Dae return ret; 4341c248b7dSInki Dae } 43501ed50ddSJoonyoung Shim 4365a0202f7SJoonyoung Shim int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 4375a0202f7SJoonyoung Shim { 4385a0202f7SJoonyoung Shim struct drm_gem_object *obj; 4395a0202f7SJoonyoung Shim int ret; 4405a0202f7SJoonyoung Shim 4415a0202f7SJoonyoung Shim /* set vm_area_struct. */ 4425a0202f7SJoonyoung Shim ret = drm_gem_mmap(filp, vma); 4435a0202f7SJoonyoung Shim if (ret < 0) { 4445a0202f7SJoonyoung Shim DRM_ERROR("failed to mmap.\n"); 4455a0202f7SJoonyoung Shim return ret; 4465a0202f7SJoonyoung Shim } 4475a0202f7SJoonyoung Shim 4485a0202f7SJoonyoung Shim obj = vma->vm_private_data; 4495a0202f7SJoonyoung Shim 45055b19fc7SJoonyoung Shim if (obj->import_attach) 45155b19fc7SJoonyoung Shim return dma_buf_mmap(obj->dma_buf, vma, 0); 45255b19fc7SJoonyoung Shim 4535a0202f7SJoonyoung Shim return exynos_drm_gem_mmap_obj(obj, vma); 4545a0202f7SJoonyoung Shim } 4555a0202f7SJoonyoung Shim 45601ed50ddSJoonyoung Shim /* low-level interface prime helpers */ 45789452d4aSMarek Szyprowski struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, 45889452d4aSMarek Szyprowski struct dma_buf *dma_buf) 45989452d4aSMarek Szyprowski { 46089452d4aSMarek Szyprowski return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev)); 46189452d4aSMarek Szyprowski } 46289452d4aSMarek Szyprowski 46301ed50ddSJoonyoung Shim struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 46401ed50ddSJoonyoung Shim { 465813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); 46601ed50ddSJoonyoung Shim int npages; 46701ed50ddSJoonyoung Shim 468813fd67bSJoonyoung Shim npages = exynos_gem->size >> PAGE_SHIFT; 46901ed50ddSJoonyoung Shim 470813fd67bSJoonyoung Shim return drm_prime_pages_to_sg(exynos_gem->pages, npages); 47101ed50ddSJoonyoung Shim } 47201ed50ddSJoonyoung Shim 47301ed50ddSJoonyoung Shim struct drm_gem_object * 47401ed50ddSJoonyoung Shim exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, 47501ed50ddSJoonyoung Shim struct dma_buf_attachment *attach, 47601ed50ddSJoonyoung Shim struct sg_table *sgt) 47701ed50ddSJoonyoung Shim { 478813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 47901ed50ddSJoonyoung Shim int npages; 48001ed50ddSJoonyoung Shim int ret; 48101ed50ddSJoonyoung Shim 482813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size); 483813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) { 484813fd67bSJoonyoung Shim ret = PTR_ERR(exynos_gem); 48550002d4cSInki Dae return ERR_PTR(ret); 48601ed50ddSJoonyoung Shim } 48701ed50ddSJoonyoung Shim 488813fd67bSJoonyoung Shim exynos_gem->dma_addr = sg_dma_address(sgt->sgl); 4892a8cb489SJoonyoung Shim 490813fd67bSJoonyoung Shim npages = exynos_gem->size >> PAGE_SHIFT; 4912098105eSMichal Hocko exynos_gem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); 492813fd67bSJoonyoung Shim if (!exynos_gem->pages) { 4932a8cb489SJoonyoung Shim ret = -ENOMEM; 4942a8cb489SJoonyoung Shim goto err; 4952a8cb489SJoonyoung Shim } 4962a8cb489SJoonyoung Shim 497813fd67bSJoonyoung Shim ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL, 4982a8cb489SJoonyoung Shim npages); 4992a8cb489SJoonyoung Shim if (ret < 0) 5002a8cb489SJoonyoung Shim goto err_free_large; 5012a8cb489SJoonyoung Shim 502813fd67bSJoonyoung Shim exynos_gem->sgt = sgt; 5037c93537aSJoonyoung Shim 50401ed50ddSJoonyoung Shim if (sgt->nents == 1) { 50501ed50ddSJoonyoung Shim /* always physically continuous memory if sgt->nents is 1. */ 506813fd67bSJoonyoung Shim exynos_gem->flags |= EXYNOS_BO_CONTIG; 50701ed50ddSJoonyoung Shim } else { 50801ed50ddSJoonyoung Shim /* 50901ed50ddSJoonyoung Shim * this case could be CONTIG or NONCONTIG type but for now 51001ed50ddSJoonyoung Shim * sets NONCONTIG. 51101ed50ddSJoonyoung Shim * TODO. we have to find a way that exporter can notify 51201ed50ddSJoonyoung Shim * the type of its own buffer to importer. 51301ed50ddSJoonyoung Shim */ 514813fd67bSJoonyoung Shim exynos_gem->flags |= EXYNOS_BO_NONCONTIG; 51501ed50ddSJoonyoung Shim } 51601ed50ddSJoonyoung Shim 517813fd67bSJoonyoung Shim return &exynos_gem->base; 51801ed50ddSJoonyoung Shim 51901ed50ddSJoonyoung Shim err_free_large: 5202098105eSMichal Hocko kvfree(exynos_gem->pages); 52101ed50ddSJoonyoung Shim err: 522813fd67bSJoonyoung Shim drm_gem_object_release(&exynos_gem->base); 523813fd67bSJoonyoung Shim kfree(exynos_gem); 52401ed50ddSJoonyoung Shim return ERR_PTR(ret); 52501ed50ddSJoonyoung Shim } 52601ed50ddSJoonyoung Shim 52701ed50ddSJoonyoung Shim void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj) 52801ed50ddSJoonyoung Shim { 52901ed50ddSJoonyoung Shim return NULL; 53001ed50ddSJoonyoung Shim } 53101ed50ddSJoonyoung Shim 53201ed50ddSJoonyoung Shim void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) 53301ed50ddSJoonyoung Shim { 53401ed50ddSJoonyoung Shim /* Nothing to do */ 53501ed50ddSJoonyoung Shim } 5365a0202f7SJoonyoung Shim 5375a0202f7SJoonyoung Shim int exynos_drm_gem_prime_mmap(struct drm_gem_object *obj, 5385a0202f7SJoonyoung Shim struct vm_area_struct *vma) 5395a0202f7SJoonyoung Shim { 5405a0202f7SJoonyoung Shim int ret; 5415a0202f7SJoonyoung Shim 5425a0202f7SJoonyoung Shim ret = drm_gem_mmap_obj(obj, obj->size, vma); 5435a0202f7SJoonyoung Shim if (ret < 0) 5445a0202f7SJoonyoung Shim return ret; 5455a0202f7SJoonyoung Shim 5465a0202f7SJoonyoung Shim return exynos_drm_gem_mmap_obj(obj, vma); 5475a0202f7SJoonyoung Shim } 548