summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2008-06-23[intel-gem] Recover resources from wedged hardware.Keith Packard
Clean up queues, free objects. On the next entervt, unmark the hardware to let the user try again (presumably after resetting the chip). Someday we'll automatically recover...
2008-06-23[intel] Switch to using IMR instead of IERKeith Packard
2008-06-23[intel-gem] pwrite through GTTKeith Packard
Pin/copy_from_user/unpin through the GTT to eliminate clflush costs. Benchmarks say this helps quite a bit.
2008-06-23[intel] allow the irq code to use either enable or mask registersKeith Packard
still not sure which works best on which hardware; this will make it easier to experiment.
2008-06-23nv50: oops, keep VRAM allocations aligned at 64KiB - that's our page size..Ben Skeggs
2008-06-23nv50: use same dma object for fb/tt accessBen Skeggs
We depend on the VM fully now for memory protection, separate DMA objects for VRAM and GART are unneccesary. However, until the next interface break (soon) a client can't depend on the objects being the same and must still call NV_OBJ_SET_DMA_* methods appropriately.
2008-06-23nouveau: allocate drm-use vram buffers from end of vram.Ben Skeggs
This avoids seeing garbage from engine setup etc before X gets around to pointing the CRTCs at a new scanout buffer. Not actually a noticable problem before G80 as PRAMIN is forced to the end of VRAM by the hardware already.
2008-06-22agp: use true/false instead of TRUE/FALSEDave Airlie
2008-06-21RADEON: 0x1002 0x5657 is actually an RV410Alex Deucher
See bug 14289
2008-06-21[intel] Use IMR instead of IER to pend interrupts during ISRKeith Packard
Noting that the interrupt mask register was more reliable than the interrupt enable register for managing interrupts in user_irq_on/user_irq_off, this patch replaces the remaining IER frobbing with IMR instead. The test which exposes IER related failures is: $ glxgears & glxgears & glxgears (reposition the glxgears windows away from the upper left corner) $ while :; do x11perf -rect100 -reps 800 -repeat 1; sleep 1; done & $ while :; do runoa; runet; done &
2008-06-21[intel-gem] Add /proc/dri/*/i915_gem_interruptKeith Packard
This tracks most of the interrupt-related status, including the interrupt registers in the chip and the sequence number variables.
2008-06-21[intel] Count received interruptsKeith Packard
Another patch adds this to a /proc/dri file for debugging and monitoring.
2008-06-21[intel-gem] Remove unused variable.Keith Packard
2008-06-20[intel-gem] Use polling in i915_gem_idle instead of interrupts.Keith Packard
While waiting for the hardware to idle on leavevt or lastclose, poll for the sync sequence number instead of waiting for an interrupt. This allows the code to bail if the hardware hangs for some reason. Also, this avoids issues with signals as the exisiting wait function is interruptible.
2008-06-20[intel-gem] Add intel-specific /proc entries to help monitor gem operationKeith Packard
This adds gem_active, gem_flushing, gem_inactive, gem_request and gem_seqno entries to monitor gem operation and help debug issues.
2008-06-20Add device-specific proc_init and proc_cleanup hooksKeith Packard
This allows device drivers to add proc files
2008-06-20[intel-gem] Use shmem_getpage instead of find_or_create_pageKeith Packard
find_or_create_page doesn't quite set up pages correctly; any newly created pages aren't hooked into the shmem object quite right; user space mmaps of those pages end up mapping pages full of zeros which then get written to the real pages inappropriately. This patch requires that the kernel export shmem_getpage.
2008-06-20[intel-gem] Add DRM_IOCTL_I915_GEM_SW_FINISH to flag CPU writesKeith Packard
When a software fallback has completed, usermode must notify the kernel so that any scanout buffers can be synchronized. This ioctl should be called whenever a fallback completes to flush CPU and chipset caches.
2008-06-20drm: only use kernel ioctl cmd when doing a core ioctl.Dave Airlie
Need to overhaul the mess that is driver ioctls
2008-06-20r300: fix warningDave Airlie
2008-06-20drm: fix the ioctl to not believe userspace.Dave Airlie
believing userspace causes oopses
2008-06-18i915: Add support for Intel 4 series chipsetsZhenyu Wang
Signed-off-by: Zhenyu Wang <zhenyu.z.wang@intel.com>
2008-06-16[intel] Quirk away MSI support on 945G/GM.Eric Anholt
The PCI caps register reports MSI support even though it isn't really there.
2008-06-16[linux] Use the device's irq for handler setup instead of stale dev->irq.Eric Anholt
This fixes registration when MSI is set up after the stub function fills in dev->irq. Otherwise /proc/interrupts would report attachment to the fasteoi interrupt. dev->irq is still exposed (and updated at IRQ setup) for the drivers that use it for whatever reason.
2008-06-15radeon: *really* fix screen corruption thanks to Lukasz KrotowskiJerome Glisse
2008-06-15radeon: actualy try to fix the corruptionJerome Glisse
2008-06-15radeon: fix screen corruption introduced by last patchJerome Glisse
2008-06-13[intel-gem] Execute MI_FLUSH in leavevt_ioctlKeith Packard
In leavevt_ioctl, queue an MI_FLUSH and then block waiting for it to complete. This will empty the active and flushing lists. That leaves only the inactive list to evict.
2008-06-13[intel-gem] inactive list may contain objects in CPU write domainKeith Packard
Pin/unpin need to know whether to remove/add objects from the inactive list, inactive objects cannot be in any GPU write domain as those would be on the flushing list instead. However, inactive objects may be in the CPU write domain.
2008-06-13[intel-gem] BUG_ON active objects in gem_object_unbindKeith Packard
Now that gem_object_unbind waits for rendering to complete, objects should not be active when they are being pulled from the GTT. BUG_ON if this is broken.
2008-06-13[intel-gem] Debugging -- verify inactive list invariantsKeith Packard
Inactive list elements may not be pinned, active or have non-CPU write domains.
2008-06-13[intel-gem] whitespace fixesKeith Packard
2008-06-13[intel-gem] show total GTT space in /proc/dri/*/gem_objectsKeith Packard
2008-06-13[intel-gem] Wait for rendering to complete before unbinding.Keith Packard
Moving to the CPU domain doesn't ensure that rendering is finished, the buffer may still be in use as a texture or other data source.
2008-06-13[libdrm] Restart all ioctls on signal receiptKeith Packard
Receiving a signal should be ignored by the library, so just restart any ioctl which returns EINTR or EAGAIN.
2008-06-13[intel-gem] add gtt and pin counts to /proc/dri/*/gem_objectsKeith Packard
Not quite portable, but these are useful for intel. Some more general mechanism could be done...
2008-06-13[intel-gem] Left the last exec buffer pinned. oops.Keith Packard
Loop end variable 'pinned' was set one too low.
2008-06-13[FreeBSD] Fix another lock leakRobert Noland
Reported by vehemens
2008-06-13[intel-gem] Pin objects during execbufferKeith Packard
Pinning the objects avoids accidentally evicting them while binding other objects.
2008-06-13[intel-gem] throttle based on frames rather than time. Reduces jitter.Keith Packard
Record the last execbuffer sequence for each client. Record that sequence in the throttle ioctl as the 'throttle sequence'. Wait for the last throttle sequence in the throttle ioctl.
2008-06-13[intel-gem] evict_something was failing when wait_request freed objectsKeith Packard
When i915_wait_request clears object from the active list, it may end up freeing them and not moving them to the inactive list. This ends up unbinding objects from the GTT without there ever being new objects visible to i915_gem_evict_something on the inactive list. As the only success condition required the presence of objects on the inactive list, this would falsely assume that no GTT space had been made available, and end up returning -ENOMEM to the application.
2008-06-13[intel] Enable MSI for i915 IRQKeith Packard
2008-06-13[intel] Restructure irq to pend all work until after iir write.Keith Packard
The interrupt identity register must be writen before any work occurs lest we drop an interrupt on the floor. This patch just shuffles code around to make sure that IIR is written as early as possible.
2008-06-13[intel-gem] Use a delayed_work instead of a timer + work_structKeith Packard
We want request retirement to occur about once a second when the request queue is non-empty. This was done with a timer that queued a work_struct, using a delayed_work instead makes a lot more sense.
2008-06-13[intel-gem] Reorder i915_add_request to schedule work lastKeith Packard
i915_add_request was calling schedule_delayed_work before adding the request to the list; it makes more sense to do that last.
2008-06-13Use /bin/pwd instead of trusting shell built-inKeith Packard
2008-06-13Fix i915_wait_irq in the presence of interrupt masking.Eric Anholt
In the short-circuit code for the breadcrumb already being new enough, we need to update the sarea_priv copy of the breadcrumb just as if we had waited. Otherwise userland error checking will notice that we returned too early based on its wrong information, and call wait_irq again (leading to spinning until someone else comes along and updates the sarea_priv). This bug was hidden when we had interrupt masking disabled, such as in master, since the interrupt handler would update sarea_priv.
2008-06-13[gem] Catch -EINTR from blocking ioctls and restart them.Eric Anholt
Thanks to Thomas Hellstrom for catching the issue, no thanks to the kernel developer who authoritatively told me that they would get restarted on their own.
2008-06-13[gem] Remove the interrupt handler for retiring requests.Eric Anholt
This was insufficient once we started masking interrupts to only when someone was waiting for them (and would thus retire requests themselves). It was replaced by the retire_timer.
2008-06-13[gem] Don't require the lock in execbuf now that it's not needed for the ring.Eric Anholt
24'>724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
/* drm_bufs.h -- Generic buffer template -*- linux-c -*-
 * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
 *
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Rickard E. (Rik) Faith <faith@valinux.com>
 *    Gareth Hughes <gareth@valinux.com>
 * $FreeBSD: src/sys/dev/drm/drm_bufs.h,v 1.4 2003/03/09 02:08:28 anholt Exp $
 */

