111260SMiao.Chen@Sun.COM /*
211260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation.
311260SMiao.Chen@Sun.COM * All Rights Reserved.
411260SMiao.Chen@Sun.COM *
511260SMiao.Chen@Sun.COM * Permission is hereby granted, free of charge, to any person obtaining a
611260SMiao.Chen@Sun.COM * copy of this software and associated documentation files (the "Software"),
711260SMiao.Chen@Sun.COM * to deal in the Software without restriction, including without limitation
811260SMiao.Chen@Sun.COM * the rights to use, copy, modify, merge, publish, distribute, sublicense,
911260SMiao.Chen@Sun.COM * and/or sell copies of the Software, and to permit persons to whom the
1011260SMiao.Chen@Sun.COM * Software is furnished to do so, subject to the following conditions:
1111260SMiao.Chen@Sun.COM *
1211260SMiao.Chen@Sun.COM * The above copyright notice and this permission notice (including the next
1311260SMiao.Chen@Sun.COM * paragraph) shall be included in all copies or substantial portions of the
1411260SMiao.Chen@Sun.COM * Software.
1511260SMiao.Chen@Sun.COM *
1611260SMiao.Chen@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1711260SMiao.Chen@Sun.COM * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1811260SMiao.Chen@Sun.COM * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1911260SMiao.Chen@Sun.COM * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2011260SMiao.Chen@Sun.COM * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2111260SMiao.Chen@Sun.COM * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2211260SMiao.Chen@Sun.COM * IN THE SOFTWARE.
2311260SMiao.Chen@Sun.COM *
2411260SMiao.Chen@Sun.COM * Authors:
2511260SMiao.Chen@Sun.COM * Eric Anholt <eric@anholt.net>
2611260SMiao.Chen@Sun.COM *
2711260SMiao.Chen@Sun.COM */
2811260SMiao.Chen@Sun.COM
2911260SMiao.Chen@Sun.COM /*
3011260SMiao.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3111260SMiao.Chen@Sun.COM * Use is subject to license terms.
3211260SMiao.Chen@Sun.COM */
3311260SMiao.Chen@Sun.COM
3411260SMiao.Chen@Sun.COM #include <vm/anon.h>
3511260SMiao.Chen@Sun.COM #include <vm/seg_kmem.h>
3611260SMiao.Chen@Sun.COM #include <vm/seg_kp.h>
3711260SMiao.Chen@Sun.COM #include <vm/seg_map.h>
3811260SMiao.Chen@Sun.COM #include <sys/fcntl.h>
3911260SMiao.Chen@Sun.COM #include <sys/vnode.h>
4011260SMiao.Chen@Sun.COM #include <sys/file.h>
4111260SMiao.Chen@Sun.COM #include <sys/bitmap.h>
4211260SMiao.Chen@Sun.COM #include <sys/ddi.h>
4311260SMiao.Chen@Sun.COM #include <sys/sunddi.h>
4411260SMiao.Chen@Sun.COM #include <gfx_private.h>
4511260SMiao.Chen@Sun.COM #include "drmP.h"
4611260SMiao.Chen@Sun.COM #include "drm.h"
4711260SMiao.Chen@Sun.COM
4811260SMiao.Chen@Sun.COM /*
4911260SMiao.Chen@Sun.COM * @file drm_gem.c
5011260SMiao.Chen@Sun.COM *
5111260SMiao.Chen@Sun.COM * This file provides some of the base ioctls and library routines for
5211260SMiao.Chen@Sun.COM * the graphics memory manager implemented by each device driver.
5311260SMiao.Chen@Sun.COM *
5411260SMiao.Chen@Sun.COM * Because various devices have different requirements in terms of
5511260SMiao.Chen@Sun.COM * synchronization and migration strategies, implementing that is left up to
5611260SMiao.Chen@Sun.COM * the driver, and all that the general API provides should be generic --
5711260SMiao.Chen@Sun.COM * allocating objects, reading/writing data with the cpu, freeing objects.
5811260SMiao.Chen@Sun.COM * Even there, platform-dependent optimizations for reading/writing data with
5911260SMiao.Chen@Sun.COM * the CPU mean we'll likely hook those out to driver-specific calls. However,
6011260SMiao.Chen@Sun.COM * the DRI2 implementation wants to have at least allocate/mmap be generic.
6111260SMiao.Chen@Sun.COM *
6211260SMiao.Chen@Sun.COM * The goal was to have swap-backed object allocation managed through
6311260SMiao.Chen@Sun.COM * struct file. However, file descriptors as handles to a struct file have
6411260SMiao.Chen@Sun.COM * two major failings:
6511260SMiao.Chen@Sun.COM * - Process limits prevent more than 1024 or so being used at a time by
6611260SMiao.Chen@Sun.COM * default.
6711260SMiao.Chen@Sun.COM * - Inability to allocate high fds will aggravate the X Server's select()
6811260SMiao.Chen@Sun.COM * handling, and likely that of many GL client applications as well.
6911260SMiao.Chen@Sun.COM *
7011260SMiao.Chen@Sun.COM * This led to a plan of using our own integer IDs(called handles, following
7111260SMiao.Chen@Sun.COM * DRM terminology) to mimic fds, and implement the fd syscalls we need as
7211260SMiao.Chen@Sun.COM * ioctls. The objects themselves will still include the struct file so
7311260SMiao.Chen@Sun.COM * that we can transition to fds if the required kernel infrastructure shows
7411260SMiao.Chen@Sun.COM * up at a later date, and as our interface with shmfs for memory allocation.
7511260SMiao.Chen@Sun.COM */
7611260SMiao.Chen@Sun.COM
7711260SMiao.Chen@Sun.COM void
idr_list_init(struct idr_list * head)7811260SMiao.Chen@Sun.COM idr_list_init(struct idr_list *head)
7911260SMiao.Chen@Sun.COM {
8011260SMiao.Chen@Sun.COM struct idr_list *entry;
8111260SMiao.Chen@Sun.COM /* HASH for accelerate */
8211260SMiao.Chen@Sun.COM entry = kmem_zalloc(DRM_GEM_OBJIDR_HASHNODE
83*11359SMiao.Chen@Sun.COM * sizeof (struct idr_list), KM_SLEEP);
8411260SMiao.Chen@Sun.COM head->next = entry;
8511260SMiao.Chen@Sun.COM for (int i = 0; i < DRM_GEM_OBJIDR_HASHNODE; i++) {
8611260SMiao.Chen@Sun.COM INIT_LIST_HEAD(&entry[i]);
8711260SMiao.Chen@Sun.COM }
8811260SMiao.Chen@Sun.COM }
8911260SMiao.Chen@Sun.COM
9011260SMiao.Chen@Sun.COM int
idr_list_get_new_above(struct idr_list * head,struct drm_gem_object * obj,int * handlep)9111260SMiao.Chen@Sun.COM idr_list_get_new_above(struct idr_list *head,
9211260SMiao.Chen@Sun.COM struct drm_gem_object *obj,
9311260SMiao.Chen@Sun.COM int *handlep)
9411260SMiao.Chen@Sun.COM {
9511260SMiao.Chen@Sun.COM struct idr_list *entry;
9611260SMiao.Chen@Sun.COM int key;
97*11359SMiao.Chen@Sun.COM entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
9811260SMiao.Chen@Sun.COM key = obj->name % DRM_GEM_OBJIDR_HASHNODE;
9911260SMiao.Chen@Sun.COM list_add(entry, &head->next[key], NULL);
10011260SMiao.Chen@Sun.COM entry->obj = obj;
10111260SMiao.Chen@Sun.COM entry->handle = obj->name;
10211260SMiao.Chen@Sun.COM *handlep = obj->name;
10311260SMiao.Chen@Sun.COM return (0);
10411260SMiao.Chen@Sun.COM }
10511260SMiao.Chen@Sun.COM
10611260SMiao.Chen@Sun.COM struct drm_gem_object *
idr_list_find(struct idr_list * head,uint32_t name)10711260SMiao.Chen@Sun.COM idr_list_find(struct idr_list *head,
10811260SMiao.Chen@Sun.COM uint32_t name)
10911260SMiao.Chen@Sun.COM {
11011260SMiao.Chen@Sun.COM struct idr_list *entry;
11111260SMiao.Chen@Sun.COM int key;
11211260SMiao.Chen@Sun.COM key = name % DRM_GEM_OBJIDR_HASHNODE;
11311260SMiao.Chen@Sun.COM
11411260SMiao.Chen@Sun.COM list_for_each(entry, &head->next[key]) {
11511260SMiao.Chen@Sun.COM if (entry->handle == name)
11611260SMiao.Chen@Sun.COM return (entry->obj);
11711260SMiao.Chen@Sun.COM }
11811260SMiao.Chen@Sun.COM return (NULL);
11911260SMiao.Chen@Sun.COM }
12011260SMiao.Chen@Sun.COM
12111260SMiao.Chen@Sun.COM int
idr_list_remove(struct idr_list * head,uint32_t name)12211260SMiao.Chen@Sun.COM idr_list_remove(struct idr_list *head,
12311260SMiao.Chen@Sun.COM uint32_t name)
12411260SMiao.Chen@Sun.COM {
12511260SMiao.Chen@Sun.COM struct idr_list *entry, *temp;
12611260SMiao.Chen@Sun.COM int key;
12711260SMiao.Chen@Sun.COM key = name % DRM_GEM_OBJIDR_HASHNODE;
12811260SMiao.Chen@Sun.COM list_for_each_safe(entry, temp, &head->next[key]) {
12911260SMiao.Chen@Sun.COM if (entry->handle == name) {
13011260SMiao.Chen@Sun.COM list_del(entry);
13111260SMiao.Chen@Sun.COM kmem_free(entry, sizeof (*entry));
13211260SMiao.Chen@Sun.COM return (0);
13311260SMiao.Chen@Sun.COM }
13411260SMiao.Chen@Sun.COM }
13511260SMiao.Chen@Sun.COM DRM_ERROR("Failed to remove the object %d", name);
13611260SMiao.Chen@Sun.COM return (-1);
13711260SMiao.Chen@Sun.COM }
13811260SMiao.Chen@Sun.COM
13911260SMiao.Chen@Sun.COM void
idr_list_free(struct idr_list * head)14011260SMiao.Chen@Sun.COM idr_list_free(struct idr_list *head)
14111260SMiao.Chen@Sun.COM {
14211260SMiao.Chen@Sun.COM struct idr_list *entry, *temp;
14311260SMiao.Chen@Sun.COM for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
14411260SMiao.Chen@Sun.COM list_for_each_safe(entry, temp, &head->next[key]) {
14511260SMiao.Chen@Sun.COM list_del(entry);
14611260SMiao.Chen@Sun.COM kmem_free(entry, sizeof (*entry));
14711260SMiao.Chen@Sun.COM }
14811260SMiao.Chen@Sun.COM }
14911260SMiao.Chen@Sun.COM kmem_free(head->next,
15011260SMiao.Chen@Sun.COM DRM_GEM_OBJIDR_HASHNODE * sizeof (struct idr_list));
15111260SMiao.Chen@Sun.COM head->next = NULL;
15211260SMiao.Chen@Sun.COM }
15311260SMiao.Chen@Sun.COM
15411260SMiao.Chen@Sun.COM int
idr_list_empty(struct idr_list * head)15511260SMiao.Chen@Sun.COM idr_list_empty(struct idr_list *head)
15611260SMiao.Chen@Sun.COM {
15711260SMiao.Chen@Sun.COM int empty;
15811260SMiao.Chen@Sun.COM for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
15911260SMiao.Chen@Sun.COM empty = list_empty(&(head)->next[key]);
16011260SMiao.Chen@Sun.COM if (!empty)
16111260SMiao.Chen@Sun.COM return (empty);
16211260SMiao.Chen@Sun.COM }
16311260SMiao.Chen@Sun.COM return (1);
16411260SMiao.Chen@Sun.COM }
16511260SMiao.Chen@Sun.COM
16611260SMiao.Chen@Sun.COM static uint32_t shfile_name = 0;
16711260SMiao.Chen@Sun.COM #define SHFILE_NAME_MAX 0xffffffff
16811260SMiao.Chen@Sun.COM
16911260SMiao.Chen@Sun.COM /*
17011260SMiao.Chen@Sun.COM * will be set to 1 for 32 bit x86 systems only, in startup.c
17111260SMiao.Chen@Sun.COM */
17211260SMiao.Chen@Sun.COM extern int segkp_fromheap;
17311260SMiao.Chen@Sun.COM extern ulong_t *segkp_bitmap;
17411260SMiao.Chen@Sun.COM
17511260SMiao.Chen@Sun.COM void
drm_gem_object_reference(struct drm_gem_object * obj)17611260SMiao.Chen@Sun.COM drm_gem_object_reference(struct drm_gem_object *obj)
17711260SMiao.Chen@Sun.COM {
17811260SMiao.Chen@Sun.COM atomic_inc(&obj->refcount);
17911260SMiao.Chen@Sun.COM }
18011260SMiao.Chen@Sun.COM
18111260SMiao.Chen@Sun.COM void
drm_gem_object_unreference(struct drm_gem_object * obj)18211260SMiao.Chen@Sun.COM drm_gem_object_unreference(struct drm_gem_object *obj)
18311260SMiao.Chen@Sun.COM {
18411260SMiao.Chen@Sun.COM if (obj == NULL)
18511260SMiao.Chen@Sun.COM return;
18611260SMiao.Chen@Sun.COM
18711260SMiao.Chen@Sun.COM atomic_sub(1, &obj->refcount);
18811260SMiao.Chen@Sun.COM if (obj->refcount == 0)
18911260SMiao.Chen@Sun.COM drm_gem_object_free(obj);
19011260SMiao.Chen@Sun.COM }
19111260SMiao.Chen@Sun.COM
19211260SMiao.Chen@Sun.COM void
drm_gem_object_handle_reference(struct drm_gem_object * obj)19311260SMiao.Chen@Sun.COM drm_gem_object_handle_reference(struct drm_gem_object *obj)
19411260SMiao.Chen@Sun.COM {
19511260SMiao.Chen@Sun.COM drm_gem_object_reference(obj);
19611260SMiao.Chen@Sun.COM atomic_inc(&obj->handlecount);
19711260SMiao.Chen@Sun.COM }
19811260SMiao.Chen@Sun.COM
19911260SMiao.Chen@Sun.COM void
drm_gem_object_handle_unreference(struct drm_gem_object * obj)20011260SMiao.Chen@Sun.COM drm_gem_object_handle_unreference(struct drm_gem_object *obj)
20111260SMiao.Chen@Sun.COM {
20211260SMiao.Chen@Sun.COM if (obj == NULL)
20311260SMiao.Chen@Sun.COM return;
20411260SMiao.Chen@Sun.COM
20511260SMiao.Chen@Sun.COM /*
20611260SMiao.Chen@Sun.COM * Must bump handle count first as this may be the last
20711260SMiao.Chen@Sun.COM * ref, in which case the object would disappear before we
20811260SMiao.Chen@Sun.COM * checked for a name
20911260SMiao.Chen@Sun.COM */
21011260SMiao.Chen@Sun.COM atomic_sub(1, &obj->handlecount);
21111260SMiao.Chen@Sun.COM if (obj->handlecount == 0)
21211260SMiao.Chen@Sun.COM drm_gem_object_handle_free(obj);
21311260SMiao.Chen@Sun.COM drm_gem_object_unreference(obj);
21411260SMiao.Chen@Sun.COM }
21511260SMiao.Chen@Sun.COM
21611260SMiao.Chen@Sun.COM /*
21711260SMiao.Chen@Sun.COM * Initialize the GEM device fields
21811260SMiao.Chen@Sun.COM */
21911260SMiao.Chen@Sun.COM
22011260SMiao.Chen@Sun.COM int
drm_gem_init(struct drm_device * dev)22111260SMiao.Chen@Sun.COM drm_gem_init(struct drm_device *dev)
22211260SMiao.Chen@Sun.COM {
22311260SMiao.Chen@Sun.COM mutex_init(&dev->object_name_lock, NULL, MUTEX_DRIVER, NULL);
22411260SMiao.Chen@Sun.COM idr_list_init(&dev->object_name_idr);
22511260SMiao.Chen@Sun.COM
22611260SMiao.Chen@Sun.COM atomic_set(&dev->object_count, 0);
22711260SMiao.Chen@Sun.COM atomic_set(&dev->object_memory, 0);
22811260SMiao.Chen@Sun.COM atomic_set(&dev->pin_count, 0);
22911260SMiao.Chen@Sun.COM atomic_set(&dev->pin_memory, 0);
23011260SMiao.Chen@Sun.COM atomic_set(&dev->gtt_count, 0);
23111260SMiao.Chen@Sun.COM atomic_set(&dev->gtt_memory, 0);
23211260SMiao.Chen@Sun.COM return (0);
23311260SMiao.Chen@Sun.COM }
23411260SMiao.Chen@Sun.COM
23511260SMiao.Chen@Sun.COM /*
23611260SMiao.Chen@Sun.COM * Allocate a GEM object of the specified size with shmfs backing store
23711260SMiao.Chen@Sun.COM */
23811260SMiao.Chen@Sun.COM struct drm_gem_object *
drm_gem_object_alloc(struct drm_device * dev,size_t size)23911260SMiao.Chen@Sun.COM drm_gem_object_alloc(struct drm_device *dev, size_t size)
24011260SMiao.Chen@Sun.COM {
24111260SMiao.Chen@Sun.COM static ddi_dma_attr_t dma_attr = {
24211260SMiao.Chen@Sun.COM DMA_ATTR_V0,
24311260SMiao.Chen@Sun.COM 0U, /* dma_attr_addr_lo */
24411260SMiao.Chen@Sun.COM 0xffffffffU, /* dma_attr_addr_hi */
24511260SMiao.Chen@Sun.COM 0xffffffffU, /* dma_attr_count_max */
24611260SMiao.Chen@Sun.COM 4096, /* dma_attr_align */
24711260SMiao.Chen@Sun.COM 0x1fffU, /* dma_attr_burstsizes */
24811260SMiao.Chen@Sun.COM 1, /* dma_attr_minxfer */
24911260SMiao.Chen@Sun.COM 0xffffffffU, /* dma_attr_maxxfer */
25011260SMiao.Chen@Sun.COM 0xffffffffU, /* dma_attr_seg */
25111260SMiao.Chen@Sun.COM 1, /* dma_attr_sgllen, variable */
25211260SMiao.Chen@Sun.COM 4, /* dma_attr_granular */
25311260SMiao.Chen@Sun.COM 0 /* dma_attr_flags */
25411260SMiao.Chen@Sun.COM };
25511260SMiao.Chen@Sun.COM static ddi_device_acc_attr_t acc_attr = {
25611260SMiao.Chen@Sun.COM DDI_DEVICE_ATTR_V0,
25711260SMiao.Chen@Sun.COM DDI_NEVERSWAP_ACC,
25811260SMiao.Chen@Sun.COM DDI_MERGING_OK_ACC
25911260SMiao.Chen@Sun.COM };
26011260SMiao.Chen@Sun.COM struct drm_gem_object *obj;
26111260SMiao.Chen@Sun.COM ddi_dma_cookie_t cookie;
26211260SMiao.Chen@Sun.COM uint_t cookie_cnt;
26311260SMiao.Chen@Sun.COM drm_local_map_t *map;
26411260SMiao.Chen@Sun.COM
26511260SMiao.Chen@Sun.COM pgcnt_t real_pgcnt, pgcnt = btopr(size);
26611260SMiao.Chen@Sun.COM uint32_t paddr, cookie_end;
26711260SMiao.Chen@Sun.COM int i, n;
26811260SMiao.Chen@Sun.COM
26911260SMiao.Chen@Sun.COM obj = kmem_zalloc(sizeof (struct drm_gem_object), KM_NOSLEEP);
27011260SMiao.Chen@Sun.COM if (obj == NULL)
27111260SMiao.Chen@Sun.COM return (NULL);
27211260SMiao.Chen@Sun.COM
27311260SMiao.Chen@Sun.COM obj->dev = dev;
27411260SMiao.Chen@Sun.COM obj->flink = 0;
27511260SMiao.Chen@Sun.COM obj->size = size;
27611260SMiao.Chen@Sun.COM
27711260SMiao.Chen@Sun.COM if (shfile_name == SHFILE_NAME_MAX) {
27811260SMiao.Chen@Sun.COM DRM_ERROR("No name space for object");
27911260SMiao.Chen@Sun.COM goto err1;
28011260SMiao.Chen@Sun.COM } else {
28111260SMiao.Chen@Sun.COM obj->name = ++shfile_name;
28211260SMiao.Chen@Sun.COM }
28311260SMiao.Chen@Sun.COM
28411260SMiao.Chen@Sun.COM dma_attr.dma_attr_sgllen = (int)pgcnt;
28511260SMiao.Chen@Sun.COM
28611260SMiao.Chen@Sun.COM if (ddi_dma_alloc_handle(dev->dip, &dma_attr,
28711260SMiao.Chen@Sun.COM DDI_DMA_DONTWAIT, NULL, &obj->dma_hdl)) {
28811260SMiao.Chen@Sun.COM DRM_ERROR("drm_gem_object_alloc: "
28911260SMiao.Chen@Sun.COM "ddi_dma_alloc_handle failed");
29011260SMiao.Chen@Sun.COM goto err1;
29111260SMiao.Chen@Sun.COM }
29211260SMiao.Chen@Sun.COM if (ddi_dma_mem_alloc(obj->dma_hdl, ptob(pgcnt), &acc_attr,
29311260SMiao.Chen@Sun.COM IOMEM_DATA_UC_WR_COMBINE, DDI_DMA_DONTWAIT, NULL,
29411260SMiao.Chen@Sun.COM &obj->kaddr, &obj->real_size, &obj->acc_hdl)) {
29511260SMiao.Chen@Sun.COM DRM_ERROR("drm_gem_object_alloc: "
29611260SMiao.Chen@Sun.COM "ddi_dma_mem_alloc failed");
29711260SMiao.Chen@Sun.COM goto err2;
29811260SMiao.Chen@Sun.COM }
29911260SMiao.Chen@Sun.COM if (ddi_dma_addr_bind_handle(obj->dma_hdl, NULL,
30011260SMiao.Chen@Sun.COM obj->kaddr, obj->real_size, DDI_DMA_RDWR,
30111260SMiao.Chen@Sun.COM DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_cnt)
30211260SMiao.Chen@Sun.COM != DDI_DMA_MAPPED) {
30311260SMiao.Chen@Sun.COM DRM_ERROR("drm_gem_object_alloc: "
30411260SMiao.Chen@Sun.COM "ddi_dma_addr_bind_handle failed");
30511260SMiao.Chen@Sun.COM goto err3;
30611260SMiao.Chen@Sun.COM }
30711260SMiao.Chen@Sun.COM
30811260SMiao.Chen@Sun.COM real_pgcnt = btopr(obj->real_size);
30911260SMiao.Chen@Sun.COM
31011260SMiao.Chen@Sun.COM obj->pfnarray = kmem_zalloc(real_pgcnt * sizeof (pfn_t), KM_NOSLEEP);
31111260SMiao.Chen@Sun.COM if (obj->pfnarray == NULL) {
31211260SMiao.Chen@Sun.COM goto err4;
31311260SMiao.Chen@Sun.COM }
31411260SMiao.Chen@Sun.COM for (n = 0, i = 1; ; i++) {
31511260SMiao.Chen@Sun.COM for (paddr = cookie.dmac_address,
31611260SMiao.Chen@Sun.COM cookie_end = cookie.dmac_address + cookie.dmac_size;
31711260SMiao.Chen@Sun.COM paddr < cookie_end;
31811260SMiao.Chen@Sun.COM paddr += PAGESIZE) {
31911260SMiao.Chen@Sun.COM obj->pfnarray[n++] = btop(paddr);
32011260SMiao.Chen@Sun.COM if (n >= real_pgcnt)
32111260SMiao.Chen@Sun.COM goto addmap;
32211260SMiao.Chen@Sun.COM }
32311260SMiao.Chen@Sun.COM if (i >= cookie_cnt)
32411260SMiao.Chen@Sun.COM break;
32511260SMiao.Chen@Sun.COM ddi_dma_nextcookie(obj->dma_hdl, &cookie);
32611260SMiao.Chen@Sun.COM }
32711260SMiao.Chen@Sun.COM
32811260SMiao.Chen@Sun.COM addmap:
32911260SMiao.Chen@Sun.COM map = drm_alloc(sizeof (struct drm_local_map), DRM_MEM_MAPS);
33011260SMiao.Chen@Sun.COM if (map == NULL) {
33111260SMiao.Chen@Sun.COM goto err5;
33211260SMiao.Chen@Sun.COM }
33311260SMiao.Chen@Sun.COM
33411260SMiao.Chen@Sun.COM map->handle = obj;
33511260SMiao.Chen@Sun.COM map->offset = (uintptr_t)map->handle;
33611260SMiao.Chen@Sun.COM map->offset &= 0xffffffffUL;
33711260SMiao.Chen@Sun.COM map->dev_addr = map->handle;
33811260SMiao.Chen@Sun.COM map->size = obj->real_size;
33911260SMiao.Chen@Sun.COM map->type = _DRM_TTM;
34011260SMiao.Chen@Sun.COM map->flags = _DRM_WRITE_COMBINING | _DRM_REMOVABLE;
34111260SMiao.Chen@Sun.COM map->drm_umem_cookie =
34211260SMiao.Chen@Sun.COM gfxp_umem_cookie_init(obj->kaddr, obj->real_size);
34311260SMiao.Chen@Sun.COM if (map->drm_umem_cookie == NULL) {
34411260SMiao.Chen@Sun.COM goto err6;
34511260SMiao.Chen@Sun.COM }
34611260SMiao.Chen@Sun.COM
34711260SMiao.Chen@Sun.COM obj->map = map;
34811260SMiao.Chen@Sun.COM
34911260SMiao.Chen@Sun.COM atomic_set(&obj->refcount, 1);
35011260SMiao.Chen@Sun.COM atomic_set(&obj->handlecount, 1);
35111260SMiao.Chen@Sun.COM if (dev->driver->gem_init_object != NULL &&
35211260SMiao.Chen@Sun.COM dev->driver->gem_init_object(obj) != 0) {
35311260SMiao.Chen@Sun.COM goto err7;
35411260SMiao.Chen@Sun.COM }
35511260SMiao.Chen@Sun.COM atomic_inc(&dev->object_count);
35611260SMiao.Chen@Sun.COM atomic_add(obj->size, &dev->object_memory);
35711260SMiao.Chen@Sun.COM
35811260SMiao.Chen@Sun.COM return (obj);
35911260SMiao.Chen@Sun.COM
36011260SMiao.Chen@Sun.COM err7:
36111260SMiao.Chen@Sun.COM gfxp_umem_cookie_destroy(map->drm_umem_cookie);
36211260SMiao.Chen@Sun.COM err6:
36311260SMiao.Chen@Sun.COM drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
36411260SMiao.Chen@Sun.COM err5:
36511260SMiao.Chen@Sun.COM kmem_free(obj->pfnarray, real_pgcnt * sizeof (pfn_t));
36611260SMiao.Chen@Sun.COM err4:
36711260SMiao.Chen@Sun.COM (void) ddi_dma_unbind_handle(obj->dma_hdl);
36811260SMiao.Chen@Sun.COM err3:
36911260SMiao.Chen@Sun.COM ddi_dma_mem_free(&obj->acc_hdl);
37011260SMiao.Chen@Sun.COM err2:
37111260SMiao.Chen@Sun.COM ddi_dma_free_handle(&obj->dma_hdl);
37211260SMiao.Chen@Sun.COM err1:
37311260SMiao.Chen@Sun.COM kmem_free(obj, sizeof (struct drm_gem_object));
37411260SMiao.Chen@Sun.COM
37511260SMiao.Chen@Sun.COM return (NULL);
37611260SMiao.Chen@Sun.COM }
37711260SMiao.Chen@Sun.COM
37811260SMiao.Chen@Sun.COM /*
37911260SMiao.Chen@Sun.COM * Removes the mapping from handle to filp for this object.
38011260SMiao.Chen@Sun.COM */
38111260SMiao.Chen@Sun.COM static int
drm_gem_handle_delete(struct drm_file * filp,int handle)38211260SMiao.Chen@Sun.COM drm_gem_handle_delete(struct drm_file *filp, int handle)
38311260SMiao.Chen@Sun.COM {
38411260SMiao.Chen@Sun.COM struct drm_device *dev;
38511260SMiao.Chen@Sun.COM struct drm_gem_object *obj;
38611260SMiao.Chen@Sun.COM int err;
38711260SMiao.Chen@Sun.COM /*
38811260SMiao.Chen@Sun.COM * This is gross. The idr system doesn't let us try a delete and
38911260SMiao.Chen@Sun.COM * return an error code. It just spews if you fail at deleting.
39011260SMiao.Chen@Sun.COM * So, we have to grab a lock around finding the object and then
39111260SMiao.Chen@Sun.COM * doing the delete on it and dropping the refcount, or the user
39211260SMiao.Chen@Sun.COM * could race us to double-decrement the refcount and cause a
39311260SMiao.Chen@Sun.COM * use-after-free later. Given the frequency of our handle lookups,
39411260SMiao.Chen@Sun.COM * we may want to use ida for number allocation and a hash table
39511260SMiao.Chen@Sun.COM * for the pointers, anyway.
39611260SMiao.Chen@Sun.COM */
39711260SMiao.Chen@Sun.COM spin_lock(&filp->table_lock);
39811260SMiao.Chen@Sun.COM
39911260SMiao.Chen@Sun.COM /* Check if we currently have a reference on the object */
40011260SMiao.Chen@Sun.COM obj = idr_list_find(&filp->object_idr, handle);
40111260SMiao.Chen@Sun.COM if (obj == NULL) {
40211260SMiao.Chen@Sun.COM spin_unlock(&filp->table_lock);
40311260SMiao.Chen@Sun.COM DRM_ERROR("obj %d is not in tne list, failed to close", handle);
40411260SMiao.Chen@Sun.COM return (EINVAL);
40511260SMiao.Chen@Sun.COM }
40611260SMiao.Chen@Sun.COM dev = obj->dev;
40711260SMiao.Chen@Sun.COM
40811260SMiao.Chen@Sun.COM /* Release reference and decrement refcount. */
40911260SMiao.Chen@Sun.COM err = idr_list_remove(&filp->object_idr, handle);
41011260SMiao.Chen@Sun.COM if (err == -1)
41111260SMiao.Chen@Sun.COM DRM_ERROR("%s", __func__);
41211260SMiao.Chen@Sun.COM
41311260SMiao.Chen@Sun.COM spin_unlock(&filp->table_lock);
41411260SMiao.Chen@Sun.COM
41511260SMiao.Chen@Sun.COM spin_lock(&dev->struct_mutex);
41611260SMiao.Chen@Sun.COM drm_gem_object_handle_unreference(obj);
41711260SMiao.Chen@Sun.COM spin_unlock(&dev->struct_mutex);
41811260SMiao.Chen@Sun.COM return (0);
41911260SMiao.Chen@Sun.COM }
42011260SMiao.Chen@Sun.COM
42111260SMiao.Chen@Sun.COM /*
42211260SMiao.Chen@Sun.COM * Create a handle for this object. This adds a handle reference
42311260SMiao.Chen@Sun.COM * to the object, which includes a regular reference count. Callers
42411260SMiao.Chen@Sun.COM * will likely want to dereference the object afterwards.
42511260SMiao.Chen@Sun.COM */
42611260SMiao.Chen@Sun.COM int
drm_gem_handle_create(struct drm_file * file_priv,struct drm_gem_object * obj,int * handlep)42711260SMiao.Chen@Sun.COM drm_gem_handle_create(struct drm_file *file_priv,
42811260SMiao.Chen@Sun.COM struct drm_gem_object *obj,
42911260SMiao.Chen@Sun.COM int *handlep)
43011260SMiao.Chen@Sun.COM {
43111260SMiao.Chen@Sun.COM int ret;
43211260SMiao.Chen@Sun.COM
43311260SMiao.Chen@Sun.COM /*
43411260SMiao.Chen@Sun.COM * Get the user-visible handle using idr.
43511260SMiao.Chen@Sun.COM */
43611260SMiao.Chen@Sun.COM again:
43711260SMiao.Chen@Sun.COM /* ensure there is space available to allocate a handle */
43811260SMiao.Chen@Sun.COM
43911260SMiao.Chen@Sun.COM /* do the allocation under our spinlock */
44011260SMiao.Chen@Sun.COM spin_lock(&file_priv->table_lock);
44111260SMiao.Chen@Sun.COM ret = idr_list_get_new_above(&file_priv->object_idr, obj, handlep);
44211260SMiao.Chen@Sun.COM spin_unlock(&file_priv->table_lock);
44311260SMiao.Chen@Sun.COM if (ret == -EAGAIN)
44411260SMiao.Chen@Sun.COM goto again;
44511260SMiao.Chen@Sun.COM
44611260SMiao.Chen@Sun.COM if (ret != 0) {
44711260SMiao.Chen@Sun.COM DRM_ERROR("Failed to create handle");
44811260SMiao.Chen@Sun.COM return (ret);
44911260SMiao.Chen@Sun.COM }
45011260SMiao.Chen@Sun.COM
45111260SMiao.Chen@Sun.COM drm_gem_object_handle_reference(obj);
45211260SMiao.Chen@Sun.COM return (0);
45311260SMiao.Chen@Sun.COM }
45411260SMiao.Chen@Sun.COM
45511260SMiao.Chen@Sun.COM /* Returns a reference to the object named by the handle. */
45611260SMiao.Chen@Sun.COM struct drm_gem_object *
drm_gem_object_lookup(struct drm_file * filp,int handle)45711260SMiao.Chen@Sun.COM drm_gem_object_lookup(struct drm_file *filp,
45811260SMiao.Chen@Sun.COM int handle)
45911260SMiao.Chen@Sun.COM {
46011260SMiao.Chen@Sun.COM struct drm_gem_object *obj;
46111260SMiao.Chen@Sun.COM
46211260SMiao.Chen@Sun.COM spin_lock(&filp->table_lock);
46311260SMiao.Chen@Sun.COM
46411260SMiao.Chen@Sun.COM /* Check if we currently have a reference on the object */
46511260SMiao.Chen@Sun.COM obj = idr_list_find(&filp->object_idr, handle);
46611260SMiao.Chen@Sun.COM if (obj == NULL) {
46711260SMiao.Chen@Sun.COM spin_unlock(&filp->table_lock);
46811260SMiao.Chen@Sun.COM DRM_ERROR("object_lookup failed, handle %d", handle);
46911260SMiao.Chen@Sun.COM return (NULL);
47011260SMiao.Chen@Sun.COM }
47111260SMiao.Chen@Sun.COM
47211260SMiao.Chen@Sun.COM drm_gem_object_reference(obj);
47311260SMiao.Chen@Sun.COM
47411260SMiao.Chen@Sun.COM spin_unlock(&filp->table_lock);
47511260SMiao.Chen@Sun.COM
47611260SMiao.Chen@Sun.COM return (obj);
47711260SMiao.Chen@Sun.COM }
47811260SMiao.Chen@Sun.COM
47911260SMiao.Chen@Sun.COM /*
48011260SMiao.Chen@Sun.COM * Releases the handle to an mm object.
48111260SMiao.Chen@Sun.COM */
48211260SMiao.Chen@Sun.COM /*ARGSUSED*/
48311260SMiao.Chen@Sun.COM int
drm_gem_close_ioctl(DRM_IOCTL_ARGS)48411260SMiao.Chen@Sun.COM drm_gem_close_ioctl(DRM_IOCTL_ARGS)
48511260SMiao.Chen@Sun.COM {
48611260SMiao.Chen@Sun.COM DRM_DEVICE;
48711260SMiao.Chen@Sun.COM struct drm_gem_close args;
48811260SMiao.Chen@Sun.COM int ret;
48911260SMiao.Chen@Sun.COM
49011260SMiao.Chen@Sun.COM if (!(dev->driver->use_gem == 1))
49111260SMiao.Chen@Sun.COM return (ENODEV);
49211260SMiao.Chen@Sun.COM
49311260SMiao.Chen@Sun.COM DRM_COPYFROM_WITH_RETURN(&args,
49411260SMiao.Chen@Sun.COM (void *)data, sizeof (args));
49511260SMiao.Chen@Sun.COM
49611260SMiao.Chen@Sun.COM ret = drm_gem_handle_delete(fpriv, args.handle);
49711260SMiao.Chen@Sun.COM
49811260SMiao.Chen@Sun.COM return (ret);
49911260SMiao.Chen@Sun.COM }
50011260SMiao.Chen@Sun.COM
50111260SMiao.Chen@Sun.COM /*
50211260SMiao.Chen@Sun.COM * Create a global name for an object, returning the name.
50311260SMiao.Chen@Sun.COM *
50411260SMiao.Chen@Sun.COM * Note that the name does not hold a reference; when the object
50511260SMiao.Chen@Sun.COM * is freed, the name goes away.
50611260SMiao.Chen@Sun.COM */
50711260SMiao.Chen@Sun.COM /*ARGSUSED*/
50811260SMiao.Chen@Sun.COM int
drm_gem_flink_ioctl(DRM_IOCTL_ARGS)50911260SMiao.Chen@Sun.COM drm_gem_flink_ioctl(DRM_IOCTL_ARGS)
51011260SMiao.Chen@Sun.COM {
51111260SMiao.Chen@Sun.COM DRM_DEVICE;
51211260SMiao.Chen@Sun.COM struct drm_gem_flink args;
51311260SMiao.Chen@Sun.COM struct drm_gem_object *obj;
51411260SMiao.Chen@Sun.COM int ret, handle;
51511260SMiao.Chen@Sun.COM
51611260SMiao.Chen@Sun.COM if (!(dev->driver->use_gem == 1))
51711260SMiao.Chen@Sun.COM return (ENODEV);
51811260SMiao.Chen@Sun.COM
51911260SMiao.Chen@Sun.COM DRM_COPYFROM_WITH_RETURN(&args,
52011260SMiao.Chen@Sun.COM (void *)data, sizeof (args));
52111260SMiao.Chen@Sun.COM obj = drm_gem_object_lookup(fpriv, args.handle);
52211260SMiao.Chen@Sun.COM if (obj == NULL)
52311260SMiao.Chen@Sun.COM return (EINVAL);
52411260SMiao.Chen@Sun.COM handle = args.handle;
52511260SMiao.Chen@Sun.COM spin_lock(&dev->object_name_lock);
52611260SMiao.Chen@Sun.COM if (!obj->flink) {
52711260SMiao.Chen@Sun.COM /* only creat a node in object_name_idr, no update anything */
52811260SMiao.Chen@Sun.COM ret = idr_list_get_new_above(&dev->object_name_idr,
52911260SMiao.Chen@Sun.COM obj, &handle);
53011260SMiao.Chen@Sun.COM obj->flink = obj->name;
53111260SMiao.Chen@Sun.COM /* Allocate a reference for the name table. */
53211260SMiao.Chen@Sun.COM drm_gem_object_reference(obj);
53311260SMiao.Chen@Sun.COM }
53411260SMiao.Chen@Sun.COM /*
53511260SMiao.Chen@Sun.COM * Leave the reference from the lookup around as the
53611260SMiao.Chen@Sun.COM * name table now holds one
53711260SMiao.Chen@Sun.COM */
53811260SMiao.Chen@Sun.COM args.name = obj->name;
53911260SMiao.Chen@Sun.COM
54011260SMiao.Chen@Sun.COM spin_unlock(&dev->object_name_lock);
54111260SMiao.Chen@Sun.COM ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
54211260SMiao.Chen@Sun.COM if (ret != 0)
54311260SMiao.Chen@Sun.COM DRM_ERROR(" gem flink error! %d", ret);
54411260SMiao.Chen@Sun.COM
54511260SMiao.Chen@Sun.COM spin_lock(&dev->struct_mutex);
54611260SMiao.Chen@Sun.COM drm_gem_object_unreference(obj);
54711260SMiao.Chen@Sun.COM spin_unlock(&dev->struct_mutex);
54811260SMiao.Chen@Sun.COM
54911260SMiao.Chen@Sun.COM return (ret);
55011260SMiao.Chen@Sun.COM }
55111260SMiao.Chen@Sun.COM
55211260SMiao.Chen@Sun.COM /*
55311260SMiao.Chen@Sun.COM * Open an object using the global name, returning a handle and the size.
55411260SMiao.Chen@Sun.COM *
55511260SMiao.Chen@Sun.COM * This handle (of course) holds a reference to the object, so the object
55611260SMiao.Chen@Sun.COM * will not go away until the handle is deleted.
55711260SMiao.Chen@Sun.COM */
55811260SMiao.Chen@Sun.COM /*ARGSUSED*/
55911260SMiao.Chen@Sun.COM int
drm_gem_open_ioctl(DRM_IOCTL_ARGS)56011260SMiao.Chen@Sun.COM drm_gem_open_ioctl(DRM_IOCTL_ARGS)
56111260SMiao.Chen@Sun.COM {
56211260SMiao.Chen@Sun.COM DRM_DEVICE;
56311260SMiao.Chen@Sun.COM struct drm_gem_open args;
56411260SMiao.Chen@Sun.COM struct drm_gem_object *obj;
56511260SMiao.Chen@Sun.COM int ret;
56611260SMiao.Chen@Sun.COM int handle;
56711260SMiao.Chen@Sun.COM
56811260SMiao.Chen@Sun.COM if (!(dev->driver->use_gem == 1)) {
56911260SMiao.Chen@Sun.COM DRM_ERROR("Not support GEM");
57011260SMiao.Chen@Sun.COM return (ENODEV);
57111260SMiao.Chen@Sun.COM }
57211260SMiao.Chen@Sun.COM DRM_COPYFROM_WITH_RETURN(&args,
57311260SMiao.Chen@Sun.COM (void *) data, sizeof (args));
57411260SMiao.Chen@Sun.COM
57511260SMiao.Chen@Sun.COM spin_lock(&dev->object_name_lock);
57611260SMiao.Chen@Sun.COM
57711260SMiao.Chen@Sun.COM obj = idr_list_find(&dev->object_name_idr, args.name);
57811260SMiao.Chen@Sun.COM
57911260SMiao.Chen@Sun.COM if (obj)
58011260SMiao.Chen@Sun.COM drm_gem_object_reference(obj);
58111260SMiao.Chen@Sun.COM spin_unlock(&dev->object_name_lock);
58211260SMiao.Chen@Sun.COM if (!obj) {
58311260SMiao.Chen@Sun.COM DRM_ERROR("Can't find the obj %d", args.name);
58411260SMiao.Chen@Sun.COM return (ENOENT);
58511260SMiao.Chen@Sun.COM }
58611260SMiao.Chen@Sun.COM
58711260SMiao.Chen@Sun.COM ret = drm_gem_handle_create(fpriv, obj, &handle);
58811260SMiao.Chen@Sun.COM spin_lock(&dev->struct_mutex);
58911260SMiao.Chen@Sun.COM drm_gem_object_unreference(obj);
59011260SMiao.Chen@Sun.COM spin_unlock(&dev->struct_mutex);
59111260SMiao.Chen@Sun.COM
59211260SMiao.Chen@Sun.COM args.handle = args.name;
59311260SMiao.Chen@Sun.COM args.size = obj->size;
59411260SMiao.Chen@Sun.COM
59511260SMiao.Chen@Sun.COM ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
59611260SMiao.Chen@Sun.COM if (ret != 0)
59711260SMiao.Chen@Sun.COM DRM_ERROR(" gem open error! %d", ret);
59811260SMiao.Chen@Sun.COM return (ret);
59911260SMiao.Chen@Sun.COM }
60011260SMiao.Chen@Sun.COM
60111260SMiao.Chen@Sun.COM /*
60211260SMiao.Chen@Sun.COM * Called at device open time, sets up the structure for handling refcounting
60311260SMiao.Chen@Sun.COM * of mm objects.
60411260SMiao.Chen@Sun.COM */
60511260SMiao.Chen@Sun.COM void
drm_gem_open(struct drm_file * file_private)60611260SMiao.Chen@Sun.COM drm_gem_open(struct drm_file *file_private)
60711260SMiao.Chen@Sun.COM {
60811260SMiao.Chen@Sun.COM idr_list_init(&file_private->object_idr);
60911260SMiao.Chen@Sun.COM mutex_init(&file_private->table_lock, NULL, MUTEX_DRIVER, NULL);
61011260SMiao.Chen@Sun.COM }
61111260SMiao.Chen@Sun.COM
61211260SMiao.Chen@Sun.COM /*
61311260SMiao.Chen@Sun.COM * Called at device close to release the file's
61411260SMiao.Chen@Sun.COM * handle references on objects.
61511260SMiao.Chen@Sun.COM */
61611260SMiao.Chen@Sun.COM static void
drm_gem_object_release_handle(struct drm_gem_object * obj)61711260SMiao.Chen@Sun.COM drm_gem_object_release_handle(struct drm_gem_object *obj)
61811260SMiao.Chen@Sun.COM {
61911260SMiao.Chen@Sun.COM drm_gem_object_handle_unreference(obj);
62011260SMiao.Chen@Sun.COM }
62111260SMiao.Chen@Sun.COM
62211260SMiao.Chen@Sun.COM /*
62311260SMiao.Chen@Sun.COM * Called at close time when the filp is going away.
62411260SMiao.Chen@Sun.COM *
62511260SMiao.Chen@Sun.COM * Releases any remaining references on objects by this filp.
62611260SMiao.Chen@Sun.COM */
62711260SMiao.Chen@Sun.COM void
drm_gem_release(struct drm_device * dev,struct drm_file * file_private)62811260SMiao.Chen@Sun.COM drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
62911260SMiao.Chen@Sun.COM {
63011260SMiao.Chen@Sun.COM struct idr_list *entry;
63111260SMiao.Chen@Sun.COM spin_lock(&dev->struct_mutex);
63211260SMiao.Chen@Sun.COM
63311260SMiao.Chen@Sun.COM idr_list_for_each(entry, &file_private->object_idr)
63411260SMiao.Chen@Sun.COM drm_gem_object_release_handle(entry->obj);
63511260SMiao.Chen@Sun.COM
63611260SMiao.Chen@Sun.COM idr_list_free(&file_private->object_idr);
63711260SMiao.Chen@Sun.COM spin_unlock(&dev->struct_mutex);
63811260SMiao.Chen@Sun.COM
63911260SMiao.Chen@Sun.COM }
64011260SMiao.Chen@Sun.COM
64111260SMiao.Chen@Sun.COM /*
64211260SMiao.Chen@Sun.COM * Called after the last reference to the object has been lost.
64311260SMiao.Chen@Sun.COM *
64411260SMiao.Chen@Sun.COM * Frees the object
64511260SMiao.Chen@Sun.COM */
64611260SMiao.Chen@Sun.COM void
drm_gem_object_free(struct drm_gem_object * obj)64711260SMiao.Chen@Sun.COM drm_gem_object_free(struct drm_gem_object *obj)
64811260SMiao.Chen@Sun.COM {
64911260SMiao.Chen@Sun.COM struct drm_device *dev = obj->dev;
65011260SMiao.Chen@Sun.COM struct drm_local_map *map = obj->map;
65111260SMiao.Chen@Sun.COM
65211260SMiao.Chen@Sun.COM if (dev->driver->gem_free_object != NULL)
65311260SMiao.Chen@Sun.COM dev->driver->gem_free_object(obj);
65411260SMiao.Chen@Sun.COM
65511260SMiao.Chen@Sun.COM gfxp_umem_cookie_destroy(map->drm_umem_cookie);
65611260SMiao.Chen@Sun.COM drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
65711260SMiao.Chen@Sun.COM
65811260SMiao.Chen@Sun.COM kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
65911260SMiao.Chen@Sun.COM
66011260SMiao.Chen@Sun.COM (void) ddi_dma_unbind_handle(obj->dma_hdl);
66111260SMiao.Chen@Sun.COM ddi_dma_mem_free(&obj->acc_hdl);
66211260SMiao.Chen@Sun.COM ddi_dma_free_handle(&obj->dma_hdl);
66311260SMiao.Chen@Sun.COM
66411260SMiao.Chen@Sun.COM atomic_dec(&dev->object_count);
66511260SMiao.Chen@Sun.COM atomic_sub(obj->size, &dev->object_memory);
66611260SMiao.Chen@Sun.COM kmem_free(obj, sizeof (struct drm_gem_object));
66711260SMiao.Chen@Sun.COM }
66811260SMiao.Chen@Sun.COM
66911260SMiao.Chen@Sun.COM /*
67011260SMiao.Chen@Sun.COM * Called after the last handle to the object has been closed
67111260SMiao.Chen@Sun.COM *
67211260SMiao.Chen@Sun.COM * Removes any name for the object. Note that this must be
67311260SMiao.Chen@Sun.COM * called before drm_gem_object_free or we'll be touching
67411260SMiao.Chen@Sun.COM * freed memory
67511260SMiao.Chen@Sun.COM */
67611260SMiao.Chen@Sun.COM void
drm_gem_object_handle_free(struct drm_gem_object * obj)67711260SMiao.Chen@Sun.COM drm_gem_object_handle_free(struct drm_gem_object *obj)
67811260SMiao.Chen@Sun.COM {
67911260SMiao.Chen@Sun.COM int err;
68011260SMiao.Chen@Sun.COM struct drm_device *dev = obj->dev;
68111260SMiao.Chen@Sun.COM /* Remove any name for this object */
68211260SMiao.Chen@Sun.COM spin_lock(&dev->object_name_lock);
68311260SMiao.Chen@Sun.COM if (obj->flink) {
68411260SMiao.Chen@Sun.COM err = idr_list_remove(&dev->object_name_idr, obj->name);
68511260SMiao.Chen@Sun.COM if (err == -1)
68611260SMiao.Chen@Sun.COM DRM_ERROR("%s", __func__);
68711260SMiao.Chen@Sun.COM obj->flink = 0;
68811260SMiao.Chen@Sun.COM spin_unlock(&dev->object_name_lock);
68911260SMiao.Chen@Sun.COM /*
69011260SMiao.Chen@Sun.COM * The object name held a reference to this object, drop
69111260SMiao.Chen@Sun.COM * that now.
69211260SMiao.Chen@Sun.COM */
69311260SMiao.Chen@Sun.COM drm_gem_object_unreference(obj);
69411260SMiao.Chen@Sun.COM } else
69511260SMiao.Chen@Sun.COM
69611260SMiao.Chen@Sun.COM spin_unlock(&dev->object_name_lock);
69711260SMiao.Chen@Sun.COM
69811260SMiao.Chen@Sun.COM }
699