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