#include "drmP.h"

#ifndef __HAVE_PCI_DMA
#define __HAVE_PCI_DMA		0
#endif

#ifndef __HAVE_SG
#define __HAVE_SG		0
#endif

#ifndef DRIVER_BUF_PRIV_T
#define DRIVER_BUF_PRIV_T		u32
#endif
#ifndef DRIVER_AGP_BUFFERS_MAP
#if __HAVE_AGP && __HAVE_DMA
#error "You must define DRIVER_AGP_BUFFERS_MAP()"
#else
#define DRIVER_AGP_BUFFERS_MAP( dev )	NULL
#endif
#endif

/*
 * Compute order.  Can be made faster.
 */
int DRM(order)( unsigned long size )
{
	int order;
	unsigned long tmp;

	for ( order = 0, tmp = size ; tmp >>= 1 ; ++order );

	if ( size & ~(1 << order) )
		++order;

	return order;
}

int DRM(addmap)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_map_t request;
	drm_local_map_t *map;
	drm_map_list_entry_t *list;
	
	if (!(dev->flags & (FREAD|FWRITE)))
		return DRM_ERR(EACCES); /* Require read/write */

	DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(drm_map_t) );

	map = (drm_local_map_t *) DRM(alloc)( sizeof(*map), DRM_MEM_MAPS );
	if ( !map )
		return DRM_ERR(ENOMEM);

	map->offset = request.offset;
	map->size = request.size;
	map->type = request.type;
	map->flags = request.flags;
	map->mtrr   = -1;
	map->handle = 0;
	
	/* Only allow shared memory to be removable since we only keep enough
	 * book keeping information about shared memory to allow for removal
	 * when processes fork.
	 */
	if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) {
		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
		return DRM_ERR(EINVAL);
	}
	DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
		   map->offset, map->size, map->type );
	if ( (map->offset & PAGE_MASK) || (map->size & PAGE_MASK) ) {
		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
		return DRM_ERR(EINVAL);
	}

	switch ( map->type ) {
	case _DRM_REGISTERS:
	case _DRM_FRAME_BUFFER:
		if ( map->offset + map->size < map->offset ) {
			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
			return DRM_ERR(EINVAL);
		}
#if __REALLY_HAVE_MTRR
		if ( map->type == _DRM_FRAME_BUFFER ||
		     (map->flags & _DRM_WRITE_COMBINING) ) {
#ifdef __FreeBSD__
			int retcode = 0, act;
			struct mem_range_desc mrdesc;
			mrdesc.mr_base = map->offset;
			mrdesc.mr_len = map->size;
			mrdesc.mr_flags = MDF_WRITECOMBINE;
			act = MEMRANGE_SET_UPDATE;
			bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
			retcode = mem_range_attr_set(&mrdesc, &act);
			map->mtrr=1;
#elif defined __NetBSD__
			struct mtrr mtrrmap;
			int one = 1;
			mtrrmap.base = map->offset;
			mtrrmap.len = map->size;
			mtrrmap.type = MTRR_TYPE_WC;
			mtrrmap.flags = MTRR_VALID;
			map->mtrr = mtrr_set( &mtrrmap, &one, p, MTRR_GETSET_KERNEL );
#endif
		}
#endif /* __REALLY_HAVE_MTRR */
		DRM_IOREMAP(map);
		break;

	case _DRM_SHM:
		map->handle = (void *)DRM(alloc)(map->size, DRM_MEM_SAREA);
		DRM_DEBUG( "%ld %d %p\n",
			   map->size, DRM(order)( map->size ), map->handle );
		if ( !map->handle ) {
			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
			return DRM_ERR(ENOMEM);
		}
		map->offset = (unsigned long)map->handle;
		if ( map->flags & _DRM_CONTAINS_LOCK ) {
			dev->lock.hw_lock = map->handle; /* Pointer to lock */
		}
		break;
#if __REALLY_HAVE_AGP
	case _DRM_AGP:
		map->offset += dev->agp->base;
		map->mtrr   = dev->agp->agp_mtrr; /* for getmap */
		break;
#endif
	case _DRM_SCATTER_GATHER:
		if (!dev->sg) {
			DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
			return DRM_ERR(EINVAL);
		}
		map->offset = map->offset + dev->sg->handle;
		break;

	default:
		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
		return DRM_ERR(EINVAL);
	}

	list = DRM(alloc)(sizeof(*list), DRM_MEM_MAPS);
	if(!list) {
		DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
		return DRM_ERR(EINVAL);
	}
	memset(list, 0, sizeof(*list));
	list->map = map;

	DRM_LOCK;
	TAILQ_INSERT_TAIL(dev->maplist, list, link);
	DRM_UNLOCK;

	request.offset = map->offset;
	request.size = map->size;
	request.type = map->type;
	request.flags = map->flags;
	request.mtrr   = map->mtrr;
	request.handle = map->handle;

	if ( request.type != _DRM_SHM ) {
		request.handle = (void *)request.offset;
	}

	DRM_COPY_TO_USER_IOCTL( (drm_map_t *)data, request, sizeof(drm_map_t) );

	return 0;
}


