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 * 61c248b7dSInki Dae * Permission is hereby granted, free of charge, to any person obtaining a 71c248b7dSInki Dae * copy of this software and associated documentation files (the "Software"), 81c248b7dSInki Dae * to deal in the Software without restriction, including without limitation 91c248b7dSInki Dae * the rights to use, copy, modify, merge, publish, distribute, sublicense, 101c248b7dSInki Dae * and/or sell copies of the Software, and to permit persons to whom the 111c248b7dSInki Dae * Software is furnished to do so, subject to the following conditions: 121c248b7dSInki Dae * 131c248b7dSInki Dae * The above copyright notice and this permission notice (including the next 141c248b7dSInki Dae * paragraph) shall be included in all copies or substantial portions of the 151c248b7dSInki Dae * Software. 161c248b7dSInki Dae * 171c248b7dSInki Dae * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 181c248b7dSInki Dae * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 191c248b7dSInki Dae * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 201c248b7dSInki Dae * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 211c248b7dSInki Dae * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 221c248b7dSInki Dae * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 231c248b7dSInki Dae * OTHER DEALINGS IN THE SOFTWARE. 241c248b7dSInki Dae */ 251c248b7dSInki Dae 261c248b7dSInki Dae #include "drmP.h" 271c248b7dSInki Dae #include "drm.h" 281c248b7dSInki Dae 291c248b7dSInki Dae #include <drm/exynos_drm.h> 301c248b7dSInki Dae 311c248b7dSInki Dae #include "exynos_drm_drv.h" 321c248b7dSInki Dae #include "exynos_drm_gem.h" 331c248b7dSInki Dae #include "exynos_drm_buf.h" 341c248b7dSInki Dae 351c248b7dSInki Dae static unsigned int convert_to_vm_err_msg(int msg) 361c248b7dSInki Dae { 371c248b7dSInki Dae unsigned int out_msg; 381c248b7dSInki Dae 391c248b7dSInki Dae switch (msg) { 401c248b7dSInki Dae case 0: 411c248b7dSInki Dae case -ERESTARTSYS: 421c248b7dSInki Dae case -EINTR: 431c248b7dSInki Dae out_msg = VM_FAULT_NOPAGE; 441c248b7dSInki Dae break; 451c248b7dSInki Dae 461c248b7dSInki Dae case -ENOMEM: 471c248b7dSInki Dae out_msg = VM_FAULT_OOM; 481c248b7dSInki Dae break; 491c248b7dSInki Dae 501c248b7dSInki Dae default: 511c248b7dSInki Dae out_msg = VM_FAULT_SIGBUS; 521c248b7dSInki Dae break; 531c248b7dSInki Dae } 541c248b7dSInki Dae 551c248b7dSInki Dae return out_msg; 561c248b7dSInki Dae } 571c248b7dSInki Dae 581c248b7dSInki Dae static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) 591c248b7dSInki Dae { 601c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 611c248b7dSInki Dae 621c248b7dSInki Dae return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; 631c248b7dSInki Dae } 641c248b7dSInki Dae 651c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv, 661c248b7dSInki Dae struct drm_device *dev, unsigned int size, 671c248b7dSInki Dae unsigned int *handle) 681c248b7dSInki Dae { 691c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 701c248b7dSInki Dae struct exynos_drm_buf_entry *entry; 711c248b7dSInki Dae struct drm_gem_object *obj; 721c248b7dSInki Dae int ret; 731c248b7dSInki Dae 741c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 751c248b7dSInki Dae 761c248b7dSInki Dae size = roundup(size, PAGE_SIZE); 771c248b7dSInki Dae 781c248b7dSInki Dae exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 791c248b7dSInki Dae if (!exynos_gem_obj) { 801c248b7dSInki Dae DRM_ERROR("failed to allocate exynos gem object.\n"); 811c248b7dSInki Dae return ERR_PTR(-ENOMEM); 821c248b7dSInki Dae } 831c248b7dSInki Dae 841c248b7dSInki Dae /* allocate the new buffer object and memory region. */ 851c248b7dSInki Dae entry = exynos_drm_buf_create(dev, size); 861c248b7dSInki Dae if (!entry) { 871c248b7dSInki Dae kfree(exynos_gem_obj); 881c248b7dSInki Dae return ERR_PTR(-ENOMEM); 891c248b7dSInki Dae } 901c248b7dSInki Dae 911c248b7dSInki Dae exynos_gem_obj->entry = entry; 921c248b7dSInki Dae 931c248b7dSInki Dae obj = &exynos_gem_obj->base; 941c248b7dSInki Dae 951c248b7dSInki Dae ret = drm_gem_object_init(dev, obj, size); 961c248b7dSInki Dae if (ret < 0) { 971c248b7dSInki Dae DRM_ERROR("failed to initailize gem object.\n"); 981c248b7dSInki Dae goto err_obj_init; 991c248b7dSInki Dae } 1001c248b7dSInki Dae 1011c248b7dSInki Dae DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 1021c248b7dSInki Dae 1031c248b7dSInki Dae ret = drm_gem_create_mmap_offset(obj); 1041c248b7dSInki Dae if (ret < 0) { 1051c248b7dSInki Dae DRM_ERROR("failed to allocate mmap offset.\n"); 1061c248b7dSInki Dae goto err_create_mmap_offset; 1071c248b7dSInki Dae } 1081c248b7dSInki Dae 1091c248b7dSInki Dae /* 1101c248b7dSInki Dae * allocate a id of idr table where the obj is registered 1111c248b7dSInki Dae * and handle has the id what user can see. 1121c248b7dSInki Dae */ 1131c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 1141c248b7dSInki Dae if (ret) 1151c248b7dSInki Dae goto err_handle_create; 1161c248b7dSInki Dae 1171c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 1181c248b7dSInki Dae 1191c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 1201c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 1211c248b7dSInki Dae 1221c248b7dSInki Dae return exynos_gem_obj; 1231c248b7dSInki Dae 1241c248b7dSInki Dae err_handle_create: 1251c248b7dSInki Dae drm_gem_free_mmap_offset(obj); 1261c248b7dSInki Dae 1271c248b7dSInki Dae err_create_mmap_offset: 1281c248b7dSInki Dae drm_gem_object_release(obj); 1291c248b7dSInki Dae 1301c248b7dSInki Dae err_obj_init: 1311c248b7dSInki Dae exynos_drm_buf_destroy(dev, exynos_gem_obj->entry); 1321c248b7dSInki Dae 1331c248b7dSInki Dae kfree(exynos_gem_obj); 1341c248b7dSInki Dae 1351c248b7dSInki Dae return ERR_PTR(ret); 1361c248b7dSInki Dae } 1371c248b7dSInki Dae 1381c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 1391c248b7dSInki Dae struct drm_file *file_priv) 1401c248b7dSInki Dae { 1411c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 1421c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 1431c248b7dSInki Dae 1441c248b7dSInki Dae DRM_DEBUG_KMS("%s : size = 0x%x\n", __FILE__, args->size); 1451c248b7dSInki Dae 1461c248b7dSInki Dae exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size, 1471c248b7dSInki Dae &args->handle); 1481c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 1491c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 1501c248b7dSInki Dae 1511c248b7dSInki Dae return 0; 1521c248b7dSInki Dae } 1531c248b7dSInki Dae 1541c248b7dSInki Dae int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, 1551c248b7dSInki Dae struct drm_file *file_priv) 1561c248b7dSInki Dae { 1571c248b7dSInki Dae struct drm_exynos_gem_map_off *args = data; 1581c248b7dSInki Dae 1591c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1601c248b7dSInki Dae 1611c248b7dSInki Dae DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n", 1621c248b7dSInki Dae args->handle, (unsigned long)args->offset); 1631c248b7dSInki Dae 1641c248b7dSInki Dae if (!(dev->driver->driver_features & DRIVER_GEM)) { 1651c248b7dSInki Dae DRM_ERROR("does not support GEM.\n"); 1661c248b7dSInki Dae return -ENODEV; 1671c248b7dSInki Dae } 1681c248b7dSInki Dae 1691c248b7dSInki Dae return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle, 1701c248b7dSInki Dae &args->offset); 1711c248b7dSInki Dae } 1721c248b7dSInki Dae 1731c248b7dSInki Dae static int exynos_drm_gem_mmap_buffer(struct file *filp, 1741c248b7dSInki Dae struct vm_area_struct *vma) 1751c248b7dSInki Dae { 1761c248b7dSInki Dae struct drm_gem_object *obj = filp->private_data; 1771c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 1781c248b7dSInki Dae struct exynos_drm_buf_entry *entry; 1791c248b7dSInki Dae unsigned long pfn, vm_size; 1801c248b7dSInki Dae 1811c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1821c248b7dSInki Dae 1831c248b7dSInki Dae vma->vm_flags |= (VM_IO | VM_RESERVED); 1841c248b7dSInki Dae 1851c248b7dSInki Dae vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1861c248b7dSInki Dae vma->vm_file = filp; 1871c248b7dSInki Dae 1881c248b7dSInki Dae vm_size = vma->vm_end - vma->vm_start; 1891c248b7dSInki Dae /* 1901c248b7dSInki Dae * a entry contains information to physically continuous memory 1911c248b7dSInki Dae * allocated by user request or at framebuffer creation. 1921c248b7dSInki Dae */ 1931c248b7dSInki Dae entry = exynos_gem_obj->entry; 1941c248b7dSInki Dae 1951c248b7dSInki Dae /* check if user-requested size is valid. */ 1961c248b7dSInki Dae if (vm_size > entry->size) 1971c248b7dSInki Dae return -EINVAL; 1981c248b7dSInki Dae 1991c248b7dSInki Dae /* 2001c248b7dSInki Dae * get page frame number to physical memory to be mapped 2011c248b7dSInki Dae * to user space. 2021c248b7dSInki Dae */ 2031c248b7dSInki Dae pfn = exynos_gem_obj->entry->paddr >> PAGE_SHIFT; 2041c248b7dSInki Dae 2051c248b7dSInki Dae DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn); 2061c248b7dSInki Dae 2071c248b7dSInki Dae if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size, 2081c248b7dSInki Dae vma->vm_page_prot)) { 2091c248b7dSInki Dae DRM_ERROR("failed to remap pfn range.\n"); 2101c248b7dSInki Dae return -EAGAIN; 2111c248b7dSInki Dae } 2121c248b7dSInki Dae 2131c248b7dSInki Dae return 0; 2141c248b7dSInki Dae } 2151c248b7dSInki Dae 2161c248b7dSInki Dae static const struct file_operations exynos_drm_gem_fops = { 2171c248b7dSInki Dae .mmap = exynos_drm_gem_mmap_buffer, 2181c248b7dSInki Dae }; 2191c248b7dSInki Dae 2201c248b7dSInki Dae int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 2211c248b7dSInki Dae struct drm_file *file_priv) 2221c248b7dSInki Dae { 2231c248b7dSInki Dae struct drm_exynos_gem_mmap *args = data; 2241c248b7dSInki Dae struct drm_gem_object *obj; 2251c248b7dSInki Dae unsigned int addr; 2261c248b7dSInki Dae 2271c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2281c248b7dSInki Dae 2291c248b7dSInki Dae if (!(dev->driver->driver_features & DRIVER_GEM)) { 2301c248b7dSInki Dae DRM_ERROR("does not support GEM.\n"); 2311c248b7dSInki Dae return -ENODEV; 2321c248b7dSInki Dae } 2331c248b7dSInki Dae 2341c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 2351c248b7dSInki Dae if (!obj) { 2361c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 2371c248b7dSInki Dae return -EINVAL; 2381c248b7dSInki Dae } 2391c248b7dSInki Dae 2401c248b7dSInki Dae obj->filp->f_op = &exynos_drm_gem_fops; 2411c248b7dSInki Dae obj->filp->private_data = obj; 2421c248b7dSInki Dae 2431c248b7dSInki Dae down_write(¤t->mm->mmap_sem); 2441c248b7dSInki Dae addr = do_mmap(obj->filp, 0, args->size, 2451c248b7dSInki Dae PROT_READ | PROT_WRITE, MAP_SHARED, 0); 2461c248b7dSInki Dae up_write(¤t->mm->mmap_sem); 2471c248b7dSInki Dae 2481c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 2491c248b7dSInki Dae 2501c248b7dSInki Dae if (IS_ERR((void *)addr)) 2511c248b7dSInki Dae return PTR_ERR((void *)addr); 2521c248b7dSInki Dae 2531c248b7dSInki Dae args->mapped = addr; 2541c248b7dSInki Dae 2551c248b7dSInki Dae DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped); 2561c248b7dSInki Dae 2571c248b7dSInki Dae return 0; 2581c248b7dSInki Dae } 2591c248b7dSInki Dae 2601c248b7dSInki Dae int exynos_drm_gem_init_object(struct drm_gem_object *obj) 2611c248b7dSInki Dae { 2621c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2631c248b7dSInki Dae 2641c248b7dSInki Dae return 0; 2651c248b7dSInki Dae } 2661c248b7dSInki Dae 2671c248b7dSInki Dae void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj) 2681c248b7dSInki Dae { 2691c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 2701c248b7dSInki Dae 2711c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2721c248b7dSInki Dae 2731c248b7dSInki Dae DRM_DEBUG_KMS("handle count = %d\n", 2741c248b7dSInki Dae atomic_read(&gem_obj->handle_count)); 2751c248b7dSInki Dae 2761c248b7dSInki Dae if (gem_obj->map_list.map) 2771c248b7dSInki Dae drm_gem_free_mmap_offset(gem_obj); 2781c248b7dSInki Dae 2791c248b7dSInki Dae /* release file pointer to gem object. */ 2801c248b7dSInki Dae drm_gem_object_release(gem_obj); 2811c248b7dSInki Dae 2821c248b7dSInki Dae exynos_gem_obj = to_exynos_gem_obj(gem_obj); 2831c248b7dSInki Dae 2841c248b7dSInki Dae exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->entry); 2851c248b7dSInki Dae 2861c248b7dSInki Dae kfree(exynos_gem_obj); 2871c248b7dSInki Dae } 2881c248b7dSInki Dae 2891c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 2901c248b7dSInki Dae struct drm_device *dev, struct drm_mode_create_dumb *args) 2911c248b7dSInki Dae { 2921c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 2931c248b7dSInki Dae 2941c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2951c248b7dSInki Dae 2961c248b7dSInki Dae /* 2971c248b7dSInki Dae * alocate memory to be used for framebuffer. 2981c248b7dSInki Dae * - this callback would be called by user application 2991c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 3001c248b7dSInki Dae */ 3011c248b7dSInki Dae 3021c248b7dSInki Dae args->pitch = args->width * args->bpp >> 3; 3031c248b7dSInki Dae args->size = args->pitch * args->height; 3041c248b7dSInki Dae 3051c248b7dSInki Dae exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size, 3061c248b7dSInki Dae &args->handle); 3071c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 3081c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 3091c248b7dSInki Dae 3101c248b7dSInki Dae return 0; 3111c248b7dSInki Dae } 3121c248b7dSInki Dae 3131c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 3141c248b7dSInki Dae struct drm_device *dev, uint32_t handle, uint64_t *offset) 3151c248b7dSInki Dae { 3161c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 3171c248b7dSInki Dae struct drm_gem_object *obj; 3181c248b7dSInki Dae 3191c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 3201c248b7dSInki Dae 3211c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 3221c248b7dSInki Dae 3231c248b7dSInki Dae /* 3241c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 3251c248b7dSInki Dae * - this callback would be called by user application 3261c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 3271c248b7dSInki Dae */ 3281c248b7dSInki Dae 3291c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 3301c248b7dSInki Dae if (!obj) { 3311c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 3321c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 3331c248b7dSInki Dae return -EINVAL; 3341c248b7dSInki Dae } 3351c248b7dSInki Dae 3361c248b7dSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 3371c248b7dSInki Dae 3381c248b7dSInki Dae *offset = get_gem_mmap_offset(&exynos_gem_obj->base); 3391c248b7dSInki Dae 3401c248b7dSInki Dae drm_gem_object_unreference(obj); 3411c248b7dSInki Dae 3421c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 3431c248b7dSInki Dae 3441c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 3451c248b7dSInki Dae 3461c248b7dSInki Dae return 0; 3471c248b7dSInki Dae } 3481c248b7dSInki Dae 3491c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 3501c248b7dSInki Dae { 3511c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 3521c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 3531c248b7dSInki Dae struct drm_device *dev = obj->dev; 3541c248b7dSInki Dae unsigned long pfn; 3551c248b7dSInki Dae pgoff_t page_offset; 3561c248b7dSInki Dae int ret; 3571c248b7dSInki Dae 3581c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 3591c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 3601c248b7dSInki Dae 3611c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 3621c248b7dSInki Dae 3631c248b7dSInki Dae pfn = (exynos_gem_obj->entry->paddr >> PAGE_SHIFT) + page_offset; 3641c248b7dSInki Dae 3651c248b7dSInki Dae ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 3661c248b7dSInki Dae 3671c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 3681c248b7dSInki Dae 3691c248b7dSInki Dae return convert_to_vm_err_msg(ret); 3701c248b7dSInki Dae } 3711c248b7dSInki Dae 3721c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 3731c248b7dSInki Dae { 3741c248b7dSInki Dae int ret; 3751c248b7dSInki Dae 3761c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 3771c248b7dSInki Dae 3781c248b7dSInki Dae /* set vm_area_struct. */ 3791c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 3801c248b7dSInki Dae if (ret < 0) { 3811c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 3821c248b7dSInki Dae return ret; 3831c248b7dSInki Dae } 3841c248b7dSInki Dae 3851c248b7dSInki Dae vma->vm_flags &= ~VM_PFNMAP; 3861c248b7dSInki Dae vma->vm_flags |= VM_MIXEDMAP; 3871c248b7dSInki Dae 3881c248b7dSInki Dae return ret; 3891c248b7dSInki Dae } 3901c248b7dSInki Dae 3911c248b7dSInki Dae 3921c248b7dSInki Dae int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv, 3931c248b7dSInki Dae struct drm_device *dev, unsigned int handle) 3941c248b7dSInki Dae { 3951c248b7dSInki Dae int ret; 3961c248b7dSInki Dae 3971c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 3981c248b7dSInki Dae 3991c248b7dSInki Dae /* 4001c248b7dSInki Dae * obj->refcount and obj->handle_count are decreased and 4011c248b7dSInki Dae * if both them are 0 then exynos_drm_gem_free_object() 4021c248b7dSInki Dae * would be called by callback to release resources. 4031c248b7dSInki Dae */ 4041c248b7dSInki Dae ret = drm_gem_handle_delete(file_priv, handle); 4051c248b7dSInki Dae if (ret < 0) { 4061c248b7dSInki Dae DRM_ERROR("failed to delete drm_gem_handle.\n"); 4071c248b7dSInki Dae return ret; 4081c248b7dSInki Dae } 4091c248b7dSInki Dae 4101c248b7dSInki Dae return 0; 4111c248b7dSInki Dae } 4121c248b7dSInki Dae 4131c248b7dSInki Dae MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 4141c248b7dSInki Dae MODULE_DESCRIPTION("Samsung SoC DRM GEM Module"); 4151c248b7dSInki Dae MODULE_LICENSE("GPL"); 416