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 58ee5e770eSJoonyoung Shim static struct exynos_drm_gem_obj * 59ee5e770eSJoonyoung Shim exynos_drm_gem_init(struct drm_device *drm_dev, struct drm_file *file_priv, 60ee5e770eSJoonyoung Shim unsigned int *handle, unsigned int size) 611c248b7dSInki Dae { 621c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 631c248b7dSInki Dae struct drm_gem_object *obj; 641c248b7dSInki Dae int ret; 651c248b7dSInki Dae 661c248b7dSInki Dae exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); 671c248b7dSInki Dae if (!exynos_gem_obj) { 681c248b7dSInki Dae DRM_ERROR("failed to allocate exynos gem object.\n"); 691c248b7dSInki Dae return ERR_PTR(-ENOMEM); 701c248b7dSInki Dae } 711c248b7dSInki Dae 721c248b7dSInki Dae obj = &exynos_gem_obj->base; 731c248b7dSInki Dae 74f088d5a9SInki Dae ret = drm_gem_object_init(drm_dev, obj, size); 751c248b7dSInki Dae if (ret < 0) { 76f088d5a9SInki Dae DRM_ERROR("failed to initialize gem object.\n"); 77f088d5a9SInki Dae ret = -EINVAL; 78ee5e770eSJoonyoung Shim goto err; 791c248b7dSInki Dae } 801c248b7dSInki Dae 811c248b7dSInki Dae DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); 821c248b7dSInki Dae 831c248b7dSInki Dae /* 841c248b7dSInki Dae * allocate a id of idr table where the obj is registered 851c248b7dSInki Dae * and handle has the id what user can see. 861c248b7dSInki Dae */ 871c248b7dSInki Dae ret = drm_gem_handle_create(file_priv, obj, handle); 881c248b7dSInki Dae if (ret) 892d91cf17SJoonyoung Shim goto err_release; 901c248b7dSInki Dae 911c248b7dSInki Dae DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle); 921c248b7dSInki Dae 931c248b7dSInki Dae /* drop reference from allocate - handle holds it now. */ 941c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 951c248b7dSInki Dae 961c248b7dSInki Dae return exynos_gem_obj; 971c248b7dSInki Dae 98ee5e770eSJoonyoung Shim err_release: 991c248b7dSInki Dae drm_gem_object_release(obj); 1001c248b7dSInki Dae 101ee5e770eSJoonyoung Shim err: 1021c248b7dSInki Dae kfree(exynos_gem_obj); 1031c248b7dSInki Dae return ERR_PTR(ret); 1041c248b7dSInki Dae } 1051c248b7dSInki Dae 106f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, 107f088d5a9SInki Dae struct drm_file *file_priv, 108ee5e770eSJoonyoung Shim unsigned int *handle, 109ee5e770eSJoonyoung Shim unsigned long size) 110f088d5a9SInki Dae { 111f088d5a9SInki Dae 112ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1132c871127SInki Dae struct exynos_drm_gem_buf *buffer; 114f088d5a9SInki Dae 115f088d5a9SInki Dae size = roundup(size, PAGE_SIZE); 116f088d5a9SInki Dae DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); 117f088d5a9SInki Dae 1182c871127SInki Dae buffer = exynos_drm_buf_create(dev, size); 119ee5e770eSJoonyoung Shim if (!buffer) 120ee5e770eSJoonyoung Shim return ERR_PTR(-ENOMEM); 121f088d5a9SInki Dae 122f088d5a9SInki Dae exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size); 123f088d5a9SInki Dae if (IS_ERR(exynos_gem_obj)) { 124ca22e3ccSSeung-Woo Kim exynos_drm_buf_destroy(dev, buffer); 125ca22e3ccSSeung-Woo Kim return exynos_gem_obj; 126f088d5a9SInki Dae } 127f088d5a9SInki Dae 1282c871127SInki Dae exynos_gem_obj->buffer = buffer; 129f088d5a9SInki Dae 130f088d5a9SInki Dae return exynos_gem_obj; 131f088d5a9SInki Dae } 132f088d5a9SInki Dae 1331c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, 1341c248b7dSInki Dae struct drm_file *file_priv) 1351c248b7dSInki Dae { 1361c248b7dSInki Dae struct drm_exynos_gem_create *args = data; 137ee5e770eSJoonyoung Shim struct exynos_drm_gem_obj *exynos_gem_obj; 1381c248b7dSInki Dae 139f088d5a9SInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1401c248b7dSInki Dae 141ee5e770eSJoonyoung Shim exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle, 142ee5e770eSJoonyoung Shim args->size); 1431c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 1441c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 1451c248b7dSInki Dae 1461c248b7dSInki Dae return 0; 1471c248b7dSInki Dae } 1481c248b7dSInki Dae 1491c248b7dSInki Dae int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, 1501c248b7dSInki Dae struct drm_file *file_priv) 1511c248b7dSInki Dae { 1521c248b7dSInki Dae struct drm_exynos_gem_map_off *args = data; 1531c248b7dSInki Dae 1541c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1551c248b7dSInki Dae 1561c248b7dSInki Dae DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n", 1571c248b7dSInki Dae args->handle, (unsigned long)args->offset); 1581c248b7dSInki Dae 1591c248b7dSInki Dae if (!(dev->driver->driver_features & DRIVER_GEM)) { 1601c248b7dSInki Dae DRM_ERROR("does not support GEM.\n"); 1611c248b7dSInki Dae return -ENODEV; 1621c248b7dSInki Dae } 1631c248b7dSInki Dae 1641c248b7dSInki Dae return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle, 1651c248b7dSInki Dae &args->offset); 1661c248b7dSInki Dae } 1671c248b7dSInki Dae 1681c248b7dSInki Dae static int exynos_drm_gem_mmap_buffer(struct file *filp, 1691c248b7dSInki Dae struct vm_area_struct *vma) 1701c248b7dSInki Dae { 1711c248b7dSInki Dae struct drm_gem_object *obj = filp->private_data; 1721c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 1732c871127SInki Dae struct exynos_drm_gem_buf *buffer; 1741c248b7dSInki Dae unsigned long pfn, vm_size; 1751c248b7dSInki Dae 1761c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 1771c248b7dSInki Dae 1781c248b7dSInki Dae vma->vm_flags |= (VM_IO | VM_RESERVED); 1791c248b7dSInki Dae 1801c248b7dSInki Dae vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1811c248b7dSInki Dae vma->vm_file = filp; 1821c248b7dSInki Dae 1831c248b7dSInki Dae vm_size = vma->vm_end - vma->vm_start; 1841c248b7dSInki Dae /* 1852c871127SInki Dae * a buffer contains information to physically continuous memory 1861c248b7dSInki Dae * allocated by user request or at framebuffer creation. 1871c248b7dSInki Dae */ 1882c871127SInki Dae buffer = exynos_gem_obj->buffer; 1891c248b7dSInki Dae 1901c248b7dSInki Dae /* check if user-requested size is valid. */ 1912c871127SInki Dae if (vm_size > buffer->size) 1921c248b7dSInki Dae return -EINVAL; 1931c248b7dSInki Dae 1941c248b7dSInki Dae /* 1951c248b7dSInki Dae * get page frame number to physical memory to be mapped 1961c248b7dSInki Dae * to user space. 1971c248b7dSInki Dae */ 1982c871127SInki Dae pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT; 1991c248b7dSInki Dae 2001c248b7dSInki Dae DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn); 2011c248b7dSInki Dae 2021c248b7dSInki Dae if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size, 2031c248b7dSInki Dae vma->vm_page_prot)) { 2041c248b7dSInki Dae DRM_ERROR("failed to remap pfn range.\n"); 2051c248b7dSInki Dae return -EAGAIN; 2061c248b7dSInki Dae } 2071c248b7dSInki Dae 2081c248b7dSInki Dae return 0; 2091c248b7dSInki Dae } 2101c248b7dSInki Dae 2111c248b7dSInki Dae static const struct file_operations exynos_drm_gem_fops = { 2121c248b7dSInki Dae .mmap = exynos_drm_gem_mmap_buffer, 2131c248b7dSInki Dae }; 2141c248b7dSInki Dae 2151c248b7dSInki Dae int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, 2161c248b7dSInki Dae struct drm_file *file_priv) 2171c248b7dSInki Dae { 2181c248b7dSInki Dae struct drm_exynos_gem_mmap *args = data; 2191c248b7dSInki Dae struct drm_gem_object *obj; 2201c248b7dSInki Dae unsigned int addr; 2211c248b7dSInki Dae 2221c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2231c248b7dSInki Dae 2241c248b7dSInki Dae if (!(dev->driver->driver_features & DRIVER_GEM)) { 2251c248b7dSInki Dae DRM_ERROR("does not support GEM.\n"); 2261c248b7dSInki Dae return -ENODEV; 2271c248b7dSInki Dae } 2281c248b7dSInki Dae 2291c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, args->handle); 2301c248b7dSInki Dae if (!obj) { 2311c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 2321c248b7dSInki Dae return -EINVAL; 2331c248b7dSInki Dae } 2341c248b7dSInki Dae 2351c248b7dSInki Dae obj->filp->f_op = &exynos_drm_gem_fops; 2361c248b7dSInki Dae obj->filp->private_data = obj; 2371c248b7dSInki Dae 2381c248b7dSInki Dae down_write(¤t->mm->mmap_sem); 2391c248b7dSInki Dae addr = do_mmap(obj->filp, 0, args->size, 2401c248b7dSInki Dae PROT_READ | PROT_WRITE, MAP_SHARED, 0); 2411c248b7dSInki Dae up_write(¤t->mm->mmap_sem); 2421c248b7dSInki Dae 2431c248b7dSInki Dae drm_gem_object_unreference_unlocked(obj); 2441c248b7dSInki Dae 2451c248b7dSInki Dae if (IS_ERR((void *)addr)) 2461c248b7dSInki Dae return PTR_ERR((void *)addr); 2471c248b7dSInki Dae 2481c248b7dSInki Dae args->mapped = addr; 2491c248b7dSInki Dae 2501c248b7dSInki Dae DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped); 2511c248b7dSInki Dae 2521c248b7dSInki Dae return 0; 2531c248b7dSInki Dae } 2541c248b7dSInki Dae 2551c248b7dSInki Dae int exynos_drm_gem_init_object(struct drm_gem_object *obj) 2561c248b7dSInki Dae { 2571c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2581c248b7dSInki Dae 2591c248b7dSInki Dae return 0; 2601c248b7dSInki Dae } 2611c248b7dSInki Dae 262ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj) 2631c248b7dSInki Dae { 2641c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 2651c248b7dSInki Dae 2661c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2671c248b7dSInki Dae 2681c248b7dSInki Dae DRM_DEBUG_KMS("handle count = %d\n", 269ee5e770eSJoonyoung Shim atomic_read(&obj->handle_count)); 2701c248b7dSInki Dae 271ee5e770eSJoonyoung Shim if (obj->map_list.map) 272ee5e770eSJoonyoung Shim drm_gem_free_mmap_offset(obj); 2731c248b7dSInki Dae 2741c248b7dSInki Dae /* release file pointer to gem object. */ 275ee5e770eSJoonyoung Shim drm_gem_object_release(obj); 2761c248b7dSInki Dae 277ee5e770eSJoonyoung Shim exynos_gem_obj = to_exynos_gem_obj(obj); 2781c248b7dSInki Dae 279ee5e770eSJoonyoung Shim exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer); 2801c248b7dSInki Dae 2811c248b7dSInki Dae kfree(exynos_gem_obj); 2821c248b7dSInki Dae } 2831c248b7dSInki Dae 2841c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv, 285ee5e770eSJoonyoung Shim struct drm_device *dev, 286ee5e770eSJoonyoung Shim struct drm_mode_create_dumb *args) 2871c248b7dSInki Dae { 2881c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 2891c248b7dSInki Dae 2901c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 2911c248b7dSInki Dae 2921c248b7dSInki Dae /* 2931c248b7dSInki Dae * alocate memory to be used for framebuffer. 2941c248b7dSInki Dae * - this callback would be called by user application 2951c248b7dSInki Dae * with DRM_IOCTL_MODE_CREATE_DUMB command. 2961c248b7dSInki Dae */ 2971c248b7dSInki Dae 2981c248b7dSInki Dae args->pitch = args->width * args->bpp >> 3; 2991c248b7dSInki Dae args->size = args->pitch * args->height; 3001c248b7dSInki Dae 301f088d5a9SInki Dae exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle, 302f088d5a9SInki Dae args->size); 3031c248b7dSInki Dae if (IS_ERR(exynos_gem_obj)) 3041c248b7dSInki Dae return PTR_ERR(exynos_gem_obj); 3051c248b7dSInki Dae 3061c248b7dSInki Dae return 0; 3071c248b7dSInki Dae } 3081c248b7dSInki Dae 3091c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, 310ee5e770eSJoonyoung Shim struct drm_device *dev, uint32_t handle, 311ee5e770eSJoonyoung Shim uint64_t *offset) 3121c248b7dSInki Dae { 3131c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj; 3141c248b7dSInki Dae struct drm_gem_object *obj; 3152d91cf17SJoonyoung Shim int ret = 0; 3161c248b7dSInki Dae 3171c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 3181c248b7dSInki Dae 3191c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 3201c248b7dSInki Dae 3211c248b7dSInki Dae /* 3221c248b7dSInki Dae * get offset of memory allocated for drm framebuffer. 3231c248b7dSInki Dae * - this callback would be called by user application 3241c248b7dSInki Dae * with DRM_IOCTL_MODE_MAP_DUMB command. 3251c248b7dSInki Dae */ 3261c248b7dSInki Dae 3271c248b7dSInki Dae obj = drm_gem_object_lookup(dev, file_priv, handle); 3281c248b7dSInki Dae if (!obj) { 3291c248b7dSInki Dae DRM_ERROR("failed to lookup gem object.\n"); 3302d91cf17SJoonyoung Shim ret = -EINVAL; 3312d91cf17SJoonyoung Shim goto unlock; 3321c248b7dSInki Dae } 3331c248b7dSInki Dae 3341c248b7dSInki Dae exynos_gem_obj = to_exynos_gem_obj(obj); 3351c248b7dSInki Dae 3362d91cf17SJoonyoung Shim if (!exynos_gem_obj->base.map_list.map) { 3372d91cf17SJoonyoung Shim ret = drm_gem_create_mmap_offset(&exynos_gem_obj->base); 3382d91cf17SJoonyoung Shim if (ret) 3392d91cf17SJoonyoung Shim goto out; 3402d91cf17SJoonyoung Shim } 3411c248b7dSInki Dae 3422d91cf17SJoonyoung Shim *offset = (u64)exynos_gem_obj->base.map_list.hash.key << PAGE_SHIFT; 3431c248b7dSInki Dae DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset); 3441c248b7dSInki Dae 3452d91cf17SJoonyoung Shim out: 3462d91cf17SJoonyoung Shim drm_gem_object_unreference(obj); 3472d91cf17SJoonyoung Shim unlock: 3481c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 3492d91cf17SJoonyoung Shim return ret; 3501c248b7dSInki Dae } 3511c248b7dSInki Dae 352ee5e770eSJoonyoung Shim int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv, 353ee5e770eSJoonyoung Shim struct drm_device *dev, 354ee5e770eSJoonyoung Shim unsigned int handle) 355ee5e770eSJoonyoung Shim { 356ee5e770eSJoonyoung Shim int ret; 357ee5e770eSJoonyoung Shim 358ee5e770eSJoonyoung Shim DRM_DEBUG_KMS("%s\n", __FILE__); 359ee5e770eSJoonyoung Shim 360ee5e770eSJoonyoung Shim /* 361ee5e770eSJoonyoung Shim * obj->refcount and obj->handle_count are decreased and 362ee5e770eSJoonyoung Shim * if both them are 0 then exynos_drm_gem_free_object() 363ee5e770eSJoonyoung Shim * would be called by callback to release resources. 364ee5e770eSJoonyoung Shim */ 365ee5e770eSJoonyoung Shim ret = drm_gem_handle_delete(file_priv, handle); 366ee5e770eSJoonyoung Shim if (ret < 0) { 367ee5e770eSJoonyoung Shim DRM_ERROR("failed to delete drm_gem_handle.\n"); 368ee5e770eSJoonyoung Shim return ret; 369ee5e770eSJoonyoung Shim } 370ee5e770eSJoonyoung Shim 371ee5e770eSJoonyoung Shim return 0; 372ee5e770eSJoonyoung Shim } 373ee5e770eSJoonyoung Shim 3741c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 3751c248b7dSInki Dae { 3761c248b7dSInki Dae struct drm_gem_object *obj = vma->vm_private_data; 3771c248b7dSInki Dae struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); 3781c248b7dSInki Dae struct drm_device *dev = obj->dev; 3791c248b7dSInki Dae unsigned long pfn; 3801c248b7dSInki Dae pgoff_t page_offset; 3811c248b7dSInki Dae int ret; 3821c248b7dSInki Dae 3831c248b7dSInki Dae page_offset = ((unsigned long)vmf->virtual_address - 3841c248b7dSInki Dae vma->vm_start) >> PAGE_SHIFT; 3851c248b7dSInki Dae 3861c248b7dSInki Dae mutex_lock(&dev->struct_mutex); 3871c248b7dSInki Dae 3882c871127SInki Dae pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >> 3892c871127SInki Dae PAGE_SHIFT) + page_offset; 3901c248b7dSInki Dae 3911c248b7dSInki Dae ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); 3921c248b7dSInki Dae 3931c248b7dSInki Dae mutex_unlock(&dev->struct_mutex); 3941c248b7dSInki Dae 3951c248b7dSInki Dae return convert_to_vm_err_msg(ret); 3961c248b7dSInki Dae } 3971c248b7dSInki Dae 3981c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 3991c248b7dSInki Dae { 4001c248b7dSInki Dae int ret; 4011c248b7dSInki Dae 4021c248b7dSInki Dae DRM_DEBUG_KMS("%s\n", __FILE__); 4031c248b7dSInki Dae 4041c248b7dSInki Dae /* set vm_area_struct. */ 4051c248b7dSInki Dae ret = drm_gem_mmap(filp, vma); 4061c248b7dSInki Dae if (ret < 0) { 4071c248b7dSInki Dae DRM_ERROR("failed to mmap.\n"); 4081c248b7dSInki Dae return ret; 4091c248b7dSInki Dae } 4101c248b7dSInki Dae 4111c248b7dSInki Dae vma->vm_flags &= ~VM_PFNMAP; 4121c248b7dSInki Dae vma->vm_flags |= VM_MIXEDMAP; 4131c248b7dSInki Dae 4141c248b7dSInki Dae return ret; 4151c248b7dSInki Dae } 4161c248b7dSInki Dae 4171c248b7dSInki Dae MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 4181c248b7dSInki Dae MODULE_DESCRIPTION("Samsung SoC DRM GEM Module"); 4191c248b7dSInki Dae MODULE_LICENSE("GPL"); 420