/* Remove a map private from list and deallocate resources if the mapping
 * isn't in use.
 */

int DRM(rmmap)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_map_list_entry_t *list;
	drm_local_map_t *map;
	drm_map_t request;
	int found_maps = 0;

	DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(request) );

	DRM_LOCK;
	TAILQ_FOREACH(list, dev->maplist, link) {
		map = list->map;
		if(map->handle == request.handle &&
		   map->flags & _DRM_REMOVABLE) break;
	}

	/* List has wrapped around to the head pointer, or its empty we didn't
	 * find anything.
	 */
	if(list == NULL) {
		DRM_UNLOCK;
		return DRM_ERR(EINVAL);
	}
	TAILQ_REMOVE(dev->maplist, list, link);
	DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);


	if(!found_maps) {
		switch (map->type) {
		case _DRM_REGISTERS:
		case _DRM_FRAME_BUFFER:
#if __REALLY_HAVE_MTRR
			if (map->mtrr >= 0) {
				int retcode;
#ifdef __FreeBSD__
				int act;
				struct mem_range_desc mrdesc;
				mrdesc.mr_base = map->offset;
				mrdesc.mr_len = map->size;
				mrdesc.mr_flags = MDF_WRITECOMBINE;
				act = MEMRANGE_SET_REMOVE;
				bcopy(DRIVER_NAME, &mrdesc.mr_owner, strlen(DRIVER_NAME));
				retcode = mem_range_attr_set(&mrdesc, &act);
#elif defined __NetBSD__
				struct mtrr mtrrmap;
				int one = 1;
				mtrrmap.base = map->offset;
				mtrrmap.len = map->size;
				mtrrmap.type = 0;
				mtrrmap.flags = 0;
				mtrrmap.owner = p->p_pid;
				retcode = mtrr_set( &mtrrmap, &one, p, MTRR_GETSET_KERNEL);
				DRM_DEBUG("mtrr_del = %d\n", retcode);
#endif
			}
#endif
			DRM(ioremapfree)( map );
			break;
		case _DRM_SHM:
			DRM(free)( map->handle, map->size, DRM_MEM_SAREA );
			break;
		case _DRM_AGP:
		case _DRM_SCATTER_GATHER:
			break;
		}
		DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
	}
	DRM_UNLOCK;
	return 0;
}

