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(&current->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(&current->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