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