#if __HAVE_DMA


static void DRM(cleanup_buf_error)(drm_buf_entry_t *entry)
{
	int i;

	if (entry->seg_count) {
		for (i = 0; i < entry->seg_count; i++) {
			DRM(free)((void *)entry->seglist[i],
					entry->buf_size,
					DRM_MEM_DMA);
		}
		DRM(free)(entry->seglist,
			  entry->seg_count *
			  sizeof(*entry->seglist),
			  DRM_MEM_SEGS);

		entry->seg_count = 0;
	}

   	if(entry->buf_count) {
	   	for(i = 0; i < entry->buf_count; i++) {
			if(entry->buflist[i].dev_private) {
				DRM(free)(entry->buflist[i].dev_private,
					  entry->buflist[i].dev_priv_size,
					  DRM_MEM_BUFS);
			}
		}
		DRM(free)(entry->buflist,
			  entry->buf_count *
			  sizeof(*entry->buflist),
			  DRM_MEM_BUFS);

#if __HAVE_DMA_FREELIST
	   	DRM(freelist_destroy)(&entry->freelist);
#endif

		entry->buf_count = 0;
	}
}

#if __REALLY_HAVE_AGP
int DRM(addbufs_agp)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_desc_t request;
	drm_buf_entry_t *entry;
	drm_buf_t *buf;
	unsigned long offset;
	unsigned long agp_offset;
	int count;
	int order;
	int size;
	int alignment;
	int page_order;
	int total;
	int byte_count;
	int i;
	drm_buf_t **temp_buflist;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) );

	count = request.count;
	order = DRM(order)( request.size );
	size = 1 << order;

	alignment  = (request.flags & _DRM_PAGE_ALIGN)
		? round_page(size) : size;
	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
	total = PAGE_SIZE << page_order;

	byte_count = 0;
	agp_offset = dev->agp->base + request.agp_start;

	DRM_DEBUG( "count:      %d\n",  count );
	DRM_DEBUG( "order:      %d\n",  order );
	DRM_DEBUG( "size:       %d\n",  size );
	DRM_DEBUG( "agp_offset: 0x%lx\n", agp_offset );
	DRM_DEBUG( "alignment:  %d\n",  alignment );
	DRM_DEBUG( "page_order: %d\n",  page_order );
	DRM_DEBUG( "total:      %d\n",  total );

	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) 
		return DRM_ERR(EINVAL);
	if ( dev->queue_count ) 
		return DRM_ERR(EBUSY); /* Not while in use */

	DRM_SPINLOCK( &dev->count_lock );
	if ( dev->buf_use ) {
		DRM_SPINUNLOCK( &dev->count_lock );
		return DRM_ERR(EBUSY);
	}
	atomic_inc( &dev->buf_alloc );
	DRM_SPINUNLOCK( &dev->count_lock );

	DRM_LOCK;
	entry = &dma->bufs[order];
	if ( entry->buf_count ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM); /* May only call once for each order */
	}

	if (count < 0 || count > 4096) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(EINVAL);
	}

	entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
				    DRM_MEM_BUFS );
	if ( !entry->buflist ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	memset( entry->buflist, 0, count * sizeof(*entry->buflist) );

	entry->buf_size = size;
	entry->page_order = page_order;

	offset = 0;

	while ( entry->buf_count < count ) {
		buf          = &entry->buflist[entry->buf_count];
		buf->idx     = dma->buf_count + entry->buf_count;
		buf->total   = alignment;
		buf->order   = order;
		buf->used    = 0;

		buf->offset  = (dma->byte_count + offset);
		buf->bus_address = agp_offset + offset;
		buf->address = (void *)(agp_offset + offset);
		buf->next    = NULL;
		buf->waiting = 0;
		buf->pending = 0;
		buf->dma_wait = 0;
		buf->filp    = NULL;

		buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
		buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
					       DRM_MEM_BUFS );
		if(!buf->dev_private) {
			/* Set count correctly so we free the proper amount. */
			entry->buf_count = count;
			DRM(cleanup_buf_error)(entry);
		}
		memset( buf->dev_private, 0, buf->dev_priv_size );

#if __HAVE_DMA_HISTOGRAM
		buf->time_queued = 0;
		buf->time_dispatched = 0;
		buf->time_completed = 0;
		buf->time_freed = 0;
#endif

		offset += alignment;
		entry->buf_count++;
		byte_count += PAGE_SIZE << page_order;
	}

	DRM_DEBUG( "byte_count: %d\n", byte_count );

	temp_buflist = DRM(realloc)( dma->buflist,
				     dma->buf_count * sizeof(*dma->buflist),
				     (dma->buf_count + entry->buf_count)
				     * sizeof(*dma->buflist),
				     DRM_MEM_BUFS );
	if(!temp_buflist) {
		/* Free the entry because it isn't valid */
		DRM(cleanup_buf_error)(entry);
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	dma->buflist = temp_buflist;

	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
	}

	dma->buf_count += entry->buf_count;
	dma->byte_count += byte_count;

	DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
	DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );

