xref: /freebsd/sys/dev/drm2/drm_gem.c (revision 592ffb217505586a6c69e91549a3c14132875f16)
1*592ffb21SWarner Losh /*-
2*592ffb21SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*592ffb21SWarner Losh  *
4*592ffb21SWarner Losh  * Copyright (c) 2011 The FreeBSD Foundation
5*592ffb21SWarner Losh  * All rights reserved.
6*592ffb21SWarner Losh  *
7*592ffb21SWarner Losh  * This software was developed by Konstantin Belousov under sponsorship from
8*592ffb21SWarner Losh  * the FreeBSD Foundation.
9*592ffb21SWarner Losh  *
10*592ffb21SWarner Losh  * Redistribution and use in source and binary forms, with or without
11*592ffb21SWarner Losh  * modification, are permitted provided that the following conditions
12*592ffb21SWarner Losh  * are met:
13*592ffb21SWarner Losh  * 1. Redistributions of source code must retain the above copyright
14*592ffb21SWarner Losh  *    notice, this list of conditions and the following disclaimer.
15*592ffb21SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
16*592ffb21SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
17*592ffb21SWarner Losh  *    documentation and/or other materials provided with the distribution.
18*592ffb21SWarner Losh  *
19*592ffb21SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20*592ffb21SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*592ffb21SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*592ffb21SWarner Losh  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23*592ffb21SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*592ffb21SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*592ffb21SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*592ffb21SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*592ffb21SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*592ffb21SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*592ffb21SWarner Losh  * SUCH DAMAGE.
30*592ffb21SWarner Losh  */
31*592ffb21SWarner Losh 
32*592ffb21SWarner Losh #include <sys/cdefs.h>
33*592ffb21SWarner Losh __FBSDID("$FreeBSD$");
34*592ffb21SWarner Losh 
35*592ffb21SWarner Losh #include "opt_vm.h"
36*592ffb21SWarner Losh 
37*592ffb21SWarner Losh #include <sys/param.h>
38*592ffb21SWarner Losh #include <sys/systm.h>
39*592ffb21SWarner Losh #include <sys/limits.h>
40*592ffb21SWarner Losh #include <sys/lock.h>
41*592ffb21SWarner Losh #include <sys/mutex.h>
42*592ffb21SWarner Losh 
43*592ffb21SWarner Losh #include <vm/vm.h>
44*592ffb21SWarner Losh #include <vm/vm_page.h>
45*592ffb21SWarner Losh 
46*592ffb21SWarner Losh #include <dev/drm2/drmP.h>
47*592ffb21SWarner Losh #include <dev/drm2/drm.h>
48*592ffb21SWarner Losh #include <dev/drm2/drm_sarea.h>
49*592ffb21SWarner Losh 
50*592ffb21SWarner Losh /*
51*592ffb21SWarner Losh  * We make up offsets for buffer objects so we can recognize them at
52*592ffb21SWarner Losh  * mmap time.
53*592ffb21SWarner Losh  */
54*592ffb21SWarner Losh 
55*592ffb21SWarner Losh /* pgoff in mmap is an unsigned long, so we need to make sure that
56*592ffb21SWarner Losh  * the faked up offset will fit
57*592ffb21SWarner Losh  */
58*592ffb21SWarner Losh 
59*592ffb21SWarner Losh #if BITS_PER_LONG == 64
60*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
61*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
62*592ffb21SWarner Losh #else
63*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
64*592ffb21SWarner Losh #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
65*592ffb21SWarner Losh #endif
66*592ffb21SWarner Losh 
67*592ffb21SWarner Losh /**
68*592ffb21SWarner Losh  * Initialize the GEM device fields
69*592ffb21SWarner Losh  */
70*592ffb21SWarner Losh 
71*592ffb21SWarner Losh int
72*592ffb21SWarner Losh drm_gem_init(struct drm_device *dev)
73*592ffb21SWarner Losh {
74*592ffb21SWarner Losh 	struct drm_gem_mm *mm;
75*592ffb21SWarner Losh 
76*592ffb21SWarner Losh 	drm_gem_names_init(&dev->object_names);
77*592ffb21SWarner Losh 
78*592ffb21SWarner Losh 	mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_NOWAIT);
79*592ffb21SWarner Losh 	if (!mm) {
80*592ffb21SWarner Losh 		DRM_ERROR("out of memory\n");
81*592ffb21SWarner Losh 		return -ENOMEM;
82*592ffb21SWarner Losh 	}
83*592ffb21SWarner Losh 
84*592ffb21SWarner Losh 	dev->mm_private = mm;
85*592ffb21SWarner Losh 
86*592ffb21SWarner Losh 	if (drm_ht_create(&mm->offset_hash, 19)) {
87*592ffb21SWarner Losh 		free(mm, DRM_MEM_DRIVER);
88*592ffb21SWarner Losh 		return -ENOMEM;
89*592ffb21SWarner Losh 	}
90*592ffb21SWarner Losh 
91*592ffb21SWarner Losh 	mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL);
92*592ffb21SWarner Losh 
93*592ffb21SWarner Losh 	return 0;
94*592ffb21SWarner Losh }
95*592ffb21SWarner Losh 
96*592ffb21SWarner Losh void
97*592ffb21SWarner Losh drm_gem_destroy(struct drm_device *dev)
98*592ffb21SWarner Losh {
99*592ffb21SWarner Losh 	struct drm_gem_mm *mm = dev->mm_private;
100*592ffb21SWarner Losh 
101*592ffb21SWarner Losh 	dev->mm_private = NULL;
102*592ffb21SWarner Losh 	drm_ht_remove(&mm->offset_hash);
103*592ffb21SWarner Losh 	delete_unrhdr(mm->idxunr);
104*592ffb21SWarner Losh 	free(mm, DRM_MEM_DRIVER);
105*592ffb21SWarner Losh 	drm_gem_names_fini(&dev->object_names);
106*592ffb21SWarner Losh }
107*592ffb21SWarner Losh 
108*592ffb21SWarner Losh int drm_gem_object_init(struct drm_device *dev,
109*592ffb21SWarner Losh 			struct drm_gem_object *obj, size_t size)
110*592ffb21SWarner Losh {
111*592ffb21SWarner Losh 	KASSERT((size & (PAGE_SIZE - 1)) == 0,
112*592ffb21SWarner Losh 	    ("Bad size %ju", (uintmax_t)size));
113*592ffb21SWarner Losh 
114*592ffb21SWarner Losh 	obj->dev = dev;
115*592ffb21SWarner Losh 	obj->vm_obj = vm_pager_allocate(OBJT_DEFAULT, NULL, size,
116*592ffb21SWarner Losh 	    VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred);
117*592ffb21SWarner Losh 
118*592ffb21SWarner Losh 	obj->refcount = 1;
119*592ffb21SWarner Losh 	obj->handle_count = 0;
120*592ffb21SWarner Losh 	obj->size = size;
121*592ffb21SWarner Losh 
122*592ffb21SWarner Losh 	return 0;
123*592ffb21SWarner Losh }
124*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_init);
125*592ffb21SWarner Losh 
126*592ffb21SWarner Losh /**
127*592ffb21SWarner Losh  * Initialize an already allocated GEM object of the specified size with
128*592ffb21SWarner Losh  * no GEM provided backing store. Instead the caller is responsible for
129*592ffb21SWarner Losh  * backing the object and handling it.
130*592ffb21SWarner Losh  */
131*592ffb21SWarner Losh int drm_gem_private_object_init(struct drm_device *dev,
132*592ffb21SWarner Losh 			struct drm_gem_object *obj, size_t size)
133*592ffb21SWarner Losh {
134*592ffb21SWarner Losh 	MPASS((size & (PAGE_SIZE - 1)) == 0);
135*592ffb21SWarner Losh 
136*592ffb21SWarner Losh 	obj->dev = dev;
137*592ffb21SWarner Losh 	obj->vm_obj = NULL;
138*592ffb21SWarner Losh 
139*592ffb21SWarner Losh 	obj->refcount = 1;
140*592ffb21SWarner Losh 	atomic_store_rel_int(&obj->handle_count, 0);
141*592ffb21SWarner Losh 	obj->size = size;
142*592ffb21SWarner Losh 
143*592ffb21SWarner Losh 	return 0;
144*592ffb21SWarner Losh }
145*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_private_object_init);
146*592ffb21SWarner Losh 
147*592ffb21SWarner Losh struct drm_gem_object *
148*592ffb21SWarner Losh drm_gem_object_alloc(struct drm_device *dev, size_t size)
149*592ffb21SWarner Losh {
150*592ffb21SWarner Losh 	struct drm_gem_object *obj;
151*592ffb21SWarner Losh 
152*592ffb21SWarner Losh 	obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
153*592ffb21SWarner Losh 	if (!obj)
154*592ffb21SWarner Losh 		goto free;
155*592ffb21SWarner Losh 
156*592ffb21SWarner Losh 	if (drm_gem_object_init(dev, obj, size) != 0)
157*592ffb21SWarner Losh 		goto free;
158*592ffb21SWarner Losh 
159*592ffb21SWarner Losh 	if (dev->driver->gem_init_object != NULL &&
160*592ffb21SWarner Losh 	    dev->driver->gem_init_object(obj) != 0) {
161*592ffb21SWarner Losh 		goto dealloc;
162*592ffb21SWarner Losh 	}
163*592ffb21SWarner Losh 	return obj;
164*592ffb21SWarner Losh dealloc:
165*592ffb21SWarner Losh 	vm_object_deallocate(obj->vm_obj);
166*592ffb21SWarner Losh free:
167*592ffb21SWarner Losh 	free(obj, DRM_MEM_DRIVER);
168*592ffb21SWarner Losh 	return NULL;
169*592ffb21SWarner Losh }
170*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_alloc);
171*592ffb21SWarner Losh 
172*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET)
173*592ffb21SWarner Losh static void
174*592ffb21SWarner Losh drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
175*592ffb21SWarner Losh {
176*592ffb21SWarner Losh 	if (obj->import_attach) {
177*592ffb21SWarner Losh 		drm_prime_remove_buf_handle(&filp->prime,
178*592ffb21SWarner Losh 				obj->import_attach->dmabuf);
179*592ffb21SWarner Losh 	}
180*592ffb21SWarner Losh 	if (obj->export_dma_buf) {
181*592ffb21SWarner Losh 		drm_prime_remove_buf_handle(&filp->prime,
182*592ffb21SWarner Losh 				obj->export_dma_buf);
183*592ffb21SWarner Losh 	}
184*592ffb21SWarner Losh }
185*592ffb21SWarner Losh #endif
186*592ffb21SWarner Losh 
187*592ffb21SWarner Losh /**
188*592ffb21SWarner Losh  * Removes the mapping from handle to filp for this object.
189*592ffb21SWarner Losh  */
190*592ffb21SWarner Losh int
191*592ffb21SWarner Losh drm_gem_handle_delete(struct drm_file *filp, u32 handle)
192*592ffb21SWarner Losh {
193*592ffb21SWarner Losh 	struct drm_device *dev;
194*592ffb21SWarner Losh 	struct drm_gem_object *obj;
195*592ffb21SWarner Losh 
196*592ffb21SWarner Losh 	obj = drm_gem_names_remove(&filp->object_names, handle);
197*592ffb21SWarner Losh 	if (obj == NULL) {
198*592ffb21SWarner Losh 		return -EINVAL;
199*592ffb21SWarner Losh 	}
200*592ffb21SWarner Losh 	dev = obj->dev;
201*592ffb21SWarner Losh 
202*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET)
203*592ffb21SWarner Losh 	drm_gem_remove_prime_handles(obj, filp);
204*592ffb21SWarner Losh #endif
205*592ffb21SWarner Losh 
206*592ffb21SWarner Losh 	if (dev->driver->gem_close_object)
207*592ffb21SWarner Losh 		dev->driver->gem_close_object(obj, filp);
208*592ffb21SWarner Losh 	drm_gem_object_handle_unreference_unlocked(obj);
209*592ffb21SWarner Losh 
210*592ffb21SWarner Losh 	return 0;
211*592ffb21SWarner Losh }
212*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_delete);
213*592ffb21SWarner Losh 
214*592ffb21SWarner Losh /**
215*592ffb21SWarner Losh  * Create a handle for this object. This adds a handle reference
216*592ffb21SWarner Losh  * to the object, which includes a regular reference count. Callers
217*592ffb21SWarner Losh  * will likely want to dereference the object afterwards.
218*592ffb21SWarner Losh  */
219*592ffb21SWarner Losh int
220*592ffb21SWarner Losh drm_gem_handle_create(struct drm_file *file_priv,
221*592ffb21SWarner Losh 		       struct drm_gem_object *obj,
222*592ffb21SWarner Losh 		       u32 *handlep)
223*592ffb21SWarner Losh {
224*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
225*592ffb21SWarner Losh 	int ret;
226*592ffb21SWarner Losh 
227*592ffb21SWarner Losh 	*handlep = 0;
228*592ffb21SWarner Losh 	ret = drm_gem_name_create(&file_priv->object_names, obj, handlep);
229*592ffb21SWarner Losh 	if (ret != 0)
230*592ffb21SWarner Losh 		return ret;
231*592ffb21SWarner Losh 
232*592ffb21SWarner Losh 	drm_gem_object_handle_reference(obj);
233*592ffb21SWarner Losh 
234*592ffb21SWarner Losh 	if (dev->driver->gem_open_object) {
235*592ffb21SWarner Losh 		ret = dev->driver->gem_open_object(obj, file_priv);
236*592ffb21SWarner Losh 		if (ret) {
237*592ffb21SWarner Losh 			drm_gem_handle_delete(file_priv, *handlep);
238*592ffb21SWarner Losh 			return ret;
239*592ffb21SWarner Losh 		}
240*592ffb21SWarner Losh 	}
241*592ffb21SWarner Losh 
242*592ffb21SWarner Losh 	return 0;
243*592ffb21SWarner Losh }
244*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_handle_create);
245*592ffb21SWarner Losh 
246*592ffb21SWarner Losh void
247*592ffb21SWarner Losh drm_gem_free_mmap_offset(struct drm_gem_object *obj)
248*592ffb21SWarner Losh {
249*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
250*592ffb21SWarner Losh 	struct drm_gem_mm *mm = dev->mm_private;
251*592ffb21SWarner Losh 	struct drm_hash_item *list = &obj->map_list;
252*592ffb21SWarner Losh 
253*592ffb21SWarner Losh 	if (!obj->on_map)
254*592ffb21SWarner Losh 		return;
255*592ffb21SWarner Losh 
256*592ffb21SWarner Losh 	drm_ht_remove_item(&mm->offset_hash, list);
257*592ffb21SWarner Losh 	free_unr(mm->idxunr, list->key);
258*592ffb21SWarner Losh 	obj->on_map = false;
259*592ffb21SWarner Losh }
260*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_free_mmap_offset);
261*592ffb21SWarner Losh 
262*592ffb21SWarner Losh int
263*592ffb21SWarner Losh drm_gem_create_mmap_offset(struct drm_gem_object *obj)
264*592ffb21SWarner Losh {
265*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
266*592ffb21SWarner Losh 	struct drm_gem_mm *mm = dev->mm_private;
267*592ffb21SWarner Losh 	int ret;
268*592ffb21SWarner Losh 
269*592ffb21SWarner Losh 	if (obj->on_map)
270*592ffb21SWarner Losh 		return 0;
271*592ffb21SWarner Losh 
272*592ffb21SWarner Losh 	obj->map_list.key = alloc_unr(mm->idxunr);
273*592ffb21SWarner Losh 	ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
274*592ffb21SWarner Losh 	if (ret) {
275*592ffb21SWarner Losh 		DRM_ERROR("failed to add to map hash\n");
276*592ffb21SWarner Losh 		free_unr(mm->idxunr, obj->map_list.key);
277*592ffb21SWarner Losh 		return ret;
278*592ffb21SWarner Losh 	}
279*592ffb21SWarner Losh 	obj->on_map = true;
280*592ffb21SWarner Losh 
281*592ffb21SWarner Losh 	return 0;
282*592ffb21SWarner Losh }
283*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_create_mmap_offset);
284*592ffb21SWarner Losh 
285*592ffb21SWarner Losh /** Returns a reference to the object named by the handle. */
286*592ffb21SWarner Losh struct drm_gem_object *
287*592ffb21SWarner Losh drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
288*592ffb21SWarner Losh 		      u32 handle)
289*592ffb21SWarner Losh {
290*592ffb21SWarner Losh 	struct drm_gem_object *obj;
291*592ffb21SWarner Losh 
292*592ffb21SWarner Losh 	obj = drm_gem_name_ref(&filp->object_names, handle,
293*592ffb21SWarner Losh 	    (void (*)(void *))drm_gem_object_reference);
294*592ffb21SWarner Losh 
295*592ffb21SWarner Losh 	return obj;
296*592ffb21SWarner Losh }
297*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_lookup);
298*592ffb21SWarner Losh 
299*592ffb21SWarner Losh int
300*592ffb21SWarner Losh drm_gem_close_ioctl(struct drm_device *dev, void *data,
301*592ffb21SWarner Losh 		    struct drm_file *file_priv)
302*592ffb21SWarner Losh {
303*592ffb21SWarner Losh 	struct drm_gem_close *args = data;
304*592ffb21SWarner Losh 	int ret;
305*592ffb21SWarner Losh 
306*592ffb21SWarner Losh 	if (!(dev->driver->driver_features & DRIVER_GEM))
307*592ffb21SWarner Losh 		return -ENODEV;
308*592ffb21SWarner Losh 
309*592ffb21SWarner Losh 	ret = drm_gem_handle_delete(file_priv, args->handle);
310*592ffb21SWarner Losh 
311*592ffb21SWarner Losh 	return ret;
312*592ffb21SWarner Losh }
313*592ffb21SWarner Losh 
314*592ffb21SWarner Losh int
315*592ffb21SWarner Losh drm_gem_flink_ioctl(struct drm_device *dev, void *data,
316*592ffb21SWarner Losh 		    struct drm_file *file_priv)
317*592ffb21SWarner Losh {
318*592ffb21SWarner Losh 	struct drm_gem_flink *args = data;
319*592ffb21SWarner Losh 	struct drm_gem_object *obj;
320*592ffb21SWarner Losh 	int ret;
321*592ffb21SWarner Losh 
322*592ffb21SWarner Losh 	if (!(dev->driver->driver_features & DRIVER_GEM))
323*592ffb21SWarner Losh 		return -ENODEV;
324*592ffb21SWarner Losh 
325*592ffb21SWarner Losh 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
326*592ffb21SWarner Losh 	if (obj == NULL)
327*592ffb21SWarner Losh 		return -ENOENT;
328*592ffb21SWarner Losh 
329*592ffb21SWarner Losh 	ret = drm_gem_name_create(&dev->object_names, obj, &obj->name);
330*592ffb21SWarner Losh 	if (ret != 0) {
331*592ffb21SWarner Losh 		if (ret == -EALREADY)
332*592ffb21SWarner Losh 			ret = 0;
333*592ffb21SWarner Losh 		drm_gem_object_unreference_unlocked(obj);
334*592ffb21SWarner Losh 	}
335*592ffb21SWarner Losh 	if (ret == 0)
336*592ffb21SWarner Losh 		args->name = obj->name;
337*592ffb21SWarner Losh 	return ret;
338*592ffb21SWarner Losh }
339*592ffb21SWarner Losh 
340*592ffb21SWarner Losh int
341*592ffb21SWarner Losh drm_gem_open_ioctl(struct drm_device *dev, void *data,
342*592ffb21SWarner Losh 		   struct drm_file *file_priv)
343*592ffb21SWarner Losh {
344*592ffb21SWarner Losh 	struct drm_gem_open *args = data;
345*592ffb21SWarner Losh 	struct drm_gem_object *obj;
346*592ffb21SWarner Losh 	int ret;
347*592ffb21SWarner Losh 	u32 handle;
348*592ffb21SWarner Losh 
349*592ffb21SWarner Losh 	if (!(dev->driver->driver_features & DRIVER_GEM))
350*592ffb21SWarner Losh 		return -ENODEV;
351*592ffb21SWarner Losh 
352*592ffb21SWarner Losh 	obj = drm_gem_name_ref(&dev->object_names, args->name,
353*592ffb21SWarner Losh 	    (void (*)(void *))drm_gem_object_reference);
354*592ffb21SWarner Losh 	if (!obj)
355*592ffb21SWarner Losh 		return -ENOENT;
356*592ffb21SWarner Losh 
357*592ffb21SWarner Losh 	ret = drm_gem_handle_create(file_priv, obj, &handle);
358*592ffb21SWarner Losh 	drm_gem_object_unreference_unlocked(obj);
359*592ffb21SWarner Losh 	if (ret)
360*592ffb21SWarner Losh 		return ret;
361*592ffb21SWarner Losh 
362*592ffb21SWarner Losh 	args->handle = handle;
363*592ffb21SWarner Losh 	args->size = obj->size;
364*592ffb21SWarner Losh 
365*592ffb21SWarner Losh 	return 0;
366*592ffb21SWarner Losh }
367*592ffb21SWarner Losh 
368*592ffb21SWarner Losh void
369*592ffb21SWarner Losh drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
370*592ffb21SWarner Losh {
371*592ffb21SWarner Losh 
372*592ffb21SWarner Losh 	drm_gem_names_init(&file_private->object_names);
373*592ffb21SWarner Losh }
374*592ffb21SWarner Losh 
375*592ffb21SWarner Losh static int
376*592ffb21SWarner Losh drm_gem_object_release_handle(uint32_t name, void *ptr, void *data)
377*592ffb21SWarner Losh {
378*592ffb21SWarner Losh 	struct drm_file *file_priv = data;
379*592ffb21SWarner Losh 	struct drm_gem_object *obj = ptr;
380*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
381*592ffb21SWarner Losh 
382*592ffb21SWarner Losh #if defined(FREEBSD_NOTYET)
383*592ffb21SWarner Losh 	drm_gem_remove_prime_handles(obj, file_priv);
384*592ffb21SWarner Losh #endif
385*592ffb21SWarner Losh 
386*592ffb21SWarner Losh 	if (dev->driver->gem_close_object)
387*592ffb21SWarner Losh 		dev->driver->gem_close_object(obj, file_priv);
388*592ffb21SWarner Losh 
389*592ffb21SWarner Losh 	drm_gem_object_handle_unreference_unlocked(obj);
390*592ffb21SWarner Losh 
391*592ffb21SWarner Losh 	return 0;
392*592ffb21SWarner Losh }
393*592ffb21SWarner Losh 
394*592ffb21SWarner Losh void
395*592ffb21SWarner Losh drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
396*592ffb21SWarner Losh {
397*592ffb21SWarner Losh 	drm_gem_names_foreach(&file_private->object_names,
398*592ffb21SWarner Losh 	    drm_gem_object_release_handle, file_private);
399*592ffb21SWarner Losh 
400*592ffb21SWarner Losh 	drm_gem_names_fini(&file_private->object_names);
401*592ffb21SWarner Losh }
402*592ffb21SWarner Losh 
403*592ffb21SWarner Losh void
404*592ffb21SWarner Losh drm_gem_object_release(struct drm_gem_object *obj)
405*592ffb21SWarner Losh {
406*592ffb21SWarner Losh 
407*592ffb21SWarner Losh 	/*
408*592ffb21SWarner Losh 	 * obj->vm_obj can be NULL for private gem objects.
409*592ffb21SWarner Losh 	 */
410*592ffb21SWarner Losh 	vm_object_deallocate(obj->vm_obj);
411*592ffb21SWarner Losh }
412*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_release);
413*592ffb21SWarner Losh 
414*592ffb21SWarner Losh void
415*592ffb21SWarner Losh drm_gem_object_free(struct drm_gem_object *obj)
416*592ffb21SWarner Losh {
417*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
418*592ffb21SWarner Losh 
419*592ffb21SWarner Losh 	DRM_LOCK_ASSERT(dev);
420*592ffb21SWarner Losh 	if (dev->driver->gem_free_object != NULL)
421*592ffb21SWarner Losh 		dev->driver->gem_free_object(obj);
422*592ffb21SWarner Losh }
423*592ffb21SWarner Losh EXPORT_SYMBOL(drm_gem_object_free);
424*592ffb21SWarner Losh 
425*592ffb21SWarner Losh void drm_gem_object_handle_free(struct drm_gem_object *obj)
426*592ffb21SWarner Losh {
427*592ffb21SWarner Losh 	struct drm_device *dev = obj->dev;
428*592ffb21SWarner Losh 	struct drm_gem_object *obj1;
429*592ffb21SWarner Losh 
430*592ffb21SWarner Losh 	if (obj->name) {
431*592ffb21SWarner Losh 		obj1 = drm_gem_names_remove(&dev->object_names, obj->name);
432*592ffb21SWarner Losh 		obj->name = 0;
433*592ffb21SWarner Losh 		drm_gem_object_unreference(obj1);
434*592ffb21SWarner Losh 	}
435*592ffb21SWarner Losh }
436*592ffb21SWarner Losh 
437*592ffb21SWarner Losh static struct drm_gem_object *
438*592ffb21SWarner Losh drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset)
439*592ffb21SWarner Losh {
440*592ffb21SWarner Losh 	struct drm_gem_object *obj;
441*592ffb21SWarner Losh 	struct drm_gem_mm *mm;
442*592ffb21SWarner Losh 	struct drm_hash_item *map_list;
443*592ffb21SWarner Losh 
444*592ffb21SWarner Losh 	if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY)
445*592ffb21SWarner Losh 		return (NULL);
446*592ffb21SWarner Losh 	offset &= ~DRM_GEM_MAPPING_KEY;
447*592ffb21SWarner Losh 	mm = dev->mm_private;
448*592ffb21SWarner Losh 	if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset),
449*592ffb21SWarner Losh 	    &map_list) != 0) {
450*592ffb21SWarner Losh 	DRM_DEBUG("drm_gem_object_from_offset: offset 0x%jx obj not found\n",
451*592ffb21SWarner Losh 		    (uintmax_t)offset);
452*592ffb21SWarner Losh 		return (NULL);
453*592ffb21SWarner Losh 	}
454*592ffb21SWarner Losh 	obj = __containerof(map_list, struct drm_gem_object, map_list);
455*592ffb21SWarner Losh 	return (obj);
456*592ffb21SWarner Losh }
457*592ffb21SWarner Losh 
458*592ffb21SWarner Losh int
459*592ffb21SWarner Losh drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size,
460*592ffb21SWarner Losh     struct vm_object **obj_res, int nprot)
461*592ffb21SWarner Losh {
462*592ffb21SWarner Losh 	struct drm_gem_object *gem_obj;
463*592ffb21SWarner Losh 	struct vm_object *vm_obj;
464*592ffb21SWarner Losh 
465*592ffb21SWarner Losh 	DRM_LOCK(dev);
466*592ffb21SWarner Losh 	gem_obj = drm_gem_object_from_offset(dev, *offset);
467*592ffb21SWarner Losh 	if (gem_obj == NULL) {
468*592ffb21SWarner Losh 		DRM_UNLOCK(dev);
469*592ffb21SWarner Losh 		return (-ENODEV);
470*592ffb21SWarner Losh 	}
471*592ffb21SWarner Losh 	drm_gem_object_reference(gem_obj);
472*592ffb21SWarner Losh 	DRM_UNLOCK(dev);
473*592ffb21SWarner Losh 	vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE,
474*592ffb21SWarner Losh 	    dev->driver->gem_pager_ops, size, nprot,
475*592ffb21SWarner Losh 	    DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred);
476*592ffb21SWarner Losh 	if (vm_obj == NULL) {
477*592ffb21SWarner Losh 		drm_gem_object_unreference_unlocked(gem_obj);
478*592ffb21SWarner Losh 		return (-EINVAL);
479*592ffb21SWarner Losh 	}
480*592ffb21SWarner Losh 	*offset = DRM_GEM_MAPPING_MAPOFF(*offset);
481*592ffb21SWarner Losh 	*obj_res = vm_obj;
482*592ffb21SWarner Losh 	return (0);
483*592ffb21SWarner Losh }
484*592ffb21SWarner Losh 
485*592ffb21SWarner Losh void
486*592ffb21SWarner Losh drm_gem_pager_dtr(void *handle)
487*592ffb21SWarner Losh {
488*592ffb21SWarner Losh 	struct drm_gem_object *obj;
489*592ffb21SWarner Losh 	struct drm_device *dev;
490*592ffb21SWarner Losh 
491*592ffb21SWarner Losh 	obj = handle;
492*592ffb21SWarner Losh 	dev = obj->dev;
493*592ffb21SWarner Losh 
494*592ffb21SWarner Losh 	DRM_LOCK(dev);
495*592ffb21SWarner Losh 	drm_gem_free_mmap_offset(obj);
496*592ffb21SWarner Losh 	drm_gem_object_unreference(obj);
497*592ffb21SWarner Losh 	DRM_UNLOCK(dev);
498*592ffb21SWarner Losh }
499