xref: /dflybsd-src/sys/dev/drm/drm_gem.c (revision 11050bbcfb34283a9d27bc1ded58120cc5862897)
1d2c87355SFrançois Tigeot /*
2d2c87355SFrançois Tigeot  * Copyright © 2008 Intel Corporation
3d2c87355SFrançois Tigeot  *
4d2c87355SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5d2c87355SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6d2c87355SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7d2c87355SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d2c87355SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9d2c87355SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10d2c87355SFrançois Tigeot  *
11d2c87355SFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12d2c87355SFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13d2c87355SFrançois Tigeot  * Software.
14d2c87355SFrançois Tigeot  *
15d2c87355SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16d2c87355SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17d2c87355SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18d2c87355SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19d2c87355SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20d2c87355SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21d2c87355SFrançois Tigeot  * IN THE SOFTWARE.
22d2c87355SFrançois Tigeot  *
23d2c87355SFrançois Tigeot  * Authors:
24d2c87355SFrançois Tigeot  *    Eric Anholt <eric@anholt.net>
25d2c87355SFrançois Tigeot  *
26d2c87355SFrançois Tigeot  */
275718399fSFrançois Tigeot /*-
285718399fSFrançois Tigeot  * Copyright (c) 2011 The FreeBSD Foundation
295718399fSFrançois Tigeot  * All rights reserved.
305718399fSFrançois Tigeot  *
315718399fSFrançois Tigeot  * This software was developed by Konstantin Belousov under sponsorship from
325718399fSFrançois Tigeot  * the FreeBSD Foundation.
335718399fSFrançois Tigeot  *
345718399fSFrançois Tigeot  * Redistribution and use in source and binary forms, with or without
355718399fSFrançois Tigeot  * modification, are permitted provided that the following conditions
365718399fSFrançois Tigeot  * are met:
375718399fSFrançois Tigeot  * 1. Redistributions of source code must retain the above copyright
385718399fSFrançois Tigeot  *    notice, this list of conditions and the following disclaimer.
395718399fSFrançois Tigeot  * 2. Redistributions in binary form must reproduce the above copyright
405718399fSFrançois Tigeot  *    notice, this list of conditions and the following disclaimer in the
415718399fSFrançois Tigeot  *    documentation and/or other materials provided with the distribution.
425718399fSFrançois Tigeot  *
435718399fSFrançois Tigeot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
445718399fSFrançois Tigeot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
455718399fSFrançois Tigeot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
465718399fSFrançois Tigeot  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
475718399fSFrançois Tigeot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
485718399fSFrançois Tigeot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
495718399fSFrançois Tigeot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
505718399fSFrançois Tigeot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
515718399fSFrançois Tigeot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
525718399fSFrançois Tigeot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
535718399fSFrançois Tigeot  * SUCH DAMAGE.
545718399fSFrançois Tigeot  */
555718399fSFrançois Tigeot 
56a85cb24fSFrançois Tigeot #include <linux/types.h>
57a85cb24fSFrançois Tigeot #include <linux/slab.h>
58a85cb24fSFrançois Tigeot #include <linux/mm.h>
59a85cb24fSFrançois Tigeot #include <linux/uaccess.h>
60a85cb24fSFrançois Tigeot #include <linux/fs.h>
61a85cb24fSFrançois Tigeot #include <linux/file.h>
62a85cb24fSFrançois Tigeot #include <linux/module.h>
63*3f2dd94aSFrançois Tigeot #include <linux/mman.h>
64a85cb24fSFrançois Tigeot #include <linux/pagemap.h>
65a85cb24fSFrançois Tigeot #include <linux/shmem_fs.h>
66a85cb24fSFrançois Tigeot #include <linux/dma-buf.h>
67a85cb24fSFrançois Tigeot #include <drm/drmP.h>
68a85cb24fSFrançois Tigeot #include <drm/drm_vma_manager.h>
69a85cb24fSFrançois Tigeot #include <drm/drm_gem.h>
70a85cb24fSFrançois Tigeot #include "drm_internal.h"
715718399fSFrançois Tigeot 
72a85cb24fSFrançois Tigeot #ifdef __DragonFly__
73a85cb24fSFrançois Tigeot struct drm_gem_mm {
74a85cb24fSFrançois Tigeot 	struct drm_mm offset_manager;	/**< Offset mgmt for buffer objects */
75a85cb24fSFrançois Tigeot 	struct drm_open_hash offset_hash; /**< User token hash table for maps */
76a85cb24fSFrançois Tigeot 	struct unrhdr *idxunr;
77a85cb24fSFrançois Tigeot };
78a85cb24fSFrançois Tigeot #endif
795718399fSFrançois Tigeot 
80d2c87355SFrançois Tigeot /** @file drm_gem.c
81d2c87355SFrançois Tigeot  *
82d2c87355SFrançois Tigeot  * This file provides some of the base ioctls and library routines for
83d2c87355SFrançois Tigeot  * the graphics memory manager implemented by each device driver.
84d2c87355SFrançois Tigeot  *
85d2c87355SFrançois Tigeot  * Because various devices have different requirements in terms of
86d2c87355SFrançois Tigeot  * synchronization and migration strategies, implementing that is left up to
87d2c87355SFrançois Tigeot  * the driver, and all that the general API provides should be generic --
88d2c87355SFrançois Tigeot  * allocating objects, reading/writing data with the cpu, freeing objects.
89d2c87355SFrançois Tigeot  * Even there, platform-dependent optimizations for reading/writing data with
90d2c87355SFrançois Tigeot  * the CPU mean we'll likely hook those out to driver-specific calls.  However,
91d2c87355SFrançois Tigeot  * the DRI2 implementation wants to have at least allocate/mmap be generic.
92d2c87355SFrançois Tigeot  *
93d2c87355SFrançois Tigeot  * The goal was to have swap-backed object allocation managed through
94d2c87355SFrançois Tigeot  * struct file.  However, file descriptors as handles to a struct file have
95d2c87355SFrançois Tigeot  * two major failings:
96d2c87355SFrançois Tigeot  * - Process limits prevent more than 1024 or so being used at a time by
97d2c87355SFrançois Tigeot  *   default.
98d2c87355SFrançois Tigeot  * - Inability to allocate high fds will aggravate the X Server's select()
99d2c87355SFrançois Tigeot  *   handling, and likely that of many GL client applications as well.
100d2c87355SFrançois Tigeot  *
101d2c87355SFrançois Tigeot  * This led to a plan of using our own integer IDs (called handles, following
102d2c87355SFrançois Tigeot  * DRM terminology) to mimic fds, and implement the fd syscalls we need as
103d2c87355SFrançois Tigeot  * ioctls.  The objects themselves will still include the struct file so
104d2c87355SFrançois Tigeot  * that we can transition to fds if the required kernel infrastructure shows
105d2c87355SFrançois Tigeot  * up at a later date, and as our interface with shmfs for memory allocation.
106d2c87355SFrançois Tigeot  */
107d2c87355SFrançois Tigeot 
1085718399fSFrançois Tigeot /*
1095718399fSFrançois Tigeot  * We make up offsets for buffer objects so we can recognize them at
1105718399fSFrançois Tigeot  * mmap time.
1115718399fSFrançois Tigeot  */
1125718399fSFrançois Tigeot 
1135718399fSFrançois Tigeot /* pgoff in mmap is an unsigned long, so we need to make sure that
1145718399fSFrançois Tigeot  * the faked up offset will fit
1155718399fSFrançois Tigeot  */
1165718399fSFrançois Tigeot 
117d2c87355SFrançois Tigeot #if BITS_PER_LONG == 64
1185718399fSFrançois Tigeot #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
1195718399fSFrançois Tigeot #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
1205718399fSFrançois Tigeot #else
1215718399fSFrançois Tigeot #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
1225718399fSFrançois Tigeot #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
1235718399fSFrançois Tigeot #endif
1245718399fSFrançois Tigeot 
125c7e1c9ddSFrançois Tigeot /**
126ba55f2f5SFrançois Tigeot  * drm_gem_init - Initialize the GEM device fields
127ba55f2f5SFrançois Tigeot  * @dev: drm_devic structure to initialize
128c7e1c9ddSFrançois Tigeot  */
1295718399fSFrançois Tigeot int
drm_gem_init(struct drm_device * dev)1305718399fSFrançois Tigeot drm_gem_init(struct drm_device *dev)
1315718399fSFrançois Tigeot {
1325718399fSFrançois Tigeot 	struct drm_gem_mm *mm;
133*3f2dd94aSFrançois Tigeot 	struct drm_vma_offset_manager *vma_offset_manager;
1345718399fSFrançois Tigeot 
13598a11977SFrançois Tigeot 	lockinit(&dev->object_name_lock, "objnam", 0, LK_CANRECURSE);
136c7e1c9ddSFrançois Tigeot 	idr_init(&dev->object_name_idr);
137c7e1c9ddSFrançois Tigeot 
138d2c87355SFrançois Tigeot 	mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
139*3f2dd94aSFrançois Tigeot 	vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL);
140*3f2dd94aSFrançois Tigeot 	if (!vma_offset_manager) {
141c7e1c9ddSFrançois Tigeot 		DRM_ERROR("out of memory\n");
142c7e1c9ddSFrançois Tigeot 		return -ENOMEM;
1435718399fSFrançois Tigeot 	}
144c7e1c9ddSFrançois Tigeot 
145c7e1c9ddSFrançois Tigeot 	dev->mm_private = mm;
146c7e1c9ddSFrançois Tigeot 
147c7e1c9ddSFrançois Tigeot 	if (drm_ht_create(&mm->offset_hash, 12)) {
148d2c87355SFrançois Tigeot 		kfree(mm);
149c7e1c9ddSFrançois Tigeot 		return -ENOMEM;
150c7e1c9ddSFrançois Tigeot 	}
151c7e1c9ddSFrançois Tigeot 
1525718399fSFrançois Tigeot 	mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL);
15340c22ea1SFrançois Tigeot 	drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
15440c22ea1SFrançois Tigeot 		    DRM_FILE_PAGE_OFFSET_SIZE);
155*3f2dd94aSFrançois Tigeot 
156*3f2dd94aSFrançois Tigeot 	dev->vma_offset_manager = vma_offset_manager;
157*3f2dd94aSFrançois Tigeot 	drm_vma_offset_manager_init(vma_offset_manager,
1589edbd4a0SFrançois Tigeot 				    DRM_FILE_PAGE_OFFSET_START,
1599edbd4a0SFrançois Tigeot 				    DRM_FILE_PAGE_OFFSET_SIZE);
160ba55f2f5SFrançois Tigeot 
161c7e1c9ddSFrançois Tigeot 	return 0;
1625718399fSFrançois Tigeot }
1635718399fSFrançois Tigeot 
1645718399fSFrançois Tigeot void
drm_gem_destroy(struct drm_device * dev)1655718399fSFrançois Tigeot drm_gem_destroy(struct drm_device *dev)
1665718399fSFrançois Tigeot {
167c7e1c9ddSFrançois Tigeot 	struct drm_gem_mm *mm = dev->mm_private;
1685718399fSFrançois Tigeot 
16940c22ea1SFrançois Tigeot 	drm_mm_takedown(&mm->offset_manager);
1705718399fSFrançois Tigeot 	drm_ht_remove(&mm->offset_hash);
1715718399fSFrançois Tigeot 	delete_unrhdr(mm->idxunr);
172d2c87355SFrançois Tigeot 	kfree(mm);
173c7e1c9ddSFrançois Tigeot 	dev->mm_private = NULL;
174*3f2dd94aSFrançois Tigeot 
175*3f2dd94aSFrançois Tigeot 	drm_vma_offset_manager_destroy(dev->vma_offset_manager);
176*3f2dd94aSFrançois Tigeot 	kfree(dev->vma_offset_manager);
177*3f2dd94aSFrançois Tigeot 	dev->vma_offset_manager = NULL;
1785718399fSFrançois Tigeot }
1795718399fSFrançois Tigeot 
1807ed079a2SFrançois Tigeot /**
181a85cb24fSFrançois Tigeot  * drm_gem_object_init - initialize an allocated shmem-backed GEM object
182a85cb24fSFrançois Tigeot  * @dev: drm_device the object should be initialized for
183a85cb24fSFrançois Tigeot  * @obj: drm_gem_object to initialize
184a85cb24fSFrançois Tigeot  * @size: object size
185a85cb24fSFrançois Tigeot  *
1867ed079a2SFrançois Tigeot  * Initialize an already allocated GEM object of the specified size with
1877ed079a2SFrançois Tigeot  * shmfs backing store.
1887ed079a2SFrançois Tigeot  */
drm_gem_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size)1897ed079a2SFrançois Tigeot int drm_gem_object_init(struct drm_device *dev,
1907ed079a2SFrançois Tigeot 			struct drm_gem_object *obj, size_t size)
1915718399fSFrançois Tigeot {
192*3f2dd94aSFrançois Tigeot 	struct vm_object *filp;
193*3f2dd94aSFrançois Tigeot 
194ba55f2f5SFrançois Tigeot 	drm_gem_private_object_init(dev, obj, size);
1955718399fSFrançois Tigeot 
196*3f2dd94aSFrançois Tigeot 	filp = default_pager_alloc(NULL, size,
1975718399fSFrançois Tigeot 	    VM_PROT_READ | VM_PROT_WRITE, 0);
1985718399fSFrançois Tigeot 
199*3f2dd94aSFrançois Tigeot 	obj->filp = filp;
200*3f2dd94aSFrançois Tigeot 
201d2c87355SFrançois Tigeot 	return 0;
2025718399fSFrançois Tigeot }
203d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_init);
2045718399fSFrançois Tigeot 
2057ed079a2SFrançois Tigeot /**
206a85cb24fSFrançois Tigeot  * drm_gem_private_object_init - initialize an allocated private GEM object
207ba55f2f5SFrançois Tigeot  * @dev: drm_device the object should be initialized for
208ba55f2f5SFrançois Tigeot  * @obj: drm_gem_object to initialize
209ba55f2f5SFrançois Tigeot  * @size: object size
210ba55f2f5SFrançois Tigeot  *
2117ed079a2SFrançois Tigeot  * Initialize an already allocated GEM object of the specified size with
2127ed079a2SFrançois Tigeot  * no GEM provided backing store. Instead the caller is responsible for
2137ed079a2SFrançois Tigeot  * backing the object and handling it.
2147ed079a2SFrançois Tigeot  */
drm_gem_private_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size)2159edbd4a0SFrançois Tigeot void drm_gem_private_object_init(struct drm_device *dev,
2167ed079a2SFrançois Tigeot 				 struct drm_gem_object *obj, size_t size)
2175718399fSFrançois Tigeot {
218d2c87355SFrançois Tigeot 	BUG_ON((size & (PAGE_SIZE - 1)) != 0);
2195718399fSFrançois Tigeot 
2205718399fSFrançois Tigeot 	obj->dev = dev;
2217ca4ece0SFrançois Tigeot 	obj->filp = NULL;
2225718399fSFrançois Tigeot 
2237ed079a2SFrançois Tigeot 	kref_init(&obj->refcount);
224ba55f2f5SFrançois Tigeot 	obj->handle_count = 0;
2255718399fSFrançois Tigeot 	obj->size = size;
2269edbd4a0SFrançois Tigeot 	drm_vma_node_reset(&obj->vma_node);
2275718399fSFrançois Tigeot }
228d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_private_object_init);
2295718399fSFrançois Tigeot 
230d2c87355SFrançois Tigeot static void
drm_gem_remove_prime_handles(struct drm_gem_object * obj,struct drm_file * filp)231d2c87355SFrançois Tigeot drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
2325718399fSFrançois Tigeot {
2337ca4ece0SFrançois Tigeot 	/*
2347ca4ece0SFrançois Tigeot 	 * Note: obj->dma_buf can't disappear as long as we still hold a
2357ca4ece0SFrançois Tigeot 	 * handle reference in obj->handle_count.
2367ca4ece0SFrançois Tigeot 	 */
2377ca4ece0SFrançois Tigeot 	mutex_lock(&filp->prime.lock);
2387ca4ece0SFrançois Tigeot 	if (obj->dma_buf) {
2397ca4ece0SFrançois Tigeot 		drm_prime_remove_buf_handle_locked(&filp->prime,
2407ca4ece0SFrançois Tigeot 						   obj->dma_buf);
241c7e1c9ddSFrançois Tigeot 	}
2427ca4ece0SFrançois Tigeot 	mutex_unlock(&filp->prime.lock);
243ba55f2f5SFrançois Tigeot }
244ba55f2f5SFrançois Tigeot 
245c7e1c9ddSFrançois Tigeot /**
2467ca4ece0SFrançois Tigeot  * drm_gem_object_handle_free - release resources bound to userspace handles
247ba55f2f5SFrançois Tigeot  * @obj: GEM object to clean up.
248ba55f2f5SFrançois Tigeot  *
2499edbd4a0SFrançois Tigeot  * Called after the last handle to the object has been closed
2509edbd4a0SFrançois Tigeot  *
2519edbd4a0SFrançois Tigeot  * Removes any name for the object. Note that this must be
2529edbd4a0SFrançois Tigeot  * called before drm_gem_object_free or we'll be touching
2539edbd4a0SFrançois Tigeot  * freed memory
2549edbd4a0SFrançois Tigeot  */
drm_gem_object_handle_free(struct drm_gem_object * obj)2559edbd4a0SFrançois Tigeot static void drm_gem_object_handle_free(struct drm_gem_object *obj)
2569edbd4a0SFrançois Tigeot {
2579edbd4a0SFrançois Tigeot 	struct drm_device *dev = obj->dev;
2589edbd4a0SFrançois Tigeot 
2599edbd4a0SFrançois Tigeot 	/* Remove any name for this object */
2609edbd4a0SFrançois Tigeot 	if (obj->name) {
2619edbd4a0SFrançois Tigeot 		idr_remove(&dev->object_name_idr, obj->name);
2629edbd4a0SFrançois Tigeot 		obj->name = 0;
2639edbd4a0SFrançois Tigeot 	}
2649edbd4a0SFrançois Tigeot }
2659edbd4a0SFrançois Tigeot 
drm_gem_object_exported_dma_buf_free(struct drm_gem_object * obj)2669edbd4a0SFrançois Tigeot static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
2679edbd4a0SFrançois Tigeot {
2689edbd4a0SFrançois Tigeot 	/* Unbreak the reference cycle if we have an exported dma_buf. */
2699edbd4a0SFrançois Tigeot 	if (obj->dma_buf) {
2709edbd4a0SFrançois Tigeot 		dma_buf_put(obj->dma_buf);
2719edbd4a0SFrançois Tigeot 		obj->dma_buf = NULL;
2729edbd4a0SFrançois Tigeot 	}
2737ca4ece0SFrançois Tigeot }
2749edbd4a0SFrançois Tigeot 
2759edbd4a0SFrançois Tigeot static void
drm_gem_object_handle_put_unlocked(struct drm_gem_object * obj)276a85cb24fSFrançois Tigeot drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
2779edbd4a0SFrançois Tigeot {
2787ca4ece0SFrançois Tigeot 	struct drm_device *dev = obj->dev;
2794be47400SFrançois Tigeot 	bool final = false;
2807ca4ece0SFrançois Tigeot 
281ba55f2f5SFrançois Tigeot 	if (WARN_ON(obj->handle_count == 0))
2829edbd4a0SFrançois Tigeot 		return;
2839edbd4a0SFrançois Tigeot 
2849edbd4a0SFrançois Tigeot 	/*
2859edbd4a0SFrançois Tigeot 	* Must bump handle count first as this may be the last
2869edbd4a0SFrançois Tigeot 	* ref, in which case the object would disappear before we
2879edbd4a0SFrançois Tigeot 	* checked for a name
2889edbd4a0SFrançois Tigeot 	*/
2899edbd4a0SFrançois Tigeot 
2907ca4ece0SFrançois Tigeot 	mutex_lock(&dev->object_name_lock);
2917ca4ece0SFrançois Tigeot 	if (--obj->handle_count == 0) {
2929edbd4a0SFrançois Tigeot 		drm_gem_object_handle_free(obj);
2937ca4ece0SFrançois Tigeot 		drm_gem_object_exported_dma_buf_free(obj);
2944be47400SFrançois Tigeot 		final = true;
2957ca4ece0SFrançois Tigeot 	}
2967ca4ece0SFrançois Tigeot 	mutex_unlock(&dev->object_name_lock);
297ba55f2f5SFrançois Tigeot 
2984be47400SFrançois Tigeot 	if (final)
299a85cb24fSFrançois Tigeot 		drm_gem_object_put_unlocked(obj);
3009edbd4a0SFrançois Tigeot }
3019edbd4a0SFrançois Tigeot 
3028621f407SFrançois Tigeot /*
3037ca4ece0SFrançois Tigeot  * Called at device or object close to release the file's
3048621f407SFrançois Tigeot  * handle references on objects.
3058621f407SFrançois Tigeot  */
3068621f407SFrançois Tigeot static int
drm_gem_object_release_handle(int id,void * ptr,void * data)3078621f407SFrançois Tigeot drm_gem_object_release_handle(int id, void *ptr, void *data)
3088621f407SFrançois Tigeot {
3098621f407SFrançois Tigeot 	struct drm_file *file_priv = data;
3108621f407SFrançois Tigeot 	struct drm_gem_object *obj = ptr;
3118621f407SFrançois Tigeot 	struct drm_device *dev = obj->dev;
3128621f407SFrançois Tigeot 
313a85cb24fSFrançois Tigeot 	if (dev->driver->gem_close_object)
314a85cb24fSFrançois Tigeot 		dev->driver->gem_close_object(obj, file_priv);
315a85cb24fSFrançois Tigeot 
3164be47400SFrançois Tigeot 	if (drm_core_check_feature(dev, DRIVER_PRIME))
3178621f407SFrançois Tigeot 		drm_gem_remove_prime_handles(obj, file_priv);
3184be47400SFrançois Tigeot 	drm_vma_node_revoke(&obj->vma_node, file_priv);
3198621f407SFrançois Tigeot 
320a85cb24fSFrançois Tigeot 	drm_gem_object_handle_put_unlocked(obj);
3218621f407SFrançois Tigeot 
3228621f407SFrançois Tigeot 	return 0;
3238621f407SFrançois Tigeot }
3248621f407SFrançois Tigeot 
3259edbd4a0SFrançois Tigeot /**
326ba55f2f5SFrançois Tigeot  * drm_gem_handle_delete - deletes the given file-private handle
327ba55f2f5SFrançois Tigeot  * @filp: drm file-private structure to use for the handle look up
328ba55f2f5SFrançois Tigeot  * @handle: userspace handle to delete
329ba55f2f5SFrançois Tigeot  *
330aee94f86SFrançois Tigeot  * Removes the GEM handle from the @filp lookup table which has been added with
331aee94f86SFrançois Tigeot  * drm_gem_handle_create(). If this is the last handle also cleans up linked
332aee94f86SFrançois Tigeot  * resources like GEM names.
333c7e1c9ddSFrançois Tigeot  */
334c7e1c9ddSFrançois Tigeot int
drm_gem_handle_delete(struct drm_file * filp,u32 handle)335c7e1c9ddSFrançois Tigeot drm_gem_handle_delete(struct drm_file *filp, u32 handle)
3365718399fSFrançois Tigeot {
337c7e1c9ddSFrançois Tigeot 	struct drm_gem_object *obj;
3385718399fSFrançois Tigeot 
339c7e1c9ddSFrançois Tigeot 	/* This is gross. The idr system doesn't let us try a delete and
340c7e1c9ddSFrançois Tigeot 	 * return an error code.  It just spews if you fail at deleting.
341c7e1c9ddSFrançois Tigeot 	 * So, we have to grab a lock around finding the object and then
342c7e1c9ddSFrançois Tigeot 	 * doing the delete on it and dropping the refcount, or the user
343c7e1c9ddSFrançois Tigeot 	 * could race us to double-decrement the refcount and cause a
344c7e1c9ddSFrançois Tigeot 	 * use-after-free later.  Given the frequency of our handle lookups,
345c7e1c9ddSFrançois Tigeot 	 * we may want to use ida for number allocation and a hash table
346c7e1c9ddSFrançois Tigeot 	 * for the pointers, anyway.
347c7e1c9ddSFrançois Tigeot 	 */
34898a11977SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_EXCLUSIVE);
349c7e1c9ddSFrançois Tigeot 
350c7e1c9ddSFrançois Tigeot 	/* Check if we currently have a reference on the object */
3514be47400SFrançois Tigeot 	obj = idr_replace(&filp->object_idr, NULL, handle);
35298a11977SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_RELEASE);
3534be47400SFrançois Tigeot 	if (IS_ERR_OR_NULL(obj))
354c7e1c9ddSFrançois Tigeot 		return -EINVAL;
355c7e1c9ddSFrançois Tigeot 
3564be47400SFrançois Tigeot 	/* Release driver's reference and decrement refcount. */
3574be47400SFrançois Tigeot 	drm_gem_object_release_handle(handle, obj, filp);
3584be47400SFrançois Tigeot 
3594be47400SFrançois Tigeot 	/* And finally make the handle available for future allocations. */
3604be47400SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_EXCLUSIVE);
361c7e1c9ddSFrançois Tigeot 	idr_remove(&filp->object_idr, handle);
36298a11977SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_RELEASE);
363c7e1c9ddSFrançois Tigeot 
364c7e1c9ddSFrançois Tigeot 	return 0;
3655718399fSFrançois Tigeot }
366d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_handle_delete);
3675718399fSFrançois Tigeot 
368c7e1c9ddSFrançois Tigeot /**
369*3f2dd94aSFrançois Tigeot  * drm_gem_dumb_map_offset - return the fake mmap offset for a gem object
370*3f2dd94aSFrançois Tigeot  * @file: drm file-private structure containing the gem object
371*3f2dd94aSFrançois Tigeot  * @dev: corresponding drm_device
372*3f2dd94aSFrançois Tigeot  * @handle: gem object handle
373*3f2dd94aSFrançois Tigeot  * @offset: return location for the fake mmap offset
374*3f2dd94aSFrançois Tigeot  *
375*3f2dd94aSFrançois Tigeot  * This implements the &drm_driver.dumb_map_offset kms driver callback for
376*3f2dd94aSFrançois Tigeot  * drivers which use gem to manage their backing storage.
377*3f2dd94aSFrançois Tigeot  *
378*3f2dd94aSFrançois Tigeot  * Returns:
379*3f2dd94aSFrançois Tigeot  * 0 on success or a negative error code on failure.
380*3f2dd94aSFrançois Tigeot  */
drm_gem_dumb_map_offset(struct drm_file * file,struct drm_device * dev,u32 handle,u64 * offset)381*3f2dd94aSFrançois Tigeot int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
382*3f2dd94aSFrançois Tigeot 			    u32 handle, u64 *offset)
383*3f2dd94aSFrançois Tigeot {
384*3f2dd94aSFrançois Tigeot 	struct drm_gem_object *obj;
385*3f2dd94aSFrançois Tigeot 	int ret;
386*3f2dd94aSFrançois Tigeot 
387*3f2dd94aSFrançois Tigeot 	obj = drm_gem_object_lookup(file, handle);
388*3f2dd94aSFrançois Tigeot 	if (!obj)
389*3f2dd94aSFrançois Tigeot 		return -ENOENT;
390*3f2dd94aSFrançois Tigeot 
391*3f2dd94aSFrançois Tigeot 	/* Don't allow imported objects to be mapped */
392*3f2dd94aSFrançois Tigeot 	if (obj->import_attach) {
393*3f2dd94aSFrançois Tigeot 		ret = -EINVAL;
394*3f2dd94aSFrançois Tigeot 		goto out;
395*3f2dd94aSFrançois Tigeot 	}
396*3f2dd94aSFrançois Tigeot 
397*3f2dd94aSFrançois Tigeot 	ret = drm_gem_create_mmap_offset(obj);
398*3f2dd94aSFrançois Tigeot 	if (ret)
399*3f2dd94aSFrançois Tigeot 		goto out;
400*3f2dd94aSFrançois Tigeot 
401*3f2dd94aSFrançois Tigeot 	*offset = drm_vma_node_offset_addr(&obj->vma_node);
402*3f2dd94aSFrançois Tigeot out:
403*3f2dd94aSFrançois Tigeot 	drm_gem_object_put_unlocked(obj);
404*3f2dd94aSFrançois Tigeot 
405*3f2dd94aSFrançois Tigeot 	return ret;
406*3f2dd94aSFrançois Tigeot }
407*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL_GPL(drm_gem_dumb_map_offset);
408*3f2dd94aSFrançois Tigeot 
409*3f2dd94aSFrançois Tigeot /**
4109edbd4a0SFrançois Tigeot  * drm_gem_dumb_destroy - dumb fb callback helper for gem based drivers
411ba55f2f5SFrançois Tigeot  * @file: drm file-private structure to remove the dumb handle from
412ba55f2f5SFrançois Tigeot  * @dev: corresponding drm_device
413ba55f2f5SFrançois Tigeot  * @handle: the dumb handle to remove
4149edbd4a0SFrançois Tigeot  *
415a85cb24fSFrançois Tigeot  * This implements the &drm_driver.dumb_destroy kms driver callback for drivers
416a85cb24fSFrançois Tigeot  * which use gem to manage their backing storage.
4179edbd4a0SFrançois Tigeot  */
drm_gem_dumb_destroy(struct drm_file * file,struct drm_device * dev,uint32_t handle)4189edbd4a0SFrançois Tigeot int drm_gem_dumb_destroy(struct drm_file *file,
4199edbd4a0SFrançois Tigeot 			 struct drm_device *dev,
4209edbd4a0SFrançois Tigeot 			 uint32_t handle)
4219edbd4a0SFrançois Tigeot {
4229edbd4a0SFrançois Tigeot 	return drm_gem_handle_delete(file, handle);
4239edbd4a0SFrançois Tigeot }
4249edbd4a0SFrançois Tigeot EXPORT_SYMBOL(drm_gem_dumb_destroy);
4259edbd4a0SFrançois Tigeot 
4269edbd4a0SFrançois Tigeot /**
4272c9916cdSFrançois Tigeot  * drm_gem_handle_create_tail - internal functions to create a handle
4282c9916cdSFrançois Tigeot  * @file_priv: drm file-private structure to register the handle for
4292c9916cdSFrançois Tigeot  * @obj: object to register
4302c9916cdSFrançois Tigeot  * @handlep: pointer to return the created handle to the caller
4312c9916cdSFrançois Tigeot  *
432a85cb24fSFrançois Tigeot  * This expects the &drm_device.object_name_lock to be held already and will
433a85cb24fSFrançois Tigeot  * drop it before returning. Used to avoid races in establishing new handles
434a85cb24fSFrançois Tigeot  * when importing an object from either an flink name or a dma-buf.
435aee94f86SFrançois Tigeot  *
436aee94f86SFrançois Tigeot  * Handles must be release again through drm_gem_handle_delete(). This is done
437aee94f86SFrançois Tigeot  * when userspace closes @file_priv for all attached handles, or through the
438aee94f86SFrançois Tigeot  * GEM_CLOSE ioctl for individual handles.
439c7e1c9ddSFrançois Tigeot  */
4405718399fSFrançois Tigeot int
drm_gem_handle_create_tail(struct drm_file * file_priv,struct drm_gem_object * obj,u32 * handlep)4412c9916cdSFrançois Tigeot drm_gem_handle_create_tail(struct drm_file *file_priv,
442c7e1c9ddSFrançois Tigeot 			   struct drm_gem_object *obj,
443c7e1c9ddSFrançois Tigeot 			   u32 *handlep)
4445718399fSFrançois Tigeot {
4456f486c69SFrançois Tigeot 	struct drm_device *dev = obj->dev;
4464be47400SFrançois Tigeot 	u32 handle;
4476f486c69SFrançois Tigeot 	int ret;
4485718399fSFrançois Tigeot 
4492c9916cdSFrançois Tigeot 	WARN_ON(!mutex_is_locked(&dev->object_name_lock));
4504be47400SFrançois Tigeot 	if (obj->handle_count++ == 0)
451a85cb24fSFrançois Tigeot 		drm_gem_object_get(obj);
4522c9916cdSFrançois Tigeot 
453c7e1c9ddSFrançois Tigeot 	/*
4542c9916cdSFrançois Tigeot 	 * Get the user-visible handle using idr.  Preload and perform
4552c9916cdSFrançois Tigeot 	 * allocation under our spinlock.
456c7e1c9ddSFrançois Tigeot 	 */
457ba55f2f5SFrançois Tigeot 	idr_preload(GFP_KERNEL);
45898a11977SFrançois Tigeot 	lockmgr(&file_priv->table_lock, LK_EXCLUSIVE);
459c7e1c9ddSFrançois Tigeot 
460ba55f2f5SFrançois Tigeot 	ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
4614be47400SFrançois Tigeot 
462ba55f2f5SFrançois Tigeot 	lockmgr(&file_priv->table_lock, LK_RELEASE);
463ba55f2f5SFrançois Tigeot 	idr_preload_end();
464ba55f2f5SFrançois Tigeot 
4654be47400SFrançois Tigeot 	mutex_unlock(&dev->object_name_lock);
4664be47400SFrançois Tigeot 	if (ret < 0)
4674be47400SFrançois Tigeot 		goto err_unref;
4684be47400SFrançois Tigeot 
4694be47400SFrançois Tigeot 	handle = ret;
4704be47400SFrançois Tigeot 
4714be47400SFrançois Tigeot 	ret = drm_vma_node_allow(&obj->vma_node, file_priv);
4724be47400SFrançois Tigeot 	if (ret)
4734be47400SFrançois Tigeot 		goto err_remove;
4746f486c69SFrançois Tigeot 
4756f486c69SFrançois Tigeot 	if (dev->driver->gem_open_object) {
4766f486c69SFrançois Tigeot 		ret = dev->driver->gem_open_object(obj, file_priv);
4774be47400SFrançois Tigeot 		if (ret)
4784be47400SFrançois Tigeot 			goto err_revoke;
4796f486c69SFrançois Tigeot 	}
4806f486c69SFrançois Tigeot 
4814be47400SFrançois Tigeot 	*handlep = handle;
482c7e1c9ddSFrançois Tigeot 	return 0;
4834be47400SFrançois Tigeot 
4844be47400SFrançois Tigeot err_revoke:
4854be47400SFrançois Tigeot 	drm_vma_node_revoke(&obj->vma_node, file_priv);
4864be47400SFrançois Tigeot err_remove:
4874be47400SFrançois Tigeot 	lockmgr(&file_priv->table_lock, LK_EXCLUSIVE);
4884be47400SFrançois Tigeot 	idr_remove(&file_priv->object_idr, handle);
4894be47400SFrançois Tigeot 	lockmgr(&file_priv->table_lock, LK_RELEASE);
4904be47400SFrançois Tigeot err_unref:
491a85cb24fSFrançois Tigeot 	drm_gem_object_handle_put_unlocked(obj);
4924be47400SFrançois Tigeot 	return ret;
4935718399fSFrançois Tigeot }
494d2c87355SFrançois Tigeot 
4952c9916cdSFrançois Tigeot /**
4962c9916cdSFrançois Tigeot  * drm_gem_handle_create - create a gem handle for an object
4972c9916cdSFrançois Tigeot  * @file_priv: drm file-private structure to register the handle for
4982c9916cdSFrançois Tigeot  * @obj: object to register
4992c9916cdSFrançois Tigeot  * @handlep: pionter to return the created handle to the caller
5002c9916cdSFrançois Tigeot  *
5012c9916cdSFrançois Tigeot  * Create a handle for this object. This adds a handle reference
5022c9916cdSFrançois Tigeot  * to the object, which includes a regular reference count. Callers
5032c9916cdSFrançois Tigeot  * will likely want to dereference the object afterwards.
5042c9916cdSFrançois Tigeot  */
drm_gem_handle_create(struct drm_file * file_priv,struct drm_gem_object * obj,u32 * handlep)5052c9916cdSFrançois Tigeot int drm_gem_handle_create(struct drm_file *file_priv,
5062c9916cdSFrançois Tigeot 			  struct drm_gem_object *obj,
5072c9916cdSFrançois Tigeot 			  u32 *handlep)
5082c9916cdSFrançois Tigeot {
5092c9916cdSFrançois Tigeot 	mutex_lock(&obj->dev->object_name_lock);
5102c9916cdSFrançois Tigeot 
5112c9916cdSFrançois Tigeot 	return drm_gem_handle_create_tail(file_priv, obj, handlep);
5122c9916cdSFrançois Tigeot }
5132c9916cdSFrançois Tigeot EXPORT_SYMBOL(drm_gem_handle_create);
514d2c87355SFrançois Tigeot 
515d2c87355SFrançois Tigeot /**
516d2c87355SFrançois Tigeot  * drm_gem_free_mmap_offset - release a fake mmap offset for an object
517d2c87355SFrançois Tigeot  * @obj: obj in question
518d2c87355SFrançois Tigeot  *
519d2c87355SFrançois Tigeot  * This routine frees fake offsets allocated by drm_gem_create_mmap_offset().
5208621f407SFrançois Tigeot  *
5218621f407SFrançois Tigeot  * Note that drm_gem_object_release() already calls this function, so drivers
5228621f407SFrançois Tigeot  * don't have to take care of releasing the mmap offset themselves when freeing
5238621f407SFrançois Tigeot  * the GEM object.
524d2c87355SFrançois Tigeot  */
525d2c87355SFrançois Tigeot void
drm_gem_free_mmap_offset(struct drm_gem_object * obj)526d2c87355SFrançois Tigeot drm_gem_free_mmap_offset(struct drm_gem_object *obj)
527d2c87355SFrançois Tigeot {
528d2c87355SFrançois Tigeot 	struct drm_device *dev = obj->dev;
529*3f2dd94aSFrançois Tigeot 
530d2c87355SFrançois Tigeot 	struct drm_gem_mm *mm = dev->mm_private;
531d2c87355SFrançois Tigeot 	struct drm_hash_item *list;
532d2c87355SFrançois Tigeot 
533d2c87355SFrançois Tigeot 	if (!obj->on_map)
534d2c87355SFrançois Tigeot 		return;
535d2c87355SFrançois Tigeot 	list = &obj->map_list;
536d2c87355SFrançois Tigeot 
537d2c87355SFrançois Tigeot 	drm_ht_remove_item(&mm->offset_hash, list);
538d2c87355SFrançois Tigeot 	free_unr(mm->idxunr, list->key);
539d2c87355SFrançois Tigeot 	obj->on_map = false;
5409edbd4a0SFrançois Tigeot 
541*3f2dd94aSFrançois Tigeot 	drm_vma_offset_remove(dev->vma_offset_manager, &obj->vma_node);
542d2c87355SFrançois Tigeot }
543d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_free_mmap_offset);
544d2c87355SFrançois Tigeot 
545d2c87355SFrançois Tigeot /**
5469edbd4a0SFrançois Tigeot  * drm_gem_create_mmap_offset_size - create a fake mmap offset for an object
5479edbd4a0SFrançois Tigeot  * @obj: obj in question
5489edbd4a0SFrançois Tigeot  * @size: the virtual size
5499edbd4a0SFrançois Tigeot  *
5509edbd4a0SFrançois Tigeot  * GEM memory mapping works by handing back to userspace a fake mmap offset
5519edbd4a0SFrançois Tigeot  * it can use in a subsequent mmap(2) call.  The DRM core code then looks
5529edbd4a0SFrançois Tigeot  * up the object based on the offset and sets up the various memory mapping
5539edbd4a0SFrançois Tigeot  * structures.
5549edbd4a0SFrançois Tigeot  *
5559edbd4a0SFrançois Tigeot  * This routine allocates and attaches a fake offset for @obj, in cases where
556a85cb24fSFrançois Tigeot  * the virtual size differs from the physical size (ie. &drm_gem_object.size).
557a85cb24fSFrançois Tigeot  * Otherwise just use drm_gem_create_mmap_offset().
5588621f407SFrançois Tigeot  *
5598621f407SFrançois Tigeot  * This function is idempotent and handles an already allocated mmap offset
5608621f407SFrançois Tigeot  * transparently. Drivers do not need to check for this case.
5619edbd4a0SFrançois Tigeot  */
5629edbd4a0SFrançois Tigeot int
drm_gem_create_mmap_offset_size(struct drm_gem_object * obj,size_t size)5639edbd4a0SFrançois Tigeot drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
5649edbd4a0SFrançois Tigeot {
5659edbd4a0SFrançois Tigeot 	struct drm_device *dev = obj->dev;
5669edbd4a0SFrançois Tigeot 	struct drm_gem_mm *mm = dev->mm_private;
5679edbd4a0SFrançois Tigeot 	int ret = 0;
5689edbd4a0SFrançois Tigeot 
5699edbd4a0SFrançois Tigeot 	if (obj->on_map)
5709edbd4a0SFrançois Tigeot 		return (0);
5719edbd4a0SFrançois Tigeot 
5729edbd4a0SFrançois Tigeot 	obj->map_list.key = alloc_unr(mm->idxunr);
5739edbd4a0SFrançois Tigeot 	ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
5749edbd4a0SFrançois Tigeot 	if (ret != 0) {
5759edbd4a0SFrançois Tigeot 		DRM_ERROR("failed to add to map hash\n");
5769edbd4a0SFrançois Tigeot 		free_unr(mm->idxunr, obj->map_list.key);
5779edbd4a0SFrançois Tigeot 		return (ret);
5789edbd4a0SFrançois Tigeot 	}
5799edbd4a0SFrançois Tigeot 	obj->on_map = true;
5809edbd4a0SFrançois Tigeot 
581*3f2dd94aSFrançois Tigeot 	return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node,
5829edbd4a0SFrançois Tigeot 				  size / PAGE_SIZE);
5839edbd4a0SFrançois Tigeot }
5849edbd4a0SFrançois Tigeot EXPORT_SYMBOL(drm_gem_create_mmap_offset_size);
5859edbd4a0SFrançois Tigeot 
5869edbd4a0SFrançois Tigeot /**
587d2c87355SFrançois Tigeot  * drm_gem_create_mmap_offset - create a fake mmap offset for an object
588d2c87355SFrançois Tigeot  * @obj: obj in question
589d2c87355SFrançois Tigeot  *
590d2c87355SFrançois Tigeot  * GEM memory mapping works by handing back to userspace a fake mmap offset
591d2c87355SFrançois Tigeot  * it can use in a subsequent mmap(2) call.  The DRM core code then looks
592d2c87355SFrançois Tigeot  * up the object based on the offset and sets up the various memory mapping
593d2c87355SFrançois Tigeot  * structures.
594d2c87355SFrançois Tigeot  *
595d2c87355SFrançois Tigeot  * This routine allocates and attaches a fake offset for @obj.
5968621f407SFrançois Tigeot  *
5978621f407SFrançois Tigeot  * Drivers can call drm_gem_free_mmap_offset() before freeing @obj to release
5988621f407SFrançois Tigeot  * the fake offset again.
599d2c87355SFrançois Tigeot  */
drm_gem_create_mmap_offset(struct drm_gem_object * obj)6009edbd4a0SFrançois Tigeot int drm_gem_create_mmap_offset(struct drm_gem_object *obj)
601d2c87355SFrançois Tigeot {
6029edbd4a0SFrançois Tigeot 	return drm_gem_create_mmap_offset_size(obj, obj->size);
603d2c87355SFrançois Tigeot }
604d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_create_mmap_offset);
6055718399fSFrançois Tigeot 
606aee94f86SFrançois Tigeot /**
607aee94f86SFrançois Tigeot  * drm_gem_object_lookup - look up a GEM object from it's handle
608aee94f86SFrançois Tigeot  * @filp: DRM file private date
609aee94f86SFrançois Tigeot  * @handle: userspace handle
610aee94f86SFrançois Tigeot  *
611aee94f86SFrançois Tigeot  * Returns:
612aee94f86SFrançois Tigeot  *
613aee94f86SFrançois Tigeot  * A reference to the object named by the handle if such exists on @filp, NULL
614aee94f86SFrançois Tigeot  * otherwise.
615aee94f86SFrançois Tigeot  */
616c7e1c9ddSFrançois Tigeot struct drm_gem_object *
drm_gem_object_lookup(struct drm_file * filp,u32 handle)6178621f407SFrançois Tigeot drm_gem_object_lookup(struct drm_file *filp, u32 handle)
6185718399fSFrançois Tigeot {
6195718399fSFrançois Tigeot 	struct drm_gem_object *obj;
6205718399fSFrançois Tigeot 
62198a11977SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_EXCLUSIVE);
6226f486c69SFrançois Tigeot 
623c7e1c9ddSFrançois Tigeot 	/* Check if we currently have a reference on the object */
624c7e1c9ddSFrançois Tigeot 	obj = idr_find(&filp->object_idr, handle);
6256c7b277cSFrançois Tigeot 	if (obj)
626a85cb24fSFrançois Tigeot 		drm_gem_object_get(obj);
6275718399fSFrançois Tigeot 
62898a11977SFrançois Tigeot 	lockmgr(&filp->table_lock, LK_RELEASE);
6295718399fSFrançois Tigeot 
630c7e1c9ddSFrançois Tigeot 	return obj;
6315718399fSFrançois Tigeot }
632d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_lookup);
6335718399fSFrançois Tigeot 
634d2c87355SFrançois Tigeot /**
635ba55f2f5SFrançois Tigeot  * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl
636ba55f2f5SFrançois Tigeot  * @dev: drm_device
637ba55f2f5SFrançois Tigeot  * @data: ioctl data
638ba55f2f5SFrançois Tigeot  * @file_priv: drm file-private structure
639ba55f2f5SFrançois Tigeot  *
640d2c87355SFrançois Tigeot  * Releases the handle to an mm object.
641d2c87355SFrançois Tigeot  */
6425718399fSFrançois Tigeot int
drm_gem_close_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)6435718399fSFrançois Tigeot drm_gem_close_ioctl(struct drm_device *dev, void *data,
6445718399fSFrançois Tigeot 		    struct drm_file *file_priv)
6455718399fSFrançois Tigeot {
646d2c87355SFrançois Tigeot 	struct drm_gem_close *args = data;
6477786d093SFrançois Tigeot 	int ret;
6485718399fSFrançois Tigeot 
6491b13d190SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_GEM))
6507786d093SFrançois Tigeot 		return -ENODEV;
6515718399fSFrançois Tigeot 
6527786d093SFrançois Tigeot 	ret = drm_gem_handle_delete(file_priv, args->handle);
6537786d093SFrançois Tigeot 
6547786d093SFrançois Tigeot 	return ret;
6555718399fSFrançois Tigeot }
6565718399fSFrançois Tigeot 
657c7e1c9ddSFrançois Tigeot /**
6584be47400SFrançois Tigeot  * drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl
6594be47400SFrançois Tigeot  * @dev: drm_device
6604be47400SFrançois Tigeot  * @data: ioctl data
6614be47400SFrançois Tigeot  * @file_priv: drm file-private structure
6624be47400SFrançois Tigeot  *
663c7e1c9ddSFrançois Tigeot  * Create a global name for an object, returning the name.
664c7e1c9ddSFrançois Tigeot  *
665c7e1c9ddSFrançois Tigeot  * Note that the name does not hold a reference; when the object
666c7e1c9ddSFrançois Tigeot  * is freed, the name goes away.
667c7e1c9ddSFrançois Tigeot  */
6685718399fSFrançois Tigeot int
drm_gem_flink_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)6695718399fSFrançois Tigeot drm_gem_flink_ioctl(struct drm_device *dev, void *data,
6705718399fSFrançois Tigeot 		    struct drm_file *file_priv)
6715718399fSFrançois Tigeot {
672c7e1c9ddSFrançois Tigeot 	struct drm_gem_flink *args = data;
6735718399fSFrançois Tigeot 	struct drm_gem_object *obj;
674c7e1c9ddSFrançois Tigeot 	int ret;
6755718399fSFrançois Tigeot 
6761b13d190SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_GEM))
677c7e1c9ddSFrançois Tigeot 		return -ENODEV;
6785718399fSFrançois Tigeot 
6798621f407SFrançois Tigeot 	obj = drm_gem_object_lookup(file_priv, args->handle);
6805718399fSFrançois Tigeot 	if (obj == NULL)
681c7e1c9ddSFrançois Tigeot 		return -ENOENT;
682c7e1c9ddSFrançois Tigeot 
6834be47400SFrançois Tigeot 	mutex_lock(&dev->object_name_lock);
684ba55f2f5SFrançois Tigeot 	/* prevent races with concurrent gem_close. */
685ba55f2f5SFrançois Tigeot 	if (obj->handle_count == 0) {
686ba55f2f5SFrançois Tigeot 		ret = -ENOENT;
687ba55f2f5SFrançois Tigeot 		goto err;
688ba55f2f5SFrançois Tigeot 	}
689c7e1c9ddSFrançois Tigeot 
690ba55f2f5SFrançois Tigeot 	if (!obj->name) {
6914be47400SFrançois Tigeot 		ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_KERNEL);
692ba55f2f5SFrançois Tigeot 		if (ret < 0)
693c7e1c9ddSFrançois Tigeot 			goto err;
694c7e1c9ddSFrançois Tigeot 
695ba55f2f5SFrançois Tigeot 		obj->name = ret;
696c7e1c9ddSFrançois Tigeot 	}
697c7e1c9ddSFrançois Tigeot 
698ba55f2f5SFrançois Tigeot 	args->name = (uint64_t) obj->name;
699ba55f2f5SFrançois Tigeot 	ret = 0;
700ba55f2f5SFrançois Tigeot 
701c7e1c9ddSFrançois Tigeot err:
7024be47400SFrançois Tigeot 	mutex_unlock(&dev->object_name_lock);
703a85cb24fSFrançois Tigeot 	drm_gem_object_put_unlocked(obj);
704c7e1c9ddSFrançois Tigeot 	return ret;
7055718399fSFrançois Tigeot }
7065718399fSFrançois Tigeot 
707c7e1c9ddSFrançois Tigeot /**
708ba55f2f5SFrançois Tigeot  * drm_gem_open - implementation of the GEM_OPEN ioctl
709ba55f2f5SFrançois Tigeot  * @dev: drm_device
710ba55f2f5SFrançois Tigeot  * @data: ioctl data
711ba55f2f5SFrançois Tigeot  * @file_priv: drm file-private structure
712ba55f2f5SFrançois Tigeot  *
713c7e1c9ddSFrançois Tigeot  * Open an object using the global name, returning a handle and the size.
714c7e1c9ddSFrançois Tigeot  *
715c7e1c9ddSFrançois Tigeot  * This handle (of course) holds a reference to the object, so the object
716c7e1c9ddSFrançois Tigeot  * will not go away until the handle is deleted.
717c7e1c9ddSFrançois Tigeot  */
718c7e1c9ddSFrançois Tigeot int
drm_gem_open_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)719c7e1c9ddSFrançois Tigeot drm_gem_open_ioctl(struct drm_device *dev, void *data,
720c7e1c9ddSFrançois Tigeot 		   struct drm_file *file_priv)
7215718399fSFrançois Tigeot {
722c7e1c9ddSFrançois Tigeot 	struct drm_gem_open *args = data;
7235718399fSFrançois Tigeot 	struct drm_gem_object *obj;
724c7e1c9ddSFrançois Tigeot 	int ret;
725c7e1c9ddSFrançois Tigeot 	u32 handle;
7265718399fSFrançois Tigeot 
7271b13d190SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_GEM))
728c7e1c9ddSFrançois Tigeot 		return -ENODEV;
729c7e1c9ddSFrançois Tigeot 
7304be47400SFrançois Tigeot 	mutex_lock(&dev->object_name_lock);
731c7e1c9ddSFrançois Tigeot 	obj = idr_find(&dev->object_name_idr, (int) args->name);
7324be47400SFrançois Tigeot 	if (obj) {
733a85cb24fSFrançois Tigeot 		drm_gem_object_get(obj);
7344be47400SFrançois Tigeot 	} else {
7354be47400SFrançois Tigeot 		mutex_unlock(&dev->object_name_lock);
736c7e1c9ddSFrançois Tigeot 		return -ENOENT;
7374be47400SFrançois Tigeot 	}
738c7e1c9ddSFrançois Tigeot 
7394be47400SFrançois Tigeot 	/* drm_gem_handle_create_tail unlocks dev->object_name_lock. */
7404be47400SFrançois Tigeot 	ret = drm_gem_handle_create_tail(file_priv, obj, &handle);
741a85cb24fSFrançois Tigeot 	drm_gem_object_put_unlocked(obj);
742c7e1c9ddSFrançois Tigeot 	if (ret)
743c7e1c9ddSFrançois Tigeot 		return ret;
744c7e1c9ddSFrançois Tigeot 
745c7e1c9ddSFrançois Tigeot 	args->handle = handle;
746c7e1c9ddSFrançois Tigeot 	args->size = obj->size;
747c7e1c9ddSFrançois Tigeot 
748c7e1c9ddSFrançois Tigeot 	return 0;
749c7e1c9ddSFrançois Tigeot }
750c7e1c9ddSFrançois Tigeot 
751c7e1c9ddSFrançois Tigeot /**
752ba55f2f5SFrançois Tigeot  * gem_gem_open - initalizes GEM file-private structures at devnode open time
753ba55f2f5SFrançois Tigeot  * @dev: drm_device which is being opened by userspace
754ba55f2f5SFrançois Tigeot  * @file_private: drm file-private structure to set up
755ba55f2f5SFrançois Tigeot  *
756c7e1c9ddSFrançois Tigeot  * Called at device open time, sets up the structure for handling refcounting
757c7e1c9ddSFrançois Tigeot  * of mm objects.
758c7e1c9ddSFrançois Tigeot  */
759c7e1c9ddSFrançois Tigeot void
drm_gem_open(struct drm_device * dev,struct drm_file * file_private)760c7e1c9ddSFrançois Tigeot drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
761c7e1c9ddSFrançois Tigeot {
762c7e1c9ddSFrançois Tigeot 	idr_init(&file_private->object_idr);
763a85cb24fSFrançois Tigeot 	lockinit(&file_private->table_lock, "fptab", 0, 0);
764c7e1c9ddSFrançois Tigeot }
765c7e1c9ddSFrançois Tigeot 
766c7e1c9ddSFrançois Tigeot /**
767ba55f2f5SFrançois Tigeot  * drm_gem_release - release file-private GEM resources
768ba55f2f5SFrançois Tigeot  * @dev: drm_device which is being closed by userspace
769ba55f2f5SFrançois Tigeot  * @file_private: drm file-private structure to clean up
770ba55f2f5SFrançois Tigeot  *
771c7e1c9ddSFrançois Tigeot  * Called at close time when the filp is going away.
772c7e1c9ddSFrançois Tigeot  *
773c7e1c9ddSFrançois Tigeot  * Releases any remaining references on objects by this filp.
774c7e1c9ddSFrançois Tigeot  */
775c7e1c9ddSFrançois Tigeot void
drm_gem_release(struct drm_device * dev,struct drm_file * file_private)776c7e1c9ddSFrançois Tigeot drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
777c7e1c9ddSFrançois Tigeot {
778c7e1c9ddSFrançois Tigeot 	idr_for_each(&file_private->object_idr,
779c7e1c9ddSFrançois Tigeot 		     &drm_gem_object_release_handle, file_private);
780c7e1c9ddSFrançois Tigeot 	idr_destroy(&file_private->object_idr);
7815718399fSFrançois Tigeot }
7825718399fSFrançois Tigeot 
7838621f407SFrançois Tigeot /**
7848621f407SFrançois Tigeot  * drm_gem_object_release - release GEM buffer object resources
7858621f407SFrançois Tigeot  * @obj: GEM buffer object
7868621f407SFrançois Tigeot  *
7878621f407SFrançois Tigeot  * This releases any structures and resources used by @obj and is the invers of
7888621f407SFrançois Tigeot  * drm_gem_object_init().
7898621f407SFrançois Tigeot  */
790d2c87355SFrançois Tigeot void
drm_gem_object_release(struct drm_gem_object * obj)791d2c87355SFrançois Tigeot drm_gem_object_release(struct drm_gem_object *obj)
792d2c87355SFrançois Tigeot {
793a85cb24fSFrançois Tigeot 	WARN_ON(obj->dma_buf);
794d2c87355SFrançois Tigeot 
795d2c87355SFrançois Tigeot 	/*
796d2c87355SFrançois Tigeot 	 * obj->vm_obj can be NULL for private gem objects.
797d2c87355SFrançois Tigeot 	 */
7987ca4ece0SFrançois Tigeot 	vm_object_deallocate(obj->filp);
799a85cb24fSFrançois Tigeot 
800a85cb24fSFrançois Tigeot 	drm_gem_free_mmap_offset(obj);
801d2c87355SFrançois Tigeot }
802d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_release);
803d2c87355SFrançois Tigeot 
804d2c87355SFrançois Tigeot /**
805ba55f2f5SFrançois Tigeot  * drm_gem_object_free - free a GEM object
806ba55f2f5SFrançois Tigeot  * @kref: kref of the object to free
807ba55f2f5SFrançois Tigeot  *
808d2c87355SFrançois Tigeot  * Called after the last reference to the object has been lost.
809a85cb24fSFrançois Tigeot  * Must be called holding &drm_device.struct_mutex.
810d2c87355SFrançois Tigeot  *
811d2c87355SFrançois Tigeot  * Frees the object
812d2c87355SFrançois Tigeot  */
813d2c87355SFrançois Tigeot void
drm_gem_object_free(struct kref * kref)814d2c87355SFrançois Tigeot drm_gem_object_free(struct kref *kref)
815d2c87355SFrançois Tigeot {
816352ff8bdSFrançois Tigeot 	struct drm_gem_object *obj =
817352ff8bdSFrançois Tigeot 		container_of(kref, struct drm_gem_object, refcount);
818d2c87355SFrançois Tigeot 	struct drm_device *dev = obj->dev;
819d2c87355SFrançois Tigeot 
820d78d3a22SFrançois Tigeot 	if (dev->driver->gem_free_object_unlocked) {
821d78d3a22SFrançois Tigeot 		dev->driver->gem_free_object_unlocked(obj);
822d78d3a22SFrançois Tigeot 	} else if (dev->driver->gem_free_object) {
823a05eeebfSFrançois Tigeot 		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
824d2c87355SFrançois Tigeot 
825d2c87355SFrançois Tigeot 		dev->driver->gem_free_object(obj);
826d2c87355SFrançois Tigeot 	}
827d78d3a22SFrançois Tigeot }
828d2c87355SFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_free);
829d2c87355SFrançois Tigeot 
830ab5862ffSFrançois Tigeot /**
831a85cb24fSFrançois Tigeot  * drm_gem_object_put_unlocked - drop a GEM buffer object reference
832ab5862ffSFrançois Tigeot  * @obj: GEM buffer object
833ab5862ffSFrançois Tigeot  *
834ab5862ffSFrançois Tigeot  * This releases a reference to @obj. Callers must not hold the
835a85cb24fSFrançois Tigeot  * &drm_device.struct_mutex lock when calling this function.
836ab5862ffSFrançois Tigeot  *
837a85cb24fSFrançois Tigeot  * See also __drm_gem_object_put().
838ab5862ffSFrançois Tigeot  */
839ab5862ffSFrançois Tigeot void
drm_gem_object_put_unlocked(struct drm_gem_object * obj)840a85cb24fSFrançois Tigeot drm_gem_object_put_unlocked(struct drm_gem_object *obj)
841ab5862ffSFrançois Tigeot {
842ab5862ffSFrançois Tigeot 	struct drm_device *dev;
843ab5862ffSFrançois Tigeot 
844ab5862ffSFrançois Tigeot 	if (!obj)
845ab5862ffSFrançois Tigeot 		return;
846ab5862ffSFrançois Tigeot 
847ab5862ffSFrançois Tigeot 	dev = obj->dev;
848ab5862ffSFrançois Tigeot 	might_lock(&dev->struct_mutex);
849d78d3a22SFrançois Tigeot 
850d78d3a22SFrançois Tigeot 	if (dev->driver->gem_free_object_unlocked)
851d78d3a22SFrançois Tigeot 		kref_put(&obj->refcount, drm_gem_object_free);
852d78d3a22SFrançois Tigeot 	else if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
853d78d3a22SFrançois Tigeot 				&dev->struct_mutex))
854d78d3a22SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
855ab5862ffSFrançois Tigeot }
856a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_put_unlocked);
857ab5862ffSFrançois Tigeot 
858ab5862ffSFrançois Tigeot /**
859a85cb24fSFrançois Tigeot  * drm_gem_object_put - release a GEM buffer object reference
860ab5862ffSFrançois Tigeot  * @obj: GEM buffer object
861ab5862ffSFrançois Tigeot  *
862a85cb24fSFrançois Tigeot  * This releases a reference to @obj. Callers must hold the
863a85cb24fSFrançois Tigeot  * &drm_device.struct_mutex lock when calling this function, even when the
864a85cb24fSFrançois Tigeot  * driver doesn't use &drm_device.struct_mutex for anything.
865ab5862ffSFrançois Tigeot  *
866ab5862ffSFrançois Tigeot  * For drivers not encumbered with legacy locking use
867a85cb24fSFrançois Tigeot  * drm_gem_object_put_unlocked() instead.
868ab5862ffSFrançois Tigeot  */
869ab5862ffSFrançois Tigeot void
drm_gem_object_put(struct drm_gem_object * obj)870a85cb24fSFrançois Tigeot drm_gem_object_put(struct drm_gem_object *obj)
871ab5862ffSFrançois Tigeot {
872d78d3a22SFrançois Tigeot 	if (obj) {
873ab5862ffSFrançois Tigeot 		WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
874ab5862ffSFrançois Tigeot 
875ab5862ffSFrançois Tigeot 		kref_put(&obj->refcount, drm_gem_object_free);
876ab5862ffSFrançois Tigeot 	}
877ab5862ffSFrançois Tigeot }
878a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_gem_object_put);
879a85cb24fSFrançois Tigeot 
880a85cb24fSFrançois Tigeot /**
881a85cb24fSFrançois Tigeot  * drm_gem_vm_open - vma->ops->open implementation for GEM
882a85cb24fSFrançois Tigeot  * @vma: VM area structure
883a85cb24fSFrançois Tigeot  *
884a85cb24fSFrançois Tigeot  * This function implements the #vm_operations_struct open() callback for GEM
885a85cb24fSFrançois Tigeot  * drivers. This must be used together with drm_gem_vm_close().
886a85cb24fSFrançois Tigeot  */
drm_gem_vm_open(struct vm_area_struct * vma)887a85cb24fSFrançois Tigeot void drm_gem_vm_open(struct vm_area_struct *vma)
888a85cb24fSFrançois Tigeot {
889a85cb24fSFrançois Tigeot 	struct drm_gem_object *obj = vma->vm_private_data;
890a85cb24fSFrançois Tigeot 
891a85cb24fSFrançois Tigeot 	drm_gem_object_get(obj);
892a85cb24fSFrançois Tigeot }
893a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_gem_vm_open);
894a85cb24fSFrançois Tigeot 
895a85cb24fSFrançois Tigeot /**
896a85cb24fSFrançois Tigeot  * drm_gem_vm_close - vma->ops->close implementation for GEM
897a85cb24fSFrançois Tigeot  * @vma: VM area structure
898a85cb24fSFrançois Tigeot  *
899a85cb24fSFrançois Tigeot  * This function implements the #vm_operations_struct close() callback for GEM
900a85cb24fSFrançois Tigeot  * drivers. This must be used together with drm_gem_vm_open().
901a85cb24fSFrançois Tigeot  */
drm_gem_vm_close(struct vm_area_struct * vma)902a85cb24fSFrançois Tigeot void drm_gem_vm_close(struct vm_area_struct *vma)
903a85cb24fSFrançois Tigeot {
904a85cb24fSFrançois Tigeot 	struct drm_gem_object *obj = vma->vm_private_data;
905a85cb24fSFrançois Tigeot 
906a85cb24fSFrançois Tigeot 	drm_gem_object_put_unlocked(obj);
907a85cb24fSFrançois Tigeot }
908a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_gem_vm_close);
909ab5862ffSFrançois Tigeot 
910*3f2dd94aSFrançois Tigeot #if 0
911*3f2dd94aSFrançois Tigeot /**
912*3f2dd94aSFrançois Tigeot  * drm_gem_mmap_obj - memory map a GEM object
913*3f2dd94aSFrançois Tigeot  * @obj: the GEM object to map
914*3f2dd94aSFrançois Tigeot  * @obj_size: the object size to be mapped, in bytes
915*3f2dd94aSFrançois Tigeot  * @vma: VMA for the area to be mapped
916*3f2dd94aSFrançois Tigeot  *
917*3f2dd94aSFrançois Tigeot  * Set up the VMA to prepare mapping of the GEM object using the gem_vm_ops
918*3f2dd94aSFrançois Tigeot  * provided by the driver. Depending on their requirements, drivers can either
919*3f2dd94aSFrançois Tigeot  * provide a fault handler in their gem_vm_ops (in which case any accesses to
920*3f2dd94aSFrançois Tigeot  * the object will be trapped, to perform migration, GTT binding, surface
921*3f2dd94aSFrançois Tigeot  * register allocation, or performance monitoring), or mmap the buffer memory
922*3f2dd94aSFrançois Tigeot  * synchronously after calling drm_gem_mmap_obj.
923*3f2dd94aSFrançois Tigeot  *
924*3f2dd94aSFrançois Tigeot  * This function is mainly intended to implement the DMABUF mmap operation, when
925*3f2dd94aSFrançois Tigeot  * the GEM object is not looked up based on its fake offset. To implement the
926*3f2dd94aSFrançois Tigeot  * DRM mmap operation, drivers should use the drm_gem_mmap() function.
927*3f2dd94aSFrançois Tigeot  *
928*3f2dd94aSFrançois Tigeot  * drm_gem_mmap_obj() assumes the user is granted access to the buffer while
929*3f2dd94aSFrançois Tigeot  * drm_gem_mmap() prevents unprivileged users from mapping random objects. So
930*3f2dd94aSFrançois Tigeot  * callers must verify access restrictions before calling this helper.
931*3f2dd94aSFrançois Tigeot  *
932*3f2dd94aSFrançois Tigeot  * Return 0 or success or -EINVAL if the object size is smaller than the VMA
933*3f2dd94aSFrançois Tigeot  * size, or if no gem_vm_ops are provided.
934*3f2dd94aSFrançois Tigeot  */
935*3f2dd94aSFrançois Tigeot int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
936*3f2dd94aSFrançois Tigeot 		     struct vm_area_struct *vma)
937*3f2dd94aSFrançois Tigeot {
938*3f2dd94aSFrançois Tigeot 	struct drm_device *dev = obj->dev;
939*3f2dd94aSFrançois Tigeot 
940*3f2dd94aSFrançois Tigeot 	/* Check for valid size. */
941*3f2dd94aSFrançois Tigeot 	if (obj_size < vma->vm_end - vma->vm_start)
942*3f2dd94aSFrançois Tigeot 		return -EINVAL;
943*3f2dd94aSFrançois Tigeot 
944*3f2dd94aSFrançois Tigeot 	if (!dev->driver->gem_vm_ops)
945*3f2dd94aSFrançois Tigeot 		return -EINVAL;
946*3f2dd94aSFrançois Tigeot 
947*3f2dd94aSFrançois Tigeot 	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
948*3f2dd94aSFrançois Tigeot 	vma->vm_ops = dev->driver->gem_vm_ops;
949*3f2dd94aSFrançois Tigeot 	vma->vm_private_data = obj;
950*3f2dd94aSFrançois Tigeot 	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
951*3f2dd94aSFrançois Tigeot 	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
952*3f2dd94aSFrançois Tigeot 
953*3f2dd94aSFrançois Tigeot 	/* Take a ref for this mapping of the object, so that the fault
954*3f2dd94aSFrançois Tigeot 	 * handler can dereference the mmap offset's pointer to the object.
955*3f2dd94aSFrançois Tigeot 	 * This reference is cleaned up by the corresponding vm_close
956*3f2dd94aSFrançois Tigeot 	 * (which should happen whether the vma was created by this call, or
957*3f2dd94aSFrançois Tigeot 	 * by a vm_open due to mremap or partial unmap or whatever).
958*3f2dd94aSFrançois Tigeot 	 */
959*3f2dd94aSFrançois Tigeot 	drm_gem_object_get(obj);
960*3f2dd94aSFrançois Tigeot 
961*3f2dd94aSFrançois Tigeot 	return 0;
962*3f2dd94aSFrançois Tigeot }
963*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_gem_mmap_obj);
964*3f2dd94aSFrançois Tigeot 
965*3f2dd94aSFrançois Tigeot /**
966*3f2dd94aSFrançois Tigeot  * drm_gem_mmap - memory map routine for GEM objects
967*3f2dd94aSFrançois Tigeot  * @filp: DRM file pointer
968*3f2dd94aSFrançois Tigeot  * @vma: VMA for the area to be mapped
969*3f2dd94aSFrançois Tigeot  *
970*3f2dd94aSFrançois Tigeot  * If a driver supports GEM object mapping, mmap calls on the DRM file
971*3f2dd94aSFrançois Tigeot  * descriptor will end up here.
972*3f2dd94aSFrançois Tigeot  *
973*3f2dd94aSFrançois Tigeot  * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
974*3f2dd94aSFrançois Tigeot  * contain the fake offset we created when the GTT map ioctl was called on
975*3f2dd94aSFrançois Tigeot  * the object) and map it with a call to drm_gem_mmap_obj().
976*3f2dd94aSFrançois Tigeot  *
977*3f2dd94aSFrançois Tigeot  * If the caller is not granted access to the buffer object, the mmap will fail
978*3f2dd94aSFrançois Tigeot  * with EACCES. Please see the vma manager for more information.
979*3f2dd94aSFrançois Tigeot  */
980*3f2dd94aSFrançois Tigeot int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
981*3f2dd94aSFrançois Tigeot {
982*3f2dd94aSFrançois Tigeot 	struct drm_file *priv = filp->private_data;
983*3f2dd94aSFrançois Tigeot 	struct drm_device *dev = priv->minor->dev;
984*3f2dd94aSFrançois Tigeot 	struct drm_gem_object *obj = NULL;
985*3f2dd94aSFrançois Tigeot 	struct drm_vma_offset_node *node;
986*3f2dd94aSFrançois Tigeot 	int ret;
987*3f2dd94aSFrançois Tigeot 
988*3f2dd94aSFrançois Tigeot 	if (drm_dev_is_unplugged(dev))
989*3f2dd94aSFrançois Tigeot 		return -ENODEV;
990*3f2dd94aSFrançois Tigeot 
991*3f2dd94aSFrançois Tigeot 	drm_vma_offset_lock_lookup(dev->vma_offset_manager);
992*3f2dd94aSFrançois Tigeot 	node = drm_vma_offset_exact_lookup_locked(dev->vma_offset_manager,
993*3f2dd94aSFrançois Tigeot 						  vma->vm_pgoff,
994*3f2dd94aSFrançois Tigeot 						  vma_pages(vma));
995*3f2dd94aSFrançois Tigeot 	if (likely(node)) {
996*3f2dd94aSFrançois Tigeot 		obj = container_of(node, struct drm_gem_object, vma_node);
997*3f2dd94aSFrançois Tigeot 		/*
998*3f2dd94aSFrançois Tigeot 		 * When the object is being freed, after it hits 0-refcnt it
999*3f2dd94aSFrançois Tigeot 		 * proceeds to tear down the object. In the process it will
1000*3f2dd94aSFrançois Tigeot 		 * attempt to remove the VMA offset and so acquire this
1001*3f2dd94aSFrançois Tigeot 		 * mgr->vm_lock.  Therefore if we find an object with a 0-refcnt
1002*3f2dd94aSFrançois Tigeot 		 * that matches our range, we know it is in the process of being
1003*3f2dd94aSFrançois Tigeot 		 * destroyed and will be freed as soon as we release the lock -
1004*3f2dd94aSFrançois Tigeot 		 * so we have to check for the 0-refcnted object and treat it as
1005*3f2dd94aSFrançois Tigeot 		 * invalid.
1006*3f2dd94aSFrançois Tigeot 		 */
1007*3f2dd94aSFrançois Tigeot 		if (!kref_get_unless_zero(&obj->refcount))
1008*3f2dd94aSFrançois Tigeot 			obj = NULL;
1009*3f2dd94aSFrançois Tigeot 	}
1010*3f2dd94aSFrançois Tigeot 	drm_vma_offset_unlock_lookup(dev->vma_offset_manager);
1011*3f2dd94aSFrançois Tigeot 
1012*3f2dd94aSFrançois Tigeot 	if (!obj)
1013*3f2dd94aSFrançois Tigeot 		return -EINVAL;
1014*3f2dd94aSFrançois Tigeot 
1015*3f2dd94aSFrançois Tigeot 	if (!drm_vma_node_is_allowed(node, priv)) {
1016*3f2dd94aSFrançois Tigeot 		drm_gem_object_put_unlocked(obj);
1017*3f2dd94aSFrançois Tigeot 		return -EACCES;
1018*3f2dd94aSFrançois Tigeot 	}
1019*3f2dd94aSFrançois Tigeot 
1020*3f2dd94aSFrançois Tigeot 	ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT,
1021*3f2dd94aSFrançois Tigeot 			       vma);
1022*3f2dd94aSFrançois Tigeot 
1023*3f2dd94aSFrançois Tigeot 	drm_gem_object_put_unlocked(obj);
1024*3f2dd94aSFrançois Tigeot 
1025*3f2dd94aSFrançois Tigeot 	return ret;
1026*3f2dd94aSFrançois Tigeot }
1027*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_gem_mmap);
1028*3f2dd94aSFrançois Tigeot #endif
1029*3f2dd94aSFrançois Tigeot 
1030*3f2dd94aSFrançois Tigeot #ifdef __DragonFly__
10315718399fSFrançois Tigeot static struct drm_gem_object *
drm_gem_object_from_offset(struct drm_device * dev,vm_ooffset_t offset)10325718399fSFrançois Tigeot drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset)
10335718399fSFrançois Tigeot {
10345718399fSFrançois Tigeot 	struct drm_gem_object *obj;
10359edbd4a0SFrançois Tigeot 	struct drm_gem_mm *mm = dev->mm_private;
10369edbd4a0SFrançois Tigeot 	struct drm_hash_item *hash;
10375718399fSFrançois Tigeot 
10385718399fSFrançois Tigeot 	if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY)
10395718399fSFrançois Tigeot 		return (NULL);
10405718399fSFrançois Tigeot 	offset &= ~DRM_GEM_MAPPING_KEY;
10419edbd4a0SFrançois Tigeot 
10425718399fSFrançois Tigeot 	if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset),
10439edbd4a0SFrançois Tigeot 	    &hash) != 0) {
10445718399fSFrançois Tigeot 		return (NULL);
10455718399fSFrançois Tigeot 	}
10469edbd4a0SFrançois Tigeot 	obj = container_of(hash, struct drm_gem_object, map_list);
10475718399fSFrançois Tigeot 	return (obj);
10485718399fSFrançois Tigeot }
10495718399fSFrançois Tigeot 
10505718399fSFrançois Tigeot int
drm_gem_mmap_single(struct drm_device * dev,vm_ooffset_t * offset,vm_size_t size,struct vm_object ** obj_res,int nprot)10515718399fSFrançois Tigeot drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size,
10525718399fSFrançois Tigeot     struct vm_object **obj_res, int nprot)
10535718399fSFrançois Tigeot {
10545718399fSFrançois Tigeot 	struct drm_gem_object *gem_obj;
10555718399fSFrançois Tigeot 	struct vm_object *vm_obj;
10565718399fSFrançois Tigeot 
10575718399fSFrançois Tigeot 	DRM_LOCK(dev);
10585718399fSFrançois Tigeot 	gem_obj = drm_gem_object_from_offset(dev, *offset);
10595718399fSFrançois Tigeot 	if (gem_obj == NULL) {
10605718399fSFrançois Tigeot 		DRM_UNLOCK(dev);
10615718399fSFrançois Tigeot 		return (ENODEV);
10625718399fSFrançois Tigeot 	}
10639edbd4a0SFrançois Tigeot 
10645718399fSFrançois Tigeot 	drm_gem_object_reference(gem_obj);
10655718399fSFrançois Tigeot 	DRM_UNLOCK(dev);
10665718399fSFrançois Tigeot 	vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE,
1067d4d73b30SFrançois Tigeot 	    dev->driver->gem_vm_ops, size, nprot,
10685718399fSFrançois Tigeot 	    DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred);
10695718399fSFrançois Tigeot 	if (vm_obj == NULL) {
10705718399fSFrançois Tigeot 		drm_gem_object_unreference_unlocked(gem_obj);
10715718399fSFrançois Tigeot 		return (EINVAL);
10725718399fSFrançois Tigeot 	}
10735718399fSFrançois Tigeot 	*offset = DRM_GEM_MAPPING_MAPOFF(*offset);
10745718399fSFrançois Tigeot 	*obj_res = vm_obj;
10755718399fSFrançois Tigeot 	return (0);
10765718399fSFrançois Tigeot }
1077*3f2dd94aSFrançois Tigeot #endif
1078