#if __HAVE_DMA_FREELIST
	DRM(freelist_create)( &entry->freelist, entry->buf_count );
	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
	}
#endif
	DRM_UNLOCK;

	request.count = entry->buf_count;
	request.size = size;

	DRM_COPY_TO_USER_IOCTL( (drm_buf_desc_t *)data, request, sizeof(request) );

	dma->flags = _DRM_DMA_USE_AGP;

	atomic_dec( &dev->buf_alloc );
	return 0;
}
#endif /* __REALLY_HAVE_AGP */

#if __HAVE_PCI_DMA
int DRM(addbufs_pci)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_desc_t request;
	int count;
	int order;
	int size;
	int total;
	int page_order;
	drm_buf_entry_t *entry;
	unsigned long page;
	drm_buf_t *buf;
	int alignment;
	unsigned long offset;
	int i;
	int byte_count;
	int page_count;
	unsigned long *temp_pagelist;
	drm_buf_t **temp_buflist;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) );

	count = request.count;
	order = DRM(order)( request.size );
	size = 1 << order;

	DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
		   request.count, request.size, size,
		   order, dev->queue_count );

	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) 
		return DRM_ERR(EINVAL);
	if ( dev->queue_count ) 
		return DRM_ERR(EBUSY); /* Not while in use */

	alignment = (request.flags & _DRM_PAGE_ALIGN)
		? round_page(size) : size;
	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
	total = PAGE_SIZE << page_order;

	DRM_SPINLOCK( &dev->count_lock );
	if ( dev->buf_use ) {
		DRM_SPINUNLOCK( &dev->count_lock );
		return DRM_ERR(EBUSY);
	}
	atomic_inc( &dev->buf_alloc );
	DRM_SPINUNLOCK( &dev->count_lock );

	DRM_LOCK;
	entry = &dma->bufs[order];
	if ( entry->buf_count ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);	/* May only call once for each order */
	}

	if (count < 0 || count > 4096) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(EINVAL);
	}

	entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
				    DRM_MEM_BUFS );
	if ( !entry->buflist ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	memset( entry->buflist, 0, count * sizeof(*entry->buflist) );

	entry->seglist = DRM(alloc)( count * sizeof(*entry->seglist),
				    DRM_MEM_SEGS );
	if ( !entry->seglist ) {
		DRM(free)( entry->buflist,
			  count * sizeof(*entry->buflist),
			  DRM_MEM_BUFS );
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	memset( entry->seglist, 0, count * sizeof(*entry->seglist) );

	temp_pagelist = DRM(realloc)( dma->pagelist,
				      dma->page_count * sizeof(*dma->pagelist),
				      (dma->page_count + (count << page_order))
				      * sizeof(*dma->pagelist),
				      DRM_MEM_PAGES );
	if(!temp_pagelist) {
		DRM(free)( entry->buflist,
			   count * sizeof(*entry->buflist),
			   DRM_MEM_BUFS );
		DRM(free)( entry->seglist,
			   count * sizeof(*entry->seglist),
			   DRM_MEM_SEGS );
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}

	dma->pagelist = temp_pagelist;
	DRM_DEBUG( "pagelist: %d entries\n",
		   dma->page_count + (count << page_order) );

	entry->buf_size	= size;
	entry->page_order = page_order;
	byte_count = 0;
	page_count = 0;

	while ( entry->buf_count < count ) {
		page = (unsigned long)DRM(alloc)( size, DRM_MEM_DMA );
		if ( !page ) break;
		entry->seglist[entry->seg_count++] = page;
		for ( i = 0 ; i < (1 << page_order) ; i++ ) {
			DRM_DEBUG( "page %d @ 0x%08lx\n",
				   dma->page_count + page_count,
				   page + PAGE_SIZE * i );
			dma->pagelist[dma->page_count + page_count++]
				= page + PAGE_SIZE * i;
		}
		for ( offset = 0 ;
		      offset + size <= total && entry->buf_count < count ;
		      offset += alignment, ++entry->buf_count ) {
			buf	     = &entry->buflist[entry->buf_count];
			buf->idx     = dma->buf_count + entry->buf_count;
			buf->total   = alignment;
			buf->order   = order;
			buf->used    = 0;
			buf->offset  = (dma->byte_count + byte_count + offset);
			buf->address = (void *)(page + offset);
			buf->next    = NULL;
			buf->waiting = 0;
			buf->pending = 0;
			buf->dma_wait = 0;
			buf->filp    = NULL;
#if __HAVE_DMA_HISTOGRAM
			buf->time_queued     = 0;
			buf->time_dispatched = 0;
			buf->time_completed  = 0;
			buf->time_freed      = 0;
#endif
			DRM_DEBUG( "buffer %d @ %p\n",
				   entry->buf_count, buf->address );
		}
		byte_count += PAGE_SIZE << page_order;
	}

	temp_buflist = DRM(realloc)( dma->buflist,
				     dma->buf_count * sizeof(*dma->buflist),
				     (dma->buf_count + entry->buf_count)
				     * sizeof(*dma->buflist),
				     DRM_MEM_BUFS );
	if(!temp_buflist) {
		/* Free the entry because it isn't valid */
		DRM(cleanup_buf_error)(entry);
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	dma->buflist = temp_buflist;

	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
	}

	dma->buf_count += entry->buf_count;
	dma->seg_count += entry->seg_count;
	dma->page_count += entry->seg_count << page_order;
	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);

#if __HAVE_DMA_FREELIST
	DRM(freelist_create)( &entry->freelist, entry->buf_count );
	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
	}
