xref: /titanic_44/usr/src/uts/common/io/drm/drm_bufs.c (revision 0035d21c77a24d02faf34c10aabc120ca692efb5)
160405de4Skz151634 /*
260405de4Skz151634  * drm_bufs.h -- Generic buffer template -*- linux-c -*-
360405de4Skz151634  * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
460405de4Skz151634  */
560405de4Skz151634 /*
660405de4Skz151634  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
760405de4Skz151634  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
8*0035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright (c) 2009, Intel Corporation.
960405de4Skz151634  * All Rights Reserved.
1060405de4Skz151634  *
1160405de4Skz151634  * Permission is hereby granted, free of charge, to any person obtaining a
1260405de4Skz151634  * copy of this software and associated documentation files (the "Software"),
1360405de4Skz151634  * to deal in the Software without restriction, including without limitation
1460405de4Skz151634  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1560405de4Skz151634  * and/or sell copies of the Software, and to permit persons to whom the
1660405de4Skz151634  * Software is furnished to do so, subject to the following conditions:
1760405de4Skz151634  *
1860405de4Skz151634  * The above copyright notice and this permission notice (including the next
1960405de4Skz151634  * paragraph) shall be included in all copies or substantial portions of the
2060405de4Skz151634  * Software.
2160405de4Skz151634  *
2260405de4Skz151634  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2360405de4Skz151634  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2460405de4Skz151634  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2560405de4Skz151634  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2660405de4Skz151634  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2760405de4Skz151634  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2860405de4Skz151634  * OTHER DEALINGS IN THE SOFTWARE.
2960405de4Skz151634  *
3060405de4Skz151634  * Authors:
3160405de4Skz151634  *    Rickard E. (Rik) Faith <faith@valinux.com>
3260405de4Skz151634  *    Gareth Hughes <gareth@valinux.com>
3360405de4Skz151634  *
3460405de4Skz151634  */
3560405de4Skz151634 
36e92e3a86Szw161486 /*
37d0231070Smiao chen - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
38e92e3a86Szw161486  * Use is subject to license terms.
39e92e3a86Szw161486  */
40e92e3a86Szw161486 
4160405de4Skz151634 #include "drmP.h"
42d0538f66Scg149915 #include <gfx_private.h>
43d0538f66Scg149915 #include "drm_io32.h"
44d0538f66Scg149915 
4560405de4Skz151634 
4660405de4Skz151634 #define	PAGE_MASK	(PAGE_SIZE-1)
4760405de4Skz151634 #define	round_page(x)	(((x) + PAGE_MASK) & ~PAGE_MASK)
4860405de4Skz151634 
4960405de4Skz151634 /*
5060405de4Skz151634  * Compute order.  Can be made faster.
5160405de4Skz151634  */
5260405de4Skz151634 int
drm_order(unsigned long size)5360405de4Skz151634 drm_order(unsigned long size)
5460405de4Skz151634 {
55d0538f66Scg149915 	int order = 0;
56d0538f66Scg149915 	unsigned long tmp = size;
5760405de4Skz151634 
58d0538f66Scg149915 	while (tmp >>= 1)
59d0538f66Scg149915 		order ++;
6060405de4Skz151634 
6160405de4Skz151634 	if (size & ~(1 << order))
6260405de4Skz151634 		++order;
6360405de4Skz151634 
6460405de4Skz151634 	return (order);
6560405de4Skz151634 }
6660405de4Skz151634 
67d0538f66Scg149915 static inline drm_local_map_t *
drm_find_map(drm_device_t * dev,u_offset_t offset,int type)68d0538f66Scg149915 drm_find_map(drm_device_t *dev, u_offset_t offset, int type)
6960405de4Skz151634 {
7060405de4Skz151634 	drm_local_map_t		*map;
7160405de4Skz151634 
72d0538f66Scg149915 	TAILQ_FOREACH(map, &dev->maplist, link) {
73d0538f66Scg149915 		if ((map->type == type) && ((map->offset == offset) ||
74d0538f66Scg149915 		    (map->flags == _DRM_CONTAINS_LOCK) &&
75d0538f66Scg149915 		    (map->type == _DRM_SHM)))
76d0538f66Scg149915 			return (map);
77d0538f66Scg149915 	}
78d0538f66Scg149915 
79d0538f66Scg149915 	return (NULL);
80d0538f66Scg149915 }
81d0538f66Scg149915 
drm_addmap(drm_device_t * dev,unsigned long offset,unsigned long size,drm_map_type_t type,drm_map_flags_t flags,drm_local_map_t ** map_ptr)82d0538f66Scg149915 int drm_addmap(drm_device_t *dev, unsigned long offset,
83d0538f66Scg149915     unsigned long size, drm_map_type_t type,
84d0538f66Scg149915     drm_map_flags_t flags, drm_local_map_t **map_ptr)
85d0538f66Scg149915 {
86d0538f66Scg149915 	drm_local_map_t *map;
87d0538f66Scg149915 	caddr_t		kva;
88d0538f66Scg149915 	int		retval;
8960405de4Skz151634 
9060405de4Skz151634 	/*
91d0538f66Scg149915 	 * Only allow shared memory to be removable since we only keep
92d0538f66Scg149915 	 * enough book keeping information about shared memory to allow
93d0538f66Scg149915 	 * for removal when processes fork.
9460405de4Skz151634 	 */
9560405de4Skz151634 	if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM)
96d0538f66Scg149915 		return (EINVAL);
9760405de4Skz151634 	if ((offset & PAGE_MASK) || (size & PAGE_MASK))
98d0538f66Scg149915 		return (EINVAL);
9960405de4Skz151634 	if (offset + size < offset)
100d0538f66Scg149915 		return (EINVAL);
10160405de4Skz151634 
10260405de4Skz151634 	/*
103d0538f66Scg149915 	 * Check if this is just another version of a kernel-allocated
104d0538f66Scg149915 	 * map, and just hand that back if so.
10560405de4Skz151634 	 */
106d0538f66Scg149915 	map = drm_find_map(dev, offset, type);
107d0538f66Scg149915 	if (map != NULL) {
10860405de4Skz151634 		goto done;
10960405de4Skz151634 	}
11060405de4Skz151634 
11160405de4Skz151634 	/*
112d0538f66Scg149915 	 * Allocate a new map structure, fill it in, and do any
113d0538f66Scg149915 	 * type-specific initialization necessary.
11460405de4Skz151634 	 */
11560405de4Skz151634 	map = drm_alloc(sizeof (*map), DRM_MEM_MAPS);
11660405de4Skz151634 	if (!map)
117d0538f66Scg149915 		return (ENOMEM);
11860405de4Skz151634 
119d0538f66Scg149915 	map->offset = offset;
12060405de4Skz151634 	map->size = size;
12160405de4Skz151634 	map->type = type;
12260405de4Skz151634 	map->flags = flags;
12360405de4Skz151634 
12460405de4Skz151634 	switch (map->type) {
12560405de4Skz151634 	case _DRM_REGISTERS:
12660405de4Skz151634 	case _DRM_FRAME_BUFFER:
127d0538f66Scg149915 		retval = drm_ioremap(dev, map);
128d0538f66Scg149915 		if (retval)
129d0538f66Scg149915 			return (retval);
13060405de4Skz151634 		break;
131d0538f66Scg149915 
13260405de4Skz151634 	case _DRM_SHM:
133d0538f66Scg149915 		/*
134d0538f66Scg149915 		 * ddi_umem_alloc() grants page-aligned memory. We needn't
135d0538f66Scg149915 		 * handle alignment issue here.
136d0538f66Scg149915 		 */
137d0538f66Scg149915 		map->handle = ddi_umem_alloc(map->size,
138d0538f66Scg149915 		    DDI_UMEM_NOSLEEP, &map->drm_umem_cookie);
13960405de4Skz151634 		if (!map->handle) {
14060405de4Skz151634 			DRM_ERROR("drm_addmap: ddi_umem_alloc failed");
14160405de4Skz151634 			drm_free(map, sizeof (*map), DRM_MEM_MAPS);
142d0538f66Scg149915 			return (ENOMEM);
14360405de4Skz151634 		}
14460405de4Skz151634 		/*
145d0538f66Scg149915 		 * record only low 32-bit of this handle, since 32-bit
146d0538f66Scg149915 		 * user app is incapable of passing in 64bit offset when
147d0538f66Scg149915 		 * doing mmap.
14860405de4Skz151634 		 */
149d0538f66Scg149915 		map->offset = (uintptr_t)map->handle;
150d0538f66Scg149915 		map->offset &= 0xffffffffUL;
15160405de4Skz151634 		if (map->flags & _DRM_CONTAINS_LOCK) {
15260405de4Skz151634 			/* Prevent a 2nd X Server from creating a 2nd lock */
15360405de4Skz151634 			if (dev->lock.hw_lock != NULL) {
15460405de4Skz151634 				ddi_umem_free(map->drm_umem_cookie);
15560405de4Skz151634 				drm_free(map, sizeof (*map), DRM_MEM_MAPS);
156d0538f66Scg149915 				return (EBUSY);
15760405de4Skz151634 			}
15860405de4Skz151634 			dev->lock.hw_lock = map->handle; /* Pointer to lock */
15960405de4Skz151634 		}
160d0538f66Scg149915 		map->dev_addr = map->handle;
16160405de4Skz151634 		break;
16260405de4Skz151634 	case _DRM_SCATTER_GATHER:
16360405de4Skz151634 		if (!dev->sg) {
16460405de4Skz151634 			drm_free(map, sizeof (*map), DRM_MEM_MAPS);
165d0538f66Scg149915 			return (EINVAL);
16660405de4Skz151634 		}
167d0538f66Scg149915 		map->offset += (uintptr_t)dev->sg->virtual;
168d0538f66Scg149915 		map->handle = (void *)(uintptr_t)map->offset;
169d0538f66Scg149915 		map->dev_addr = dev->sg->virtual;
170d0538f66Scg149915 		map->dev_handle = dev->sg->dmah_sg->acc_hdl;
17160405de4Skz151634 		break;
172d0538f66Scg149915 
17360405de4Skz151634 	case _DRM_CONSISTENT:
174*0035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("%d DRM_AGP_CONSISTENT", __LINE__);
175d0538f66Scg149915 		return (ENOTSUP);
17660405de4Skz151634 	case _DRM_AGP:
177d0538f66Scg149915 		map->offset += dev->agp->base;
178d0538f66Scg149915 		kva = gfxp_map_kernel_space(map->offset, map->size,
179d0538f66Scg149915 		    GFXP_MEMORY_WRITECOMBINED);
180d0538f66Scg149915 		if (kva == 0) {
181d0538f66Scg149915 			drm_free(map, sizeof (*map), DRM_MEM_MAPS);
182d0538f66Scg149915 			cmn_err(CE_WARN,
183d0538f66Scg149915 			    "drm_addmap: failed to map AGP aperture");
184d0538f66Scg149915 			return (ENOMEM);
185d0538f66Scg149915 		}
186d0538f66Scg149915 		map->handle = (void *)(uintptr_t)kva;
187d0538f66Scg149915 		map->dev_addr = kva;
18860405de4Skz151634 		break;
18960405de4Skz151634 	default:
19060405de4Skz151634 		drm_free(map, sizeof (*map), DRM_MEM_MAPS);
191d0538f66Scg149915 		return (EINVAL);
19260405de4Skz151634 	}
19360405de4Skz151634 
19460405de4Skz151634 	TAILQ_INSERT_TAIL(&dev->maplist, map, link);
19560405de4Skz151634 
19660405de4Skz151634 done:
19760405de4Skz151634 	/* Jumped to, with lock held, when a kernel map is found. */
19860405de4Skz151634 	*map_ptr = map;
19960405de4Skz151634 
20060405de4Skz151634 	return (0);
20160405de4Skz151634 }
20260405de4Skz151634 
20360405de4Skz151634 /*ARGSUSED*/
20460405de4Skz151634 int
drm_addmap_ioctl(DRM_IOCTL_ARGS)20560405de4Skz151634 drm_addmap_ioctl(DRM_IOCTL_ARGS)
20660405de4Skz151634 {
20760405de4Skz151634 	drm_map_t request;
20860405de4Skz151634 	drm_local_map_t *map;
20960405de4Skz151634 	int err;
21060405de4Skz151634 	DRM_DEVICE;
21160405de4Skz151634 
212d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
21360405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
214d0538f66Scg149915 		drm_map_32_t request32;
215d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request32,
216d0538f66Scg149915 		    (void *)data, sizeof (request32));
21760405de4Skz151634 		request.offset = request32.offset;
21860405de4Skz151634 		request.size = request32.size;
21960405de4Skz151634 		request.type = request32.type;
22060405de4Skz151634 		request.flags = request32.flags;
22160405de4Skz151634 		request.mtrr = request32.mtrr;
22260405de4Skz151634 	} else
223d0538f66Scg149915 #endif
224d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request,
225d0538f66Scg149915 		    (void *)data, sizeof (request));
22660405de4Skz151634 
22760405de4Skz151634 	err = drm_addmap(dev, request.offset, request.size, request.type,
22860405de4Skz151634 	    request.flags, &map);
22960405de4Skz151634 
23060405de4Skz151634 	if (err != 0)
23160405de4Skz151634 		return (err);
23260405de4Skz151634 
233d0538f66Scg149915 	request.offset = map->offset;
23460405de4Skz151634 	request.size = map->size;
23560405de4Skz151634 	request.type = map->type;
23660405de4Skz151634 	request.flags = map->flags;
23760405de4Skz151634 	request.mtrr   = map->mtrr;
238d0538f66Scg149915 	request.handle = (uintptr_t)map->handle;
23960405de4Skz151634 
240d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
24160405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
242d0538f66Scg149915 		drm_map_32_t request32;
24360405de4Skz151634 		request32.offset = request.offset;
244d0538f66Scg149915 		request32.size = (uint32_t)request.size;
24560405de4Skz151634 		request32.type = request.type;
24660405de4Skz151634 		request32.flags = request.flags;
24760405de4Skz151634 		request32.handle = request.handle;
24860405de4Skz151634 		request32.mtrr = request.mtrr;
249d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
250d0538f66Scg149915 		    &request32, sizeof (request32));
25160405de4Skz151634 	} else
252d0538f66Scg149915 #endif
253d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
254d0538f66Scg149915 		    &request, sizeof (request));
25560405de4Skz151634 
25660405de4Skz151634 	return (0);
25760405de4Skz151634 }
25860405de4Skz151634 
25960405de4Skz151634 void
drm_rmmap(drm_device_t * dev,drm_local_map_t * map)26060405de4Skz151634 drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
26160405de4Skz151634 {
26260405de4Skz151634 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
26360405de4Skz151634 
26460405de4Skz151634 	TAILQ_REMOVE(&dev->maplist, map, link);
26560405de4Skz151634 
26660405de4Skz151634 	switch (map->type) {
26760405de4Skz151634 	case _DRM_REGISTERS:
26860405de4Skz151634 		drm_ioremapfree(map);
26960405de4Skz151634 		break;
27060405de4Skz151634 		/* FALLTHROUGH */
27160405de4Skz151634 	case _DRM_FRAME_BUFFER:
27260405de4Skz151634 		drm_ioremapfree(map);
27360405de4Skz151634 		break;
27460405de4Skz151634 	case _DRM_SHM:
27560405de4Skz151634 		ddi_umem_free(map->drm_umem_cookie);
27660405de4Skz151634 		break;
27760405de4Skz151634 	case _DRM_AGP:
278d0538f66Scg149915 		/*
279d0538f66Scg149915 		 * we mapped AGP aperture into kernel space in drm_addmap,
280d0538f66Scg149915 		 * here, unmap them and release kernel virtual address space
281d0538f66Scg149915 		 */
282d0538f66Scg149915 		gfxp_unmap_kernel_space(map->dev_addr, map->size);
283d0538f66Scg149915 		break;
284d0538f66Scg149915 
28560405de4Skz151634 	case _DRM_SCATTER_GATHER:
28660405de4Skz151634 		break;
28760405de4Skz151634 	case _DRM_CONSISTENT:
28860405de4Skz151634 		break;
28960405de4Skz151634 	default:
29060405de4Skz151634 		break;
29160405de4Skz151634 	}
29260405de4Skz151634 
29360405de4Skz151634 	drm_free(map, sizeof (*map), DRM_MEM_MAPS);
29460405de4Skz151634 }
29560405de4Skz151634 
29660405de4Skz151634 /*
297d0538f66Scg149915  * Remove a map private from list and deallocate resources if the
298d0538f66Scg149915  * mapping isn't in use.
29960405de4Skz151634  */
30060405de4Skz151634 /*ARGSUSED*/
30160405de4Skz151634 int
drm_rmmap_ioctl(DRM_IOCTL_ARGS)30260405de4Skz151634 drm_rmmap_ioctl(DRM_IOCTL_ARGS)
30360405de4Skz151634 {
30460405de4Skz151634 	DRM_DEVICE;
30560405de4Skz151634 	drm_local_map_t *map;
30660405de4Skz151634 	drm_map_t request;
30760405de4Skz151634 
308d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
30960405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
310d0538f66Scg149915 		drm_map_32_t request32;
311d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request32,
312d0538f66Scg149915 		    (void *)data, sizeof (drm_map_32_t));
31360405de4Skz151634 		request.offset = request32.offset;
31460405de4Skz151634 		request.size = request32.size;
31560405de4Skz151634 		request.type = request32.type;
31660405de4Skz151634 		request.flags = request32.flags;
31760405de4Skz151634 		request.handle = request32.handle;
31860405de4Skz151634 		request.mtrr = request32.mtrr;
31960405de4Skz151634 	} else
320d0538f66Scg149915 #endif
321d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request,
322d0538f66Scg149915 		    (void *)data, sizeof (request));
32360405de4Skz151634 
32460405de4Skz151634 	DRM_LOCK();
32560405de4Skz151634 	TAILQ_FOREACH(map, &dev->maplist, link) {
326d0538f66Scg149915 	if (((uintptr_t)map->handle == (request.handle & 0xffffffff)) &&
32760405de4Skz151634 	    (map->flags & _DRM_REMOVABLE))
32860405de4Skz151634 			break;
32960405de4Skz151634 	}
33060405de4Skz151634 
33160405de4Skz151634 	/* No match found. */
33260405de4Skz151634 	if (map == NULL) {
33360405de4Skz151634 		DRM_UNLOCK();
334d0538f66Scg149915 		return (EINVAL);
33560405de4Skz151634 	}
33660405de4Skz151634 
33760405de4Skz151634 	drm_rmmap(dev, map);
33860405de4Skz151634 	DRM_UNLOCK();
33960405de4Skz151634 
34060405de4Skz151634 	return (0);
34160405de4Skz151634 }
34260405de4Skz151634 
34360405de4Skz151634 /*ARGSUSED*/
34460405de4Skz151634 static void
drm_cleanup_buf_error(drm_device_t * dev,drm_buf_entry_t * entry)34560405de4Skz151634 drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
34660405de4Skz151634 {
34760405de4Skz151634 	int i;
34860405de4Skz151634 
34960405de4Skz151634 	if (entry->seg_count) {
35060405de4Skz151634 		for (i = 0; i < entry->seg_count; i++) {
35160405de4Skz151634 			if (entry->seglist[i]) {
35260405de4Skz151634 				DRM_ERROR(
35360405de4Skz151634 				    "drm_cleanup_buf_error: not implemented");
35460405de4Skz151634 			}
35560405de4Skz151634 		}
35660405de4Skz151634 		drm_free(entry->seglist,
35760405de4Skz151634 		    entry->seg_count *
35860405de4Skz151634 		    sizeof (*entry->seglist), DRM_MEM_SEGS);
35960405de4Skz151634 		entry->seg_count = 0;
36060405de4Skz151634 	}
36160405de4Skz151634 
36260405de4Skz151634 	if (entry->buf_count) {
36360405de4Skz151634 		for (i = 0; i < entry->buf_count; i++) {
36460405de4Skz151634 			if (entry->buflist[i].dev_private) {
36560405de4Skz151634 				drm_free(entry->buflist[i].dev_private,
36660405de4Skz151634 				    entry->buflist[i].dev_priv_size,
36760405de4Skz151634 				    DRM_MEM_BUFS);
36860405de4Skz151634 			}
36960405de4Skz151634 		}
37060405de4Skz151634 		drm_free(entry->buflist,
37160405de4Skz151634 		    entry->buf_count *
37260405de4Skz151634 		    sizeof (*entry->buflist), DRM_MEM_BUFS);
373d0538f66Scg149915 		entry->buflist = NULL;
37460405de4Skz151634 		entry->buf_count = 0;
37560405de4Skz151634 	}
37660405de4Skz151634 }
37760405de4Skz151634 
37860405de4Skz151634 /*ARGSUSED*/
37960405de4Skz151634 int
drm_markbufs(DRM_IOCTL_ARGS)38060405de4Skz151634 drm_markbufs(DRM_IOCTL_ARGS)
38160405de4Skz151634 {
38260405de4Skz151634 	DRM_DEBUG("drm_markbufs");
383d0538f66Scg149915 	return (EINVAL);
38460405de4Skz151634 }
38560405de4Skz151634 
38660405de4Skz151634 /*ARGSUSED*/
38760405de4Skz151634 int
drm_infobufs(DRM_IOCTL_ARGS)38860405de4Skz151634 drm_infobufs(DRM_IOCTL_ARGS)
38960405de4Skz151634 {
39060405de4Skz151634 	DRM_DEBUG("drm_infobufs");
391d0538f66Scg149915 	return (EINVAL);
39260405de4Skz151634 }
39360405de4Skz151634 
39460405de4Skz151634 static int
drm_do_addbufs_agp(drm_device_t * dev,drm_buf_desc_t * request)39560405de4Skz151634 drm_do_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
39660405de4Skz151634 {
39760405de4Skz151634 	drm_device_dma_t *dma = dev->dma;
39860405de4Skz151634 	drm_buf_entry_t *entry;
399d0538f66Scg149915 	drm_buf_t **temp_buflist;
40060405de4Skz151634 	drm_buf_t *buf;
40160405de4Skz151634 	unsigned long offset;
40260405de4Skz151634 	unsigned long agp_offset;
40360405de4Skz151634 	int count;
40460405de4Skz151634 	int order;
40560405de4Skz151634 	int size;
40660405de4Skz151634 	int alignment;
40760405de4Skz151634 	int page_order;
40860405de4Skz151634 	int byte_count;
40960405de4Skz151634 	int i;
41060405de4Skz151634 
41160405de4Skz151634 	if (!dma)
412d0538f66Scg149915 		return (EINVAL);
41360405de4Skz151634 
41460405de4Skz151634 	count = request->count;
41560405de4Skz151634 	order = drm_order(request->size);
41660405de4Skz151634 	size = 1 << order;
41760405de4Skz151634 
41860405de4Skz151634 	alignment  = (request->flags & _DRM_PAGE_ALIGN)
41960405de4Skz151634 	    ? round_page(size) : size;
42060405de4Skz151634 	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
42160405de4Skz151634 
42260405de4Skz151634 	byte_count = 0;
42360405de4Skz151634 	agp_offset = dev->agp->base + request->agp_start;
42460405de4Skz151634 
42560405de4Skz151634 	entry = &dma->bufs[order];
42660405de4Skz151634 
427d0538f66Scg149915 	/* No more than one allocation per order */
428d0538f66Scg149915 	if (entry->buf_count) {
429d0538f66Scg149915 		return (ENOMEM);
430d0538f66Scg149915 	}
431d0538f66Scg149915 
43260405de4Skz151634 	entry->buflist = drm_alloc(count * sizeof (*entry->buflist),
43360405de4Skz151634 	    DRM_MEM_BUFS);
43460405de4Skz151634 	if (!entry->buflist) {
435d0538f66Scg149915 		return (ENOMEM);
43660405de4Skz151634 	}
43760405de4Skz151634 	entry->buf_size = size;
43860405de4Skz151634 	entry->page_order = page_order;
43960405de4Skz151634 
44060405de4Skz151634 	offset = 0;
44160405de4Skz151634 
44260405de4Skz151634 	while (entry->buf_count < count) {
44360405de4Skz151634 		buf		= &entry->buflist[entry->buf_count];
44460405de4Skz151634 		buf->idx	= dma->buf_count + entry->buf_count;
44560405de4Skz151634 		buf->total	= alignment;
44660405de4Skz151634 		buf->order	= order;
44760405de4Skz151634 		buf->used	= 0;
44860405de4Skz151634 
44960405de4Skz151634 		buf->offset	= (dma->byte_count + offset);
45060405de4Skz151634 		buf->bus_address = agp_offset + offset;
45160405de4Skz151634 		buf->address	= (void *)(agp_offset + offset);
45260405de4Skz151634 		buf->next	= NULL;
45360405de4Skz151634 		buf->pending	= 0;
45460405de4Skz151634 		buf->filp	= NULL;
45560405de4Skz151634 
456d0538f66Scg149915 		buf->dev_priv_size = dev->driver->buf_priv_size;
457d0538f66Scg149915 		buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
45860405de4Skz151634 		if (buf->dev_private == NULL) {
45960405de4Skz151634 			/* Set count correctly so we free the proper amount. */
46060405de4Skz151634 			entry->buf_count = count;
46160405de4Skz151634 			drm_cleanup_buf_error(dev, entry);
462d0538f66Scg149915 			return (ENOMEM);
46360405de4Skz151634 		}
46460405de4Skz151634 
46560405de4Skz151634 		offset += alignment;
46660405de4Skz151634 		entry->buf_count++;
46760405de4Skz151634 		byte_count += PAGE_SIZE << page_order;
46860405de4Skz151634 	}
46960405de4Skz151634 
47060405de4Skz151634 	temp_buflist = drm_alloc(
47160405de4Skz151634 	    (dma->buf_count + entry->buf_count) * sizeof (*dma->buflist),
47260405de4Skz151634 	    DRM_MEM_BUFS);
47360405de4Skz151634 
47460405de4Skz151634 	if (temp_buflist == NULL) {
47560405de4Skz151634 		/* Free the entry because it isn't valid */
47660405de4Skz151634 		drm_cleanup_buf_error(dev, entry);
47760405de4Skz151634 		DRM_ERROR(" temp_buflist is NULL");
478d0538f66Scg149915 		return (ENOMEM);
47960405de4Skz151634 	}
48060405de4Skz151634 
48160405de4Skz151634 	bcopy(temp_buflist, dma->buflist,
48260405de4Skz151634 	    dma->buf_count * sizeof (*dma->buflist));
48360405de4Skz151634 	kmem_free(dma->buflist, dma->buf_count *sizeof (*dma->buflist));
48460405de4Skz151634 	dma->buflist = temp_buflist;
48560405de4Skz151634 
48660405de4Skz151634 	for (i = 0; i < entry->buf_count; i++) {
48760405de4Skz151634 		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
48860405de4Skz151634 	}
48960405de4Skz151634 
49060405de4Skz151634 	dma->buf_count += entry->buf_count;
49160405de4Skz151634 	dma->byte_count += byte_count;
492d0538f66Scg149915 	dma->seg_count += entry->seg_count;
493d0538f66Scg149915 	dma->page_count += byte_count >> PAGE_SHIFT;
49460405de4Skz151634 
49560405de4Skz151634 	request->count = entry->buf_count;
49660405de4Skz151634 	request->size = size;
49760405de4Skz151634 
49860405de4Skz151634 	dma->flags = _DRM_DMA_USE_AGP;
49960405de4Skz151634 
50060405de4Skz151634 	return (0);
50160405de4Skz151634 }
50260405de4Skz151634 
50360405de4Skz151634 static int
drm_do_addbufs_sg(drm_device_t * dev,drm_buf_desc_t * request)50460405de4Skz151634 drm_do_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
50560405de4Skz151634 {
50660405de4Skz151634 	drm_device_dma_t *dma = dev->dma;
50760405de4Skz151634 	drm_buf_entry_t *entry;
50860405de4Skz151634 	drm_buf_t *buf;
50960405de4Skz151634 	unsigned long offset;
51060405de4Skz151634 	unsigned long agp_offset;
51160405de4Skz151634 	int count;
51260405de4Skz151634 	int order;
51360405de4Skz151634 	int size;
51460405de4Skz151634 	int alignment;
51560405de4Skz151634 	int page_order;
51660405de4Skz151634 	int byte_count;
51760405de4Skz151634 	int i;
51860405de4Skz151634 	drm_buf_t **temp_buflist;
51960405de4Skz151634 
52060405de4Skz151634 	count = request->count;
52160405de4Skz151634 	order = drm_order(request->size);
52260405de4Skz151634 	size = 1 << order;
52360405de4Skz151634 
52460405de4Skz151634 	alignment  = (request->flags & _DRM_PAGE_ALIGN)
52560405de4Skz151634 	    ? round_page(size) : size;
52660405de4Skz151634 	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
52760405de4Skz151634 
52860405de4Skz151634 	byte_count = 0;
52960405de4Skz151634 	agp_offset = request->agp_start;
53060405de4Skz151634 	entry = &dma->bufs[order];
53160405de4Skz151634 
53260405de4Skz151634 	entry->buflist = drm_alloc(count * sizeof (*entry->buflist),
53360405de4Skz151634 	    DRM_MEM_BUFS);
53460405de4Skz151634 	if (entry->buflist == NULL)
535d0538f66Scg149915 		return (ENOMEM);
53660405de4Skz151634 
53760405de4Skz151634 	entry->buf_size = size;
53860405de4Skz151634 	entry->page_order = page_order;
53960405de4Skz151634 
54060405de4Skz151634 	offset = 0;
54160405de4Skz151634 
54260405de4Skz151634 	while (entry->buf_count < count) {
54360405de4Skz151634 		buf		= &entry->buflist[entry->buf_count];
54460405de4Skz151634 		buf->idx	= dma->buf_count + entry->buf_count;
54560405de4Skz151634 		buf->total	= alignment;
54660405de4Skz151634 		buf->order	= order;
54760405de4Skz151634 		buf->used	= 0;
54860405de4Skz151634 
54960405de4Skz151634 		buf->offset	= (dma->byte_count + offset);
55060405de4Skz151634 		buf->bus_address = agp_offset + offset;
55160405de4Skz151634 		buf->address = (void *)(agp_offset + offset + dev->sg->handle);
55260405de4Skz151634 		buf->next	= NULL;
55360405de4Skz151634 		buf->pending	= 0;
55460405de4Skz151634 		buf->filp	= NULL;
55560405de4Skz151634 
556d0538f66Scg149915 		buf->dev_priv_size = dev->driver->buf_priv_size;
55760405de4Skz151634 		buf->dev_private = drm_alloc(buf->dev_priv_size,
55860405de4Skz151634 		    DRM_MEM_BUFS);
55960405de4Skz151634 		if (buf->dev_private == NULL) {
56060405de4Skz151634 			/* Set count correctly so we free the proper amount. */
56160405de4Skz151634 			entry->buf_count = count;
56260405de4Skz151634 			drm_cleanup_buf_error(dev, entry);
563d0538f66Scg149915 			return (ENOMEM);
56460405de4Skz151634 		}
56560405de4Skz151634 
56660405de4Skz151634 		offset += alignment;
56760405de4Skz151634 		entry->buf_count++;
56860405de4Skz151634 		byte_count += PAGE_SIZE << page_order;
56960405de4Skz151634 	}
57060405de4Skz151634 
57160405de4Skz151634 	temp_buflist = drm_realloc(dma->buflist,
57260405de4Skz151634 	    dma->buf_count * sizeof (*dma->buflist),
57360405de4Skz151634 	    (dma->buf_count + entry->buf_count)
57460405de4Skz151634 	    * sizeof (*dma->buflist), DRM_MEM_BUFS);
57560405de4Skz151634 	if (!temp_buflist) {
57660405de4Skz151634 		drm_cleanup_buf_error(dev, entry);
577d0538f66Scg149915 		return (ENOMEM);
57860405de4Skz151634 	}
57960405de4Skz151634 	dma->buflist = temp_buflist;
58060405de4Skz151634 
58160405de4Skz151634 	for (i = 0; i < entry->buf_count; i++) {
58260405de4Skz151634 		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
58360405de4Skz151634 	}
58460405de4Skz151634 
58560405de4Skz151634 	dma->buf_count += entry->buf_count;
58660405de4Skz151634 	dma->byte_count += byte_count;
58760405de4Skz151634 	request->count = entry->buf_count;
58860405de4Skz151634 	request->size = size;
58960405de4Skz151634 	dma->flags = _DRM_DMA_USE_SG;
59060405de4Skz151634 
59160405de4Skz151634 	return (0);
59260405de4Skz151634 }
59360405de4Skz151634 
59460405de4Skz151634 int
drm_addbufs_agp(drm_device_t * dev,drm_buf_desc_t * request)59560405de4Skz151634 drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
59660405de4Skz151634 {
59760405de4Skz151634 	int order, ret;
59860405de4Skz151634 
59960405de4Skz151634 	DRM_SPINLOCK(&dev->dma_lock);
60060405de4Skz151634 
60160405de4Skz151634 	if (request->count < 0 || request->count > 4096) {
60260405de4Skz151634 		DRM_SPINLOCK(&dev->dma_lock);
603d0538f66Scg149915 		return (EINVAL);
60460405de4Skz151634 	}
60560405de4Skz151634 
60660405de4Skz151634 	order = drm_order(request->size);
60760405de4Skz151634 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) {
60860405de4Skz151634 		DRM_SPINLOCK(&dev->dma_lock);
609d0538f66Scg149915 		return (EINVAL);
61060405de4Skz151634 	}
61160405de4Skz151634 
61260405de4Skz151634 	/* No more allocations after first buffer-using ioctl. */
61360405de4Skz151634 	if (dev->buf_use != 0) {
61460405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
615d0538f66Scg149915 		return (EBUSY);
61660405de4Skz151634 	}
61760405de4Skz151634 	/* No more than one allocation per order */
61860405de4Skz151634 	if (dev->dma->bufs[order].buf_count != 0) {
61960405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
620d0538f66Scg149915 		return (ENOMEM);
62160405de4Skz151634 	}
62260405de4Skz151634 
62360405de4Skz151634 	ret = drm_do_addbufs_agp(dev, request);
62460405de4Skz151634 
62560405de4Skz151634 	DRM_SPINUNLOCK(&dev->dma_lock);
62660405de4Skz151634 
62760405de4Skz151634 	return (ret);
62860405de4Skz151634 }
62960405de4Skz151634 
63060405de4Skz151634 int
drm_addbufs_sg(drm_device_t * dev,drm_buf_desc_t * request)63160405de4Skz151634 drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
63260405de4Skz151634 {
63360405de4Skz151634 	int order, ret;
63460405de4Skz151634 
63560405de4Skz151634 	DRM_SPINLOCK(&dev->dma_lock);
63660405de4Skz151634 
63760405de4Skz151634 	if (request->count < 0 || request->count > 4096) {
63860405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
639d0538f66Scg149915 		return (EINVAL);
64060405de4Skz151634 	}
64160405de4Skz151634 
64260405de4Skz151634 	order = drm_order(request->size);
64360405de4Skz151634 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) {
64460405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
645d0538f66Scg149915 		return (EINVAL);
64660405de4Skz151634 	}
64760405de4Skz151634 
64860405de4Skz151634 	/* No more allocations after first buffer-using ioctl. */
64960405de4Skz151634 	if (dev->buf_use != 0) {
65060405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
651d0538f66Scg149915 		return (EBUSY);
65260405de4Skz151634 	}
65360405de4Skz151634 
65460405de4Skz151634 	/* No more than one allocation per order */
65560405de4Skz151634 	if (dev->dma->bufs[order].buf_count != 0) {
65660405de4Skz151634 		DRM_SPINUNLOCK(&dev->dma_lock);
657d0538f66Scg149915 		return (ENOMEM);
65860405de4Skz151634 	}
65960405de4Skz151634 
66060405de4Skz151634 	ret = drm_do_addbufs_sg(dev, request);
66160405de4Skz151634 	DRM_SPINUNLOCK(&dev->dma_lock);
66260405de4Skz151634 	return (ret);
66360405de4Skz151634 }
66460405de4Skz151634 
66560405de4Skz151634 /*ARGSUSED*/
66660405de4Skz151634 int
drm_addbufs_ioctl(DRM_IOCTL_ARGS)66760405de4Skz151634 drm_addbufs_ioctl(DRM_IOCTL_ARGS)
66860405de4Skz151634 {
66960405de4Skz151634 	DRM_DEVICE;
67060405de4Skz151634 	drm_buf_desc_t request;
67160405de4Skz151634 	int err;
67260405de4Skz151634 
673d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
67460405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
675d0538f66Scg149915 		drm_buf_desc_32_t request32;
676d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request32,
677d0538f66Scg149915 		    (void *)data, sizeof (request32));
67860405de4Skz151634 		request.count = request32.count;
67960405de4Skz151634 		request.size = request32.size;
68060405de4Skz151634 		request.low_mark = request32.low_mark;
68160405de4Skz151634 		request.high_mark = request32.high_mark;
68260405de4Skz151634 		request.flags = request32.flags;
68360405de4Skz151634 		request.agp_start = request32.agp_start;
68460405de4Skz151634 	} else
685d0538f66Scg149915 #endif
686d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request,
687d0538f66Scg149915 		    (void *)data, sizeof (request));
68860405de4Skz151634 
68960405de4Skz151634 	if (request.flags & _DRM_AGP_BUFFER)
69060405de4Skz151634 		err = drm_addbufs_agp(dev, &request);
69160405de4Skz151634 	else if (request.flags & _DRM_SG_BUFFER)
69260405de4Skz151634 		err = drm_addbufs_sg(dev, &request);
69360405de4Skz151634 
694d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
69560405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
696d0538f66Scg149915 		drm_buf_desc_32_t request32;
69760405de4Skz151634 		request32.count = request.count;
69860405de4Skz151634 		request32.size = request.size;
69960405de4Skz151634 		request32.low_mark = request.low_mark;
70060405de4Skz151634 		request32.high_mark = request.high_mark;
70160405de4Skz151634 		request32.flags = request.flags;
702d0538f66Scg149915 		request32.agp_start = (uint32_t)request.agp_start;
703d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
704d0538f66Scg149915 		    &request32, sizeof (request32));
70560405de4Skz151634 	} else
706d0538f66Scg149915 #endif
707d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
708d0538f66Scg149915 		    &request, sizeof (request));
70960405de4Skz151634 
71060405de4Skz151634 	return (err);
71160405de4Skz151634 }
71260405de4Skz151634 
71360405de4Skz151634 /*ARGSUSED*/
71460405de4Skz151634 int
drm_freebufs(DRM_IOCTL_ARGS)71560405de4Skz151634 drm_freebufs(DRM_IOCTL_ARGS)
71660405de4Skz151634 {
71760405de4Skz151634 	DRM_DEVICE;
71860405de4Skz151634 	drm_device_dma_t *dma = dev->dma;
71960405de4Skz151634 	drm_buf_free_t request;
72060405de4Skz151634 	int i;
72160405de4Skz151634 	int idx;
72260405de4Skz151634 	drm_buf_t *buf;
72360405de4Skz151634 	int retcode = 0;
72460405de4Skz151634 
725d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
72660405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
727d0538f66Scg149915 		drm_buf_free_32_t request32;
728d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request32,
729d0538f66Scg149915 		    (void*)data, sizeof (request32));
73060405de4Skz151634 		request.count = request32.count;
731d0538f66Scg149915 		request.list = (int *)(uintptr_t)request32.list;
73260405de4Skz151634 	} else
733d0538f66Scg149915 #endif
734d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request,
735d0538f66Scg149915 		    (void *)data, sizeof (request));
73660405de4Skz151634 
73760405de4Skz151634 	for (i = 0; i < request.count; i++) {
73860405de4Skz151634 		if (DRM_COPY_FROM_USER(&idx, &request.list[i], sizeof (idx))) {
739d0538f66Scg149915 			retcode = EFAULT;
74060405de4Skz151634 			break;
74160405de4Skz151634 		}
74260405de4Skz151634 		if (idx < 0 || idx >= dma->buf_count) {
74360405de4Skz151634 			DRM_ERROR("drm_freebufs: Index %d (of %d max)\n",
74460405de4Skz151634 			    idx, dma->buf_count - 1);
745d0538f66Scg149915 			retcode = EINVAL;
74660405de4Skz151634 			break;
74760405de4Skz151634 		}
74860405de4Skz151634 		buf = dma->buflist[idx];
749d0538f66Scg149915 		if (buf->filp != fpriv) {
75060405de4Skz151634 			DRM_ERROR(
75160405de4Skz151634 			    "drm_freebufs: process %d not owning the buffer.\n",
75260405de4Skz151634 			    DRM_CURRENTPID);
753d0538f66Scg149915 			retcode = EINVAL;
75460405de4Skz151634 			break;
75560405de4Skz151634 		}
75660405de4Skz151634 		drm_free_buffer(dev, buf);
75760405de4Skz151634 	}
75860405de4Skz151634 
75960405de4Skz151634 	return (retcode);
76060405de4Skz151634 }
76160405de4Skz151634 
762d0538f66Scg149915 #ifdef _LP64
763d0538f66Scg149915 extern caddr_t smmap64(caddr_t, size_t, int, int, int, off_t);
764d0538f66Scg149915 #define	drm_smmap	smmap64
765d0538f66Scg149915 #else
766d0538f66Scg149915 #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
767d0538f66Scg149915 extern caddr_t smmap32(caddr32_t, size32_t, int, int, int, off32_t);
768d0538f66Scg149915 #define	drm_smmap smmap32
769d0538f66Scg149915 #else
770d0538f66Scg149915 #error "No define for _LP64, _SYSCALL32_IMPL or _ILP32"
771d0538f66Scg149915 #endif
772d0538f66Scg149915 #endif
773d0538f66Scg149915 
774d0538f66Scg149915 
77560405de4Skz151634 /*ARGSUSED*/
77660405de4Skz151634 int
drm_mapbufs(DRM_IOCTL_ARGS)77760405de4Skz151634 drm_mapbufs(DRM_IOCTL_ARGS)
77860405de4Skz151634 {
77960405de4Skz151634 	DRM_DEVICE;
78060405de4Skz151634 	drm_buf_map_t request;
78160405de4Skz151634 	const int zero = 0;
78260405de4Skz151634 	unsigned long	vaddr;
78360405de4Skz151634 	unsigned long address;
78460405de4Skz151634 	drm_device_dma_t *dma = dev->dma;
785d0538f66Scg149915 	uint_t	size;
786d0538f66Scg149915 	uint_t	foff;
78760405de4Skz151634 	int		ret_tmp;
788d0538f66Scg149915 	int 	i;
789d0538f66Scg149915 
790d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
791d0538f66Scg149915 	drm_buf_map_32_t request32;
792d0538f66Scg149915 	drm_buf_pub_32_t	*list32;
793d0538f66Scg149915 	uint_t		address32;
79460405de4Skz151634 
79560405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
796d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request32,
797d0538f66Scg149915 		    (void *)data, sizeof (request32));
79860405de4Skz151634 		request.count = request32.count;
799d0538f66Scg149915 		request.virtual = (void *)(uintptr_t)request32.virtual;
800d0538f66Scg149915 		request.list = (drm_buf_pub_t *)(uintptr_t)request32.list;
801d0538f66Scg149915 		request.fd = request32.fd;
80260405de4Skz151634 	} else
803d0538f66Scg149915 #endif
804d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&request,
805d0538f66Scg149915 		    (void *)data, sizeof (request));
80660405de4Skz151634 
80760405de4Skz151634 	dev->buf_use++;
80860405de4Skz151634 
80960405de4Skz151634 	if (request.count < dma->buf_count)
81060405de4Skz151634 		goto done;
81160405de4Skz151634 
812d0538f66Scg149915 	if ((dev->driver->use_agp && (dma->flags & _DRM_DMA_USE_AGP)) ||
813d0538f66Scg149915 	    (dev->driver->use_sg && (dma->flags & _DRM_DMA_USE_SG))) {
814d0538f66Scg149915 		drm_local_map_t *map = dev->agp_buffer_map;
815d0538f66Scg149915 		if (map == NULL)
816d0538f66Scg149915 			return (EINVAL);
817d0538f66Scg149915 		size = round_page(map->size);
818d0538f66Scg149915 		foff = (uintptr_t)map->handle;
819d0538f66Scg149915 	} else {
820d0538f66Scg149915 		size = round_page(dma->byte_count);
821d0538f66Scg149915 		foff = 0;
822d0538f66Scg149915 	}
823d0538f66Scg149915 	request.virtual = drm_smmap(NULL, size, PROT_READ | PROT_WRITE,
824d0538f66Scg149915 	    MAP_SHARED, request.fd, foff);
82560405de4Skz151634 	if (request.virtual == NULL) {
82660405de4Skz151634 		DRM_ERROR("drm_mapbufs: request.virtual is NULL");
827d0538f66Scg149915 		return (EINVAL);
82860405de4Skz151634 	}
82960405de4Skz151634 
830d0538f66Scg149915 	vaddr = (unsigned long) request.virtual;
831d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
832d0538f66Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
833d0538f66Scg149915 		list32 = (drm_buf_pub_32_t *)(uintptr_t)request32.list;
834d0538f66Scg149915 		for (i = 0; i < dma->buf_count; i++) {
835d0538f66Scg149915 			if (DRM_COPY_TO_USER(&list32[i].idx,
836d0538f66Scg149915 			    &dma->buflist[i]->idx, sizeof (list32[0].idx))) {
837d0538f66Scg149915 				return (EFAULT);
838d0538f66Scg149915 			}
839d0538f66Scg149915 			if (DRM_COPY_TO_USER(&list32[i].total,
840d0538f66Scg149915 			    &dma->buflist[i]->total,
841d0538f66Scg149915 			    sizeof (list32[0].total))) {
842d0538f66Scg149915 				return (EFAULT);
843d0538f66Scg149915 			}
844d0538f66Scg149915 			if (DRM_COPY_TO_USER(&list32[i].used,
845d0538f66Scg149915 			    &zero, sizeof (zero))) {
846d0538f66Scg149915 				return (EFAULT);
847d0538f66Scg149915 			}
848d0538f66Scg149915 			address32 = vaddr + dma->buflist[i]->offset; /* *** */
849d0538f66Scg149915 			ret_tmp = DRM_COPY_TO_USER(&list32[i].address,
850d0538f66Scg149915 			    &address32, sizeof (list32[0].address));
851d0538f66Scg149915 			if (ret_tmp)
852d0538f66Scg149915 				return (EFAULT);
853d0538f66Scg149915 		}
854d0538f66Scg149915 		goto done;
855d0538f66Scg149915 	}
856d0538f66Scg149915 #endif
857d0538f66Scg149915 
858d0538f66Scg149915 	ASSERT(ddi_model_convert_from(mode & FMODELS) != DDI_MODEL_ILP32);
85960405de4Skz151634 	for (i = 0; i < dma->buf_count; i++) {
86060405de4Skz151634 		if (DRM_COPY_TO_USER(&request.list[i].idx,
86160405de4Skz151634 		    &dma->buflist[i]->idx, sizeof (request.list[0].idx))) {
862d0538f66Scg149915 			return (EFAULT);
86360405de4Skz151634 		}
86460405de4Skz151634 		if (DRM_COPY_TO_USER(&request.list[i].total,
86560405de4Skz151634 		    &dma->buflist[i]->total, sizeof (request.list[0].total))) {
866d0538f66Scg149915 			return (EFAULT);
86760405de4Skz151634 		}
86860405de4Skz151634 		if (DRM_COPY_TO_USER(&request.list[i].used, &zero,
86960405de4Skz151634 		    sizeof (zero))) {
870d0538f66Scg149915 			return (EFAULT);
87160405de4Skz151634 		}
87260405de4Skz151634 		address = vaddr + dma->buflist[i]->offset; /* *** */
87360405de4Skz151634 
87460405de4Skz151634 		ret_tmp = DRM_COPY_TO_USER(&request.list[i].address,
87560405de4Skz151634 		    &address, sizeof (address));
87660405de4Skz151634 		if (ret_tmp) {
877d0538f66Scg149915 			return (EFAULT);
87860405de4Skz151634 		}
87960405de4Skz151634 	}
88060405de4Skz151634 
88160405de4Skz151634 done:
882d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
88360405de4Skz151634 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
884d0538f66Scg149915 		request32.count = dma->buf_count;
88560405de4Skz151634 		request32.virtual = (caddr32_t)(uintptr_t)request.virtual;
886d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
887d0538f66Scg149915 		    &request32, sizeof (request32));
888d0538f66Scg149915 	} else {
889d0538f66Scg149915 #endif
890d0538f66Scg149915 		request.count = dma->buf_count;
891d0538f66Scg149915 		DRM_COPYTO_WITH_RETURN((void *)data,
892d0538f66Scg149915 		    &request, sizeof (request));
893d0538f66Scg149915 #ifdef	_MULTI_DATAMODEL
894d0538f66Scg149915 	}
895d0538f66Scg149915 #endif
896d0538f66Scg149915 	return (0);
89760405de4Skz151634 }
898