xref: /gfx-drm/usr/src/uts/common/io/drm/drm_gem.c (revision e49fc716)
1829150b0SGordon Ross /*
247dc10d7SGordon Ross  * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
347dc10d7SGordon Ross  */
447dc10d7SGordon Ross 
547dc10d7SGordon Ross /*
647dc10d7SGordon Ross  * Copyright (c) 2009, 2013, Intel Corporation.
7829150b0SGordon Ross  * All Rights Reserved.
8829150b0SGordon Ross  *
9829150b0SGordon Ross  * Permission is hereby granted, free of charge, to any person obtaining a
10829150b0SGordon Ross  * copy of this software and associated documentation files (the "Software"),
11829150b0SGordon Ross  * to deal in the Software without restriction, including without limitation
12829150b0SGordon Ross  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13829150b0SGordon Ross  * and/or sell copies of the Software, and to permit persons to whom the
14829150b0SGordon Ross  * Software is furnished to do so, subject to the following conditions:
15829150b0SGordon Ross  *
16829150b0SGordon Ross  * The above copyright notice and this permission notice (including the next
17829150b0SGordon Ross  * paragraph) shall be included in all copies or substantial portions of the
18829150b0SGordon Ross  * Software.
19829150b0SGordon Ross  *
20829150b0SGordon Ross  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21829150b0SGordon Ross  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22829150b0SGordon Ross  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23829150b0SGordon Ross  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24829150b0SGordon Ross  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25829150b0SGordon Ross  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26829150b0SGordon Ross  * IN THE SOFTWARE.
27829150b0SGordon Ross  *
28829150b0SGordon Ross  * Authors:
29829150b0SGordon Ross  *    Eric Anholt <eric@anholt.net>
30829150b0SGordon Ross  *
31829150b0SGordon Ross  */
32829150b0SGordon Ross 
33829150b0SGordon Ross #include "drmP.h"
3447dc10d7SGordon Ross #include <vm/seg_kmem.h>
35829150b0SGordon Ross 
3647dc10d7SGordon Ross /** @file drm_gem.c
37829150b0SGordon Ross  *
38829150b0SGordon Ross  * This file provides some of the base ioctls and library routines for
39829150b0SGordon Ross  * the graphics memory manager implemented by each device driver.
40829150b0SGordon Ross  *
41829150b0SGordon Ross  * Because various devices have different requirements in terms of
42829150b0SGordon Ross  * synchronization and migration strategies, implementing that is left up to
43829150b0SGordon Ross  * the driver, and all that the general API provides should be generic --
44829150b0SGordon Ross  * allocating objects, reading/writing data with the cpu, freeing objects.
45829150b0SGordon Ross  * Even there, platform-dependent optimizations for reading/writing data with
46829150b0SGordon Ross  * the CPU mean we'll likely hook those out to driver-specific calls.  However,
47829150b0SGordon Ross  * the DRI2 implementation wants to have at least allocate/mmap be generic.
48829150b0SGordon Ross  *
49829150b0SGordon Ross  * The goal was to have swap-backed object allocation managed through
50829150b0SGordon Ross  * struct file.  However, file descriptors as handles to a struct file have
51829150b0SGordon Ross  * two major failings:
52829150b0SGordon Ross  * - Process limits prevent more than 1024 or so being used at a time by
53829150b0SGordon Ross  *   default.
54829150b0SGordon Ross  * - Inability to allocate high fds will aggravate the X Server's select()
55829150b0SGordon Ross  *   handling, and likely that of many GL client applications as well.
56829150b0SGordon Ross  *
5747dc10d7SGordon Ross  * This led to a plan of using our own integer IDs (called handles, following
58829150b0SGordon Ross  * DRM terminology) to mimic fds, and implement the fd syscalls we need as
59829150b0SGordon Ross  * ioctls.  The objects themselves will still include the struct file so
60829150b0SGordon Ross  * that we can transition to fds if the required kernel infrastructure shows
61829150b0SGordon Ross  * up at a later date, and as our interface with shmfs for memory allocation.
62829150b0SGordon Ross  */
63829150b0SGordon Ross 
6447dc10d7SGordon Ross /*
6547dc10d7SGordon Ross  * We make up offsets for buffer objects so we can recognize them at
6647dc10d7SGordon Ross  * mmap time.
6747dc10d7SGordon Ross  */
6847dc10d7SGordon Ross #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
6947dc10d7SGordon Ross #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
70829150b0SGordon Ross 
7147dc10d7SGordon Ross int drm_use_mem_pool = 0;
7247dc10d7SGordon Ross /* memory pool is used for all platforms now */
7347dc10d7SGordon Ross #define	HAS_MEM_POOL(gen)	((gen > 30) && (drm_use_mem_pool))
74829150b0SGordon Ross 
7547dc10d7SGordon Ross /**
7647dc10d7SGordon Ross  * Initialize the GEM device fields
7747dc10d7SGordon Ross  */
78829150b0SGordon Ross 
79829150b0SGordon Ross int
drm_gem_init(struct drm_device * dev)8047dc10d7SGordon Ross drm_gem_init(struct drm_device *dev)
81829150b0SGordon Ross {
82829150b0SGordon Ross 
8347dc10d7SGordon Ross 	spin_lock_init(&dev->object_name_lock);
8447dc10d7SGordon Ross 	idr_list_init(&dev->object_name_idr);
85829150b0SGordon Ross 
8647dc10d7SGordon Ross 	gfxp_mempool_init();
87829150b0SGordon Ross 
8847dc10d7SGordon Ross 	return 0;
89829150b0SGordon Ross }
90829150b0SGordon Ross 
91829150b0SGordon Ross void
9247dc10d7SGordon Ross /* LINTED */
drm_gem_destroy(struct drm_device * dev)9347dc10d7SGordon Ross drm_gem_destroy(struct drm_device *dev)
94829150b0SGordon Ross {
95829150b0SGordon Ross }
96829150b0SGordon Ross 
9747dc10d7SGordon Ross static void
drm_gem_object_free_internal(struct drm_gem_object * obj,int gen)9847dc10d7SGordon Ross drm_gem_object_free_internal(struct drm_gem_object *obj, int gen)
99829150b0SGordon Ross {
10047dc10d7SGordon Ross 	if (obj->pfnarray != NULL)
10147dc10d7SGordon Ross 		kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
10247dc10d7SGordon Ross 	if (HAS_MEM_POOL(gen)) {
10347dc10d7SGordon Ross 		gfxp_free_mempool(&obj->mempool_cookie, obj->kaddr, obj->real_size);
10447dc10d7SGordon Ross 	} else {
10547dc10d7SGordon Ross 		(void) ddi_dma_unbind_handle(obj->dma_hdl);
10647dc10d7SGordon Ross 		ddi_dma_mem_free(&obj->acc_hdl);
10747dc10d7SGordon Ross 		ddi_dma_free_handle(&obj->dma_hdl);
10847dc10d7SGordon Ross 	}
10947dc10d7SGordon Ross 	obj->kaddr = NULL;
110829150b0SGordon Ross }
111829150b0SGordon Ross 
11247dc10d7SGordon Ross static ddi_dma_attr_t old_dma_attr = {
11347dc10d7SGordon Ross 	DMA_ATTR_V0,
11434389f68SGordon Ross 	0,				/* dma_attr_addr_lo */
11547dc10d7SGordon Ross 	0xffffffffU,			/* dma_attr_addr_hi */
11647dc10d7SGordon Ross 	0xffffffffU,			/* dma_attr_count_max */
11747dc10d7SGordon Ross 	4096,				/* dma_attr_align */
11847dc10d7SGordon Ross 	0x1fffU,			/* dma_attr_burstsizes */
11947dc10d7SGordon Ross 	1,				/* dma_attr_minxfer */
12047dc10d7SGordon Ross 	0xffffffffU,			/* dma_attr_maxxfer */
12147dc10d7SGordon Ross 	0xffffffffU,			/* dma_attr_seg */
12247dc10d7SGordon Ross 	1,				/* dma_attr_sgllen, variable */
12347dc10d7SGordon Ross 	4,				/* dma_attr_granular */
12447dc10d7SGordon Ross 	DDI_DMA_FLAGERR,		/* dma_attr_flags */
12547dc10d7SGordon Ross };
12647dc10d7SGordon Ross 
12747dc10d7SGordon Ross static ddi_device_acc_attr_t old_acc_attr = {
12847dc10d7SGordon Ross 	DDI_DEVICE_ATTR_V0,
12947dc10d7SGordon Ross 	DDI_NEVERSWAP_ACC,
13047dc10d7SGordon Ross 	DDI_MERGING_OK_ACC,
13147dc10d7SGordon Ross 	DDI_FLAGERR_ACC
13247dc10d7SGordon Ross };
133829150b0SGordon Ross 
13447dc10d7SGordon Ross static int
drm_gem_object_alloc_internal_normal(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int flag)13547dc10d7SGordon Ross drm_gem_object_alloc_internal_normal(struct drm_device *dev, struct drm_gem_object *obj,
13647dc10d7SGordon Ross 				size_t size, int flag)
137829150b0SGordon Ross {
138829150b0SGordon Ross 	ddi_dma_cookie_t cookie;
139829150b0SGordon Ross 	uint_t cookie_cnt;
140829150b0SGordon Ross 	pgcnt_t real_pgcnt, pgcnt = btopr(size);
14147dc10d7SGordon Ross 	uint64_t paddr, cookie_end;
142829150b0SGordon Ross 	int i, n;
14347dc10d7SGordon Ross 	int (*cb)(caddr_t);
14447dc10d7SGordon Ross 	ddi_device_acc_attr_t *acc_attr;
14547dc10d7SGordon Ross 	ddi_dma_attr_t* dma_attr;
14647dc10d7SGordon Ross 	uint_t mode_flag;
147829150b0SGordon Ross 
14847dc10d7SGordon Ross 	acc_attr = &old_acc_attr;
14947dc10d7SGordon Ross 	dma_attr = &old_dma_attr;
15047dc10d7SGordon Ross 	mode_flag = IOMEM_DATA_UC_WR_COMBINE;
151829150b0SGordon Ross 
15247dc10d7SGordon Ross 	cb = (flag == 0) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
15347dc10d7SGordon Ross 	dma_attr->dma_attr_sgllen = (int)pgcnt;
154829150b0SGordon Ross 
15547dc10d7SGordon Ross 	if (ddi_dma_alloc_handle(dev->devinfo, dma_attr,
15647dc10d7SGordon Ross 	    cb, NULL, &obj->dma_hdl)) {
15747dc10d7SGordon Ross 		DRM_ERROR("ddi_dma_alloc_handle failed");
158829150b0SGordon Ross 		goto err1;
159829150b0SGordon Ross 	}
16047dc10d7SGordon Ross 	if (ddi_dma_mem_alloc(obj->dma_hdl, ptob(pgcnt), acc_attr,
16147dc10d7SGordon Ross 	    mode_flag, cb, NULL,
162829150b0SGordon Ross 	    &obj->kaddr, &obj->real_size, &obj->acc_hdl)) {
16347dc10d7SGordon Ross 		DRM_ERROR("ddi_dma_mem_alloc failed");
164829150b0SGordon Ross 		goto err2;
165829150b0SGordon Ross 	}
166829150b0SGordon Ross 	if (ddi_dma_addr_bind_handle(obj->dma_hdl, NULL,
167829150b0SGordon Ross 	    obj->kaddr, obj->real_size, DDI_DMA_RDWR,
16847dc10d7SGordon Ross 	    cb, NULL, &cookie, &cookie_cnt)
169829150b0SGordon Ross 	    != DDI_DMA_MAPPED) {
17047dc10d7SGordon Ross 		DRM_ERROR("ddi_dma_addr_bind_handle failed");
171829150b0SGordon Ross 		goto err3;
172829150b0SGordon Ross 	}
173829150b0SGordon Ross 
174829150b0SGordon Ross 	real_pgcnt = btopr(obj->real_size);
175829150b0SGordon Ross 
176829150b0SGordon Ross 	obj->pfnarray = kmem_zalloc(real_pgcnt * sizeof (pfn_t), KM_NOSLEEP);
177829150b0SGordon Ross 	if (obj->pfnarray == NULL) {
17847dc10d7SGordon Ross 		DRM_DEBUG("pfnarray == NULL");
179829150b0SGordon Ross 		goto err4;
180829150b0SGordon Ross 	}
18147dc10d7SGordon Ross 
182829150b0SGordon Ross 	for (n = 0, i = 1; ; i++) {
18347dc10d7SGordon Ross 		for (paddr = cookie.dmac_laddress,
18447dc10d7SGordon Ross 		    cookie_end = cookie.dmac_laddress + cookie.dmac_size;
185829150b0SGordon Ross 		    paddr < cookie_end;
186829150b0SGordon Ross 		    paddr += PAGESIZE) {
187829150b0SGordon Ross 			obj->pfnarray[n++] = btop(paddr);
188829150b0SGordon Ross 			if (n >= real_pgcnt)
18947dc10d7SGordon Ross 				return (0);
190829150b0SGordon Ross 		}
191829150b0SGordon Ross 		if (i >= cookie_cnt)
192829150b0SGordon Ross 			break;
193829150b0SGordon Ross 		ddi_dma_nextcookie(obj->dma_hdl, &cookie);
194829150b0SGordon Ross 	}
195829150b0SGordon Ross 
19647dc10d7SGordon Ross err4:
19747dc10d7SGordon Ross 	(void) ddi_dma_unbind_handle(obj->dma_hdl);
19847dc10d7SGordon Ross err3:
19947dc10d7SGordon Ross 	ddi_dma_mem_free(&obj->acc_hdl);
20047dc10d7SGordon Ross err2:
20147dc10d7SGordon Ross 	ddi_dma_free_handle(&obj->dma_hdl);
20247dc10d7SGordon Ross err1:
20347dc10d7SGordon Ross 	return (-1);
20447dc10d7SGordon Ross 
20547dc10d7SGordon Ross }
20647dc10d7SGordon Ross 
20747dc10d7SGordon Ross /* Alloc GEM object by memory pool */
20847dc10d7SGordon Ross static int
drm_gem_object_alloc_internal_mempool(struct drm_gem_object * obj,size_t size,int flag)20947dc10d7SGordon Ross drm_gem_object_alloc_internal_mempool(struct drm_gem_object *obj,
21047dc10d7SGordon Ross 				size_t size, int flag)
21147dc10d7SGordon Ross {
21247dc10d7SGordon Ross 	int ret;
21347dc10d7SGordon Ross 	pgcnt_t pgcnt = btopr(size);
21447dc10d7SGordon Ross 
21547dc10d7SGordon Ross 	obj->pfnarray = kmem_zalloc(pgcnt * sizeof (pfn_t), KM_NOSLEEP);
21647dc10d7SGordon Ross 	if (obj->pfnarray == NULL) {
21747dc10d7SGordon Ross 		DRM_ERROR("Failed to allocate pfnarray ");
21847dc10d7SGordon Ross 		return (-1);
21947dc10d7SGordon Ross 	}
22047dc10d7SGordon Ross 
22147dc10d7SGordon Ross 	ret = gfxp_alloc_from_mempool(&obj->mempool_cookie, &obj->kaddr,
22247dc10d7SGordon Ross 					obj->pfnarray, pgcnt, flag);
22347dc10d7SGordon Ross 	if (ret) {
22447dc10d7SGordon Ross 		DRM_ERROR("Failed to alloc pages from memory pool");
22547dc10d7SGordon Ross 		kmem_free(obj->pfnarray, pgcnt * sizeof (pfn_t));
22647dc10d7SGordon Ross 		return (-1);
22747dc10d7SGordon Ross 	}
22847dc10d7SGordon Ross 
22947dc10d7SGordon Ross 	obj->real_size = size;
23047dc10d7SGordon Ross 	return (0);
23147dc10d7SGordon Ross }
23247dc10d7SGordon Ross 
23347dc10d7SGordon Ross static int
drm_gem_object_internal(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int gen)23447dc10d7SGordon Ross drm_gem_object_internal(struct drm_device *dev, struct drm_gem_object *obj,
23547dc10d7SGordon Ross 			size_t size, int gen)
23647dc10d7SGordon Ross {
23747dc10d7SGordon Ross 	pfn_t tmp_pfn;
23847dc10d7SGordon Ross 	int ret, num = 0;
23947dc10d7SGordon Ross 
24047dc10d7SGordon Ross alloc_again:
24147dc10d7SGordon Ross 	if (HAS_MEM_POOL(gen)) {
24247dc10d7SGordon Ross 		uint32_t mode;
24347dc10d7SGordon Ross 		if (gen >= 60)
24447dc10d7SGordon Ross 			mode = GFXP_MEMORY_CACHED;
24547dc10d7SGordon Ross 		else
24647dc10d7SGordon Ross 			mode = GFXP_MEMORY_WRITECOMBINED;
24747dc10d7SGordon Ross 		ret = drm_gem_object_alloc_internal_mempool(obj, size, mode);
24847dc10d7SGordon Ross                 if (ret)
24947dc10d7SGordon Ross                         return (-1);
25047dc10d7SGordon Ross 	} else {
25147dc10d7SGordon Ross 		ret = drm_gem_object_alloc_internal_normal(dev, obj, size, 0);
25247dc10d7SGordon Ross 		if (ret)
25347dc10d7SGordon Ross 			return (-1);
25447dc10d7SGordon Ross 	}
25547dc10d7SGordon Ross 	tmp_pfn = hat_getpfnum(kas.a_hat, obj->kaddr);
25647dc10d7SGordon Ross 	if (tmp_pfn != obj->pfnarray[0]) {
25747dc10d7SGordon Ross 		DRM_ERROR("obj %p map incorrect 0x%lx != 0x%lx",
25847dc10d7SGordon Ross 		    (void *)obj, tmp_pfn, obj->pfnarray[0]);
25947dc10d7SGordon Ross 		drm_gem_object_free_internal(obj, gen);
26047dc10d7SGordon Ross 		udelay(150);
26147dc10d7SGordon Ross 
26247dc10d7SGordon Ross 		if (num++ < 5)
26347dc10d7SGordon Ross 			goto alloc_again;
26447dc10d7SGordon Ross 		else
26547dc10d7SGordon Ross 			return (-1);
26647dc10d7SGordon Ross 	}
26747dc10d7SGordon Ross 
26847dc10d7SGordon Ross 	return (0);
26947dc10d7SGordon Ross }
27047dc10d7SGordon Ross /*
27147dc10d7SGordon Ross  * Initialize an already allocate GEM object of the specified size with
27247dc10d7SGordon Ross  * shmfs backing store.
27347dc10d7SGordon Ross  */
27447dc10d7SGordon Ross int
drm_gem_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size,int gen)27547dc10d7SGordon Ross drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
27647dc10d7SGordon Ross 				size_t size, int gen)
27747dc10d7SGordon Ross {
27847dc10d7SGordon Ross 	drm_local_map_t *map;
27947dc10d7SGordon Ross 	int ret;
28047dc10d7SGordon Ross 
28147dc10d7SGordon Ross 	if (size == 0) {
28247dc10d7SGordon Ross 		DRM_DEBUG("size == 0");
28347dc10d7SGordon Ross 		return (-1);
28447dc10d7SGordon Ross 	}
28547dc10d7SGordon Ross 
28647dc10d7SGordon Ross 	obj->dev = dev;
28747dc10d7SGordon Ross 	obj->size = size;
28847dc10d7SGordon Ross 
28947dc10d7SGordon Ross 	ret = drm_gem_object_internal(dev, obj, size, gen);
29047dc10d7SGordon Ross 	if (ret)
29147dc10d7SGordon Ross 		return (-1);
29247dc10d7SGordon Ross 
293829150b0SGordon Ross 	map = drm_alloc(sizeof (struct drm_local_map), DRM_MEM_MAPS);
294829150b0SGordon Ross 	if (map == NULL) {
29547dc10d7SGordon Ross 		DRM_DEBUG("map == NULL");
296829150b0SGordon Ross 		goto err5;
297829150b0SGordon Ross 	}
298829150b0SGordon Ross 
299829150b0SGordon Ross 	map->handle = obj;
300829150b0SGordon Ross 	map->offset = (uintptr_t)map->handle;
301829150b0SGordon Ross 	map->offset &= 0xffffffffUL;
302829150b0SGordon Ross 	map->size = obj->real_size;
30347dc10d7SGordon Ross 	map->type = _DRM_GEM;
30447dc10d7SGordon Ross 	map->callback = 0;
305829150b0SGordon Ross 	map->flags = _DRM_WRITE_COMBINING | _DRM_REMOVABLE;
30647dc10d7SGordon Ross 	map->umem_cookie =
307829150b0SGordon Ross 	    gfxp_umem_cookie_init(obj->kaddr, obj->real_size);
30847dc10d7SGordon Ross 	if (map->umem_cookie == NULL) {
30947dc10d7SGordon Ross 		DRM_DEBUG("umem_cookie == NULL");
310829150b0SGordon Ross 		goto err6;
311829150b0SGordon Ross 	}
312829150b0SGordon Ross 
31347dc10d7SGordon Ross 	obj->maplist.map = map;
31447dc10d7SGordon Ross 	if (drm_map_handle(dev, &obj->maplist)) {
31547dc10d7SGordon Ross 		DRM_DEBUG("drm_map_handle failed");
316829150b0SGordon Ross 		goto err7;
317829150b0SGordon Ross 	}
318829150b0SGordon Ross 
31947dc10d7SGordon Ross 	kref_init(&obj->refcount);
32047dc10d7SGordon Ross 	atomic_set(&obj->handle_count, 0);
32147dc10d7SGordon Ross 
32247dc10d7SGordon Ross 	if (MDB_TRACK_ENABLE) {
32347dc10d7SGordon Ross 		INIT_LIST_HEAD(&obj->track_list);
32447dc10d7SGordon Ross 		spin_lock(&dev->track_lock);
32547dc10d7SGordon Ross 		list_add_tail(&obj->track_list, &dev->gem_objects_list, (caddr_t)obj);
32647dc10d7SGordon Ross 		spin_unlock(&dev->track_lock);
32747dc10d7SGordon Ross 
32847dc10d7SGordon Ross 		INIT_LIST_HEAD(&obj->his_list);
32947dc10d7SGordon Ross 		drm_gem_object_track(obj, "obj init", 0, 0, NULL);
33047dc10d7SGordon Ross 	}
33147dc10d7SGordon Ross 
33247dc10d7SGordon Ross 	INIT_LIST_HEAD(&obj->seg_list);
33347dc10d7SGordon Ross 
33447dc10d7SGordon Ross 	return (0);
335829150b0SGordon Ross 
336829150b0SGordon Ross err7:
33747dc10d7SGordon Ross 	gfxp_umem_cookie_destroy(map->umem_cookie);
338829150b0SGordon Ross err6:
339829150b0SGordon Ross 	drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
340829150b0SGordon Ross err5:
34147dc10d7SGordon Ross 	drm_gem_object_free_internal(obj, gen);
34247dc10d7SGordon Ross 	return (-1);
34347dc10d7SGordon Ross }
344829150b0SGordon Ross 
34547dc10d7SGordon Ross /**
34647dc10d7SGordon Ross  * Initialize an already allocated GEM object of the specified size with
34747dc10d7SGordon Ross  * no GEM provided backing store. Instead the caller is responsible for
34847dc10d7SGordon Ross  * backing the object and handling it.
34947dc10d7SGordon Ross  */
drm_gem_private_object_init(struct drm_device * dev,struct drm_gem_object * obj,size_t size)35047dc10d7SGordon Ross int drm_gem_private_object_init(struct drm_device *dev,
35147dc10d7SGordon Ross 			struct drm_gem_object *obj, size_t size)
35247dc10d7SGordon Ross {
35347dc10d7SGordon Ross 	BUG_ON((size & (PAGE_SIZE - 1)) != 0);
35447dc10d7SGordon Ross 
35547dc10d7SGordon Ross 	obj->dev = dev;
35647dc10d7SGordon Ross 
35747dc10d7SGordon Ross 	kref_init(&obj->refcount);
35847dc10d7SGordon Ross 	atomic_set(&obj->handle_count, 0);
35947dc10d7SGordon Ross 	obj->size = size;
36047dc10d7SGordon Ross 
36147dc10d7SGordon Ross 	return 0;
362829150b0SGordon Ross }
363829150b0SGordon Ross 
36447dc10d7SGordon Ross /**
36547dc10d7SGordon Ross  * Allocate a GEM object of the specified size with shmfs backing store
36647dc10d7SGordon Ross  */
36747dc10d7SGordon Ross struct drm_gem_object *
drm_gem_object_alloc(struct drm_device * dev,size_t size)36847dc10d7SGordon Ross drm_gem_object_alloc(struct drm_device *dev, size_t size)
36947dc10d7SGordon Ross {
37047dc10d7SGordon Ross 	struct drm_gem_object *obj;
37147dc10d7SGordon Ross 
37247dc10d7SGordon Ross 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
37347dc10d7SGordon Ross 	if (!obj)
37447dc10d7SGordon Ross 		goto free;
37547dc10d7SGordon Ross 
37647dc10d7SGordon Ross 	if (drm_gem_object_init(dev, obj, size, 0) != 0) {
37747dc10d7SGordon Ross 		kmem_free(obj, sizeof (struct drm_gem_object));
37847dc10d7SGordon Ross 		return NULL;
37947dc10d7SGordon Ross 	}
38047dc10d7SGordon Ross 
38147dc10d7SGordon Ross 	if (dev->driver->gem_init_object != NULL &&
38247dc10d7SGordon Ross 	    dev->driver->gem_init_object(obj) != 0) {
38347dc10d7SGordon Ross 		goto fput;
38447dc10d7SGordon Ross 	}
38547dc10d7SGordon Ross 	return obj;
38647dc10d7SGordon Ross fput:
38747dc10d7SGordon Ross 	/* Object_init mangles the global counters - readjust them. */
38847dc10d7SGordon Ross 	drm_gem_object_release(obj);
38947dc10d7SGordon Ross 	kfree(obj, sizeof(*obj));
39047dc10d7SGordon Ross free:
39147dc10d7SGordon Ross 	return NULL;
39247dc10d7SGordon Ross }
39347dc10d7SGordon Ross 
39447dc10d7SGordon Ross /**
395829150b0SGordon Ross  * Removes the mapping from handle to filp for this object.
396829150b0SGordon Ross  */
39747dc10d7SGordon Ross int
drm_gem_handle_delete(struct drm_file * filp,u32 handle)39847dc10d7SGordon Ross drm_gem_handle_delete(struct drm_file *filp, u32 handle)
399829150b0SGordon Ross {
400829150b0SGordon Ross 	struct drm_device *dev;
401829150b0SGordon Ross 	struct drm_gem_object *obj;
40247dc10d7SGordon Ross 
40347dc10d7SGordon Ross 	/* This is gross. The idr system doesn't let us try a delete and
404829150b0SGordon Ross 	 * return an error code.  It just spews if you fail at deleting.
405829150b0SGordon Ross 	 * So, we have to grab a lock around finding the object and then
406829150b0SGordon Ross 	 * doing the delete on it and dropping the refcount, or the user
407829150b0SGordon Ross 	 * could race us to double-decrement the refcount and cause a
408829150b0SGordon Ross 	 * use-after-free later.  Given the frequency of our handle lookups,
409829150b0SGordon Ross 	 * we may want to use ida for number allocation and a hash table
410829150b0SGordon Ross 	 * for the pointers, anyway.
411829150b0SGordon Ross 	 */
412829150b0SGordon Ross 	spin_lock(&filp->table_lock);
413829150b0SGordon Ross 
414829150b0SGordon Ross 	/* Check if we currently have a reference on the object */
415829150b0SGordon Ross 	obj = idr_list_find(&filp->object_idr, handle);
416829150b0SGordon Ross 	if (obj == NULL) {
417829150b0SGordon Ross 		spin_unlock(&filp->table_lock);
41847dc10d7SGordon Ross 		return -EINVAL;
419829150b0SGordon Ross 	}
420829150b0SGordon Ross 	dev = obj->dev;
421829150b0SGordon Ross 
422829150b0SGordon Ross 	/* Release reference and decrement refcount. */
42347dc10d7SGordon Ross 	(void) idr_list_remove(&filp->object_idr, handle);
424829150b0SGordon Ross 	spin_unlock(&filp->table_lock);
425829150b0SGordon Ross 
42647dc10d7SGordon Ross 	if (dev->driver->gem_close_object)
42747dc10d7SGordon Ross 		dev->driver->gem_close_object(obj, filp);
42847dc10d7SGordon Ross 	drm_gem_object_handle_unreference_unlocked(obj);
42947dc10d7SGordon Ross 
43047dc10d7SGordon Ross 	return 0;
431829150b0SGordon Ross }
432829150b0SGordon Ross 
43347dc10d7SGordon Ross /**
434829150b0SGordon Ross  * Create a handle for this object. This adds a handle reference
435829150b0SGordon Ross  * to the object, which includes a regular reference count. Callers
436829150b0SGordon Ross  * will likely want to dereference the object afterwards.
437829150b0SGordon Ross  */
438829150b0SGordon Ross int
drm_gem_handle_create(struct drm_file * file_priv,struct drm_gem_object * obj,u32 * handlep)439829150b0SGordon Ross drm_gem_handle_create(struct drm_file *file_priv,
44047dc10d7SGordon Ross 		       struct drm_gem_object *obj,
44147dc10d7SGordon Ross 		       u32 *handlep)
442829150b0SGordon Ross {
44347dc10d7SGordon Ross 	struct drm_device *dev = obj->dev;
444829150b0SGordon Ross 	int	ret;
445829150b0SGordon Ross 
446829150b0SGordon Ross 	/*
447829150b0SGordon Ross 	 * Get the user-visible handle using idr.
448829150b0SGordon Ross 	 */
449829150b0SGordon Ross again:
450829150b0SGordon Ross 	/* ensure there is space available to allocate a handle */
45147dc10d7SGordon Ross 	if (idr_list_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
45247dc10d7SGordon Ross 		return -ENOMEM;
453829150b0SGordon Ross 
454829150b0SGordon Ross 	/* do the allocation under our spinlock */
455829150b0SGordon Ross 	spin_lock(&file_priv->table_lock);
45647dc10d7SGordon Ross 	ret = idr_list_get_new_above(&file_priv->object_idr, (void *)obj, (int *)handlep);
457829150b0SGordon Ross 	spin_unlock(&file_priv->table_lock);
458829150b0SGordon Ross 	if (ret == -EAGAIN)
459829150b0SGordon Ross 		goto again;
460829150b0SGordon Ross 
46147dc10d7SGordon Ross 	if (ret != 0)
46247dc10d7SGordon Ross 		return ret;
463829150b0SGordon Ross 
464829150b0SGordon Ross 	drm_gem_object_handle_reference(obj);
46547dc10d7SGordon Ross 
46647dc10d7SGordon Ross 	if (dev->driver->gem_open_object) {
46747dc10d7SGordon Ross 		ret = dev->driver->gem_open_object(obj, file_priv);
46847dc10d7SGordon Ross 		if (ret) {
46947dc10d7SGordon Ross 			(void) drm_gem_handle_delete(file_priv, *handlep);
47047dc10d7SGordon Ross 			return ret;
47147dc10d7SGordon Ross 		}
47247dc10d7SGordon Ross 	}
47347dc10d7SGordon Ross 
47447dc10d7SGordon Ross 	return 0;
475829150b0SGordon Ross }
476829150b0SGordon Ross 
47747dc10d7SGordon Ross /** Returns a reference to the object named by the handle. */
478829150b0SGordon Ross struct drm_gem_object *
47947dc10d7SGordon Ross /* LINTED */
drm_gem_object_lookup(struct drm_device * dev,struct drm_file * filp,u32 handle)48047dc10d7SGordon Ross drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
48147dc10d7SGordon Ross 		      u32 handle)
482829150b0SGordon Ross {
483829150b0SGordon Ross 	struct drm_gem_object *obj;
484829150b0SGordon Ross 
485829150b0SGordon Ross 	spin_lock(&filp->table_lock);
486829150b0SGordon Ross 
487829150b0SGordon Ross 	/* Check if we currently have a reference on the object */
488829150b0SGordon Ross 	obj = idr_list_find(&filp->object_idr, handle);
48947dc10d7SGordon Ross 	if (obj == NULL) {
49047dc10d7SGordon Ross 		spin_unlock(&filp->table_lock);
49147dc10d7SGordon Ross 		return NULL;
49247dc10d7SGordon Ross 	}
493829150b0SGordon Ross 
494829150b0SGordon Ross 	drm_gem_object_reference(obj);
495829150b0SGordon Ross 
496829150b0SGordon Ross 	spin_unlock(&filp->table_lock);
497829150b0SGordon Ross 
49847dc10d7SGordon Ross 	return obj;
499829150b0SGordon Ross }
500829150b0SGordon Ross 
50147dc10d7SGordon Ross /**
502829150b0SGordon Ross  * Releases the handle to an mm object.
503829150b0SGordon Ross  */
504829150b0SGordon Ross int
50547dc10d7SGordon Ross /* LINTED */
drm_gem_close_ioctl(DRM_IOCTL_ARGS)506829150b0SGordon Ross drm_gem_close_ioctl(DRM_IOCTL_ARGS)
507829150b0SGordon Ross {
50847dc10d7SGordon Ross 	struct drm_gem_close *args = data;
509829150b0SGordon Ross 	int ret;
510829150b0SGordon Ross 
51147dc10d7SGordon Ross 	if (!(dev->driver->driver_features & DRIVER_GEM))
51247dc10d7SGordon Ross 		return -ENODEV;
513829150b0SGordon Ross 
51447dc10d7SGordon Ross 	ret = drm_gem_handle_delete(file, args->handle);
515829150b0SGordon Ross 
51647dc10d7SGordon Ross 	return ret;
517829150b0SGordon Ross }
518829150b0SGordon Ross 
51947dc10d7SGordon Ross /**
520829150b0SGordon Ross  * Create a global name for an object, returning the name.
521829150b0SGordon Ross  *
522829150b0SGordon Ross  * Note that the name does not hold a reference; when the object
523829150b0SGordon Ross  * is freed, the name goes away.
524829150b0SGordon Ross  */
525829150b0SGordon Ross int
52647dc10d7SGordon Ross /* LINTED */
drm_gem_flink_ioctl(DRM_IOCTL_ARGS)527829150b0SGordon Ross drm_gem_flink_ioctl(DRM_IOCTL_ARGS)
528829150b0SGordon Ross {
52947dc10d7SGordon Ross 	struct drm_gem_flink *args = data;
530829150b0SGordon Ross 	struct drm_gem_object *obj;
53147dc10d7SGordon Ross 	int ret;
532829150b0SGordon Ross 
53347dc10d7SGordon Ross 	if (!(dev->driver->driver_features & DRIVER_GEM))
53447dc10d7SGordon Ross 		return -ENODEV;
535829150b0SGordon Ross 
53647dc10d7SGordon Ross 	obj = drm_gem_object_lookup(dev, file, args->handle);
537829150b0SGordon Ross 	if (obj == NULL)
53847dc10d7SGordon Ross 		return -ENOENT;
53947dc10d7SGordon Ross 
54047dc10d7SGordon Ross again:
54147dc10d7SGordon Ross 	if (idr_list_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
54247dc10d7SGordon Ross 		ret = -ENOMEM;
54347dc10d7SGordon Ross 		goto err;
54447dc10d7SGordon Ross 	}
54547dc10d7SGordon Ross 
546829150b0SGordon Ross 	spin_lock(&dev->object_name_lock);
54747dc10d7SGordon Ross 	if (!obj->name) {
54847dc10d7SGordon Ross 		ret = idr_list_get_new_above(&dev->object_name_idr, (void *) obj,
54947dc10d7SGordon Ross 					&obj->name);
55047dc10d7SGordon Ross 		args->name = (uint64_t) obj->name;
55147dc10d7SGordon Ross 		spin_unlock(&dev->object_name_lock);
55247dc10d7SGordon Ross 
55347dc10d7SGordon Ross 		if (ret == -EAGAIN)
55447dc10d7SGordon Ross 			goto again;
55547dc10d7SGordon Ross 
55647dc10d7SGordon Ross 		if (ret != 0)
55747dc10d7SGordon Ross 			goto err;
55847dc10d7SGordon Ross 
559829150b0SGordon Ross 		/* Allocate a reference for the name table.  */
560829150b0SGordon Ross 		drm_gem_object_reference(obj);
56147dc10d7SGordon Ross 	} else {
56247dc10d7SGordon Ross 		args->name = (uint64_t) obj->name;
56347dc10d7SGordon Ross 		spin_unlock(&dev->object_name_lock);
56447dc10d7SGordon Ross 		ret = 0;
565829150b0SGordon Ross 	}
566829150b0SGordon Ross 
56747dc10d7SGordon Ross err:
56847dc10d7SGordon Ross 	drm_gem_object_unreference_unlocked(obj);
56947dc10d7SGordon Ross 	return ret;
570829150b0SGordon Ross }
571829150b0SGordon Ross 
57247dc10d7SGordon Ross /**
573829150b0SGordon Ross  * Open an object using the global name, returning a handle and the size.
574829150b0SGordon Ross  *
575829150b0SGordon Ross  * This handle (of course) holds a reference to the object, so the object
576829150b0SGordon Ross  * will not go away until the handle is deleted.
577829150b0SGordon Ross  */
578829150b0SGordon Ross int
57947dc10d7SGordon Ross /* LINTED */
drm_gem_open_ioctl(DRM_IOCTL_ARGS)580829150b0SGordon Ross drm_gem_open_ioctl(DRM_IOCTL_ARGS)
581829150b0SGordon Ross {
58247dc10d7SGordon Ross 	struct drm_gem_open *args = data;
583829150b0SGordon Ross 	struct drm_gem_object *obj;
584829150b0SGordon Ross 	int ret;
58547dc10d7SGordon Ross 	u32 handle;
586829150b0SGordon Ross 
58747dc10d7SGordon Ross 	if (!(dev->driver->driver_features & DRIVER_GEM))
58847dc10d7SGordon Ross 		return -ENODEV;
589829150b0SGordon Ross 
590829150b0SGordon Ross 	spin_lock(&dev->object_name_lock);
59147dc10d7SGordon Ross 	obj = idr_list_find(&dev->object_name_idr, (int) args->name);
592829150b0SGordon Ross 	if (obj)
593829150b0SGordon Ross 		drm_gem_object_reference(obj);
594829150b0SGordon Ross 	spin_unlock(&dev->object_name_lock);
59547dc10d7SGordon Ross 	if (!obj)
59647dc10d7SGordon Ross 		return -ENOENT;
597829150b0SGordon Ross 
59847dc10d7SGordon Ross 	ret = drm_gem_handle_create(file, obj, &handle);
59947dc10d7SGordon Ross 	drm_gem_object_unreference_unlocked(obj);
60047dc10d7SGordon Ross 	if (ret)
60147dc10d7SGordon Ross 		return ret;
602829150b0SGordon Ross 
60347dc10d7SGordon Ross 	args->handle = handle;
60447dc10d7SGordon Ross 	args->size = obj->size;
605829150b0SGordon Ross 
60647dc10d7SGordon Ross 	return 0;
607829150b0SGordon Ross }
608829150b0SGordon Ross 
60947dc10d7SGordon Ross /**
610829150b0SGordon Ross  * Called at device open time, sets up the structure for handling refcounting
611829150b0SGordon Ross  * of mm objects.
612829150b0SGordon Ross  */
613829150b0SGordon Ross void
61447dc10d7SGordon Ross /* LINTED */
drm_gem_open(struct drm_device * dev,struct drm_file * file_private)61547dc10d7SGordon Ross drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
616829150b0SGordon Ross {
617829150b0SGordon Ross 	idr_list_init(&file_private->object_idr);
61847dc10d7SGordon Ross 	spin_lock_init(&file_private->table_lock);
619829150b0SGordon Ross }
620829150b0SGordon Ross 
62147dc10d7SGordon Ross /**
622829150b0SGordon Ross  * Called at device close to release the file's
623829150b0SGordon Ross  * handle references on objects.
624829150b0SGordon Ross  */
62547dc10d7SGordon Ross static int
62647dc10d7SGordon Ross /* LINTED */
drm_gem_object_release_handle(int id,void * ptr,void * data)62747dc10d7SGordon Ross drm_gem_object_release_handle(int id, void *ptr, void *data)
628829150b0SGordon Ross {
62947dc10d7SGordon Ross 	struct drm_file *file_priv = data;
63047dc10d7SGordon Ross 	struct drm_gem_object *obj = ptr;
63147dc10d7SGordon Ross 	struct drm_device *dev = obj->dev;
63247dc10d7SGordon Ross 
63347dc10d7SGordon Ross 	if (dev->driver->gem_close_object)
63447dc10d7SGordon Ross 		dev->driver->gem_close_object(obj, file_priv);
63547dc10d7SGordon Ross 
63647dc10d7SGordon Ross 	drm_gem_object_handle_unreference_unlocked(obj);
63747dc10d7SGordon Ross 
63847dc10d7SGordon Ross 	return 0;
639829150b0SGordon Ross }
640829150b0SGordon Ross 
64147dc10d7SGordon Ross /**
642829150b0SGordon Ross  * Called at close time when the filp is going away.
643829150b0SGordon Ross  *
644829150b0SGordon Ross  * Releases any remaining references on objects by this filp.
645829150b0SGordon Ross  */
646829150b0SGordon Ross void
64747dc10d7SGordon Ross /* LINTED E_FUNC_ARG_UNUSED */
drm_gem_release(struct drm_device * dev,struct drm_file * file_private)648829150b0SGordon Ross drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
649829150b0SGordon Ross {
650829150b0SGordon Ross 	struct idr_list  *entry;
65147dc10d7SGordon Ross 	struct drm_gem_object *obj;
652829150b0SGordon Ross 
65347dc10d7SGordon Ross 	idr_list_for_each(entry, &file_private->object_idr) {
65447dc10d7SGordon Ross 		obj = (struct drm_gem_object *)entry->obj;
65547dc10d7SGordon Ross 		(void) drm_gem_object_release_handle(obj->name, obj, (void *)file_private);
65647dc10d7SGordon Ross 	}
657829150b0SGordon Ross 	idr_list_free(&file_private->object_idr);
65847dc10d7SGordon Ross }
659829150b0SGordon Ross 
66047dc10d7SGordon Ross void
drm_gem_object_release(struct drm_gem_object * obj)66147dc10d7SGordon Ross drm_gem_object_release(struct drm_gem_object *obj)
66247dc10d7SGordon Ross {
66347dc10d7SGordon Ross 	struct drm_device *dev = obj->dev;
66447dc10d7SGordon Ross 	struct drm_local_map *map = obj->maplist.map;
66547dc10d7SGordon Ross 
66647dc10d7SGordon Ross 	if (MDB_TRACK_ENABLE) {
66747dc10d7SGordon Ross 		spin_lock(&dev->track_lock);
66847dc10d7SGordon Ross 		list_del(&obj->track_list);
66947dc10d7SGordon Ross 		spin_unlock(&dev->track_lock);
67047dc10d7SGordon Ross 
67147dc10d7SGordon Ross 		struct drm_history_list *r_list, *list_temp;
67247dc10d7SGordon Ross 		list_for_each_entry_safe(r_list, list_temp, struct drm_history_list, &obj->his_list, head) {
67347dc10d7SGordon Ross 			list_del(&r_list->head);
67447dc10d7SGordon Ross 			drm_free(r_list, sizeof (struct drm_history_list), DRM_MEM_MAPS);
67547dc10d7SGordon Ross 		}
67647dc10d7SGordon Ross 		list_del(&obj->his_list);
67747dc10d7SGordon Ross 	}
67847dc10d7SGordon Ross 
67947dc10d7SGordon Ross 	(void) idr_remove(&dev->map_idr, obj->maplist.user_token >> PAGE_SHIFT);
68047dc10d7SGordon Ross 	gfxp_umem_cookie_destroy(map->umem_cookie);
68147dc10d7SGordon Ross 	drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
68247dc10d7SGordon Ross 
68347dc10d7SGordon Ross 	kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
68447dc10d7SGordon Ross 
68547dc10d7SGordon Ross 	if (obj->dma_hdl == NULL) {
68647dc10d7SGordon Ross 		gfxp_free_mempool(&obj->mempool_cookie, obj->kaddr, obj->real_size);
68747dc10d7SGordon Ross 	} else {
68847dc10d7SGordon Ross 		(void) ddi_dma_unbind_handle(obj->dma_hdl);
68947dc10d7SGordon Ross 		ddi_dma_mem_free(&obj->acc_hdl);
69047dc10d7SGordon Ross 		ddi_dma_free_handle(&obj->dma_hdl);
69147dc10d7SGordon Ross 	}
69247dc10d7SGordon Ross 	obj->kaddr = NULL;
693829150b0SGordon Ross }
694829150b0SGordon Ross 
69547dc10d7SGordon Ross /**
696829150b0SGordon Ross  * Called after the last reference to the object has been lost.
697829150b0SGordon Ross  *
698829150b0SGordon Ross  * Frees the object
699829150b0SGordon Ross  */
700829150b0SGordon Ross void
drm_gem_object_free(struct kref * kref)70147dc10d7SGordon Ross drm_gem_object_free(struct kref *kref)
702829150b0SGordon Ross {
70347dc10d7SGordon Ross 	/* LINTED */
70447dc10d7SGordon Ross 	struct drm_gem_object *obj = (struct drm_gem_object *) kref;
705829150b0SGordon Ross 	struct drm_device *dev = obj->dev;
70647dc10d7SGordon Ross 
70747dc10d7SGordon Ross //	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
708829150b0SGordon Ross 
709829150b0SGordon Ross 	if (dev->driver->gem_free_object != NULL)
710829150b0SGordon Ross 		dev->driver->gem_free_object(obj);
71147dc10d7SGordon Ross }
712829150b0SGordon Ross 
71347dc10d7SGordon Ross /* LINTED E_FUNC_ARG_UNUSED */
drm_gem_object_ref_bug(struct kref * list_kref)71447dc10d7SGordon Ross static void drm_gem_object_ref_bug(struct kref *list_kref)
71547dc10d7SGordon Ross {
71647dc10d7SGordon Ross 	BUG_ON(1);
717829150b0SGordon Ross }
718829150b0SGordon Ross 
71947dc10d7SGordon Ross /**
720829150b0SGordon Ross  * Called after the last handle to the object has been closed
721829150b0SGordon Ross  *
722829150b0SGordon Ross  * Removes any name for the object. Note that this must be
723829150b0SGordon Ross  * called before drm_gem_object_free or we'll be touching
724829150b0SGordon Ross  * freed memory
725829150b0SGordon Ross  */
726829150b0SGordon Ross void
drm_gem_object_handle_free(struct drm_gem_object * obj)727829150b0SGordon Ross drm_gem_object_handle_free(struct drm_gem_object *obj)
728829150b0SGordon Ross {
729829150b0SGordon Ross 	struct drm_device *dev = obj->dev;
73047dc10d7SGordon Ross 
731829150b0SGordon Ross 	/* Remove any name for this object */
732829150b0SGordon Ross 	spin_lock(&dev->object_name_lock);
73347dc10d7SGordon Ross 	if (obj->name) {
73447dc10d7SGordon Ross 		(void) idr_list_remove(&dev->object_name_idr, obj->name);
73547dc10d7SGordon Ross 		obj->name = 0;
736829150b0SGordon Ross 		spin_unlock(&dev->object_name_lock);
737829150b0SGordon Ross 		/*
738829150b0SGordon Ross 		 * The object name held a reference to this object, drop
739829150b0SGordon Ross 		 * that now.
74047dc10d7SGordon Ross 		*
74147dc10d7SGordon Ross 		* This cannot be the last reference, since the handle holds one too.
742829150b0SGordon Ross 		 */
74347dc10d7SGordon Ross 		kref_put(&obj->refcount, drm_gem_object_ref_bug);
744829150b0SGordon Ross 	} else
745829150b0SGordon Ross 		spin_unlock(&dev->object_name_lock);
746829150b0SGordon Ross 
747829150b0SGordon Ross }
74847dc10d7SGordon Ross 
74947dc10d7SGordon Ross int
drm_gem_create_mmap_offset(struct drm_gem_object * obj)75047dc10d7SGordon Ross drm_gem_create_mmap_offset(struct drm_gem_object *obj)
75147dc10d7SGordon Ross {
75247dc10d7SGordon Ross 	obj->gtt_map_kaddr = gfxp_alloc_kernel_space(obj->real_size);
75347dc10d7SGordon Ross 	if (obj->gtt_map_kaddr == NULL) {
75447dc10d7SGordon Ross 		return -ENOMEM;
75547dc10d7SGordon Ross 	}
75647dc10d7SGordon Ross 	return 0;
75747dc10d7SGordon Ross }
75847dc10d7SGordon Ross 
75947dc10d7SGordon Ross void
drm_gem_mmap(struct drm_gem_object * obj,pfn_t pfn)76047dc10d7SGordon Ross drm_gem_mmap(struct drm_gem_object *obj, pfn_t pfn)
76147dc10d7SGordon Ross {
762*e49fc716SGordon Ross 	ASSERT(obj->gtt_map_kaddr != NULL);
763*e49fc716SGordon Ross 	/* Does hat_devload() */
76447dc10d7SGordon Ross 	gfxp_load_kernel_space(pfn, obj->real_size, GFXP_MEMORY_WRITECOMBINED, obj->gtt_map_kaddr);
76547dc10d7SGordon Ross }
76647dc10d7SGordon Ross 
76747dc10d7SGordon Ross void
drm_gem_release_mmap(struct drm_gem_object * obj)76847dc10d7SGordon Ross drm_gem_release_mmap(struct drm_gem_object *obj)
76947dc10d7SGordon Ross {
770*e49fc716SGordon Ross 	ASSERT(obj->gtt_map_kaddr != NULL);
771*e49fc716SGordon Ross 	/* Does hat_unload() */
77247dc10d7SGordon Ross 	gfxp_unload_kernel_space(obj->gtt_map_kaddr, obj->real_size);
77347dc10d7SGordon Ross }
77447dc10d7SGordon Ross 
77547dc10d7SGordon Ross void
drm_gem_free_mmap_offset(struct drm_gem_object * obj)77647dc10d7SGordon Ross drm_gem_free_mmap_offset(struct drm_gem_object *obj)
77747dc10d7SGordon Ross {
77847dc10d7SGordon Ross 	struct ddi_umem_cookie *umem_cookie = obj->maplist.map->umem_cookie;
77947dc10d7SGordon Ross 	umem_cookie->cvaddr = obj->kaddr;
78047dc10d7SGordon Ross 
78147dc10d7SGordon Ross 	if (obj->maplist.map->gtt_mmap == 0) {
78247dc10d7SGordon Ross 		gfxp_free_kernel_space(obj->gtt_map_kaddr, obj->real_size);
78347dc10d7SGordon Ross 		DRM_DEBUG("already freed, don't free more than once!");
78447dc10d7SGordon Ross 	}
78547dc10d7SGordon Ross 
78647dc10d7SGordon Ross 	if (obj->maplist.map->gtt_mmap == 1) {
78747dc10d7SGordon Ross 		gfxp_unmap_kernel_space(obj->gtt_map_kaddr, obj->real_size);
78847dc10d7SGordon Ross 		obj->maplist.map->gtt_mmap = 0;
78947dc10d7SGordon Ross 	}
79047dc10d7SGordon Ross 
79147dc10d7SGordon Ross 	obj->gtt_map_kaddr = NULL;
79247dc10d7SGordon Ross }
79347dc10d7SGordon Ross 
79447dc10d7SGordon Ross void
drm_gem_object_track(struct drm_gem_object * obj,const char * name,uint32_t cur_seq,uint32_t last_seq,void * ptr)79547dc10d7SGordon Ross drm_gem_object_track(struct drm_gem_object *obj, const char *name,
79647dc10d7SGordon Ross                         uint32_t cur_seq, uint32_t last_seq, void* ptr)
79747dc10d7SGordon Ross {
79847dc10d7SGordon Ross 	struct drm_history_list *list;
79947dc10d7SGordon Ross 	list = drm_alloc(sizeof (struct drm_history_list), DRM_MEM_MAPS);
80047dc10d7SGordon Ross 	if (list != NULL) {
80147dc10d7SGordon Ross 		(void) memcpy(list->info, name, (strlen(name) * sizeof(char)));
80247dc10d7SGordon Ross 		list->cur_seq = cur_seq;
80347dc10d7SGordon Ross 		list->last_seq = last_seq;
80447dc10d7SGordon Ross 		list->ring_ptr = ptr;
80547dc10d7SGordon Ross 		list_add_tail(&list->head, &obj->his_list, (caddr_t)list);
80647dc10d7SGordon Ross 	}
80747dc10d7SGordon Ross }
808