#endif
	DRM_UNLOCK;

	request.count = entry->buf_count;
	request.size = size;

	DRM_COPY_TO_USER_IOCTL( (drm_buf_desc_t *)data, request, sizeof(request) );

	atomic_dec( &dev->buf_alloc );
	return 0;

}
#endif /* __HAVE_PCI_DMA */

#if __REALLY_HAVE_SG
int DRM(addbufs_sg)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_desc_t request;
	drm_buf_entry_t *entry;
	drm_buf_t *buf;
	unsigned long offset;
	unsigned long agp_offset;
	int count;
	int order;
	int size;
	int alignment;
	int page_order;
	int total;
	int byte_count;
	int i;
	drm_buf_t **temp_buflist;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) );

	count = request.count;
	order = DRM(order)( request.size );
	size = 1 << order;

	alignment  = (request.flags & _DRM_PAGE_ALIGN)
		? round_page(size) : size;
	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
	total = PAGE_SIZE << page_order;

	byte_count = 0;
	agp_offset = request.agp_start;

	DRM_DEBUG( "count:      %d\n",  count );
	DRM_DEBUG( "order:      %d\n",  order );
	DRM_DEBUG( "size:       %d\n",  size );
	DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
	DRM_DEBUG( "alignment:  %d\n",  alignment );
	DRM_DEBUG( "page_order: %d\n",  page_order );
	DRM_DEBUG( "total:      %d\n",  total );

	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) 
		return DRM_ERR(EINVAL);
	if ( dev->queue_count ) return DRM_ERR(EBUSY); /* Not while in use */

	DRM_SPINLOCK( &dev->count_lock );
	if ( dev->buf_use ) {
		DRM_SPINUNLOCK( &dev->count_lock );
		return DRM_ERR(EBUSY);
	}
	atomic_inc( &dev->buf_alloc );
	DRM_SPINUNLOCK( &dev->count_lock );

	DRM_LOCK;
	entry = &dma->bufs[order];
	if ( entry->buf_count ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM); /* May only call once for each order */
	}

	if (count < 0 || count > 4096) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(EINVAL);
	}

	entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
				     DRM_MEM_BUFS );
	if ( !entry->buflist ) {
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	memset( entry->buflist, 0, count * sizeof(*entry->buflist) );

	entry->buf_size = size;
	entry->page_order = page_order;

	offset = 0;

	while ( entry->buf_count < count ) {
		buf          = &entry->buflist[entry->buf_count];
		buf->idx     = dma->buf_count + entry->buf_count;
		buf->total   = alignment;
		buf->order   = order;
		buf->used    = 0;

		buf->offset  = (dma->byte_count + offset);
		buf->bus_address = agp_offset + offset;
		buf->address = (void *)(agp_offset + offset + dev->sg->handle);
		buf->next    = NULL;
		buf->waiting = 0;
		buf->pending = 0;
		buf->dma_wait = 0;
		buf->filp    = NULL;

		buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
		buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
					       DRM_MEM_BUFS );
		if(!buf->dev_private) {
			/* Set count correctly so we free the proper amount. */
			entry->buf_count = count;
			DRM(cleanup_buf_error)(entry);
			DRM_UNLOCK;
			atomic_dec( &dev->buf_alloc );
			return DRM_ERR(ENOMEM);
		}

		memset( buf->dev_private, 0, buf->dev_priv_size );

# if __HAVE_DMA_HISTOGRAM
		buf->time_queued = 0;
		buf->time_dispatched = 0;
		buf->time_completed = 0;
		buf->time_freed = 0;
# endif
		DRM_DEBUG( "buffer %d @ %p\n",
			   entry->buf_count, buf->address );

		offset += alignment;
		entry->buf_count++;
		byte_count += PAGE_SIZE << page_order;
	}

	DRM_DEBUG( "byte_count: %d\n", byte_count );

	temp_buflist = DRM(realloc)( dma->buflist,
				     dma->buf_count * sizeof(*dma->buflist),
				     (dma->buf_count + entry->buf_count)
				     * sizeof(*dma->buflist),
				     DRM_MEM_BUFS );
	if(!temp_buflist) {
		/* Free the entry because it isn't valid */
		DRM(cleanup_buf_error)(entry);
		DRM_UNLOCK;
		atomic_dec( &dev->buf_alloc );
		return DRM_ERR(ENOMEM);
	}
	dma->buflist = temp_buflist;

	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
	}

	dma->buf_count += entry->buf_count;
	dma->byte_count += byte_count;

	DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
	DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );

