xref: /titanic_50/usr/src/uts/common/io/drm/drm_gem.c (revision 2e6e901d9406e1a048063c872149376a6bf7cb63)
10035d21cSmiao chen - Sun Microsystems - Beijing China /*
20035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright (c) 2009, Intel Corporation.
30035d21cSmiao chen - Sun Microsystems - Beijing China  * All Rights Reserved.
40035d21cSmiao chen - Sun Microsystems - Beijing China  *
50035d21cSmiao chen - Sun Microsystems - Beijing China  * Permission is hereby granted, free of charge, to any person obtaining a
60035d21cSmiao chen - Sun Microsystems - Beijing China  * copy of this software and associated documentation files (the "Software"),
70035d21cSmiao chen - Sun Microsystems - Beijing China  * to deal in the Software without restriction, including without limitation
80035d21cSmiao chen - Sun Microsystems - Beijing China  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
90035d21cSmiao chen - Sun Microsystems - Beijing China  * and/or sell copies of the Software, and to permit persons to whom the
100035d21cSmiao chen - Sun Microsystems - Beijing China  * Software is furnished to do so, subject to the following conditions:
110035d21cSmiao chen - Sun Microsystems - Beijing China  *
120035d21cSmiao chen - Sun Microsystems - Beijing China  * The above copyright notice and this permission notice (including the next
130035d21cSmiao chen - Sun Microsystems - Beijing China  * paragraph) shall be included in all copies or substantial portions of the
140035d21cSmiao chen - Sun Microsystems - Beijing China  * Software.
150035d21cSmiao chen - Sun Microsystems - Beijing China  *
160035d21cSmiao chen - Sun Microsystems - Beijing China  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170035d21cSmiao chen - Sun Microsystems - Beijing China  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180035d21cSmiao chen - Sun Microsystems - Beijing China  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
190035d21cSmiao chen - Sun Microsystems - Beijing China  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200035d21cSmiao chen - Sun Microsystems - Beijing China  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
210035d21cSmiao chen - Sun Microsystems - Beijing China  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
220035d21cSmiao chen - Sun Microsystems - Beijing China  * IN THE SOFTWARE.
230035d21cSmiao chen - Sun Microsystems - Beijing China  *
240035d21cSmiao chen - Sun Microsystems - Beijing China  * Authors:
250035d21cSmiao chen - Sun Microsystems - Beijing China  *    Eric Anholt <eric@anholt.net>
260035d21cSmiao chen - Sun Microsystems - Beijing China  *
270035d21cSmiao chen - Sun Microsystems - Beijing China  */
280035d21cSmiao chen - Sun Microsystems - Beijing China 
290035d21cSmiao chen - Sun Microsystems - Beijing China /*
300035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
310035d21cSmiao chen - Sun Microsystems - Beijing China  * Use is subject to license terms.
320035d21cSmiao chen - Sun Microsystems - Beijing China  */
330035d21cSmiao chen - Sun Microsystems - Beijing China 
340035d21cSmiao chen - Sun Microsystems - Beijing China #include <vm/anon.h>
350035d21cSmiao chen - Sun Microsystems - Beijing China #include <vm/seg_kmem.h>
360035d21cSmiao chen - Sun Microsystems - Beijing China #include <vm/seg_kp.h>
370035d21cSmiao chen - Sun Microsystems - Beijing China #include <vm/seg_map.h>
380035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/fcntl.h>
390035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/vnode.h>
400035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/file.h>
410035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/bitmap.h>
420035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/ddi.h>
430035d21cSmiao chen - Sun Microsystems - Beijing China #include <sys/sunddi.h>
440035d21cSmiao chen - Sun Microsystems - Beijing China #include <gfx_private.h>
450035d21cSmiao chen - Sun Microsystems - Beijing China #include "drmP.h"
460035d21cSmiao chen - Sun Microsystems - Beijing China #include "drm.h"
470035d21cSmiao chen - Sun Microsystems - Beijing China 
480035d21cSmiao chen - Sun Microsystems - Beijing China /*
490035d21cSmiao chen - Sun Microsystems - Beijing China  * @file drm_gem.c
500035d21cSmiao chen - Sun Microsystems - Beijing China  *
510035d21cSmiao chen - Sun Microsystems - Beijing China  * This file provides some of the base ioctls and library routines for
520035d21cSmiao chen - Sun Microsystems - Beijing China  * the graphics memory manager implemented by each device driver.
530035d21cSmiao chen - Sun Microsystems - Beijing China  *
540035d21cSmiao chen - Sun Microsystems - Beijing China  * Because various devices have different requirements in terms of
550035d21cSmiao chen - Sun Microsystems - Beijing China  * synchronization and migration strategies, implementing that is left up to
560035d21cSmiao chen - Sun Microsystems - Beijing China  * the driver, and all that the general API provides should be generic --
570035d21cSmiao chen - Sun Microsystems - Beijing China  * allocating objects, reading/writing data with the cpu, freeing objects.
580035d21cSmiao chen - Sun Microsystems - Beijing China  * Even there, platform-dependent optimizations for reading/writing data with
590035d21cSmiao chen - Sun Microsystems - Beijing China  * the CPU mean we'll likely hook those out to driver-specific calls.  However,
600035d21cSmiao chen - Sun Microsystems - Beijing China  * the DRI2 implementation wants to have at least allocate/mmap be generic.
610035d21cSmiao chen - Sun Microsystems - Beijing China  *
620035d21cSmiao chen - Sun Microsystems - Beijing China  * The goal was to have swap-backed object allocation managed through
630035d21cSmiao chen - Sun Microsystems - Beijing China  * struct file.  However, file descriptors as handles to a struct file have
640035d21cSmiao chen - Sun Microsystems - Beijing China  * two major failings:
650035d21cSmiao chen - Sun Microsystems - Beijing China  * - Process limits prevent more than 1024 or so being used at a time by
660035d21cSmiao chen - Sun Microsystems - Beijing China  *   default.
670035d21cSmiao chen - Sun Microsystems - Beijing China  * - Inability to allocate high fds will aggravate the X Server's select()
680035d21cSmiao chen - Sun Microsystems - Beijing China  *   handling, and likely that of many GL client applications as well.
690035d21cSmiao chen - Sun Microsystems - Beijing China  *
700035d21cSmiao chen - Sun Microsystems - Beijing China  * This led to a plan of using our own integer IDs(called handles, following
710035d21cSmiao chen - Sun Microsystems - Beijing China  * DRM terminology) to mimic fds, and implement the fd syscalls we need as
720035d21cSmiao chen - Sun Microsystems - Beijing China  * ioctls.  The objects themselves will still include the struct file so
730035d21cSmiao chen - Sun Microsystems - Beijing China  * that we can transition to fds if the required kernel infrastructure shows
740035d21cSmiao chen - Sun Microsystems - Beijing China  * up at a later date, and as our interface with shmfs for memory allocation.
750035d21cSmiao chen - Sun Microsystems - Beijing China  */
760035d21cSmiao chen - Sun Microsystems - Beijing China 
770035d21cSmiao chen - Sun Microsystems - Beijing China void
idr_list_init(struct idr_list * head)780035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_init(struct idr_list  *head)
790035d21cSmiao chen - Sun Microsystems - Beijing China {
800035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry;
810035d21cSmiao chen - Sun Microsystems - Beijing China 	/* HASH for accelerate */
820035d21cSmiao chen - Sun Microsystems - Beijing China 	entry = kmem_zalloc(DRM_GEM_OBJIDR_HASHNODE
83*2e6e901dSmiao chen - Sun Microsystems - Beijing China 	    * sizeof (struct idr_list), KM_SLEEP);
840035d21cSmiao chen - Sun Microsystems - Beijing China 	head->next = entry;
850035d21cSmiao chen - Sun Microsystems - Beijing China 	for (int i = 0; i < DRM_GEM_OBJIDR_HASHNODE; i++) {
860035d21cSmiao chen - Sun Microsystems - Beijing China 		INIT_LIST_HEAD(&entry[i]);
870035d21cSmiao chen - Sun Microsystems - Beijing China 	}
880035d21cSmiao chen - Sun Microsystems - Beijing China }
890035d21cSmiao chen - Sun Microsystems - Beijing China 
900035d21cSmiao chen - Sun Microsystems - Beijing China int
idr_list_get_new_above(struct idr_list * head,struct drm_gem_object * obj,int * handlep)910035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_get_new_above(struct idr_list	*head,
920035d21cSmiao chen - Sun Microsystems - Beijing China 			struct drm_gem_object *obj,
930035d21cSmiao chen - Sun Microsystems - Beijing China 			int *handlep)
940035d21cSmiao chen - Sun Microsystems - Beijing China {
950035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry;
960035d21cSmiao chen - Sun Microsystems - Beijing China 	int key;
97*2e6e901dSmiao chen - Sun Microsystems - Beijing China 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
980035d21cSmiao chen - Sun Microsystems - Beijing China 	key = obj->name % DRM_GEM_OBJIDR_HASHNODE;
990035d21cSmiao chen - Sun Microsystems - Beijing China 	list_add(entry, &head->next[key], NULL);
1000035d21cSmiao chen - Sun Microsystems - Beijing China 	entry->obj = obj;
1010035d21cSmiao chen - Sun Microsystems - Beijing China 	entry->handle = obj->name;
1020035d21cSmiao chen - Sun Microsystems - Beijing China 	*handlep = obj->name;
1030035d21cSmiao chen - Sun Microsystems - Beijing China 	return (0);
1040035d21cSmiao chen - Sun Microsystems - Beijing China }
1050035d21cSmiao chen - Sun Microsystems - Beijing China 
1060035d21cSmiao chen - Sun Microsystems - Beijing China struct drm_gem_object *
idr_list_find(struct idr_list * head,uint32_t name)1070035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_find(struct idr_list  *head,
1080035d21cSmiao chen - Sun Microsystems - Beijing China 		uint32_t	name)
1090035d21cSmiao chen - Sun Microsystems - Beijing China {
1100035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry;
1110035d21cSmiao chen - Sun Microsystems - Beijing China 	int key;
1120035d21cSmiao chen - Sun Microsystems - Beijing China 	key = name % DRM_GEM_OBJIDR_HASHNODE;
1130035d21cSmiao chen - Sun Microsystems - Beijing China 
1140035d21cSmiao chen - Sun Microsystems - Beijing China 	list_for_each(entry, &head->next[key]) {
1150035d21cSmiao chen - Sun Microsystems - Beijing China 		if (entry->handle == name)
1160035d21cSmiao chen - Sun Microsystems - Beijing China 			return (entry->obj);
1170035d21cSmiao chen - Sun Microsystems - Beijing China 	}
1180035d21cSmiao chen - Sun Microsystems - Beijing China 	return (NULL);
1190035d21cSmiao chen - Sun Microsystems - Beijing China }
1200035d21cSmiao chen - Sun Microsystems - Beijing China 
1210035d21cSmiao chen - Sun Microsystems - Beijing China int
idr_list_remove(struct idr_list * head,uint32_t name)1220035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_remove(struct idr_list  *head,
1230035d21cSmiao chen - Sun Microsystems - Beijing China 		uint32_t	name)
1240035d21cSmiao chen - Sun Microsystems - Beijing China {
1250035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry, *temp;
1260035d21cSmiao chen - Sun Microsystems - Beijing China 	int key;
1270035d21cSmiao chen - Sun Microsystems - Beijing China 	key = name % DRM_GEM_OBJIDR_HASHNODE;
1280035d21cSmiao chen - Sun Microsystems - Beijing China 	list_for_each_safe(entry, temp, &head->next[key]) {
1290035d21cSmiao chen - Sun Microsystems - Beijing China 		if (entry->handle == name) {
1300035d21cSmiao chen - Sun Microsystems - Beijing China 			list_del(entry);
1310035d21cSmiao chen - Sun Microsystems - Beijing China 			kmem_free(entry, sizeof (*entry));
1320035d21cSmiao chen - Sun Microsystems - Beijing China 			return (0);
1330035d21cSmiao chen - Sun Microsystems - Beijing China 		}
1340035d21cSmiao chen - Sun Microsystems - Beijing China 	}
1350035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_ERROR("Failed to remove the object %d", name);
1360035d21cSmiao chen - Sun Microsystems - Beijing China 	return (-1);
1370035d21cSmiao chen - Sun Microsystems - Beijing China }
1380035d21cSmiao chen - Sun Microsystems - Beijing China 
1390035d21cSmiao chen - Sun Microsystems - Beijing China void
idr_list_free(struct idr_list * head)1400035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_free(struct idr_list  *head)
1410035d21cSmiao chen - Sun Microsystems - Beijing China {
1420035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry, *temp;
1430035d21cSmiao chen - Sun Microsystems - Beijing China 	for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
1440035d21cSmiao chen - Sun Microsystems - Beijing China 		list_for_each_safe(entry, temp, &head->next[key]) {
1450035d21cSmiao chen - Sun Microsystems - Beijing China 			list_del(entry);
1460035d21cSmiao chen - Sun Microsystems - Beijing China 			kmem_free(entry, sizeof (*entry));
1470035d21cSmiao chen - Sun Microsystems - Beijing China 		}
1480035d21cSmiao chen - Sun Microsystems - Beijing China 	}
1490035d21cSmiao chen - Sun Microsystems - Beijing China 	kmem_free(head->next,
1500035d21cSmiao chen - Sun Microsystems - Beijing China 	    DRM_GEM_OBJIDR_HASHNODE * sizeof (struct idr_list));
1510035d21cSmiao chen - Sun Microsystems - Beijing China 	head->next = NULL;
1520035d21cSmiao chen - Sun Microsystems - Beijing China }
1530035d21cSmiao chen - Sun Microsystems - Beijing China 
1540035d21cSmiao chen - Sun Microsystems - Beijing China int
idr_list_empty(struct idr_list * head)1550035d21cSmiao chen - Sun Microsystems - Beijing China idr_list_empty(struct idr_list  *head)
1560035d21cSmiao chen - Sun Microsystems - Beijing China {
1570035d21cSmiao chen - Sun Microsystems - Beijing China 	int empty;
1580035d21cSmiao chen - Sun Microsystems - Beijing China 	for (int key = 0; key < DRM_GEM_OBJIDR_HASHNODE; key++) {
1590035d21cSmiao chen - Sun Microsystems - Beijing China 		empty = list_empty(&(head)->next[key]);
1600035d21cSmiao chen - Sun Microsystems - Beijing China 		if (!empty)
1610035d21cSmiao chen - Sun Microsystems - Beijing China 			return (empty);
1620035d21cSmiao chen - Sun Microsystems - Beijing China 	}
1630035d21cSmiao chen - Sun Microsystems - Beijing China 	return (1);
1640035d21cSmiao chen - Sun Microsystems - Beijing China }
1650035d21cSmiao chen - Sun Microsystems - Beijing China 
1660035d21cSmiao chen - Sun Microsystems - Beijing China static	uint32_t	shfile_name = 0;
1670035d21cSmiao chen - Sun Microsystems - Beijing China #define	SHFILE_NAME_MAX	0xffffffff
1680035d21cSmiao chen - Sun Microsystems - Beijing China 
1690035d21cSmiao chen - Sun Microsystems - Beijing China /*
1700035d21cSmiao chen - Sun Microsystems - Beijing China  * will be set to 1 for 32 bit x86 systems only, in startup.c
1710035d21cSmiao chen - Sun Microsystems - Beijing China  */
1720035d21cSmiao chen - Sun Microsystems - Beijing China extern int	segkp_fromheap;
1730035d21cSmiao chen - Sun Microsystems - Beijing China extern ulong_t *segkp_bitmap;
1740035d21cSmiao chen - Sun Microsystems - Beijing China 
1750035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_reference(struct drm_gem_object * obj)1760035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_reference(struct drm_gem_object *obj)
1770035d21cSmiao chen - Sun Microsystems - Beijing China {
1780035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_inc(&obj->refcount);
1790035d21cSmiao chen - Sun Microsystems - Beijing China }
1800035d21cSmiao chen - Sun Microsystems - Beijing China 
1810035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_unreference(struct drm_gem_object * obj)1820035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_unreference(struct drm_gem_object *obj)
1830035d21cSmiao chen - Sun Microsystems - Beijing China {
1840035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj == NULL)
1850035d21cSmiao chen - Sun Microsystems - Beijing China 		return;
1860035d21cSmiao chen - Sun Microsystems - Beijing China 
1870035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_sub(1, &obj->refcount);
1880035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj->refcount == 0)
1890035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_gem_object_free(obj);
1900035d21cSmiao chen - Sun Microsystems - Beijing China }
1910035d21cSmiao chen - Sun Microsystems - Beijing China 
1920035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_handle_reference(struct drm_gem_object * obj)1930035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_handle_reference(struct drm_gem_object *obj)
1940035d21cSmiao chen - Sun Microsystems - Beijing China {
1950035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_reference(obj);
1960035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_inc(&obj->handlecount);
1970035d21cSmiao chen - Sun Microsystems - Beijing China }
1980035d21cSmiao chen - Sun Microsystems - Beijing China 
1990035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_handle_unreference(struct drm_gem_object * obj)2000035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_handle_unreference(struct drm_gem_object *obj)
2010035d21cSmiao chen - Sun Microsystems - Beijing China {
2020035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj == NULL)
2030035d21cSmiao chen - Sun Microsystems - Beijing China 		return;
2040035d21cSmiao chen - Sun Microsystems - Beijing China 
2050035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
2060035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Must bump handle count first as this may be the last
2070035d21cSmiao chen - Sun Microsystems - Beijing China 	 * ref, in which case the object would disappear before we
2080035d21cSmiao chen - Sun Microsystems - Beijing China 	 * checked for a name
2090035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
2100035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_sub(1, &obj->handlecount);
2110035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj->handlecount == 0)
2120035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_gem_object_handle_free(obj);
2130035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_unreference(obj);
2140035d21cSmiao chen - Sun Microsystems - Beijing China }
2150035d21cSmiao chen - Sun Microsystems - Beijing China 
2160035d21cSmiao chen - Sun Microsystems - Beijing China /*
2170035d21cSmiao chen - Sun Microsystems - Beijing China  * Initialize the GEM device fields
2180035d21cSmiao chen - Sun Microsystems - Beijing China  */
2190035d21cSmiao chen - Sun Microsystems - Beijing China 
2200035d21cSmiao chen - Sun Microsystems - Beijing China int
drm_gem_init(struct drm_device * dev)2210035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_init(struct drm_device *dev)
2220035d21cSmiao chen - Sun Microsystems - Beijing China {
2230035d21cSmiao chen - Sun Microsystems - Beijing China 	mutex_init(&dev->object_name_lock, NULL, MUTEX_DRIVER, NULL);
2240035d21cSmiao chen - Sun Microsystems - Beijing China 	idr_list_init(&dev->object_name_idr);
2250035d21cSmiao chen - Sun Microsystems - Beijing China 
2260035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->object_count, 0);
2270035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->object_memory, 0);
2280035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->pin_count, 0);
2290035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->pin_memory, 0);
2300035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->gtt_count, 0);
2310035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&dev->gtt_memory, 0);
2320035d21cSmiao chen - Sun Microsystems - Beijing China 	return (0);
2330035d21cSmiao chen - Sun Microsystems - Beijing China }
2340035d21cSmiao chen - Sun Microsystems - Beijing China 
2350035d21cSmiao chen - Sun Microsystems - Beijing China /*
2360035d21cSmiao chen - Sun Microsystems - Beijing China  * Allocate a GEM object of the specified size with shmfs backing store
2370035d21cSmiao chen - Sun Microsystems - Beijing China  */
2380035d21cSmiao chen - Sun Microsystems - Beijing China struct drm_gem_object *
drm_gem_object_alloc(struct drm_device * dev,size_t size)2390035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_alloc(struct drm_device *dev, size_t size)
2400035d21cSmiao chen - Sun Microsystems - Beijing China {
2410035d21cSmiao chen - Sun Microsystems - Beijing China 	static ddi_dma_attr_t dma_attr = {
2420035d21cSmiao chen - Sun Microsystems - Beijing China 		DMA_ATTR_V0,
2430035d21cSmiao chen - Sun Microsystems - Beijing China 		0U,				/* dma_attr_addr_lo */
2440035d21cSmiao chen - Sun Microsystems - Beijing China 		0xffffffffU,			/* dma_attr_addr_hi */
2450035d21cSmiao chen - Sun Microsystems - Beijing China 		0xffffffffU,			/* dma_attr_count_max */
2460035d21cSmiao chen - Sun Microsystems - Beijing China 		4096,				/* dma_attr_align */
2470035d21cSmiao chen - Sun Microsystems - Beijing China 		0x1fffU,			/* dma_attr_burstsizes */
2480035d21cSmiao chen - Sun Microsystems - Beijing China 		1,				/* dma_attr_minxfer */
2490035d21cSmiao chen - Sun Microsystems - Beijing China 		0xffffffffU,			/* dma_attr_maxxfer */
2500035d21cSmiao chen - Sun Microsystems - Beijing China 		0xffffffffU,			/* dma_attr_seg */
2510035d21cSmiao chen - Sun Microsystems - Beijing China 		1,				/* dma_attr_sgllen, variable */
2520035d21cSmiao chen - Sun Microsystems - Beijing China 		4,				/* dma_attr_granular */
2530035d21cSmiao chen - Sun Microsystems - Beijing China 		0				/* dma_attr_flags */
2540035d21cSmiao chen - Sun Microsystems - Beijing China 	};
2550035d21cSmiao chen - Sun Microsystems - Beijing China 	static ddi_device_acc_attr_t acc_attr = {
2560035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_DEVICE_ATTR_V0,
2570035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_NEVERSWAP_ACC,
2580035d21cSmiao chen - Sun Microsystems - Beijing China 		DDI_MERGING_OK_ACC
2590035d21cSmiao chen - Sun Microsystems - Beijing China 	};
2600035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_object *obj;
2610035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_dma_cookie_t cookie;
2620035d21cSmiao chen - Sun Microsystems - Beijing China 	uint_t cookie_cnt;
2630035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_local_map_t *map;
2640035d21cSmiao chen - Sun Microsystems - Beijing China 
2650035d21cSmiao chen - Sun Microsystems - Beijing China 	pgcnt_t real_pgcnt, pgcnt = btopr(size);
2660035d21cSmiao chen - Sun Microsystems - Beijing China 	uint32_t paddr, cookie_end;
2670035d21cSmiao chen - Sun Microsystems - Beijing China 	int i, n;
2680035d21cSmiao chen - Sun Microsystems - Beijing China 
2690035d21cSmiao chen - Sun Microsystems - Beijing China 	obj = kmem_zalloc(sizeof (struct drm_gem_object), KM_NOSLEEP);
2700035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj == NULL)
2710035d21cSmiao chen - Sun Microsystems - Beijing China 		return (NULL);
2720035d21cSmiao chen - Sun Microsystems - Beijing China 
2730035d21cSmiao chen - Sun Microsystems - Beijing China 	obj->dev = dev;
2740035d21cSmiao chen - Sun Microsystems - Beijing China 	obj->flink = 0;
2750035d21cSmiao chen - Sun Microsystems - Beijing China 	obj->size = size;
2760035d21cSmiao chen - Sun Microsystems - Beijing China 
2770035d21cSmiao chen - Sun Microsystems - Beijing China 	if (shfile_name == SHFILE_NAME_MAX) {
2780035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("No name space for object");
2790035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err1;
2800035d21cSmiao chen - Sun Microsystems - Beijing China 	} else {
2810035d21cSmiao chen - Sun Microsystems - Beijing China 		obj->name = ++shfile_name;
2820035d21cSmiao chen - Sun Microsystems - Beijing China 	}
2830035d21cSmiao chen - Sun Microsystems - Beijing China 
2840035d21cSmiao chen - Sun Microsystems - Beijing China 	dma_attr.dma_attr_sgllen = (int)pgcnt;
2850035d21cSmiao chen - Sun Microsystems - Beijing China 
2860035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ddi_dma_alloc_handle(dev->dip, &dma_attr,
2870035d21cSmiao chen - Sun Microsystems - Beijing China 	    DDI_DMA_DONTWAIT, NULL, &obj->dma_hdl)) {
2880035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("drm_gem_object_alloc: "
2890035d21cSmiao chen - Sun Microsystems - Beijing China 		    "ddi_dma_alloc_handle failed");
2900035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err1;
2910035d21cSmiao chen - Sun Microsystems - Beijing China 	}
2920035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ddi_dma_mem_alloc(obj->dma_hdl, ptob(pgcnt), &acc_attr,
2930035d21cSmiao chen - Sun Microsystems - Beijing China 	    IOMEM_DATA_UC_WR_COMBINE, DDI_DMA_DONTWAIT, NULL,
2940035d21cSmiao chen - Sun Microsystems - Beijing China 	    &obj->kaddr, &obj->real_size, &obj->acc_hdl)) {
2950035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("drm_gem_object_alloc: "
2960035d21cSmiao chen - Sun Microsystems - Beijing China 		    "ddi_dma_mem_alloc failed");
2970035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err2;
2980035d21cSmiao chen - Sun Microsystems - Beijing China 	}
2990035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ddi_dma_addr_bind_handle(obj->dma_hdl, NULL,
3000035d21cSmiao chen - Sun Microsystems - Beijing China 	    obj->kaddr, obj->real_size, DDI_DMA_RDWR,
3010035d21cSmiao chen - Sun Microsystems - Beijing China 	    DDI_DMA_DONTWAIT, NULL, &cookie, &cookie_cnt)
3020035d21cSmiao chen - Sun Microsystems - Beijing China 	    != DDI_DMA_MAPPED) {
3030035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("drm_gem_object_alloc: "
3040035d21cSmiao chen - Sun Microsystems - Beijing China 		    "ddi_dma_addr_bind_handle failed");
3050035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err3;
3060035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3070035d21cSmiao chen - Sun Microsystems - Beijing China 
3080035d21cSmiao chen - Sun Microsystems - Beijing China 	real_pgcnt = btopr(obj->real_size);
3090035d21cSmiao chen - Sun Microsystems - Beijing China 
3100035d21cSmiao chen - Sun Microsystems - Beijing China 	obj->pfnarray = kmem_zalloc(real_pgcnt * sizeof (pfn_t), KM_NOSLEEP);
3110035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj->pfnarray == NULL) {
3120035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err4;
3130035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3140035d21cSmiao chen - Sun Microsystems - Beijing China 	for (n = 0, i = 1; ; i++) {
3150035d21cSmiao chen - Sun Microsystems - Beijing China 		for (paddr = cookie.dmac_address,
3160035d21cSmiao chen - Sun Microsystems - Beijing China 		    cookie_end = cookie.dmac_address + cookie.dmac_size;
3170035d21cSmiao chen - Sun Microsystems - Beijing China 		    paddr < cookie_end;
3180035d21cSmiao chen - Sun Microsystems - Beijing China 		    paddr += PAGESIZE) {
3190035d21cSmiao chen - Sun Microsystems - Beijing China 			obj->pfnarray[n++] = btop(paddr);
3200035d21cSmiao chen - Sun Microsystems - Beijing China 			if (n >= real_pgcnt)
3210035d21cSmiao chen - Sun Microsystems - Beijing China 				goto addmap;
3220035d21cSmiao chen - Sun Microsystems - Beijing China 		}
3230035d21cSmiao chen - Sun Microsystems - Beijing China 		if (i >= cookie_cnt)
3240035d21cSmiao chen - Sun Microsystems - Beijing China 			break;
3250035d21cSmiao chen - Sun Microsystems - Beijing China 		ddi_dma_nextcookie(obj->dma_hdl, &cookie);
3260035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3270035d21cSmiao chen - Sun Microsystems - Beijing China 
3280035d21cSmiao chen - Sun Microsystems - Beijing China addmap:
3290035d21cSmiao chen - Sun Microsystems - Beijing China 	map = drm_alloc(sizeof (struct drm_local_map), DRM_MEM_MAPS);
3300035d21cSmiao chen - Sun Microsystems - Beijing China 	if (map == NULL) {
3310035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err5;
3320035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3330035d21cSmiao chen - Sun Microsystems - Beijing China 
3340035d21cSmiao chen - Sun Microsystems - Beijing China 	map->handle = obj;
3350035d21cSmiao chen - Sun Microsystems - Beijing China 	map->offset = (uintptr_t)map->handle;
3360035d21cSmiao chen - Sun Microsystems - Beijing China 	map->offset &= 0xffffffffUL;
3370035d21cSmiao chen - Sun Microsystems - Beijing China 	map->dev_addr = map->handle;
3380035d21cSmiao chen - Sun Microsystems - Beijing China 	map->size = obj->real_size;
3390035d21cSmiao chen - Sun Microsystems - Beijing China 	map->type = _DRM_TTM;
3400035d21cSmiao chen - Sun Microsystems - Beijing China 	map->flags = _DRM_WRITE_COMBINING | _DRM_REMOVABLE;
3410035d21cSmiao chen - Sun Microsystems - Beijing China 	map->drm_umem_cookie =
3420035d21cSmiao chen - Sun Microsystems - Beijing China 	    gfxp_umem_cookie_init(obj->kaddr, obj->real_size);
3430035d21cSmiao chen - Sun Microsystems - Beijing China 	if (map->drm_umem_cookie == NULL) {
3440035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err6;
3450035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3460035d21cSmiao chen - Sun Microsystems - Beijing China 
3470035d21cSmiao chen - Sun Microsystems - Beijing China 	obj->map = map;
3480035d21cSmiao chen - Sun Microsystems - Beijing China 
3490035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&obj->refcount, 1);
3500035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_set(&obj->handlecount, 1);
3510035d21cSmiao chen - Sun Microsystems - Beijing China 	if (dev->driver->gem_init_object != NULL &&
3520035d21cSmiao chen - Sun Microsystems - Beijing China 	    dev->driver->gem_init_object(obj) != 0) {
3530035d21cSmiao chen - Sun Microsystems - Beijing China 		goto err7;
3540035d21cSmiao chen - Sun Microsystems - Beijing China 	}
3550035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_inc(&dev->object_count);
3560035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_add(obj->size, &dev->object_memory);
3570035d21cSmiao chen - Sun Microsystems - Beijing China 
3580035d21cSmiao chen - Sun Microsystems - Beijing China 	return (obj);
3590035d21cSmiao chen - Sun Microsystems - Beijing China 
3600035d21cSmiao chen - Sun Microsystems - Beijing China err7:
3610035d21cSmiao chen - Sun Microsystems - Beijing China 	gfxp_umem_cookie_destroy(map->drm_umem_cookie);
3620035d21cSmiao chen - Sun Microsystems - Beijing China err6:
3630035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
3640035d21cSmiao chen - Sun Microsystems - Beijing China err5:
3650035d21cSmiao chen - Sun Microsystems - Beijing China 	kmem_free(obj->pfnarray, real_pgcnt * sizeof (pfn_t));
3660035d21cSmiao chen - Sun Microsystems - Beijing China err4:
3670035d21cSmiao chen - Sun Microsystems - Beijing China 	(void) ddi_dma_unbind_handle(obj->dma_hdl);
3680035d21cSmiao chen - Sun Microsystems - Beijing China err3:
3690035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_dma_mem_free(&obj->acc_hdl);
3700035d21cSmiao chen - Sun Microsystems - Beijing China err2:
3710035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_dma_free_handle(&obj->dma_hdl);
3720035d21cSmiao chen - Sun Microsystems - Beijing China err1:
3730035d21cSmiao chen - Sun Microsystems - Beijing China 	kmem_free(obj, sizeof (struct drm_gem_object));
3740035d21cSmiao chen - Sun Microsystems - Beijing China 
3750035d21cSmiao chen - Sun Microsystems - Beijing China 	return (NULL);
3760035d21cSmiao chen - Sun Microsystems - Beijing China }
3770035d21cSmiao chen - Sun Microsystems - Beijing China 
3780035d21cSmiao chen - Sun Microsystems - Beijing China /*
3790035d21cSmiao chen - Sun Microsystems - Beijing China  * Removes the mapping from handle to filp for this object.
3800035d21cSmiao chen - Sun Microsystems - Beijing China  */
3810035d21cSmiao chen - Sun Microsystems - Beijing China static int
drm_gem_handle_delete(struct drm_file * filp,int handle)3820035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_handle_delete(struct drm_file *filp, int handle)
3830035d21cSmiao chen - Sun Microsystems - Beijing China {
3840035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_device *dev;
3850035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_object *obj;
3860035d21cSmiao chen - Sun Microsystems - Beijing China 	int err;
3870035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
3880035d21cSmiao chen - Sun Microsystems - Beijing China 	 * This is gross. The idr system doesn't let us try a delete and
3890035d21cSmiao chen - Sun Microsystems - Beijing China 	 * return an error code.  It just spews if you fail at deleting.
3900035d21cSmiao chen - Sun Microsystems - Beijing China 	 * So, we have to grab a lock around finding the object and then
3910035d21cSmiao chen - Sun Microsystems - Beijing China 	 * doing the delete on it and dropping the refcount, or the user
3920035d21cSmiao chen - Sun Microsystems - Beijing China 	 * could race us to double-decrement the refcount and cause a
3930035d21cSmiao chen - Sun Microsystems - Beijing China 	 * use-after-free later.  Given the frequency of our handle lookups,
3940035d21cSmiao chen - Sun Microsystems - Beijing China 	 * we may want to use ida for number allocation and a hash table
3950035d21cSmiao chen - Sun Microsystems - Beijing China 	 * for the pointers, anyway.
3960035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
3970035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&filp->table_lock);
3980035d21cSmiao chen - Sun Microsystems - Beijing China 
3990035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Check if we currently have a reference on the object */
4000035d21cSmiao chen - Sun Microsystems - Beijing China 	obj = idr_list_find(&filp->object_idr, handle);
4010035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj == NULL) {
4020035d21cSmiao chen - Sun Microsystems - Beijing China 		spin_unlock(&filp->table_lock);
4030035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("obj %d is not in tne list, failed to close", handle);
4040035d21cSmiao chen - Sun Microsystems - Beijing China 		return (EINVAL);
4050035d21cSmiao chen - Sun Microsystems - Beijing China 	}
4060035d21cSmiao chen - Sun Microsystems - Beijing China 	dev = obj->dev;
4070035d21cSmiao chen - Sun Microsystems - Beijing China 
4080035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Release reference and decrement refcount. */
4090035d21cSmiao chen - Sun Microsystems - Beijing China 	err = idr_list_remove(&filp->object_idr, handle);
4100035d21cSmiao chen - Sun Microsystems - Beijing China 	if (err == -1)
4110035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("%s", __func__);
4120035d21cSmiao chen - Sun Microsystems - Beijing China 
4130035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&filp->table_lock);
4140035d21cSmiao chen - Sun Microsystems - Beijing China 
4150035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->struct_mutex);
4160035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_handle_unreference(obj);
4170035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->struct_mutex);
4180035d21cSmiao chen - Sun Microsystems - Beijing China 	return (0);
4190035d21cSmiao chen - Sun Microsystems - Beijing China }
4200035d21cSmiao chen - Sun Microsystems - Beijing China 
4210035d21cSmiao chen - Sun Microsystems - Beijing China /*
4220035d21cSmiao chen - Sun Microsystems - Beijing China  * Create a handle for this object. This adds a handle reference
4230035d21cSmiao chen - Sun Microsystems - Beijing China  * to the object, which includes a regular reference count. Callers
4240035d21cSmiao chen - Sun Microsystems - Beijing China  * will likely want to dereference the object afterwards.
4250035d21cSmiao chen - Sun Microsystems - Beijing China  */
4260035d21cSmiao chen - Sun Microsystems - Beijing China int
drm_gem_handle_create(struct drm_file * file_priv,struct drm_gem_object * obj,int * handlep)4270035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_handle_create(struct drm_file *file_priv,
4280035d21cSmiao chen - Sun Microsystems - Beijing China 		    struct drm_gem_object *obj,
4290035d21cSmiao chen - Sun Microsystems - Beijing China 		    int *handlep)
4300035d21cSmiao chen - Sun Microsystems - Beijing China {
4310035d21cSmiao chen - Sun Microsystems - Beijing China 	int	ret;
4320035d21cSmiao chen - Sun Microsystems - Beijing China 
4330035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
4340035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Get the user-visible handle using idr.
4350035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
4360035d21cSmiao chen - Sun Microsystems - Beijing China again:
4370035d21cSmiao chen - Sun Microsystems - Beijing China 	/* ensure there is space available to allocate a handle */
4380035d21cSmiao chen - Sun Microsystems - Beijing China 
4390035d21cSmiao chen - Sun Microsystems - Beijing China 	/* do the allocation under our spinlock */
4400035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&file_priv->table_lock);
4410035d21cSmiao chen - Sun Microsystems - Beijing China 	ret = idr_list_get_new_above(&file_priv->object_idr, obj, handlep);
4420035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&file_priv->table_lock);
4430035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ret == -EAGAIN)
4440035d21cSmiao chen - Sun Microsystems - Beijing China 		goto again;
4450035d21cSmiao chen - Sun Microsystems - Beijing China 
4460035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ret != 0) {
4470035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("Failed to create handle");
4480035d21cSmiao chen - Sun Microsystems - Beijing China 		return (ret);
4490035d21cSmiao chen - Sun Microsystems - Beijing China 	}
4500035d21cSmiao chen - Sun Microsystems - Beijing China 
4510035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_handle_reference(obj);
4520035d21cSmiao chen - Sun Microsystems - Beijing China 	return (0);
4530035d21cSmiao chen - Sun Microsystems - Beijing China }
4540035d21cSmiao chen - Sun Microsystems - Beijing China 
4550035d21cSmiao chen - Sun Microsystems - Beijing China /* Returns a reference to the object named by the handle. */
4560035d21cSmiao chen - Sun Microsystems - Beijing China struct drm_gem_object *
drm_gem_object_lookup(struct drm_file * filp,int handle)4570035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_lookup(struct drm_file *filp,
4580035d21cSmiao chen - Sun Microsystems - Beijing China 			    int handle)
4590035d21cSmiao chen - Sun Microsystems - Beijing China {
4600035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_object *obj;
4610035d21cSmiao chen - Sun Microsystems - Beijing China 
4620035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&filp->table_lock);
4630035d21cSmiao chen - Sun Microsystems - Beijing China 
4640035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Check if we currently have a reference on the object */
4650035d21cSmiao chen - Sun Microsystems - Beijing China 	obj = idr_list_find(&filp->object_idr, handle);
4660035d21cSmiao chen - Sun Microsystems - Beijing China 		if (obj == NULL) {
4670035d21cSmiao chen - Sun Microsystems - Beijing China 			spin_unlock(&filp->table_lock);
4680035d21cSmiao chen - Sun Microsystems - Beijing China 			DRM_ERROR("object_lookup failed, handle %d", handle);
4690035d21cSmiao chen - Sun Microsystems - Beijing China 			return (NULL);
4700035d21cSmiao chen - Sun Microsystems - Beijing China 		}
4710035d21cSmiao chen - Sun Microsystems - Beijing China 
4720035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_reference(obj);
4730035d21cSmiao chen - Sun Microsystems - Beijing China 
4740035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&filp->table_lock);
4750035d21cSmiao chen - Sun Microsystems - Beijing China 
4760035d21cSmiao chen - Sun Microsystems - Beijing China 	return (obj);
4770035d21cSmiao chen - Sun Microsystems - Beijing China }
4780035d21cSmiao chen - Sun Microsystems - Beijing China 
4790035d21cSmiao chen - Sun Microsystems - Beijing China /*
4800035d21cSmiao chen - Sun Microsystems - Beijing China  * Releases the handle to an mm object.
4810035d21cSmiao chen - Sun Microsystems - Beijing China  */
4820035d21cSmiao chen - Sun Microsystems - Beijing China /*ARGSUSED*/
4830035d21cSmiao chen - Sun Microsystems - Beijing China int
drm_gem_close_ioctl(DRM_IOCTL_ARGS)4840035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_close_ioctl(DRM_IOCTL_ARGS)
4850035d21cSmiao chen - Sun Microsystems - Beijing China {
4860035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_DEVICE;
4870035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_close args;
4880035d21cSmiao chen - Sun Microsystems - Beijing China 	int ret;
4890035d21cSmiao chen - Sun Microsystems - Beijing China 
4900035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!(dev->driver->use_gem == 1))
4910035d21cSmiao chen - Sun Microsystems - Beijing China 		return (ENODEV);
4920035d21cSmiao chen - Sun Microsystems - Beijing China 
4930035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_COPYFROM_WITH_RETURN(&args,
4940035d21cSmiao chen - Sun Microsystems - Beijing China 	    (void *)data, sizeof (args));
4950035d21cSmiao chen - Sun Microsystems - Beijing China 
4960035d21cSmiao chen - Sun Microsystems - Beijing China 	ret = drm_gem_handle_delete(fpriv, args.handle);
4970035d21cSmiao chen - Sun Microsystems - Beijing China 
4980035d21cSmiao chen - Sun Microsystems - Beijing China 	return (ret);
4990035d21cSmiao chen - Sun Microsystems - Beijing China }
5000035d21cSmiao chen - Sun Microsystems - Beijing China 
5010035d21cSmiao chen - Sun Microsystems - Beijing China /*
5020035d21cSmiao chen - Sun Microsystems - Beijing China  * Create a global name for an object, returning the name.
5030035d21cSmiao chen - Sun Microsystems - Beijing China  *
5040035d21cSmiao chen - Sun Microsystems - Beijing China  * Note that the name does not hold a reference; when the object
5050035d21cSmiao chen - Sun Microsystems - Beijing China  * is freed, the name goes away.
5060035d21cSmiao chen - Sun Microsystems - Beijing China  */
5070035d21cSmiao chen - Sun Microsystems - Beijing China /*ARGSUSED*/
5080035d21cSmiao chen - Sun Microsystems - Beijing China int
drm_gem_flink_ioctl(DRM_IOCTL_ARGS)5090035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_flink_ioctl(DRM_IOCTL_ARGS)
5100035d21cSmiao chen - Sun Microsystems - Beijing China {
5110035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_DEVICE;
5120035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_flink args;
5130035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_object *obj;
5140035d21cSmiao chen - Sun Microsystems - Beijing China 	int ret, handle;
5150035d21cSmiao chen - Sun Microsystems - Beijing China 
5160035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!(dev->driver->use_gem == 1))
5170035d21cSmiao chen - Sun Microsystems - Beijing China 		return (ENODEV);
5180035d21cSmiao chen - Sun Microsystems - Beijing China 
5190035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_COPYFROM_WITH_RETURN(&args,
5200035d21cSmiao chen - Sun Microsystems - Beijing China 	    (void *)data, sizeof (args));
5210035d21cSmiao chen - Sun Microsystems - Beijing China 	obj = drm_gem_object_lookup(fpriv, args.handle);
5220035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj == NULL)
5230035d21cSmiao chen - Sun Microsystems - Beijing China 		return (EINVAL);
5240035d21cSmiao chen - Sun Microsystems - Beijing China 	handle = args.handle;
5250035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->object_name_lock);
5260035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!obj->flink) {
5270035d21cSmiao chen - Sun Microsystems - Beijing China 		/* only creat a node in object_name_idr, no update anything */
5280035d21cSmiao chen - Sun Microsystems - Beijing China 		ret = idr_list_get_new_above(&dev->object_name_idr,
5290035d21cSmiao chen - Sun Microsystems - Beijing China 		    obj, &handle);
5300035d21cSmiao chen - Sun Microsystems - Beijing China 		obj->flink = obj->name;
5310035d21cSmiao chen - Sun Microsystems - Beijing China 		/* Allocate a reference for the name table.  */
5320035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_gem_object_reference(obj);
5330035d21cSmiao chen - Sun Microsystems - Beijing China 	}
5340035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
5350035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Leave the reference from the lookup around as the
5360035d21cSmiao chen - Sun Microsystems - Beijing China 	 * name table now holds one
5370035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
5380035d21cSmiao chen - Sun Microsystems - Beijing China 	args.name = obj->name;
5390035d21cSmiao chen - Sun Microsystems - Beijing China 
5400035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->object_name_lock);
5410035d21cSmiao chen - Sun Microsystems - Beijing China 	ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
5420035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ret != 0)
5430035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR(" gem flink error! %d", ret);
5440035d21cSmiao chen - Sun Microsystems - Beijing China 
5450035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->struct_mutex);
5460035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_unreference(obj);
5470035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->struct_mutex);
5480035d21cSmiao chen - Sun Microsystems - Beijing China 
5490035d21cSmiao chen - Sun Microsystems - Beijing China 	return (ret);
5500035d21cSmiao chen - Sun Microsystems - Beijing China }
5510035d21cSmiao chen - Sun Microsystems - Beijing China 
5520035d21cSmiao chen - Sun Microsystems - Beijing China /*
5530035d21cSmiao chen - Sun Microsystems - Beijing China  * Open an object using the global name, returning a handle and the size.
5540035d21cSmiao chen - Sun Microsystems - Beijing China  *
5550035d21cSmiao chen - Sun Microsystems - Beijing China  * This handle (of course) holds a reference to the object, so the object
5560035d21cSmiao chen - Sun Microsystems - Beijing China  * will not go away until the handle is deleted.
5570035d21cSmiao chen - Sun Microsystems - Beijing China  */
5580035d21cSmiao chen - Sun Microsystems - Beijing China /*ARGSUSED*/
5590035d21cSmiao chen - Sun Microsystems - Beijing China int
drm_gem_open_ioctl(DRM_IOCTL_ARGS)5600035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_open_ioctl(DRM_IOCTL_ARGS)
5610035d21cSmiao chen - Sun Microsystems - Beijing China {
5620035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_DEVICE;
5630035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_open args;
5640035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_gem_object *obj;
5650035d21cSmiao chen - Sun Microsystems - Beijing China 	int ret;
5660035d21cSmiao chen - Sun Microsystems - Beijing China 	int handle;
5670035d21cSmiao chen - Sun Microsystems - Beijing China 
5680035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!(dev->driver->use_gem == 1)) {
5690035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("Not support GEM");
5700035d21cSmiao chen - Sun Microsystems - Beijing China 		return (ENODEV);
5710035d21cSmiao chen - Sun Microsystems - Beijing China 	}
5720035d21cSmiao chen - Sun Microsystems - Beijing China 	DRM_COPYFROM_WITH_RETURN(&args,
5730035d21cSmiao chen - Sun Microsystems - Beijing China 	    (void *) data, sizeof (args));
5740035d21cSmiao chen - Sun Microsystems - Beijing China 
5750035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->object_name_lock);
5760035d21cSmiao chen - Sun Microsystems - Beijing China 
5770035d21cSmiao chen - Sun Microsystems - Beijing China 	obj = idr_list_find(&dev->object_name_idr, args.name);
5780035d21cSmiao chen - Sun Microsystems - Beijing China 
5790035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj)
5800035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_gem_object_reference(obj);
5810035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->object_name_lock);
5820035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!obj) {
5830035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("Can't find the obj %d", args.name);
5840035d21cSmiao chen - Sun Microsystems - Beijing China 		return (ENOENT);
5850035d21cSmiao chen - Sun Microsystems - Beijing China 	}
5860035d21cSmiao chen - Sun Microsystems - Beijing China 
5870035d21cSmiao chen - Sun Microsystems - Beijing China 	ret = drm_gem_handle_create(fpriv, obj, &handle);
5880035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->struct_mutex);
5890035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_unreference(obj);
5900035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->struct_mutex);
5910035d21cSmiao chen - Sun Microsystems - Beijing China 
5920035d21cSmiao chen - Sun Microsystems - Beijing China 	args.handle = args.name;
5930035d21cSmiao chen - Sun Microsystems - Beijing China 	args.size = obj->size;
5940035d21cSmiao chen - Sun Microsystems - Beijing China 
5950035d21cSmiao chen - Sun Microsystems - Beijing China 	ret = DRM_COPY_TO_USER((void *) data, &args, sizeof (args));
5960035d21cSmiao chen - Sun Microsystems - Beijing China 	if (ret != 0)
5970035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR(" gem open error! %d", ret);
5980035d21cSmiao chen - Sun Microsystems - Beijing China 	return (ret);
5990035d21cSmiao chen - Sun Microsystems - Beijing China }
6000035d21cSmiao chen - Sun Microsystems - Beijing China 
6010035d21cSmiao chen - Sun Microsystems - Beijing China /*
6020035d21cSmiao chen - Sun Microsystems - Beijing China  * Called at device open time, sets up the structure for handling refcounting
6030035d21cSmiao chen - Sun Microsystems - Beijing China  * of mm objects.
6040035d21cSmiao chen - Sun Microsystems - Beijing China  */
6050035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_open(struct drm_file * file_private)6060035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_open(struct drm_file *file_private)
6070035d21cSmiao chen - Sun Microsystems - Beijing China {
6080035d21cSmiao chen - Sun Microsystems - Beijing China 	idr_list_init(&file_private->object_idr);
6090035d21cSmiao chen - Sun Microsystems - Beijing China 	mutex_init(&file_private->table_lock, NULL, MUTEX_DRIVER, NULL);
6100035d21cSmiao chen - Sun Microsystems - Beijing China }
6110035d21cSmiao chen - Sun Microsystems - Beijing China 
6120035d21cSmiao chen - Sun Microsystems - Beijing China /*
6130035d21cSmiao chen - Sun Microsystems - Beijing China  * Called at device close to release the file's
6140035d21cSmiao chen - Sun Microsystems - Beijing China  * handle references on objects.
6150035d21cSmiao chen - Sun Microsystems - Beijing China  */
6160035d21cSmiao chen - Sun Microsystems - Beijing China static void
drm_gem_object_release_handle(struct drm_gem_object * obj)6170035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_release_handle(struct drm_gem_object *obj)
6180035d21cSmiao chen - Sun Microsystems - Beijing China {
6190035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_gem_object_handle_unreference(obj);
6200035d21cSmiao chen - Sun Microsystems - Beijing China }
6210035d21cSmiao chen - Sun Microsystems - Beijing China 
6220035d21cSmiao chen - Sun Microsystems - Beijing China /*
6230035d21cSmiao chen - Sun Microsystems - Beijing China  * Called at close time when the filp is going away.
6240035d21cSmiao chen - Sun Microsystems - Beijing China  *
6250035d21cSmiao chen - Sun Microsystems - Beijing China  * Releases any remaining references on objects by this filp.
6260035d21cSmiao chen - Sun Microsystems - Beijing China  */
6270035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_release(struct drm_device * dev,struct drm_file * file_private)6280035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
6290035d21cSmiao chen - Sun Microsystems - Beijing China {
6300035d21cSmiao chen - Sun Microsystems - Beijing China 	struct idr_list  *entry;
6310035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->struct_mutex);
6320035d21cSmiao chen - Sun Microsystems - Beijing China 
6330035d21cSmiao chen - Sun Microsystems - Beijing China 	idr_list_for_each(entry, &file_private->object_idr)
6340035d21cSmiao chen - Sun Microsystems - Beijing China 	    drm_gem_object_release_handle(entry->obj);
6350035d21cSmiao chen - Sun Microsystems - Beijing China 
6360035d21cSmiao chen - Sun Microsystems - Beijing China 	idr_list_free(&file_private->object_idr);
6370035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_unlock(&dev->struct_mutex);
6380035d21cSmiao chen - Sun Microsystems - Beijing China 
6390035d21cSmiao chen - Sun Microsystems - Beijing China }
6400035d21cSmiao chen - Sun Microsystems - Beijing China 
6410035d21cSmiao chen - Sun Microsystems - Beijing China /*
6420035d21cSmiao chen - Sun Microsystems - Beijing China  * Called after the last reference to the object has been lost.
6430035d21cSmiao chen - Sun Microsystems - Beijing China  *
6440035d21cSmiao chen - Sun Microsystems - Beijing China  * Frees the object
6450035d21cSmiao chen - Sun Microsystems - Beijing China  */
6460035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_free(struct drm_gem_object * obj)6470035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_free(struct drm_gem_object *obj)
6480035d21cSmiao chen - Sun Microsystems - Beijing China {
6490035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_device *dev = obj->dev;
6500035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_local_map *map = obj->map;
6510035d21cSmiao chen - Sun Microsystems - Beijing China 
6520035d21cSmiao chen - Sun Microsystems - Beijing China 	if (dev->driver->gem_free_object != NULL)
6530035d21cSmiao chen - Sun Microsystems - Beijing China 		dev->driver->gem_free_object(obj);
6540035d21cSmiao chen - Sun Microsystems - Beijing China 
6550035d21cSmiao chen - Sun Microsystems - Beijing China 	gfxp_umem_cookie_destroy(map->drm_umem_cookie);
6560035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_free(map, sizeof (struct drm_local_map), DRM_MEM_MAPS);
6570035d21cSmiao chen - Sun Microsystems - Beijing China 
6580035d21cSmiao chen - Sun Microsystems - Beijing China 	kmem_free(obj->pfnarray, btopr(obj->real_size) * sizeof (pfn_t));
6590035d21cSmiao chen - Sun Microsystems - Beijing China 
6600035d21cSmiao chen - Sun Microsystems - Beijing China 	(void) ddi_dma_unbind_handle(obj->dma_hdl);
6610035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_dma_mem_free(&obj->acc_hdl);
6620035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_dma_free_handle(&obj->dma_hdl);
6630035d21cSmiao chen - Sun Microsystems - Beijing China 
6640035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_dec(&dev->object_count);
6650035d21cSmiao chen - Sun Microsystems - Beijing China 	atomic_sub(obj->size, &dev->object_memory);
6660035d21cSmiao chen - Sun Microsystems - Beijing China 	kmem_free(obj, sizeof (struct drm_gem_object));
6670035d21cSmiao chen - Sun Microsystems - Beijing China }
6680035d21cSmiao chen - Sun Microsystems - Beijing China 
6690035d21cSmiao chen - Sun Microsystems - Beijing China /*
6700035d21cSmiao chen - Sun Microsystems - Beijing China  * Called after the last handle to the object has been closed
6710035d21cSmiao chen - Sun Microsystems - Beijing China  *
6720035d21cSmiao chen - Sun Microsystems - Beijing China  * Removes any name for the object. Note that this must be
6730035d21cSmiao chen - Sun Microsystems - Beijing China  * called before drm_gem_object_free or we'll be touching
6740035d21cSmiao chen - Sun Microsystems - Beijing China  * freed memory
6750035d21cSmiao chen - Sun Microsystems - Beijing China  */
6760035d21cSmiao chen - Sun Microsystems - Beijing China void
drm_gem_object_handle_free(struct drm_gem_object * obj)6770035d21cSmiao chen - Sun Microsystems - Beijing China drm_gem_object_handle_free(struct drm_gem_object *obj)
6780035d21cSmiao chen - Sun Microsystems - Beijing China {
6790035d21cSmiao chen - Sun Microsystems - Beijing China 	int err;
6800035d21cSmiao chen - Sun Microsystems - Beijing China 	struct drm_device *dev = obj->dev;
6810035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Remove any name for this object */
6820035d21cSmiao chen - Sun Microsystems - Beijing China 	spin_lock(&dev->object_name_lock);
6830035d21cSmiao chen - Sun Microsystems - Beijing China 	if (obj->flink) {
6840035d21cSmiao chen - Sun Microsystems - Beijing China 		err = idr_list_remove(&dev->object_name_idr, obj->name);
6850035d21cSmiao chen - Sun Microsystems - Beijing China 		if (err == -1)
6860035d21cSmiao chen - Sun Microsystems - Beijing China 			DRM_ERROR("%s", __func__);
6870035d21cSmiao chen - Sun Microsystems - Beijing China 		obj->flink = 0;
6880035d21cSmiao chen - Sun Microsystems - Beijing China 		spin_unlock(&dev->object_name_lock);
6890035d21cSmiao chen - Sun Microsystems - Beijing China 		/*
6900035d21cSmiao chen - Sun Microsystems - Beijing China 		 * The object name held a reference to this object, drop
6910035d21cSmiao chen - Sun Microsystems - Beijing China 		 * that now.
6920035d21cSmiao chen - Sun Microsystems - Beijing China 		 */
6930035d21cSmiao chen - Sun Microsystems - Beijing China 		drm_gem_object_unreference(obj);
6940035d21cSmiao chen - Sun Microsystems - Beijing China 	} else
6950035d21cSmiao chen - Sun Microsystems - Beijing China 
6960035d21cSmiao chen - Sun Microsystems - Beijing China 		spin_unlock(&dev->object_name_lock);
6970035d21cSmiao chen - Sun Microsystems - Beijing China 
6980035d21cSmiao chen - Sun Microsystems - Beijing China }
699