blob: 7fa5c297799b1681cd25587926a1b74106abc85c [file] [log] [blame]
miao chen - Sun Microsystems - Beijing China0035d212009-12-05 13:25:40 +08001/*
2 * Copyright (c) 2009, Intel Corporation.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * Authors:
25 * Eric Anholt <eric@anholt.net>
26 *
27 */
28
29/*
30 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
31 * Use is subject to license terms.
32 */
33
34#include <vm/anon.h>
35#include <vm/seg_kmem.h>
36#include <vm/seg_kp.h>
37#include <vm/seg_map.h>
38#include <sys/fcntl.h>
39#include <sys/vnode.h>
40#include <sys/file.h>
41#include <sys/bitmap.h>
42#include <sys/ddi.h>
43#include <sys/sunddi.h>
Gordon Rossdc1b2692016-10-09 11:32:43 -040044#include <sys/gfx_private.h>
miao chen - Sun Microsystems - Beijing China0035d212009-12-05 13:25:40 +080045#include "drmP.h"
46#include "drm.h"
47
48/*
49 * @file drm_gem.c
50 *
51 * This file provides some of the base ioctls and library routines for
52 * the graphics memory manager implemented by each device driver.
53 *
54 * Because various devices have different requirements in terms of
55 * synchronization and migration strategies, implementing that is left up to
56 * the driver, and all that the general API provides should be generic --
57 * allocating objects, reading/writing data with the cpu, freeing objects.
58 * Even there, platform-dependent optimizations for reading/writing data with
59 * the CPU mean we'll likely hook those out to driver-specific calls. However,
60 * the DRI2 implementation wants to have at least allocate/mmap be generic.
61 *
62 * The goal was to have swap-backed object allocation managed through
63 * struct file. However, file descriptors as handles to a struct file have
64 * two major failings:
65 * - Process limits prevent more than 1024 or so being used at a time by
66 * default.
67 * - Inability to allocate high fds will aggravate the X Server's select()
68 * handling, and likely that of many GL client applications as well.
69 *
70 * This led to a plan of using our own integer IDs(called handles, following
71 * DRM terminology) to mimic fds, and implement the fd syscalls we need as
72 * ioctls. The objects themselves will still include the struct file so
73 * that we can transition to fds if the required kernel infrastructure shows
74 * up at a later date, and as our interface with shmfs for memory allocation.
75 */
76
77void
78idr_list_init(struct idr_list *head)
79{
80 struct idr_list *entry;
81 /* HASH for accelerate */
82 entry = kmem_zalloc(DRM_GEM_OBJIDR_HASHNODE
miao chen - Sun Microsystems - Beijing China2e6e9012009-12-19 15:01:39 +080083 * sizeof (struct idr_list), KM_SLEEP);
miao chen - Sun Microsystems - Beijing China0035d212009-12-05 13:25:40 +080084 head->next = entry;
85 for (int i = 0; i < DRM_GEM_OBJIDR_HASHNODE; i++) {
86 INIT_LIST_HEAD(&entry[i]);
87 }
88}
89
90int
91idr_list_get_new_above(struct idr_list *head,
92 struct drm_gem_object *obj,
93 int *handlep)
94{
95 struct idr_list *entry;
96 int key;
miao chen - Sun Microsystems - Beijing China2e6e9012009-12-19 15:01:39 +080097 entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
miao chen - Sun Microsystems - Beijing China0035d212009-12-05 13:25:40 +080098 key = obj->name % DRM_GEM_OBJIDR_HASHNODE;
99 list_add(entry, &head->next[key], NULL);
100 entry->obj = obj;
101 entry->handle = obj->name;
102 *handlep = obj->name;
103 return (0);
104}
105
106struct drm_gem_object *
107idr_list_find(struct idr_list *head,
108 uint32_t name)
109{
110 struct idr_list *entry;
111 int key;
112 key = name % DRM_GEM_OBJIDR_HASHNODE;
113
114 list_for_each(entry, &head->next[key]) {
115 if (entry->handle == name)
116 return (entry->obj);
117 }
118 return (NULL);
119}
120
121int
122idr_list_remove(struct idr_list *head,
123 uint32_t name)
124{
125 struct idr_list *entry, *temp;
126 int key;
127 key = name % DRM_GEM_OBJIDR_HASHNODE;
128 list_for_each_safe(entry, temp, &head->next[key]) {
129 if (entry->handle == name) {
130 list_del(entry);
131 kmem_free(entry, sizeof (*entry));
132 return (0);
133 }
134 }
135 DRM_ERROR("Failed to remove the object %d", name);
136 return (-1);
137}
138
139void
140idr_list_free(struct idr_list *head)
141{
142 struct idr_list *entry, *temp;
143 for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
144 list_for_each_safe(entry, temp, &head->next[key]) {
145 list_del(entry);
146 kmem_free(entry, sizeof (*entry));
147 }
148 }
149 kmem_free(head->next,
150 DRM_GEM_OBJIDR_HASHNODE * sizeof (struct idr_list));
151 head->next = NULL;
152}
153
154int
155idr_list_empty(struct idr_list *head)
156{
157 int empty;
158 for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
159 empty = list_empty(&(head)->next[key]);
160 if (!empty)
161 return (empty);
162 }
163 return (1);
164}
165
166static uint32_t shfile_name = 0;
167#define SHFILE_NAME_MAX 0xffffffff
168
169/*
170 * will be set to 1 for 32 bit x86 systems only, in startup.c
171 */
172extern int segkp_fromheap;
173extern ulong_t *segkp_bitmap;
174
175void
176drm_gem_object_reference(struct drm_gem_object *obj)
177{
178 atomic_inc(&obj->refcount);
179}
180
181void
182drm_gem_object_unreference(struct drm_gem_object *obj)
183{
184 if (obj == NULL)
185 return;
186
187 atomic_sub(1, &obj->refcount);
188 if (obj->refcount == 0)
189 drm_gem_object_free(obj);
190}
191
192void
193drm_gem_object_handle_reference(struct drm_gem_object *obj)
194{
195 drm_gem_object_reference(obj);
196 atomic_inc(&obj->handlecount);
197}
198
199void
200drm_gem_object_handle_unreference(struct drm_gem_object *obj)
201{
202 if (obj == NULL)
203 return;
204
205 /*
206 * Must bump handle count first as this may be the last
207 * ref, in which case the object would disappear before we
208 * checked for a name
209 */
210 atomic_sub(1, &obj->handlecount);
211 if (obj->handlecount == 0)
212 drm_gem_object_handle_free(obj);
213 drm_gem_object_unreference(obj);
214}
215
216/*
217 * Initialize the GEM device fields
218 */
219
220int
221drm_gem_init(struct drm_device *dev)
222{
223 mutex_init(&dev->object_name_lock, NULL, MUTEX_DRIVER, NULL);
224 idr_list_init(&dev->object_name_idr);
225
226 atomic_set(&dev->object_count, 0);
227 atomic_set(&dev->object_memory, 0);
228 atomic_set(&dev->pin_count, 0);
229 atomic_set(&dev->pin_memory, 0);
230 atomic_set(&dev->gtt_count, 0);
231 atomic_set(&dev->gtt_memory, 0);
232 return (0);
233}
234
235/*
236 * Allocate a GEM object of the specified size with shmfs backing store
237 */
238struct drm_gem_object *
239drm_gem_object_alloc(struct drm_device *dev, size_t size)
240{
241 static ddi_dma_attr_t dma_attr = {
242 DMA_ATTR_V0,
243 0U, /* dma_attr_addr_lo */
244 0xffffffffU, /* dma_attr_addr_hi */
245 0xffffffffU, /* dma_attr_count_max */
246 4096, /* dma_attr_align */
247 0x1fffU, /* dma_attr_burstsizes */
248 1, /* dma_attr_minxfer */
249 0xffffffffU, /* dma_attr_maxxfer */
250 0xffffffffU, /* dma_attr_seg */
251 1, /* dma_attr_sgllen, variable */
252 4, /* dma_attr_granular */
253 0 /* dma_attr_flags */
254 };
255 static ddi_device_acc_attr_t acc_attr = {
256 DDI_DEVICE_ATTR_V0,
257 DDI_NEVERSWAP_ACC,
258 DDI_MERGING_OK_ACC
259 };
260 struct drm_gem_object *obj;
261 ddi_dma_cookie_t cookie;
262 uint_t cookie_cnt;
263 drm_local_map_t *map;
264
265 pgcnt_t real_pgcnt, pgcnt = btopr(size);
266 uint32_t paddr, cookie_end;
267 int i, n;
268
269 obj = kmem_zalloc(sizeof (struct drm_gem_object), KM_NOSLEEP);
270 if (obj == NULL)
271 return (NULL);
272
273 obj->dev = dev;
274 obj->flink = 0;
275 obj->size = size;
276
277 if (shfile_name == SHFILE_NAME_MAX) {
278 DRM_ERROR("No name space for object");
279 goto err1;
280 } else {
281 obj->name = ++shfile_name;
282 }
283
284 dma_attr.dma_attr_sgllen = (int)pgcnt;
285
286 if (ddi_dma_alloc_handle(dev->dip, &dma_attr,
287 DDI_DMA_DONTWAIT, NULL, &obj->dma_hdl)) {
288 DRM_ERROR("drm_gem_object_alloc: "
289 "ddi_dma_alloc_handle failed");
290 goto err1;
291 }
292 if (ddi_dma_mem_alloc(obj->dma_hdl, ptob(pgcnt), &acc_attr,
293 IOMEM_DATA_UC_WR_COMBINE, DDI_DMA_DONTWAIT, NULL,
294 &obj->kaddr, &obj->real_size, &obj->acc_hdl)) {
295 DRM_ERROR("drm_gem_object_alloc: "
296 "ddi_dma_mem_alloc failed");
297 goto err2;
298 }
299 if (ddi_dma_addr_bind_handle(obj->dma_hdl, NULL,
300 obj->kaddr, obj->real_size, DDI_DMA_RDWR,
301 DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_cnt)
302 != DDI_DMA_MAPPED) {
303 DRM_ERROR("drm_gem_object_alloc: "
304 "ddi_dma_addr_bind_handle failed");
305 goto err3;
306 }
307
308 real_pgcnt = btopr(obj->real_size);
309
310 obj->pfnarray = kmem_zalloc(real_pgcnt * sizeof (pfn_t), KM_NOSLEEP);
311 if (obj->pfnarray == NULL) {
312 goto err4;
313 }
314 for (n = 0, i = 1; ; i++) {
315 for (paddr = cookie.dmac_address,
316 cookie_end = cookie.dmac_address + cookie.dmac_size;
317 paddr < cookie_end;
318 paddr += PAGESIZE) {
319 obj->pfnarray[n++] = btop(paddr);
320 if (n >= real_pgcnt)
321 goto addmap;
322 }
323 if (i >= cookie_cnt)
324 break;
325 ddi_dma_nextcookie(obj->dma_hdl, &cookie);
326 }
327
328addmap:
329 map = drm_alloc(sizeof (struct drm_local_map), DRM_MEM_MAPS);
330 if (map == NULL) {
331 goto err5;
332 }
333
334 map->handle = obj;
335 map->offset = (uintptr_t)map->handle;
336 map->offset &= 0xffffffffUL;
337 map->dev_addr = map->handle;
338 map->size = obj->real_size;
339 map->type = _DRM_TTM;
340 map->flags = _DRM_WRITE_COMBINING | _DRM_REMOVABLE;
341 map->drm_umem_cookie =
342 gfxp_umem_cookie_init(obj->kaddr, obj->real_size);
343 if (map->drm_umem_cookie == NULL) {
344 goto err6;
345 }
346
347 obj->map = map;
348
349 atomic_set(&obj->refcount, 1);
350 atomic_set(&obj->handlecount, 1);
351 if (dev->driver->gem_init_object != NULL &&
352 dev->driver->gem_init_object(obj) != 0) {
353 goto err7;
354 }
355 atomic_inc(&dev->object_count);
356 atomic_add(obj->size, &dev->object_memory);
357
358 return (obj);
359
360err7:
361 gfxp_umem_cookie_destroy(map->drm_umem_cookie);
362err6:
363 drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
364err5:
365 kmem_free(obj->pfnarray, real_pgcnt * sizeof (pfn_t));
366err4:
367 (void) ddi_dma_unbind_handle(obj->dma_hdl);
368err3:
369 ddi_dma_mem_free(&obj->acc_hdl);
370err2:
371 ddi_dma_free_handle(&obj->dma_hdl);
372err1:
373 kmem_free(obj, sizeof (struct drm_gem_object));
374
375 return (NULL);
376}
377
378/*
379 * Removes the mapping from handle to filp for this object.
380 */
381static int
382drm_gem_handle_delete(struct drm_file *filp, int handle)
383{
384 struct drm_device *dev;
385 struct drm_gem_object *obj;
386 int err;
387 /*
388 * This is gross. The idr system doesn't let us try a delete and
389 * return an error code. It just spews if you fail at deleting.
390 * So, we have to grab a lock around finding the object and then
391 * doing the delete on it and dropping the refcount, or the user
392 * could race us to double-decrement the refcount and cause a
393 * use-after-free later. Given the frequency of our handle lookups,
394 * we may want to use ida for number allocation and a hash table
395 * for the pointers, anyway.
396 */
397 spin_lock(&filp->table_lock);
398
399 /* Check if we currently have a reference on the object */
400 obj = idr_list_find(&filp->object_idr, handle);
401 if (obj == NULL) {
402 spin_unlock(&filp->table_lock);
403 DRM_ERROR("obj %d is not in tne list, failed to close", handle);
404 return (EINVAL);
405 }
406 dev = obj->dev;
407
408 /* Release reference and decrement refcount. */
409 err = idr_list_remove(&filp->object_idr, handle);
410 if (err == -1)
411 DRM_ERROR("%s", __func__);
412
413 spin_unlock(&filp->table_lock);
414
415 spin_lock(&dev->struct_mutex);
416 drm_gem_object_handle_unreference(obj);
417 spin_unlock(&dev->struct_mutex);
418 return (0);
419}
420
421/*
422 * Create a handle for this object. This adds a handle reference
423 * to the object, which includes a regular reference count. Callers
424 * will likely want to dereference the object afterwards.
425 */
426int
427drm_gem_handle_create(struct drm_file *file_priv,
428 struct drm_gem_object *obj,
429 int *handlep)
430{
431 int ret;
432
433 /*
434 * Get the user-visible handle using idr.
435 */
436again:
437 /* ensure there is space available to allocate a handle */
438
439 /* do the allocation under our spinlock */
440 spin_lock(&file_priv->table_lock);
441 ret = idr_list_get_new_above(&file_priv->object_idr, obj, handlep);
442 spin_unlock(&file_priv->table_lock);
443 if (ret == -EAGAIN)
444 goto again;
445
446 if (ret != 0) {
447 DRM_ERROR("Failed to create handle");
448 return (ret);
449 }
450
451 drm_gem_object_handle_reference(obj);
452 return (0);
453}
454
455/* Returns a reference to the object named by the handle. */
456struct drm_gem_object *
457drm_gem_object_lookup(struct drm_file *filp,
458 int handle)
459{
460 struct drm_gem_object *obj;
461
462 spin_lock(&filp->table_lock);
463
464 /* Check if we currently have a reference on the object */
465 obj = idr_list_find(&filp->object_idr, handle);
466 if (obj == NULL) {
467 spin_unlock(&filp->table_lock);
468 DRM_ERROR("object_lookup failed, handle %d", handle);
469 return (NULL);
470 }
471
472 drm_gem_object_reference(obj);
473
474 spin_unlock(&filp->table_lock);
475
476 return (obj);
477}
478
479/*
480 * Releases the handle to an mm object.
481 */
482/*ARGSUSED*/
483int
484drm_gem_close_ioctl(DRM_IOCTL_ARGS)
485{
486 DRM_DEVICE;
487 struct drm_gem_close args;
488 int ret;
489
490 if (!(dev->driver->use_gem == 1))
491 return (ENODEV);
492
493 DRM_COPYFROM_WITH_RETURN(&args,
494 (void *)data, sizeof (args));
495
496 ret = drm_gem_handle_delete(fpriv, args.handle);
497
498 return (ret);
499}
500
501/*
502 * Create a global name for an object, returning the name.
503 *
504 * Note that the name does not hold a reference; when the object
505 * is freed, the name goes away.
506 */
507/*ARGSUSED*/
508int
509drm_gem_flink_ioctl(DRM_IOCTL_ARGS)
510{
511 DRM_DEVICE;
512 struct drm_gem_flink args;
513 struct drm_gem_object *obj;
514 int ret, handle;
515
516 if (!(dev->driver->use_gem == 1))
517 return (ENODEV);
518
519 DRM_COPYFROM_WITH_RETURN(&args,
520 (void *)data, sizeof (args));
521 obj = drm_gem_object_lookup(fpriv, args.handle);
522 if (obj == NULL)
523 return (EINVAL);
524 handle = args.handle;
525 spin_lock(&dev->object_name_lock);
526 if (!obj->flink) {
527 /* only creat a node in object_name_idr, no update anything */
528 ret = idr_list_get_new_above(&dev->object_name_idr,
529 obj, &handle);
530 obj->flink = obj->name;
531 /* Allocate a reference for the name table. */
532 drm_gem_object_reference(obj);
533 }
534 /*
535 * Leave the reference from the lookup around as the
536 * name table now holds one
537 */
538 args.name = obj->name;
539
540 spin_unlock(&dev->object_name_lock);
541 ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
542 if (ret != 0)
543 DRM_ERROR(" gem flink error! %d", ret);
544
545 spin_lock(&dev->struct_mutex);
546 drm_gem_object_unreference(obj);
547 spin_unlock(&dev->struct_mutex);
548
549 return (ret);
550}
551
552/*
553 * Open an object using the global name, returning a handle and the size.
554 *
555 * This handle (of course) holds a reference to the object, so the object
556 * will not go away until the handle is deleted.
557 */
558/*ARGSUSED*/
559int
560drm_gem_open_ioctl(DRM_IOCTL_ARGS)
561{
562 DRM_DEVICE;
563 struct drm_gem_open args;
564 struct drm_gem_object *obj;
565 int ret;
566 int handle;
567
568 if (!(dev->driver->use_gem == 1)) {
569 DRM_ERROR("Not support GEM");
570 return (ENODEV);
571 }
572 DRM_COPYFROM_WITH_RETURN(&args,
573 (void *) data, sizeof (args));
574
575 spin_lock(&dev->object_name_lock);
576
577 obj = idr_list_find(&dev->object_name_idr, args.name);
578
579 if (obj)
580 drm_gem_object_reference(obj);
581 spin_unlock(&dev->object_name_lock);
582 if (!obj) {
583 DRM_ERROR("Can't find the obj %d", args.name);
584 return (ENOENT);
585 }
586
587 ret = drm_gem_handle_create(fpriv, obj, &handle);
588 spin_lock(&dev->struct_mutex);
589 drm_gem_object_unreference(obj);
590 spin_unlock(&dev->struct_mutex);
591
592 args.handle = args.name;
593 args.size = obj->size;
594
595 ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
596 if (ret != 0)
597 DRM_ERROR(" gem open error! %d", ret);
598 return (ret);
599}
600
601/*
602 * Called at device open time, sets up the structure for handling refcounting
603 * of mm objects.
604 */
605void
606drm_gem_open(struct drm_file *file_private)
607{
608 idr_list_init(&file_private->object_idr);
609 mutex_init(&file_private->table_lock, NULL, MUTEX_DRIVER, NULL);
610}
611
612/*
613 * Called at device close to release the file's
614 * handle references on objects.
615 */
616static void
617drm_gem_object_release_handle(struct drm_gem_object *obj)
618{
619 drm_gem_object_handle_unreference(obj);
620}
621
622/*
623 * Called at close time when the filp is going away.
624 *
625 * Releases any remaining references on objects by this filp.
626 */
627void
628drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
629{
630 struct idr_list *entry;
631 spin_lock(&dev->struct_mutex);
632
633 idr_list_for_each(entry, &file_private->object_idr)
634 drm_gem_object_release_handle(entry->obj);
635
636 idr_list_free(&file_private->object_idr);
637 spin_unlock(&dev->struct_mutex);
638
639}
640
641/*
642 * Called after the last reference to the object has been lost.
643 *
644 * Frees the object
645 */
646void
647drm_gem_object_free(struct drm_gem_object *obj)
648{
649 struct drm_device *dev = obj->dev;
650 struct drm_local_map *map = obj->map;
651
652 if (dev->driver->gem_free_object != NULL)
653 dev->driver->gem_free_object(obj);
654
655 gfxp_umem_cookie_destroy(map->drm_umem_cookie);
656 drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
657
658 kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
659
660 (void) ddi_dma_unbind_handle(obj->dma_hdl);
661 ddi_dma_mem_free(&obj->acc_hdl);
662 ddi_dma_free_handle(&obj->dma_hdl);
663
664 atomic_dec(&dev->object_count);
665 atomic_sub(obj->size, &dev->object_memory);
666 kmem_free(obj, sizeof (struct drm_gem_object));
667}
668
669/*
670 * Called after the last handle to the object has been closed
671 *
672 * Removes any name for the object. Note that this must be
673 * called before drm_gem_object_free or we'll be touching
674 * freed memory
675 */
676void
677drm_gem_object_handle_free(struct drm_gem_object *obj)
678{
679 int err;
680 struct drm_device *dev = obj->dev;
681 /* Remove any name for this object */
682 spin_lock(&dev->object_name_lock);
683 if (obj->flink) {
684 err = idr_list_remove(&dev->object_name_idr, obj->name);
685 if (err == -1)
686 DRM_ERROR("%s", __func__);
687 obj->flink = 0;
688 spin_unlock(&dev->object_name_lock);
689 /*
690 * The object name held a reference to this object, drop
691 * that now.
692 */
693 drm_gem_object_unreference(obj);
694 } else
695
696 spin_unlock(&dev->object_name_lock);
697
698}