#if __HAVE_DMA_FREELIST
	DRM(freelist_create)( &entry->freelist, entry->buf_count );
	for ( i = 0 ; i < entry->buf_count ; i++ ) {
		DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
	}
#endif
	DRM_UNLOCK;

	request.count = entry->buf_count;
	request.size = size;

	DRM_COPY_TO_USER_IOCTL( (drm_buf_desc_t *)data, request, sizeof(request) );

	dma->flags = _DRM_DMA_USE_SG;

	atomic_dec( &dev->buf_alloc );
	return 0;
}
#endif /* __REALLY_HAVE_SG */

int DRM(addbufs)( DRM_IOCTL_ARGS )
{
	drm_buf_desc_t request;

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) );

#if __REALLY_HAVE_AGP
	if ( request.flags & _DRM_AGP_BUFFER )
		return DRM(addbufs_agp)( kdev, cmd, data, flags, p, filp );
	else
#endif
#if __REALLY_HAVE_SG
	if ( request.flags & _DRM_SG_BUFFER )
		return DRM(addbufs_sg)( kdev, cmd, data, flags, p, filp );
	else
#endif
#if __HAVE_PCI_DMA
		return DRM(addbufs_pci)( kdev, cmd, data, flags, p, filp );
#else
		return DRM_ERR(EINVAL);
#endif
}

