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; 272a8cb489SJoonyoung Shim enum dma_attr 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 37813fd67bSJoonyoung Shim init_dma_attrs(&exynos_gem->dma_attrs); 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)) 45813fd67bSJoonyoung Shim dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs); 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 57813fd67bSJoonyoung Shim dma_set_attr(attr, &exynos_gem->dma_attrs); 58813fd67bSJoonyoung Shim dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &exynos_gem->dma_attrs); 592a8cb489SJoonyoung Shim 60813fd67bSJoonyoung Shim nr_pages = exynos_gem->size >> PAGE_SHIFT; 612a8cb489SJoonyoung Shim 62df547bf7SMarek Szyprowski exynos_gem->pages = drm_calloc_large(nr_pages, sizeof(struct page *)); 63813fd67bSJoonyoung Shim if (!exynos_gem->pages) { 642a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate pages.\n"); 652a8cb489SJoonyoung Shim return -ENOMEM; 662a8cb489SJoonyoung Shim } 672a8cb489SJoonyoung Shim 68f43c3596SMarek Szyprowski exynos_gem->cookie = dma_alloc_attrs(to_dma_dev(dev), exynos_gem->size, 69813fd67bSJoonyoung Shim &exynos_gem->dma_addr, GFP_KERNEL, 70813fd67bSJoonyoung Shim &exynos_gem->dma_attrs); 71813fd67bSJoonyoung Shim if (!exynos_gem->cookie) { 722a8cb489SJoonyoung Shim DRM_ERROR("failed to allocate buffer.\n"); 73df547bf7SMarek Szyprowski goto err_free; 742a8cb489SJoonyoung Shim } 752a8cb489SJoonyoung Shim 76f43c3596SMarek Szyprowski ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt, exynos_gem->cookie, 77df547bf7SMarek Szyprowski exynos_gem->dma_addr, exynos_gem->size, 78df547bf7SMarek Szyprowski &exynos_gem->dma_attrs); 79df547bf7SMarek Szyprowski if (ret < 0) { 80df547bf7SMarek Szyprowski DRM_ERROR("failed to get sgtable.\n"); 81df547bf7SMarek Szyprowski goto err_dma_free; 82df547bf7SMarek Szyprowski } 83333e8e58SJoonyoung Shim 84df547bf7SMarek Szyprowski if (drm_prime_sg_to_page_addr_arrays(&sgt, exynos_gem->pages, NULL, 85df547bf7SMarek Szyprowski nr_pages)) { 86df547bf7SMarek Szyprowski DRM_ERROR("invalid sgtable.\n"); 87df547bf7SMarek Szyprowski ret = -EINVAL; 88df547bf7SMarek Szyprowski goto err_sgt_free; 892a8cb489SJoonyoung Shim } 90df547bf7SMarek Szyprowski 91df547bf7SMarek Szyprowski sg_free_table(&sgt); 922a8cb489SJoonyoung Shim 932a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 94813fd67bSJoonyoung Shim (unsigned long)exynos_gem->dma_addr, exynos_gem->size); 952a8cb489SJoonyoung Shim 962a8cb489SJoonyoung Shim return 0; 97df547bf7SMarek Szyprowski 98df547bf7SMarek Szyprowski err_sgt_free: 99df547bf7SMarek Szyprowski sg_free_table(&sgt); 100df547bf7SMarek Szyprowski err_dma_free: 101f43c3596SMarek Szyprowski dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, 102df547bf7SMarek Szyprowski exynos_gem->dma_addr, &exynos_gem->dma_attrs); 103df547bf7SMarek Szyprowski err_free: 104df547bf7SMarek Szyprowski drm_free_large(exynos_gem->pages); 105df547bf7SMarek Szyprowski 106df547bf7SMarek Szyprowski return ret; 1072a8cb489SJoonyoung Shim } 1082a8cb489SJoonyoung Shim 109813fd67bSJoonyoung Shim static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) 1102a8cb489SJoonyoung Shim { 111813fd67bSJoonyoung Shim struct drm_device *dev = exynos_gem->base.dev; 1122a8cb489SJoonyoung Shim 113813fd67bSJoonyoung Shim if (!exynos_gem->dma_addr) { 1142a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr is invalid.\n"); 1152a8cb489SJoonyoung Shim return; 1162a8cb489SJoonyoung Shim } 1172a8cb489SJoonyoung Shim 1182a8cb489SJoonyoung Shim DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n", 119813fd67bSJoonyoung Shim (unsigned long)exynos_gem->dma_addr, exynos_gem->size); 1202a8cb489SJoonyoung Shim 121f43c3596SMarek Szyprowski dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, 122813fd67bSJoonyoung Shim (dma_addr_t)exynos_gem->dma_addr, 123813fd67bSJoonyoung Shim &exynos_gem->dma_attrs); 124333e8e58SJoonyoung Shim 125813fd67bSJoonyoung Shim drm_free_large(exynos_gem->pages); 1262a8cb489SJoonyoung Shim } 1272a8cb489SJoonyoung Shim 1282364839aSJoonyoung Shim static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, 1292364839aSJoonyoung Shim struct drm_file *file_priv, 1302364839aSJoonyoung Shim unsigned int *handle) 1311c248b7dSInki Dae { 1321c248b7dSInki Dae int ret; 1331c248b7dSInki Dae 1341c248b7dSInki Dae /* 1351c248b7dSInki Dae * allocate a id of idr table where the obj is registered 1361c248b7dSInki Dae * and handle has the id what user can see. 1371c248b7dSInki Dae */ 1381c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 1391c248b7dSInki Dae if (ret) 1402364839aSJoonyoung Shim return ret; 1411c248b7dSInki Dae 1421c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 1431c248b7dSInki Dae 1441c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 1451c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 1461c248b7dSInki Dae 1472364839aSJoonyoung Shim return 0; 1482364839aSJoonyoung Shim } 1491c248b7dSInki Dae 150813fd67bSJoonyoung Shim void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) 1512364839aSJoonyoung Shim { 152813fd67bSJoonyoung Shim struct drm_gem_object *obj = &exynos_gem->base; 1532364839aSJoonyoung Shim 154a8e11d1cSDaniel Vetter DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count); 1552364839aSJoonyoung Shim 156c374e731SInki Dae /* 157c374e731SInki Dae * do not release memory region from exporter. 158c374e731SInki Dae * 159c374e731SInki Dae * the region will be released by exporter 160c374e731SInki Dae * once dmabuf's refcount becomes 0. 161c374e731SInki Dae */ 162c374e731SInki Dae if (obj->import_attach) 163813fd67bSJoonyoung Shim drm_prime_gem_destroy(obj, exynos_gem->sgt); 1647c93537aSJoonyoung Shim else 165813fd67bSJoonyoung Shim exynos_drm_free_buf(exynos_gem); 1662b35892eSInki Dae 1672364839aSJoonyoung Shim /* release file pointer to gem object. */ 1681c248b7dSInki Dae drm_gem_object_release(obj); 1691c248b7dSInki Dae 170813fd67bSJoonyoung Shim kfree(exynos_gem); 1712364839aSJoonyoung Shim } 1722364839aSJoonyoung Shim 173a4f19aaaSInki Dae unsigned long exynos_drm_gem_get_size(struct drm_device *dev, 174a4f19aaaSInki Dae unsigned int gem_handle, 175a4f19aaaSInki Dae struct drm_file *file_priv) 176a4f19aaaSInki Dae { 177813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 178a4f19aaaSInki Dae struct drm_gem_object *obj; 179a4f19aaaSInki Dae 180a4f19aaaSInki Dae obj = drm_gem_object_lookup(dev, file_priv, gem_handle); 181a4f19aaaSInki Dae if (!obj) { 182a4f19aaaSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 183a4f19aaaSInki Dae return 0; 184a4f19aaaSInki Dae } 185a4f19aaaSInki Dae 186813fd67bSJoonyoung Shim exynos_gem = to_exynos_gem(obj); 187a4f19aaaSInki Dae 188a4f19aaaSInki Dae drm_gem_object_unreference_unlocked(obj); 189a4f19aaaSInki Dae 190813fd67bSJoonyoung Shim return exynos_gem->size; 191a4f19aaaSInki Dae } 192a4f19aaaSInki Dae 193813fd67bSJoonyoung Shim static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, 1942364839aSJoonyoung Shim unsigned long size) 1952364839aSJoonyoung Shim { 196813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 1972364839aSJoonyoung Shim struct drm_gem_object *obj; 1982364839aSJoonyoung Shim int ret; 1992364839aSJoonyoung Shim 200813fd67bSJoonyoung Shim exynos_gem = kzalloc(sizeof(*exynos_gem), GFP_KERNEL); 201813fd67bSJoonyoung Shim if (!exynos_gem) 2025f3f4266SJoonyoung Shim return ERR_PTR(-ENOMEM); 2032364839aSJoonyoung Shim 204813fd67bSJoonyoung Shim exynos_gem->size = size; 205813fd67bSJoonyoung Shim obj = &exynos_gem->base; 2062364839aSJoonyoung Shim 2072364839aSJoonyoung Shim ret = drm_gem_object_init(dev, obj, size); 2082364839aSJoonyoung Shim if (ret < 0) { 2092364839aSJoonyoung Shim DRM_ERROR("failed to initialize gem object\n"); 210813fd67bSJoonyoung Shim kfree(exynos_gem); 2115f3f4266SJoonyoung Shim return ERR_PTR(ret); 2122364839aSJoonyoung Shim } 2132364839aSJoonyoung Shim 21448cf53f4SJoonyoung Shim ret = drm_gem_create_mmap_offset(obj); 21548cf53f4SJoonyoung Shim if (ret < 0) { 21648cf53f4SJoonyoung Shim drm_gem_object_release(obj); 217813fd67bSJoonyoung Shim kfree(exynos_gem); 21848cf53f4SJoonyoung Shim return ERR_PTR(ret); 21948cf53f4SJoonyoung Shim } 22048cf53f4SJoonyoung Shim 221c5f2f0c4SMarek Szyprowski DRM_DEBUG_KMS("created file object = %p\n", obj->filp); 2222364839aSJoonyoung Shim 223813fd67bSJoonyoung Shim return exynos_gem; 2241c248b7dSInki Dae } 2251c248b7dSInki Dae 226813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_drm_gem_create(struct drm_device *dev, 2272b35892eSInki Dae unsigned int flags, 228ee5e770eSJoonyoung Shim unsigned long size) 229f088d5a9SInki Dae { 230813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 2312b35892eSInki Dae int ret; 232f088d5a9SInki Dae 233c4130bcdSJoonyoung Shim if (flags & ~(EXYNOS_BO_MASK)) { 234c4130bcdSJoonyoung Shim DRM_ERROR("invalid flags.\n"); 235c4130bcdSJoonyoung Shim return ERR_PTR(-EINVAL); 236c4130bcdSJoonyoung Shim } 237c4130bcdSJoonyoung Shim 238dcf9af82SInki Dae if (!size) { 239dcf9af82SInki Dae DRM_ERROR("invalid size.\n"); 240dcf9af82SInki Dae return ERR_PTR(-EINVAL); 241dcf9af82SInki Dae } 242f088d5a9SInki Dae 243eb57da88SJoonyoung Shim size = roundup(size, PAGE_SIZE); 244dcf9af82SInki Dae 245813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_init(dev, size); 246813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) 247813fd67bSJoonyoung Shim return exynos_gem; 2482b35892eSInki Dae 2492b35892eSInki Dae /* set memory type and cache attribute from user side. */ 250813fd67bSJoonyoung Shim exynos_gem->flags = flags; 2512b35892eSInki Dae 252813fd67bSJoonyoung Shim ret = exynos_drm_alloc_buf(exynos_gem); 2532a8cb489SJoonyoung Shim if (ret < 0) { 254813fd67bSJoonyoung Shim drm_gem_object_release(&exynos_gem->base); 255813fd67bSJoonyoung Shim kfree(exynos_gem); 2562b35892eSInki Dae return ERR_PTR(ret); 257f088d5a9SInki Dae } 258f088d5a9SInki Dae 259813fd67bSJoonyoung Shim return exynos_gem; 2602a8cb489SJoonyoung Shim } 2612a8cb489SJoonyoung Shim 2621c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 2631c248b7dSInki Dae struct drm_file *file_priv) 2641c248b7dSInki Dae { 2651c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 266813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 2672364839aSJoonyoung Shim int ret; 2681c248b7dSInki Dae 269813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_create(dev, args->flags, args->size); 270813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) 271813fd67bSJoonyoung Shim return PTR_ERR(exynos_gem); 2721c248b7dSInki Dae 273813fd67bSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, 2742364839aSJoonyoung Shim &args->handle); 2752364839aSJoonyoung Shim if (ret) { 276813fd67bSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem); 2772364839aSJoonyoung Shim return ret; 2782364839aSJoonyoung Shim } 2792364839aSJoonyoung Shim 2801c248b7dSInki Dae return 0; 2811c248b7dSInki Dae } 2821c248b7dSInki Dae 2836564c65fSJoonyoung Shim int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, 2846564c65fSJoonyoung Shim struct drm_file *file_priv) 2856564c65fSJoonyoung Shim { 2866564c65fSJoonyoung Shim struct drm_exynos_gem_map *args = data; 2876564c65fSJoonyoung Shim 2886564c65fSJoonyoung Shim return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle, 2896564c65fSJoonyoung Shim &args->offset); 2906564c65fSJoonyoung Shim } 2916564c65fSJoonyoung Shim 292d87342c1SInki Dae dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, 293f0b1bda7SInki Dae unsigned int gem_handle, 294d87342c1SInki Dae struct drm_file *filp) 295f0b1bda7SInki Dae { 296813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 297f0b1bda7SInki Dae struct drm_gem_object *obj; 298f0b1bda7SInki Dae 299d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 300f0b1bda7SInki Dae if (!obj) { 301f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 302f0b1bda7SInki Dae return ERR_PTR(-EINVAL); 303f0b1bda7SInki Dae } 304f0b1bda7SInki Dae 305813fd67bSJoonyoung Shim exynos_gem = to_exynos_gem(obj); 306f0b1bda7SInki Dae 307813fd67bSJoonyoung Shim return &exynos_gem->dma_addr; 308f0b1bda7SInki Dae } 309f0b1bda7SInki Dae 310f0b1bda7SInki Dae void exynos_drm_gem_put_dma_addr(struct drm_device *dev, 311f0b1bda7SInki Dae unsigned int gem_handle, 312d87342c1SInki Dae struct drm_file *filp) 313f0b1bda7SInki Dae { 314f0b1bda7SInki Dae struct drm_gem_object *obj; 315f0b1bda7SInki Dae 316d87342c1SInki Dae obj = drm_gem_object_lookup(dev, filp, gem_handle); 317f0b1bda7SInki Dae if (!obj) { 318f0b1bda7SInki Dae DRM_ERROR("failed to lookup gem object.\n"); 319f0b1bda7SInki Dae return; 320f0b1bda7SInki Dae } 321f0b1bda7SInki Dae 322f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 323f0b1bda7SInki Dae 324f0b1bda7SInki Dae /* 325f0b1bda7SInki Dae * decrease obj->refcount one more time because we has already 326f0b1bda7SInki Dae * increased it at exynos_drm_gem_get_dma_addr(). 327f0b1bda7SInki Dae */ 328f0b1bda7SInki Dae drm_gem_object_unreference_unlocked(obj); 329f0b1bda7SInki Dae } 330f0b1bda7SInki Dae 331813fd67bSJoonyoung Shim static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, 3321c248b7dSInki Dae struct vm_area_struct *vma) 3331c248b7dSInki Dae { 334813fd67bSJoonyoung Shim struct drm_device *drm_dev = exynos_gem->base.dev; 3350519f9a1SInki Dae unsigned long vm_size; 3365b07c660SInki Dae int ret; 3371c248b7dSInki Dae 338832316c7SInki Dae vma->vm_flags &= ~VM_PFNMAP; 339832316c7SInki Dae vma->vm_pgoff = 0; 3401c248b7dSInki Dae 3410519f9a1SInki Dae vm_size = vma->vm_end - vma->vm_start; 3422b35892eSInki Dae 3431c248b7dSInki Dae /* check if user-requested size is valid. */ 344813fd67bSJoonyoung Shim if (vm_size > exynos_gem->size) 3451c248b7dSInki Dae return -EINVAL; 3461c248b7dSInki Dae 347f43c3596SMarek Szyprowski ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, exynos_gem->cookie, 348813fd67bSJoonyoung Shim exynos_gem->dma_addr, exynos_gem->size, 349813fd67bSJoonyoung Shim &exynos_gem->dma_attrs); 3505b07c660SInki Dae if (ret < 0) { 3515b07c660SInki Dae DRM_ERROR("failed to mmap.\n"); 3525b07c660SInki Dae return ret; 3535b07c660SInki Dae } 3545b07c660SInki Dae 3551c248b7dSInki Dae return 0; 3561c248b7dSInki Dae } 3571c248b7dSInki Dae 35840cd7e0cSInki Dae int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, 35940cd7e0cSInki Dae struct drm_file *file_priv) 360b4cfd4ddSJoonyoung Shim { 361813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 36240cd7e0cSInki Dae struct drm_exynos_gem_info *args = data; 36340cd7e0cSInki Dae struct drm_gem_object *obj; 36440cd7e0cSInki Dae 36540cd7e0cSInki Dae mutex_lock(&dev->struct_mutex); 36640cd7e0cSInki Dae 36740cd7e0cSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 36840cd7e0cSInki Dae if (!obj) { 36940cd7e0cSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 37040cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 37140cd7e0cSInki Dae return -EINVAL; 37240cd7e0cSInki Dae } 37340cd7e0cSInki Dae 374813fd67bSJoonyoung Shim exynos_gem = to_exynos_gem(obj); 37540cd7e0cSInki Dae 376813fd67bSJoonyoung Shim args->flags = exynos_gem->flags; 377813fd67bSJoonyoung Shim args->size = exynos_gem->size; 37840cd7e0cSInki Dae 37940cd7e0cSInki Dae drm_gem_object_unreference(obj); 38040cd7e0cSInki Dae mutex_unlock(&dev->struct_mutex); 38140cd7e0cSInki Dae 38240cd7e0cSInki Dae return 0; 38340cd7e0cSInki Dae } 38440cd7e0cSInki Dae 3852a3098ffSInki Dae int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev, 3862a3098ffSInki Dae struct sg_table *sgt, 3872a3098ffSInki Dae enum dma_data_direction dir) 3882a3098ffSInki Dae { 3892a3098ffSInki Dae int nents; 3902a3098ffSInki Dae 3912a3098ffSInki Dae mutex_lock(&drm_dev->struct_mutex); 3922a3098ffSInki Dae 393f43c3596SMarek Szyprowski nents = dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, dir); 3942a3098ffSInki Dae if (!nents) { 3952a3098ffSInki Dae DRM_ERROR("failed to map sgl with dma.\n"); 3962a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 3972a3098ffSInki Dae return nents; 3982a3098ffSInki Dae } 3992a3098ffSInki Dae 4002a3098ffSInki Dae mutex_unlock(&drm_dev->struct_mutex); 4012a3098ffSInki Dae return 0; 4022a3098ffSInki Dae } 4032a3098ffSInki Dae 4042a3098ffSInki Dae void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev, 4052a3098ffSInki Dae struct sg_table *sgt, 4062a3098ffSInki Dae enum dma_data_direction dir) 4072a3098ffSInki Dae { 408f43c3596SMarek Szyprowski dma_unmap_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, dir); 4092a3098ffSInki Dae } 4102a3098ffSInki Dae 411ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 4121c248b7dSInki Dae { 413813fd67bSJoonyoung Shim exynos_drm_gem_destroy(to_exynos_gem(obj)); 4141c248b7dSInki Dae } 4151c248b7dSInki Dae 4161c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 417ee5e770eSJoonyoung Shim struct drm_device *dev, 418ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 4191c248b7dSInki Dae { 420813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 421333e8e58SJoonyoung Shim unsigned int flags; 4222364839aSJoonyoung Shim int ret; 4231c248b7dSInki Dae 4241c248b7dSInki Dae /* 425c6b78bc8SMasanari Iida * allocate memory to be used for framebuffer. 4261c248b7dSInki Dae * - this callback would be called by user application 4271c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 4281c248b7dSInki Dae */ 4291c248b7dSInki Dae 4303fd6b694SCooper Yuan args->pitch = args->width * ((args->bpp + 7) / 8); 4317da5907cSInki Dae args->size = args->pitch * args->height; 4321c248b7dSInki Dae 433333e8e58SJoonyoung Shim if (is_drm_iommu_supported(dev)) 434333e8e58SJoonyoung Shim flags = EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC; 435333e8e58SJoonyoung Shim else 436333e8e58SJoonyoung Shim flags = EXYNOS_BO_CONTIG | EXYNOS_BO_WC; 4373fec4532SVikas Sajjan 438813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_create(dev, flags, args->size); 439813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) { 440122beea8SRahul Sharma dev_warn(dev->dev, "FB allocation failed.\n"); 441813fd67bSJoonyoung Shim return PTR_ERR(exynos_gem); 442122beea8SRahul Sharma } 4431c248b7dSInki Dae 444813fd67bSJoonyoung Shim ret = exynos_drm_gem_handle_create(&exynos_gem->base, file_priv, 4452364839aSJoonyoung Shim &args->handle); 4462364839aSJoonyoung Shim if (ret) { 447813fd67bSJoonyoung Shim exynos_drm_gem_destroy(exynos_gem); 4482364839aSJoonyoung Shim return ret; 4492364839aSJoonyoung Shim } 4502364839aSJoonyoung Shim 4511c248b7dSInki Dae return 0; 4521c248b7dSInki Dae } 4531c248b7dSInki Dae 4541c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 455ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 456ee5e770eSJoonyoung Shim uint64_t *offset) 4571c248b7dSInki Dae { 4581c248b7dSInki Dae struct drm_gem_object *obj; 4592d91cf17SJoonyoung Shim int ret = 0; 4601c248b7dSInki Dae 4611c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 4621c248b7dSInki Dae 4631c248b7dSInki Dae /* 4641c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 4651c248b7dSInki Dae * - this callback would be called by user application 4661c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 4671c248b7dSInki Dae */ 4681c248b7dSInki Dae 4691c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 4701c248b7dSInki Dae if (!obj) { 4711c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 4722d91cf17SJoonyoung Shim ret = -EINVAL; 4732d91cf17SJoonyoung Shim goto unlock; 4741c248b7dSInki Dae } 4751c248b7dSInki Dae 4760de23977SDavid Herrmann *offset = drm_vma_node_offset_addr(&obj->vma_node); 4771c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 4781c248b7dSInki Dae 4792d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 4802d91cf17SJoonyoung Shim unlock: 4811c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 4822d91cf17SJoonyoung Shim return ret; 4831c248b7dSInki Dae } 4841c248b7dSInki Dae 4851c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 4861c248b7dSInki Dae { 4871c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 488813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); 4890e9a2ee3SJoonyoung Shim unsigned long pfn; 4901c248b7dSInki Dae pgoff_t page_offset; 4911c248b7dSInki Dae int ret; 4921c248b7dSInki Dae 4931c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 4941c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 4951c248b7dSInki Dae 496813fd67bSJoonyoung Shim if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) { 4970e9a2ee3SJoonyoung Shim DRM_ERROR("invalid page offset\n"); 4980e9a2ee3SJoonyoung Shim ret = -EINVAL; 4990e9a2ee3SJoonyoung Shim goto out; 5000e9a2ee3SJoonyoung Shim } 5011c248b7dSInki Dae 502813fd67bSJoonyoung Shim pfn = page_to_pfn(exynos_gem->pages[page_offset]); 50301c8f1c4SDan Williams ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, 50401c8f1c4SDan Williams __pfn_to_pfn_t(pfn, PFN_DEV)); 5050e9a2ee3SJoonyoung Shim 5060e9a2ee3SJoonyoung Shim out: 50723597e26SJoonyoung Shim switch (ret) { 50823597e26SJoonyoung Shim case 0: 50923597e26SJoonyoung Shim case -ERESTARTSYS: 51023597e26SJoonyoung Shim case -EINTR: 51123597e26SJoonyoung Shim return VM_FAULT_NOPAGE; 51223597e26SJoonyoung Shim case -ENOMEM: 51323597e26SJoonyoung Shim return VM_FAULT_OOM; 51423597e26SJoonyoung Shim default: 51523597e26SJoonyoung Shim return VM_FAULT_SIGBUS; 51623597e26SJoonyoung Shim } 5171c248b7dSInki Dae } 5181c248b7dSInki Dae 5191c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 5201c248b7dSInki Dae { 521813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 522c01d73faSInki Dae struct drm_gem_object *obj; 5231c248b7dSInki Dae int ret; 5241c248b7dSInki Dae 5251c248b7dSInki Dae /* set vm_area_struct. */ 5261c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 5271c248b7dSInki Dae if (ret < 0) { 5281c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 5291c248b7dSInki Dae return ret; 5301c248b7dSInki Dae } 5311c248b7dSInki Dae 532c01d73faSInki Dae obj = vma->vm_private_data; 533813fd67bSJoonyoung Shim exynos_gem = to_exynos_gem(obj); 534c01d73faSInki Dae 535813fd67bSJoonyoung Shim DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags); 536211b8878SJoonyoung Shim 537211b8878SJoonyoung Shim /* non-cachable as default. */ 538813fd67bSJoonyoung Shim if (exynos_gem->flags & EXYNOS_BO_CACHABLE) 539211b8878SJoonyoung Shim vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 540813fd67bSJoonyoung Shim else if (exynos_gem->flags & EXYNOS_BO_WC) 541211b8878SJoonyoung Shim vma->vm_page_prot = 542211b8878SJoonyoung Shim pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 543211b8878SJoonyoung Shim else 544211b8878SJoonyoung Shim vma->vm_page_prot = 545211b8878SJoonyoung Shim pgprot_noncached(vm_get_page_prot(vma->vm_flags)); 546c01d73faSInki Dae 547813fd67bSJoonyoung Shim ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma); 548832316c7SInki Dae if (ret) 549832316c7SInki Dae goto err_close_vm; 550832316c7SInki Dae 551832316c7SInki Dae return ret; 552832316c7SInki Dae 553832316c7SInki Dae err_close_vm: 554832316c7SInki Dae drm_gem_vm_close(vma); 555832316c7SInki Dae 5561c248b7dSInki Dae return ret; 5571c248b7dSInki Dae } 55801ed50ddSJoonyoung Shim 55901ed50ddSJoonyoung Shim /* low-level interface prime helpers */ 56001ed50ddSJoonyoung Shim struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 56101ed50ddSJoonyoung Shim { 562813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); 56301ed50ddSJoonyoung Shim int npages; 56401ed50ddSJoonyoung Shim 565813fd67bSJoonyoung Shim npages = exynos_gem->size >> PAGE_SHIFT; 56601ed50ddSJoonyoung Shim 567813fd67bSJoonyoung Shim return drm_prime_pages_to_sg(exynos_gem->pages, npages); 56801ed50ddSJoonyoung Shim } 56901ed50ddSJoonyoung Shim 57001ed50ddSJoonyoung Shim struct drm_gem_object * 57101ed50ddSJoonyoung Shim exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, 57201ed50ddSJoonyoung Shim struct dma_buf_attachment *attach, 57301ed50ddSJoonyoung Shim struct sg_table *sgt) 57401ed50ddSJoonyoung Shim { 575813fd67bSJoonyoung Shim struct exynos_drm_gem *exynos_gem; 57601ed50ddSJoonyoung Shim int npages; 57701ed50ddSJoonyoung Shim int ret; 57801ed50ddSJoonyoung Shim 579813fd67bSJoonyoung Shim exynos_gem = exynos_drm_gem_init(dev, attach->dmabuf->size); 580813fd67bSJoonyoung Shim if (IS_ERR(exynos_gem)) { 581813fd67bSJoonyoung Shim ret = PTR_ERR(exynos_gem); 58250002d4cSInki Dae return ERR_PTR(ret); 58301ed50ddSJoonyoung Shim } 58401ed50ddSJoonyoung Shim 585813fd67bSJoonyoung Shim exynos_gem->dma_addr = sg_dma_address(sgt->sgl); 5862a8cb489SJoonyoung Shim 587813fd67bSJoonyoung Shim npages = exynos_gem->size >> PAGE_SHIFT; 588813fd67bSJoonyoung Shim exynos_gem->pages = drm_malloc_ab(npages, sizeof(struct page *)); 589813fd67bSJoonyoung Shim if (!exynos_gem->pages) { 5902a8cb489SJoonyoung Shim ret = -ENOMEM; 5912a8cb489SJoonyoung Shim goto err; 5922a8cb489SJoonyoung Shim } 5932a8cb489SJoonyoung Shim 594813fd67bSJoonyoung Shim ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem->pages, NULL, 5952a8cb489SJoonyoung Shim npages); 5962a8cb489SJoonyoung Shim if (ret < 0) 5972a8cb489SJoonyoung Shim goto err_free_large; 5982a8cb489SJoonyoung Shim 599813fd67bSJoonyoung Shim exynos_gem->sgt = sgt; 6007c93537aSJoonyoung Shim 60101ed50ddSJoonyoung Shim if (sgt->nents == 1) { 60201ed50ddSJoonyoung Shim /* always physically continuous memory if sgt->nents is 1. */ 603813fd67bSJoonyoung Shim exynos_gem->flags |= EXYNOS_BO_CONTIG; 60401ed50ddSJoonyoung Shim } else { 60501ed50ddSJoonyoung Shim /* 60601ed50ddSJoonyoung Shim * this case could be CONTIG or NONCONTIG type but for now 60701ed50ddSJoonyoung Shim * sets NONCONTIG. 60801ed50ddSJoonyoung Shim * TODO. we have to find a way that exporter can notify 60901ed50ddSJoonyoung Shim * the type of its own buffer to importer. 61001ed50ddSJoonyoung Shim */ 611813fd67bSJoonyoung Shim exynos_gem->flags |= EXYNOS_BO_NONCONTIG; 61201ed50ddSJoonyoung Shim } 61301ed50ddSJoonyoung Shim 614813fd67bSJoonyoung Shim return &exynos_gem->base; 61501ed50ddSJoonyoung Shim 61601ed50ddSJoonyoung Shim err_free_large: 617813fd67bSJoonyoung Shim drm_free_large(exynos_gem->pages); 61801ed50ddSJoonyoung Shim err: 619813fd67bSJoonyoung Shim drm_gem_object_release(&exynos_gem->base); 620813fd67bSJoonyoung Shim kfree(exynos_gem); 62101ed50ddSJoonyoung Shim return ERR_PTR(ret); 62201ed50ddSJoonyoung Shim } 62301ed50ddSJoonyoung Shim 62401ed50ddSJoonyoung Shim void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj) 62501ed50ddSJoonyoung Shim { 62601ed50ddSJoonyoung Shim return NULL; 62701ed50ddSJoonyoung Shim } 62801ed50ddSJoonyoung Shim 62901ed50ddSJoonyoung Shim void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) 63001ed50ddSJoonyoung Shim { 63101ed50ddSJoonyoung Shim /* Nothing to do */ 63201ed50ddSJoonyoung Shim } 633