int DRM(infobufs)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_info_t request;
	int i;
	int count;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_SPINLOCK( &dev->count_lock );
	if ( atomic_read( &dev->buf_alloc ) ) {
		DRM_SPINUNLOCK( &dev->count_lock );
		return DRM_ERR(EBUSY);
	}
	++dev->buf_use;		/* Can't allocate more after this call */
	DRM_SPINUNLOCK( &dev->count_lock );

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_info_t *)data, sizeof(request) );

	for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
		if ( dma->bufs[i].buf_count ) ++count;
	}

	DRM_DEBUG( "count = %d\n", count );

	if ( request.count >= count ) {
		for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
			if ( dma->bufs[i].buf_count ) {
				drm_buf_desc_t *to = &request.list[count];
				drm_buf_entry_t *from = &dma->bufs[i];
				drm_freelist_t *list = &dma->bufs[i].freelist;
				if ( DRM_COPY_TO_USER( &to->count,
						   &from->buf_count,
						   sizeof(from->buf_count) ) ||
				     DRM_COPY_TO_USER( &to->size,
						   &from->buf_size,
						   sizeof(from->buf_size) ) ||
				     DRM_COPY_TO_USER( &to->low_mark,
						   &list->low_mark,
						   sizeof(list->low_mark) ) ||
				     DRM_COPY_TO_USER( &to->high_mark,
						   &list->high_mark,
						   sizeof(list->high_mark) ) )
					return DRM_ERR(EFAULT);

				DRM_DEBUG( "%d %d %d %d %d\n",
					   i,
					   dma->bufs[i].buf_count,
					   dma->bufs[i].buf_size,
					   dma->bufs[i].freelist.low_mark,
					   dma->bufs[i].freelist.high_mark );
				++count;
			}
		}
	}
	request.count = count;

	DRM_COPY_TO_USER_IOCTL( (drm_buf_info_t *)data, request, sizeof(request) );

	return 0;
}

int DRM(markbufs)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_desc_t request;
	int order;
	drm_buf_entry_t *entry;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) );

	DRM_DEBUG( "%d, %d, %d\n",
		   request.size, request.low_mark, request.high_mark );
	order = DRM(order)( request.size );
	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) 
		return DRM_ERR(EINVAL);
	entry = &dma->bufs[order];

	if ( request.low_mark < 0 || request.low_mark > entry->buf_count )
		return DRM_ERR(EINVAL);
	if ( request.high_mark < 0 || request.high_mark > entry->buf_count )
		return DRM_ERR(EINVAL);

	entry->freelist.low_mark  = request.low_mark;
	entry->freelist.high_mark = request.high_mark;

	return 0;
}

int DRM(freebufs)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	drm_buf_free_t request;
	int i;
	int idx;
	drm_buf_t *buf;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_free_t *)data, sizeof(request) );

	DRM_DEBUG( "%d\n", request.count );
	for ( i = 0 ; i < request.count ; i++ ) {
		if ( DRM_COPY_FROM_USER( &idx,
				     &request.list[i],
				     sizeof(idx) ) )
			return DRM_ERR(EFAULT);
		if ( idx < 0 || idx >= dma->buf_count ) {
			DRM_ERROR( "Index %d (of %d max)\n",
				   idx, dma->buf_count - 1 );
			return DRM_ERR(EINVAL);
		}
		buf = dma->buflist[idx];
		if ( buf->filp != filp ) {
			DRM_ERROR("Process %d freeing buffer not owned\n",
				   DRM_CURRENTPID);
			return DRM_ERR(EINVAL);
		}
		DRM(free_buffer)( dev, buf );
	}

	return 0;
}

int DRM(mapbufs)( DRM_IOCTL_ARGS )
{
	DRM_DEVICE;
	drm_device_dma_t *dma = dev->dma;
	int retcode = 0;
	const int zero = 0;
	vm_offset_t virtual, address;
#ifdef __FreeBSD__
#if __FreeBSD_version >= 500000
	struct vmspace *vms = p->td_proc->p_vmspace;
#else
	struct vmspace *vms = p->p_vmspace;
#endif
#endif /* __FreeBSD__ */
#ifdef __NetBSD__
	struct vnode *vn;
	struct vmspace *vms = p->p_vmspace;
#endif /* __NetBSD__ */

	drm_buf_map_t request;
	int i;

	if ( !dma ) return DRM_ERR(EINVAL);

	DRM_SPINLOCK( &dev->count_lock );
	if ( atomic_read( &dev->buf_alloc ) ) {
		DRM_SPINUNLOCK( &dev->count_lock );
		return DRM_ERR(EBUSY);
	}
	dev->buf_use++;		/* Can't allocate more after this call */
	DRM_SPINUNLOCK( &dev->count_lock );

	DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_map_t *)data, sizeof(request) );

#ifdef __NetBSD__
	if(!vfinddev(kdev, VCHR, &vn))
		return 0;	/* FIXME: Shouldn't this be EINVAL or something? */
#endif /* __NetBSD__ */

	if ( request.count >= dma->buf_count ) {
		if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) ||
		     (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) {
			drm_local_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );

			if ( !map ) {
				retcode = EINVAL;
				goto done;
			}

#ifdef __FreeBSD__
			virtual = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ);
			retcode = vm_mmap(&vms->vm_map,
					  &virtual,
					  round_page(map->size),
					  PROT_READ|PROT_WRITE, VM_PROT_ALL,
					  MAP_SHARED,
					  SLIST_FIRST(&kdev->si_hlist),
					  (unsigned long)map->offset );
#elif defined(__NetBSD__)
			virtual = round_page((vaddr_t)vms->vm_daddr + MAXDSIZ);
			retcode = uvm_mmap(&vms->vm_map,
					   (vaddr_t *)&virtual,
					   round_page(map->size),
					   UVM_PROT_READ | UVM_PROT_WRITE,
					   UVM_PROT_ALL, MAP_SHARED,