diff -Naurp old/src/external/mit/xorg/lib/libdrm/drm/Makefile new/src/external/mit/xorg/lib/libdrm/drm/Makefile
--- old/src/external/mit/xorg/lib/libdrm/drm/Makefile	2010-05-23 01:19:24.000000000 +0200
+++ new/src/external/mit/xorg/lib/libdrm/drm/Makefile	2011-02-08 11:14:00.000000000 +0100
@@ -4,29 +4,11 @@
 
 .include <bsd.own.mk>
 
-.PATH:	${X11SRCDIR.drm}/include/drm
-.PATH:	${X11SRCDIR.drm}/intel
-.PATH:	${X11SRCDIR.drm}/radeon
+.PATH:	${NETBSDSRCDIR}/sys/dev/pci/drm
 
 INCS=	drm.h \
-	drm_mode.h \
 	drm_sarea.h \
-	i915_drm.h \
-	intel_bufmgr.h \
-	mach64_drm.h \
-	mga_drm.h \
-	nouveau_drm.h \
-	r128_drm.h \
-	radeon_bo.h \
-	radeon_bo_gem.h \
-	radeon_bo_int.h \
-	radeon_cs.h \
-	radeon_cs_gem.h \
-	radeon_cs_int.h \
-	radeon_drm.h \
-	savage_drm.h \
-	sis_drm.h \
-	via_drm.h
+	i915_drm.h
 
 INCSDIR=${X11INCDIR}/libdrm
 
diff -Naurp old/src/external/mit/xorg/lib/libdrm/Makefile new/src/external/mit/xorg/lib/libdrm/Makefile
--- old/src/external/mit/xorg/lib/libdrm/Makefile	2010-05-23 01:19:24.000000000 +0200
+++ new/src/external/mit/xorg/lib/libdrm/Makefile	2011-02-08 11:14:00.000000000 +0100
@@ -5,14 +5,14 @@
 LIB=	drm
 .PATH:	${X11SRCDIR.${LIB}}
 
-SRCS=	xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c
+SRCS=	xf86drm.c xf86drmHash.c xf86drmMode.c xf86drmRandom.c xf86drmSL.c
 
 INCS=	xf86drm.h xf86drmMode.h
 INCSDIR=${X11INCDIR}
 
 CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/libdrm
 
-SUBDIR=	drm kms
+SUBDIR=	drm
 
 PKGCONFIG=	libdrm
 PKGDIST=	${LIB}
diff -Naurp old/src/external/mit/xorg/lib/libdrm_intel/Makefile new/src/external/mit/xorg/lib/libdrm_intel/Makefile
--- old/src/external/mit/xorg/lib/libdrm_intel/Makefile	2010-06-03 11:43:16.000000000 +0200
+++ new/src/external/mit/xorg/lib/libdrm_intel/Makefile	2011-02-08 11:14:00.000000000 +0100
@@ -7,6 +7,9 @@ LIB=	drm_intel
 
 SRCS=	intel_bufmgr.c intel_bufmgr_fake.c intel_bufmgr_gem.c mm.c
 
+INCS=	intel_bufmgr.h
+INCSDIR=${X11INCDIR}/libdrm
+
 CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/libdrm
 CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/X11 -I${X11SRCDIR.drm}
 
diff -Naurp old/src/external/mit/xorg/server/drivers/xf86-video-intel/Makefile new/src/external/mit/xorg/server/drivers/xf86-video-intel/Makefile
--- old/src/external/mit/xorg/server/drivers/xf86-video-intel/Makefile	2011-01-19 00:33:52.000000000 +0100
+++ new/src/external/mit/xorg/server/drivers/xf86-video-intel/Makefile	2011-02-08 11:14:00.000000000 +0100
@@ -6,25 +6,39 @@ DRIVER_NAME=	intel_drv
 SRCS=		drmmode_display.c i810_accel.c i810_cursor.c i810_dga.c
 SRCS+=		i810_driver.c i810_io.c i810_memory.c i810_video.c
 SRCS+=		i810_wmark.c i830_3d.c i830_accel.c i830_bios.c
-SRCS+=		i830_batchbuffer.c i830_crt.c i830_cursor.c i830_debug.c
+SRCS+=		i830_batchbuffer.c i830_crt.c i830_cursor.c
 SRCS+=		i830_display.c i830_quirks.c i830_driver.c i830_dvo.c
 SRCS+=		i830_hdmi.c i830_i2c.c i830_io.c i830_lvds.c i830_memory.c
 SRCS+=		i830_modes.c i830_video.c i830_sdvo.c i830_tv.c
-SRCS+=		i915_3d.c i915_video.c i965_video.c 
-SRCS+=		i830_xaa.c i830_render.c i915_render.c i965_render.c
-SRCS+=		i830_dri.c i830_exa.c
-SRCS+=		i830_hwmc.c i915_hwmc.c i965_hwmc.c
+SRCS+=		i915_3d.c i915_video.c i965_video.c
+SRCS+=		i830_uxa.c i830_render.c i915_render.c i965_render.c
+SRCS+=		i810_dri.c i830_dri.c i810_hwmc.c
+#SRCS+=		i830_hwmc.c
+SRCS+=		uxa.c uxa-accel.c uxa-glyphs.c uxa-render.c uxa-unaccel.c
 MAN=		intel.4
 
-CPPFLAGS+=      -I${DESTDIR}${X11INCDIR}/X11
-CPPFLAGS+=      -I${DESTDIR}${X11INCDIR}/X11/dri
-CPPFLAGS+=      -I${DESTDIR}${X11INCDIR}/libdrm
-CPPFLAGS+=	-DI830_XV -DI830_USE_XAA -DI830_USE_EXA -DINTEL_XVMC
+CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/X11
+CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/X11/dri
+CPPFLAGS+=	-I${DESTDIR}${X11INCDIR}/libdrm
+CPPFLAGS+=	-I${X11SRCDIR.${DRIVER}}/uxa
+CPPFLAGS+=	-I${X11SRCDIR.${DRIVER}}/src/render_program
+#CPPFLAGS+=	-DINTEL_XVMC
 
 LDADD+=		-ldrm_intel
 
 .include "../Makefile.xf86-driver"
 
+.PATH:	${X11SRCDIR.${DRIVER}}/uxa
+
+# configure disables XvMC support by default
+CPPFLAGS+=	-UENABLE_XVMC -UINTEL_XVMC
+
+# no KMS support
+CPPFLAGS+=	-UKMS_ONLY
+
+# debug messages are most welcome (for now)
+CPPFLAGS+=	-DI830DEBUG
+
 SUBDIR= ch7017 ch7xxx ivch sil164 tfp410
 
 .include <bsd.subdir.mk>
diff -Naurp old/src/sys/arch/amd64/conf/GENERIC new/src/sys/arch/amd64/conf/GENERIC
--- old/src/sys/arch/amd64/conf/GENERIC	2011-01-26 01:25:55.000000000 +0100
+++ new/src/sys/arch/amd64/conf/GENERIC	2011-02-08 11:14:00.000000000 +0100
@@ -375,14 +375,18 @@ pcppi0		at isa?
 sysbeep0	at pcppi?
 
 # DRI driver
-i915drm*	at vga?		# Intel i915, i945 DRM driver
-mach64drm*	at vga?		# mach64 (3D Rage Pro, Rage) DRM driver
-mgadrm*		at vga?		# Matrox G[24]00, G[45]50 DRM driver
-r128drm*	at vga?		# ATI Rage 128 DRM driver
-radeondrm*	at vga?		# ATI Radeon DRM driver
-savagedrm*	at vga?		# S3 Savage DRM driver
-sisdrm*		at vga?		# SiS DRM driver
-tdfxdrm*	at vga?		# 3dfx (voodoo) DRM driver
+#i915drm*	at vga?		# Intel i915, i945 DRM driver
+#mach64drm*	at vga?		# mach64 (3D Rage Pro, Rage) DRM driver
+#mgadrm*		at vga?		# Matrox G[24]00, G[45]50 DRM driver
+#r128drm*	at vga?		# ATI Rage 128 DRM driver
+#radeondrm*	at vga?		# ATI Radeon DRM driver
+#savagedrm*	at vga?		# S3 Savage DRM driver
+#sisdrm*		at vga?		# SiS DRM driver
+#tdfxdrm*	at vga?		# 3dfx (voodoo) DRM driver
+
+# New DRM/GEM driver ported from OpenBSD (Intel only)
+inteldrm*	at vga?
+drmdev*		at inteldrm?
 
 # Cryptographic Devices
 
diff -Naurp old/src/sys/arch/i386/conf/GENERIC new/src/sys/arch/i386/conf/GENERIC
--- old/src/sys/arch/i386/conf/GENERIC	2011-01-26 19:48:12.000000000 +0100
+++ new/src/sys/arch/i386/conf/GENERIC	2011-02-08 11:14:00.000000000 +0100
@@ -565,15 +565,19 @@ pcppi0		at isa?
 sysbeep0	at pcppi?
 
 # DRI driver
-i915drm*	at vga?		# Intel i915, i945 DRM driver
-mach64drm*	at vga?		# mach64 (3D Rage Pro, Rage) DRM driver
-mgadrm*		at vga?		# Matrox G[24]00, G[45]50 DRM driver
-r128drm*	at vga?		# ATI Rage 128 DRM driver
-radeondrm*	at vga?		# ATI Radeon DRM driver
-savagedrm*	at vga?		# S3 Savage DRM driver
-sisdrm*		at vga?		# SiS DRM driver
-tdfxdrm*	at vga?		# 3dfx (voodoo) DRM driver
-viadrm*		at vga?		# VIA DRM driver
+#i915drm*	at vga?		# Intel i915, i945 DRM driver
+#mach64drm*	at vga?		# mach64 (3D Rage Pro, Rage) DRM driver
+#mgadrm*		at vga?		# Matrox G[24]00, G[45]50 DRM driver
+#r128drm*	at vga?		# ATI Rage 128 DRM driver
+#radeondrm*	at vga?		# ATI Radeon DRM driver
+#savagedrm*	at vga?		# S3 Savage DRM driver
+#sisdrm*		at vga?		# SiS DRM driver
+#tdfxdrm*	at vga?		# 3dfx (voodoo) DRM driver
+#viadrm*		at vga?		# VIA DRM driver
+
+# New DRM/GEM driver ported from OpenBSD (Intel only)
+inteldrm*	at vga?
+drmdev*		at inteldrm?
 
 # Serial Devices
 
diff -Naurp old/src/sys/arch/i386/eisa/eisa_machdep.c new/src/sys/arch/i386/eisa/eisa_machdep.c
--- old/src/sys/arch/i386/eisa/eisa_machdep.c	2009-11-18 00:51:59.000000000 +0100
+++ new/src/sys/arch/i386/eisa/eisa_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -93,6 +93,7 @@ __KERNEL_RCSID(0, "$NetBSD: eisa_machdep
  * of these funcions.
  */
 struct x86_bus_dma_tag eisa_bus_dma_tag = {
+	NULL,			/* cookie */
 	0,			/* _tag_needs_free */
 	0,			/* _bounce_thresh */
 	0,			/* _bounce_alloc_lo */
diff -Naurp old/src/sys/arch/i386/mca/mca_machdep.c new/src/sys/arch/i386/mca/mca_machdep.c
--- old/src/sys/arch/i386/mca/mca_machdep.c	2010-03-23 22:18:23.000000000 +0100
+++ new/src/sys/arch/i386/mca/mca_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -101,6 +101,7 @@ static void	_mca_bus_dmamap_sync(bus_dma
 #define	MCA_DMA_BOUNCE_THRESHOLD	(16 * 1024 * 1024)
 
 struct x86_bus_dma_tag mca_bus_dma_tag = {
+	NULL,					/* cookie */
 	0,
 	MCA_DMA_BOUNCE_THRESHOLD,		/* _bounce_thresh */
 	0,					/* _bounce_alloc_lo */
diff -Naurp old/src/sys/arch/x86/conf/files.x86 new/src/sys/arch/x86/conf/files.x86
--- old/src/sys/arch/x86/conf/files.x86	2010-07-18 11:29:12.000000000 +0200
+++ new/src/sys/arch/x86/conf/files.x86	2011-02-08 11:14:00.000000000 +0100
@@ -66,6 +66,7 @@ file 	arch/x86/x86/patch.c
 file	arch/x86/x86/platform.c
 file 	arch/x86/x86/pmap.c
 file	arch/x86/x86/procfs_machdep.c	procfs
+file	arch/x86/x86/sg_dma.c
 file	arch/x86/x86/sys_machdep.c
 file	arch/x86/x86/syscall.c
 file	arch/x86/x86/vm_machdep.c
diff -Naurp old/src/sys/arch/x86/include/bus.h new/src/sys/arch/x86/include/bus.h
--- old/src/sys/arch/x86/include/bus.h	2010-04-28 21:17:04.000000000 +0200
+++ new/src/sys/arch/x86/include/bus.h	2011-02-08 11:14:00.000000000 +0100
@@ -111,6 +111,13 @@ typedef struct x86_bus_dmamap		*bus_dmam
 typedef struct x86_bus_dma_segment {
 	bus_addr_t	ds_addr;	/* DMA address */
 	bus_size_t	ds_len;		/* length of transfer */
+	/*
+	 * Ugh. need this so can pass alignment down from bus_dmamem_alloc
+	 * to scatter gather maps. only the first one is used so the rest is
+	 * wasted space. bus_dma could do with fixing the api for this.
+	 */
+	bus_size_t	_ds_boundary;	/* don't cross */
+	bus_size_t	_ds_align;	/* align to me */
 } bus_dma_segment_t;
 
 /*
@@ -142,4 +149,11 @@ struct x86_bus_dmamap {
 
 #include <sys/bus_proto.h>
 
+/*
+ * Used to tune _bus_dmamem_alloc_range() for sg_dmamem_alloc().
+ * See also comment in struct x86_bus_dma_segment.
+ * XXX Fix this!
+ */
+#define	BUS_DMA_SG		0x8000	/* Internal. memory is for SG map */
+
 #endif /* _X86_BUS_H_ */
diff -Naurp old/src/sys/arch/x86/include/bus_private.h new/src/sys/arch/x86/include/bus_private.h
--- old/src/sys/arch/x86/include/bus_private.h	2010-11-12 14:40:11.000000000 +0100
+++ new/src/sys/arch/x86/include/bus_private.h	2011-02-08 11:14:00.000000000 +0100
@@ -192,6 +192,8 @@ _bus_virt_to_bus(struct pmap *pm, vaddr_
 #endif
 
 struct x86_bus_dma_tag {
+	void	*_cookie;		/* cookie used in the guts */
+
 	/*
 	 * The `bounce threshold' is checked while we are loading
 	 * the DMA map.  If the physical address of the segment
diff -Naurp old/src/sys/arch/x86/include/sg_dma.h new/src/sys/arch/x86/include/sg_dma.h
--- old/src/sys/arch/x86/include/sg_dma.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/arch/x86/include/sg_dma.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,135 @@
+/*	$OpenBSD: bus.h,v 1.24 2010/09/06 19:05:48 kettenis Exp $	*/
+/*	$NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1996 Charles M. Hannum.  All rights reserved.
+ * Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.
+ * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Christopher G. Demetriou
+ *	for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _X86_SG_DMA_H_
+#define _X86_SG_DMA_H_
+
+#include <sys/types.h>
+#include <sys/extent.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/tree.h>
+
+#include <machine/bus.h>
+
+/* Scatter gather bus_dma functions. */
+struct sg_cookie {
+	kmutex_t	 sg_mtx;
+	struct extent	*sg_ex;
+	void		*sg_hdl;
+
+	void		(*bind_page)(void *, bus_addr_t, paddr_t, int);
+	void		(*unbind_page)(void *, bus_addr_t);
+	void		(*flush_tlb)(void *);
+};
+
+/*
+ * per-map DVMA page table
+ */
+struct sg_page_entry {
+	SPLAY_ENTRY(sg_page_entry)	spe_node;
+	paddr_t				spe_pa;
+	bus_addr_t			spe_va;
+};
+
+/* for sg_dma this will be in the map's dm_cookie. */
+struct sg_page_map {
+	SPLAY_HEAD(sg_page_tree, sg_page_entry) spm_tree;
+
+	void			*spm_origbuf;	/* pointer to original data */
+	int			 spm_buftype;	/* type of data */
+	struct proc		*spm_proc;	/* proc that owns the mapping */
+
+	int			 spm_maxpage;	/* Size of allocated page map */
+	int			 spm_pagecnt;	/* Number of entries in use */
+	bus_addr_t		 spm_start;	/* dva when bound */
+	bus_size_t		 spm_size;	/* size of bound map */
+	struct sg_page_entry	 spm_map[1];
+};
+
+struct sg_cookie	*sg_dmatag_init(char *, void *, bus_addr_t, bus_size_t,
+			    void (*)(void *, bus_addr_t, paddr_t, int),
+			    void (*)(void *, bus_addr_t), void (*)(void *));
+void	sg_dmatag_destroy(struct sg_cookie *);
+int	sg_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
+	    bus_size_t, int, bus_dmamap_t *);
+void	sg_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
+void	sg_dmamap_set_alignment(bus_dma_tag_t, bus_dmamap_t, u_long);
+int	sg_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
+	    struct proc *, int);
+int	sg_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
+	    struct mbuf *, int);
+int	sg_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int);
+int	sg_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *,
+	    int, bus_size_t, int);
+void	sg_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
+int	sg_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
+	    struct proc *, int, int *, int);
+int	sg_dmamap_load_physarray(bus_dma_tag_t, bus_dmamap_t, paddr_t *,
+	    int, int, int *, int);
+int	sg_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t,
+	    bus_dma_segment_t *, int, int *, int);
+
+#endif /* _X86_SG_DMA_H_ */
diff -Naurp old/src/sys/arch/x86/isa/isa_machdep.c new/src/sys/arch/x86/isa/isa_machdep.c
--- old/src/sys/arch/x86/isa/isa_machdep.c	2009-08-19 17:04:27.000000000 +0200
+++ new/src/sys/arch/x86/isa/isa_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -96,6 +96,7 @@ __KERNEL_RCSID(0, "$NetBSD: isa_machdep.
 static int _isa_dma_may_bounce(bus_dma_tag_t, bus_dmamap_t, int, int *);
 
 struct x86_bus_dma_tag isa_bus_dma_tag = {
+	NULL,				/* cookie */
 	0,				/* _tag_needs_free */
 	ISA_DMA_BOUNCE_THRESHOLD,	/* _bounce_thresh */
 	0,				/* _bounce_alloc_lo */
diff -Naurp old/src/sys/arch/x86/pci/agp_machdep.c new/src/sys/arch/x86/pci/agp_machdep.c
--- old/src/sys/arch/x86/pci/agp_machdep.c	2006-12-18 13:11:33.000000000 +0100
+++ new/src/sys/arch/x86/pci/agp_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -1,23 +1,464 @@
-/*	$NetBSD: agp_machdep.c,v 1.1 2006/12/18 12:11:33 christos Exp $	*/
+/*	$OpenBSD: agp_machdep.c,v 1.6 2010/05/10 22:06:04 oga Exp $	*/
 
-#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: agp_machdep.c,v 1.1 2006/12/18 12:11:33 christos Exp $");
+/*
+ * Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2002 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
 #include <sys/types.h>
 #include <sys/device.h>
-
-#include <machine/cpu.h>
-#include <machine/bus.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/agpvar.h>
 #include <dev/pci/agpreg.h>
 
+#include <machine/cpu.h>
 #include <machine/cpufunc.h>
+#include <machine/bus.h>
+#include <machine/bus_private.h>
+
+#include <x86/sg_dma.h>
+
+#include "agp_i810.h"
+
+/* bus_dma functions */
+
+#if NAGP_I810 > 0
+void	intagp_dma_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+	    bus_size_t, int);
+#endif /* NAGP_I810 > 0 */
+
+static void	agp_sg_bind_page(void *, bus_addr_t, paddr_t, int);
+static void	agp_sg_unbind_page(void *, bus_addr_t);
+static void	agp_sg_flush_tlb(void *);
 
 void
 agp_flush_cache(void)
 {
-        wbinvd();
+	wbinvd();
+}
+
+void
+agp_flush_cache_range(vaddr_t va, vsize_t sz)
+{
+#if defined(__HAVE_PMAP_FLUSH_CACHE)
+	pmap_flush_cache(va, sz);
+#else /* defined(__HAVE_PMAP_FLUSH_CACHE) */
+	wbinvd();
+#endif /* defined(__HAVE_PMAP_FLUSH_CACHE) */
+}
+
+/*
+ * functions for bus_dma used by drm for GEM
+ *
+ * We use the sg_dma backend (also used by iommu) to provide the actual
+ * implementation, so all we need provide is the magic to create the tag, and
+ * the appropriate callbacks.
+ *
+ * We give the backend drivers a chance to honour the bus_dma flags, some of
+ * these may be used, for example to provide snooped mappings (intagp).
+ * For intagp at least, we honour the BUS_DMA_COHERENT flag, though it is not
+ * used often, and is * technically to be used for dmamem_map, we use it for
+ * dmamap_load since adding coherency involes flags to the gtt pagetables.
+ * We only use it for very special circumstances since when a GTT mapping is
+ * set to coherent, the cpu can't read or write through the gtt aperture.
+ *
+ * Currently, since the userland agp driver still needs to access the gart, we
+ * only do bus_dma for a section that we've been told is ours, hence the need
+ * for the init function at present.
+ */
+
+static void
+agp_sg_bind_page(void *dev, bus_addr_t address, paddr_t physical, int flags)
+{
+	struct agp_softc *sc = dev;
+	int error;
+
+	error = AGP_BIND_PAGE(sc, address - sc->as_apaddr,
+	    _BUS_PHYS_TO_BUS(physical), flags);
+	if (error)
+		aprint_error_dev(sc->as_dev,
+		    "%s: failed: ba %#"PRIxPADDR", pa %#"PRIxPADDR"\n",
+		    __func__, address, physical);
+}
+
+static void
+agp_sg_unbind_page(void *dev, bus_addr_t address)
+{
+	struct agp_softc *sc = dev;
+	int error;
+
+	error = AGP_UNBIND_PAGE(sc, address - sc->as_apaddr);
+	if (error)
+		aprint_error_dev(sc->as_dev, "%s: failed: ba %#"PRIxPADDR"\n",
+		    __func__, address);
+}
+
+static void
+agp_sg_flush_tlb(void *dev)
+{
+	struct agp_softc *sc = dev;
+
+	AGP_FLUSH_TLB(sc);
+}
+
+int
+agp_bus_dma_init(struct agp_softc *sc, bus_addr_t start, bus_addr_t end,
+    bus_dma_tag_t *dmat)
+{
+	struct x86_bus_dma_tag	*tag;
+	struct sg_cookie	*cookie;
+
+	/*
+	 * XXX add agp map into the main queue that takes up our chunk of
+	 * GTT space to prevent the userland api stealing any of it.
+	 */
+	if ((tag = malloc(sizeof(*tag), M_DMAMAP,
+	    M_ZERO | M_WAITOK | M_CANFAIL)) == NULL)
+		return (ENOMEM);
+
+	if ((cookie = sg_dmatag_init(__UNCONST("agpgtt"), sc,
+	    start, end - start,
+	    agp_sg_bind_page, agp_sg_unbind_page, agp_sg_flush_tlb)) == NULL) {
+		free(tag, M_DMAMAP);
+		return (ENOMEM);
+	}
+
+	tag->_cookie = cookie;
+	tag->_dmamap_create = sg_dmamap_create;
+	tag->_dmamap_destroy = sg_dmamap_destroy;
+	tag->_dmamap_load = sg_dmamap_load;
+	tag->_dmamap_load_mbuf = sg_dmamap_load_mbuf;
+	tag->_dmamap_load_uio = sg_dmamap_load_uio;
+	tag->_dmamap_load_raw = sg_dmamap_load_raw;
+	tag->_dmamap_unload = sg_dmamap_unload;
+	tag->_dmamem_alloc = sg_dmamem_alloc;
+	tag->_dmamem_free = _bus_dmamem_free;
+	tag->_dmamem_map = _bus_dmamem_map;
+	tag->_dmamem_unmap = _bus_dmamem_unmap;
+	tag->_dmamem_mmap = _bus_dmamem_mmap;
+	tag->_dmatag_subregion = _bus_dmatag_subregion;
+	tag->_dmatag_destroy = _bus_dmatag_destroy;
+
+	/* Driver may need special sync handling */
+	if (sc->as_methods->dma_sync != NULL) {
+		tag->_dmamap_sync = sc->as_methods->dma_sync;
+	} else {
+#ifdef __i386__
+		tag->_dmamap_sync = NULL;
+#else
+		tag->_dmamap_sync = _bus_dmamap_sync;
+#endif
+	}
+
+	*dmat = tag;
+	return (0);
+}
+
+void
+agp_bus_dma_destroy(struct agp_softc *sc, bus_dma_tag_t dmat)
+{
+	struct sg_cookie	*cookie = dmat->_cookie;
+	bus_addr_t		 offset;
+
+
+	/*
+	 * XXX clear up blocker queue
+	 */
+
+	/*
+	 * some backends use a dummy page to avoid errors on prefetching, etc.
+	 * make sure that all of them are clean.
+	 */
+	for (offset = cookie->sg_ex->ex_start;
+	    offset < cookie->sg_ex->ex_end; offset += PAGE_SIZE)
+		agp_sg_unbind_page(sc, offset);
+
+	sg_dmatag_destroy(cookie);
+	free(dmat, M_DMAMAP);
+}
+
+void
+agp_bus_dma_set_alignment(bus_dma_tag_t tag, bus_dmamap_t dmam,
+    u_long alignment)
+{
+	sg_dmamap_set_alignment(tag, dmam, alignment);
+}
+
+struct agp_map {
+	bus_space_tag_t		bst;
+	bus_size_t		size;
+#ifdef __i386__
+	bus_addr_t		addr;
+	int			flags;
+#else
+	bus_space_handle_t	bsh;
+#endif
+};
+
+#ifdef __i386__
+extern struct extent	*ioport_ex;
+extern struct extent	*iomem_ex;
+#endif
+
+int
+agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
+    int flags, struct agp_map **mapp)
+{
+#ifdef __i386__
+	struct extent	*ex;
+#endif
+	struct agp_map	*map;
+	int		 error;
+
+#ifdef __i386__
+	if (tag->bst_type == X86_BUS_SPACE_IO) {
+		ex = ioport_ex;
+		if (flags & BUS_SPACE_MAP_LINEAR)
+			return (EINVAL);
+	} else if (tag->bst_type == X86_BUS_SPACE_MEM) {
+		ex = iomem_ex;
+	} else {
+		panic("agp_init_map: bad bus space tag");
+	}
+	/*
+	 * We grab the extent out of the bus region ourselves
+	 * so we don't need to do these allocations every time.
+	 */
+	error = extent_alloc_region(ex, address, size,
+	    EX_NOWAIT | EX_MALLOCOK);
+	if (error)
+		return (error);
+#endif
+
+	map = malloc(sizeof(*map), M_AGP, M_WAITOK | M_CANFAIL);
+	if (map == NULL)
+		return (ENOMEM);
+
+	map->bst = tag;
+	map->size = size;
+#ifdef __i386__
+	map->addr = address;
+	map->flags = flags;
+#else
+	if ((error = bus_space_map(tag, address, size, flags, &map->bsh)) != 0) {
+		free(map, M_AGP);
+		return (error);
+	}
+#endif
+
+	*mapp = map;
+	return (0);
+}
+
+void
+agp_destroy_map(struct agp_map *map)
+{
+#ifdef __i386__
+	struct extent	*ex;
+
+	if (map->bst->bst_type == X86_BUS_SPACE_IO)
+		ex = ioport_ex;
+	else if (map->bst->bst_type == X86_BUS_SPACE_MEM)
+		ex = iomem_ex;
+	else
+		panic("agp_destroy_map: bad bus space tag");
+
+	if (extent_free(ex, map->addr, map->size,
+	    EX_NOWAIT | EX_MALLOCOK ))
+		printf("agp_destroy_map: can't free region\n");
+#else
+	bus_space_unmap(map->bst, map->bsh, map->size);
+#endif
+	free(map, M_AGP);
+}
+
+
+int
+agp_map_subregion(struct agp_map *map, bus_size_t offset, bus_size_t size,
+    bus_space_handle_t *bshp)
+{
+#ifdef __i386__
+	return (_x86_memio_map(map->bst, map->addr + offset, size,
+	    map->flags, bshp));
+#else
+	if (offset > map->size || size > map->size || offset + size > map->size)
+		return (EINVAL);
+	return (bus_space_subregion(map->bst, map->bsh, offset, size, bshp));
+#endif
+}
+
+void
+agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh,
+    bus_size_t size)
+{
+#ifdef __i386__
+	return (_x86_memio_unmap(map->bst, bsh, size, NULL));
+#else
+	/* subregion doesn't need unmapping, do nothing */
+#endif
+}
+
+/*
+ * ick ick ick. However, the rest of this driver is supposedly MI (though
+ * they only exist on x86), so this can't be in dev/pci.
+ */
+
+#if NAGP_I810 > 0
+
+/*
+ * bus_dmamap_sync routine for intagp.
+ *
+ * This is tailored to the usage that drm with the GEM memory manager
+ * will be using, since intagp is for intel IGD, and thus shouldn't be
+ * used for anything other than gpu-based work. Essentially for the intel GEM
+ * driver we use bus_dma as an abstraction to convert our memory into a gtt
+ * address and deal with any cache incoherencies that we create.
+ *
+ * We use the cflush instruction to deal with clearing the caches, since our
+ * cache is physically indexed, we can even map then clear the page and it'll
+ * work. on i386 we need to check for the presence of cflush() in cpuid,
+ * however, all cpus that have a new enough intel GMCH should be suitable.
+ */
+void
+intagp_dma_sync(bus_dma_tag_t tag, bus_dmamap_t dmam,
+    bus_addr_t offset, bus_size_t size, int ops)
+{
+#if defined(__HAVE_PMAP_FLUSH_CACHE) && defined(__HAVE_PMAP_FLUSH_PAGE)
+	bus_dma_segment_t	*segp;
+	struct sg_page_map	*spm;
+	vaddr_t			 addr;
+	paddr_t	 		 pa;
+	bus_addr_t		 poff, endoff, soff;
+#endif /* defined(__HAVE_PMAP_FLUSH_CACHE) && defined(__HAVE_PMAP_FLUSH_PAGE) */
+
+#ifdef DIAGNOSTIC
+	if ((ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0 &&
+	    (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)) != 0)
+		panic("agp_dmamap_sync: mix PRE and POST");
+	if (offset >= dmam->dm_mapsize)
+		panic("_intagp_dma_sync: bad offset %lu (size = %zu)",
+		    offset, dmam->dm_mapsize);
+	if (size == 0 || (offset + size) > dmam->dm_mapsize)
+		panic("intagp_dma_sync: bad length");
+#endif /* DIAGNOSTIC */
+
+	/* Coherent mappings need no sync. */
+	if (dmam->_dm_flags & BUS_DMA_COHERENT)
+		return;
+
+	/*
+	 * We need to clflush the object cache in all cases but postwrite.
+	 *
+	 * - Due to gpu incoherency, postread we need to flush speculative
+	 * reads (which are not written back on intel cpus).
+	 *
+	 * - preread we need to flush data which will very soon be stale from
+	 * the caches
+	 *
+	 * - prewrite we need to make sure our data hits the memory before the
+	 * gpu hoovers it up.
+	 *
+	 * The chipset also may need flushing, but that fits badly into
+	 * bus_dma and it done in the driver.
+	 */
+	if (ops & BUS_DMASYNC_POSTREAD || ops & BUS_DMASYNC_PREREAD ||
+	    ops & BUS_DMASYNC_PREWRITE) {
+#if defined(__HAVE_PMAP_FLUSH_CACHE) && defined(__HAVE_PMAP_FLUSH_PAGE)
+		if (curcpu()->ci_cflush_lsize == 0) {
+			/* save some wbinvd()s. we're MD anyway so it's ok */
+			wbinvd();
+			return;
+		}
+
+		soff = trunc_page(offset);
+		endoff = round_page(offset + size);
+		x86_mfence();
+		spm = dmam->_dm_cookie;
+		switch (spm->spm_buftype) {
+		case X86_DMA_BUFTYPE_LINEAR:
+			addr = (vaddr_t)spm->spm_origbuf + soff;
+			while (soff < endoff) {
+				pmap_flush_cache(addr, PAGE_SIZE);
+				soff += PAGE_SIZE;
+				addr += PAGE_SIZE;
+			} break;
+		case X86_DMA_BUFTYPE_RAW:
+			segp = (bus_dma_segment_t *)spm->spm_origbuf;
+			poff = 0;
+
+			while (poff < soff) {
+				if (poff + segp->ds_len > soff)
+					break;
+				poff += segp->ds_len;
+				segp++;
+			}
+			/* first time round may not start at seg beginning */
+			pa = segp->ds_addr + (soff - poff);
+			while (poff < endoff) {
+				for (; pa < segp->ds_addr + segp->ds_len &&
+				    poff < endoff; pa += PAGE_SIZE) {
+					pmap_flush_page(pa);
+					poff += PAGE_SIZE;
+				}
+				segp++;
+				if (poff < endoff)
+					pa = segp->ds_addr;
+			}
+			break;
+		/* You do not want to load mbufs or uios onto a graphics card */
+		case X86_DMA_BUFTYPE_MBUF:
+			/* FALLTHROUGH */
+		case X86_DMA_BUFTYPE_UIO:
+			/* FALLTHROUGH */
+		default:
+			panic("intagp_dmamap_sync: bad buftype %d",
+			    spm->spm_buftype);
+		}
+		x86_mfence();
+#else /* defined(__HAVE_PMAP_FLUSH_CACHE) && defined(__HAVE_PMAP_FLUSH_PAGE) */
+		wbinvd();
+#endif /* defined(__HAVE_PMAP_FLUSH_CACHE) && defined(__HAVE_PMAP_FLUSH_PAGE) */
+	}
 }
+#endif /* NAGP_I810 > 0 */
diff -Naurp old/src/sys/arch/x86/pci/pci_machdep.c new/src/sys/arch/x86/pci/pci_machdep.c
--- old/src/sys/arch/x86/pci/pci_machdep.c	2010-04-30 23:05:27.000000000 +0200
+++ new/src/sys/arch/x86/pci/pci_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -191,6 +191,7 @@ struct {
  * of these functions.
  */
 struct x86_bus_dma_tag pci_bus_dma_tag = {
+	NULL,				/* cookie */
 	0,				/* tag_needs_free */
 #if defined(_LP64) || defined(PAE)
 	PCI32_DMA_BOUNCE_THRESHOLD,	/* bounce_thresh */
@@ -221,6 +222,7 @@ struct x86_bus_dma_tag pci_bus_dma_tag =
 
 #ifdef _LP64
 struct x86_bus_dma_tag pci_bus_dma64_tag = {
+	NULL,				/* cookie */
 	0,				/* tag_needs_free */
 	0,
 	0,
diff -Naurp old/src/sys/arch/x86/x86/bus_dma.c new/src/sys/arch/x86/x86/bus_dma.c
--- old/src/sys/arch/x86/x86/bus_dma.c	2010-11-06 12:46:03.000000000 +0100
+++ new/src/sys/arch/x86/x86/bus_dma.c	2011-02-08 11:14:00.000000000 +0100
@@ -162,6 +162,13 @@ _bus_dmamem_alloc_range(bus_dma_tag_t t,
 
 	KASSERT(boundary >= PAGE_SIZE || boundary == 0);
 
+	segs[0]._ds_boundary = boundary;
+	segs[0]._ds_align = alignment;
+	if (flags & BUS_DMA_SG) {
+		boundary = 0;
+		alignment = 0;
+	}
+
 	/*
 	 * Allocate pages from the VM system.
 	 * We accept boundaries < size, splitting in multiple segments
diff -Naurp old/src/sys/arch/x86/x86/sg_dma.c new/src/sys/arch/x86/x86/sg_dma.c
--- old/src/sys/arch/x86/x86/sg_dma.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/arch/x86/x86/sg_dma.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,960 @@
+/*	$OpenBSD: sg_dma.c,v 1.9 2010/04/20 23:12:01 phessler Exp $	*/
+/*
+ * Copyright (c) 2009 Owain G. Ainsworth <oga@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2003 Henric Jungheim
+ * Copyright (c) 2001, 2002 Eduardo Horvath
+ * Copyright (c) 1999, 2000 Matthew R. Green
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Support for scatter/gather style dma through agp or an iommu.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/extent.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+#include <machine/bus_private.h>
+#include <machine/cpu.h>
+
+#include <x86/sg_dma.h>
+
+#ifndef MAX_DMA_SEGS
+#define MAX_DMA_SEGS	20
+#endif
+
+/* Disable 24-bit DMA support if it's not supported by arch. */
+#ifndef BUS_DMA_24BIT
+#define BUS_DMA_24BIT	0
+#endif
+
+int		sg_dmamap_load_seg(bus_dma_tag_t, struct sg_cookie *,
+		    bus_dmamap_t, bus_dma_segment_t *, int, int, bus_size_t,
+		    bus_size_t);
+struct sg_page_map *sg_iomap_create(int);
+int		sg_dmamap_append_range(bus_dma_tag_t, bus_dmamap_t, paddr_t,
+		    bus_size_t, int, bus_size_t);
+int		sg_iomap_insert_page(struct sg_page_map *, paddr_t);
+bus_addr_t	sg_iomap_translate(struct sg_page_map *, paddr_t);
+void		sg_iomap_load_map(struct sg_cookie *, struct sg_page_map *,
+		    bus_addr_t, int);
+void		sg_iomap_unload_map(struct sg_cookie *, struct sg_page_map *);
+void		sg_iomap_destroy(struct sg_page_map *);
+void		sg_iomap_clear_pages(struct sg_page_map *);
+
+struct sg_cookie *
+sg_dmatag_init(char *name, void *hdl, bus_addr_t start, bus_size_t size,
+    void bind(void *, bus_addr_t, paddr_t, int),
+    void unbind(void *, bus_addr_t), void flush_tlb(void *))
+{
+	struct sg_cookie	*cookie;
+
+	cookie = malloc(sizeof(*cookie), M_DMAMAP, M_NOWAIT|M_ZERO);
+	if (cookie == NULL)
+		return (NULL);
+
+	cookie->sg_ex = extent_create(name, start, start + size - 1,
+	    M_DMAMAP, NULL, 0, EX_NOWAIT | EX_NOCOALESCE);
+	if (cookie->sg_ex == NULL) {
+		free(cookie, M_DMAMAP);
+		return (NULL);
+	}
+
+	cookie->sg_hdl = hdl;
+	mutex_init(&cookie->sg_mtx, MUTEX_DEFAULT, IPL_HIGH);
+	cookie->bind_page = bind;
+	cookie->unbind_page = unbind;
+	cookie->flush_tlb = flush_tlb;
+
+	return (cookie);
+}
+
+void
+sg_dmatag_destroy(struct sg_cookie *cookie)
+{
+	mutex_destroy(&cookie->sg_mtx);
+	extent_destroy(cookie->sg_ex);
+	free(cookie, M_DMAMAP);
+}
+
+int
+sg_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
+    bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamap)
+{
+	struct sg_page_map	*spm;
+	bus_dmamap_t		 map;
+	int			 ret;
+
+	if ((ret = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
+	    flags, &map)) != 0)
+		return (ret);
+
+	if ((spm = sg_iomap_create(atop(round_page(size)))) == NULL) {
+		_bus_dmamap_destroy(t, map);
+		return (ENOMEM);
+	}
+
+	map->_dm_cookie = spm;
+	*dmamap = map;
+
+	return (0);
+}
+
+void
+sg_dmamap_set_alignment(bus_dma_tag_t tag, bus_dmamap_t dmam,
+    u_long alignment)
+{
+	if (alignment < PAGE_SIZE)
+		return;
+
+	dmam->dm_segs[0]._ds_align = alignment;
+}
+
+void
+sg_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+{
+	/*
+	 * The specification (man page) requires a loaded
+	 * map to be unloaded before it is destroyed.
+	 */
+	if (map->dm_nsegs)
+		bus_dmamap_unload(t, map);
+
+        if (map->_dm_cookie)
+                sg_iomap_destroy(map->_dm_cookie);
+	map->_dm_cookie = NULL;
+	_bus_dmamap_destroy(t, map);
+}
+
+/*
+ * Load a contiguous kva buffer into a dmamap.  The physical pages are
+ * not assumed to be contiguous.  Two passes are made through the buffer
+ * and both call pmap_extract() for the same va->pa translations.  It
+ * is possible to run out of pa->dvma mappings; the code should be smart
+ * enough to resize the iomap (when the "flags" permit allocation).  It
+ * is trivial to compute the number of entries required (round the length
+ * up to the page size and then divide by the page size)...
+ */
+int
+sg_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+    bus_size_t buflen, struct proc *p, int flags)
+{
+	int err = 0;
+	bus_size_t sgsize;
+	u_long dvmaddr, sgstart, sgend;
+	bus_size_t align, boundary;
+	struct sg_cookie *is = t->_cookie;
+	struct sg_page_map *spm = map->_dm_cookie;
+	pmap_t pmap;
+
+	if (map->dm_nsegs) {
+		/*
+		 * Is it still in use? _bus_dmamap_load should have taken care
+		 * of this.
+		 */
+#ifdef DIAGNOSTIC
+		panic("sg_dmamap_load: map still in use");
+#endif
+		bus_dmamap_unload(t, map);
+	}
+
+	/*
+	 * Make sure that on error condition we return "no valid mappings".
+	 */
+	map->dm_nsegs = 0;
+
+	if (buflen < 1 || buflen > map->_dm_size)
+		return (EINVAL);
+
+	/*
+	 * A boundary presented to bus_dmamem_alloc() takes precedence
+	 * over boundary in the map.
+	 */
+	if ((boundary = (map->dm_segs[0]._ds_boundary)) == 0)
+		boundary = map->_dm_boundary;
+	align = MAX(map->dm_segs[0]._ds_align, PAGE_SIZE);
+
+	pmap = p ? p->p_vmspace->vm_map.pmap : pmap_kernel();
+
+	/* Count up the total number of pages we need */
+	sg_iomap_clear_pages(spm);
+	{ /* Scope */
+		bus_addr_t a, aend;
+		bus_addr_t addr = (bus_addr_t)buf;
+		int seg_len = buflen;
+
+		aend = round_page(addr + seg_len);
+		for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
+			paddr_t pa;
+
+			if (pmap_extract(pmap, a, &pa) == FALSE) {
+				printf("iomap pmap error addr %#"PRIxPADDR"\n", a);
+				sg_iomap_clear_pages(spm);
+				return (EFBIG);
+			}
+
+			err = sg_iomap_insert_page(spm, pa);
+			if (err) {
+				printf("iomap insert error: %d for "
+				    "va %#"PRIxPADDR" pa %#"PRIxPADDR" "
+				    "(buf %p len %zd/%zx)\n",
+				    err, a, pa, buf, buflen, buflen);
+				sg_iomap_clear_pages(spm);
+				return (EFBIG);
+			}
+		}
+	}
+	sgsize = spm->spm_pagecnt * PAGE_SIZE;
+
+	mutex_enter(&is->sg_mtx);
+	if (flags & BUS_DMA_24BIT) {
+		sgstart = MAX(is->sg_ex->ex_start, 0xff000000);
+		sgend = MIN(is->sg_ex->ex_end, 0xffffffff);
+	} else {
+		sgstart = is->sg_ex->ex_start;
+		sgend = is->sg_ex->ex_end;
+	}
+
+	/*
+	 * If our segment size is larger than the boundary we need to
+	 * split the transfer up into little pieces ourselves.
+	 */
+	err = extent_alloc_subregion1(is->sg_ex, sgstart, sgend,
+	    sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
+	    EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
+	mutex_exit(&is->sg_mtx);
+	if (err != 0) {
+		sg_iomap_clear_pages(spm);
+		return (err);
+	}
+
+	/* Set the active DVMA map */
+	spm->spm_start = dvmaddr;
+	spm->spm_size = sgsize;
+
+	map->dm_mapsize = buflen;
+
+	sg_iomap_load_map(is, spm, dvmaddr, flags);
+
+	{ /* Scope */
+		bus_addr_t a, aend;
+		bus_addr_t addr = (bus_addr_t)buf;
+		int seg_len = buflen;
+
+		aend = round_page(addr + seg_len);
+		for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
+			bus_addr_t pgstart;
+			bus_addr_t pgend;
+			paddr_t pa;
+			int pglen;
+
+			/* Yuck... Redoing the same pmap_extract... */
+			if (pmap_extract(pmap, a, &pa) == FALSE) {
+				printf("iomap pmap error addr %#"PRIxPADDR"\n", a);
+				err = EFBIG;
+				break;
+			}
+
+			pgstart = pa | (MAX(a, addr) & PAGE_MASK);
+			pgend = pa | (MIN(a + PAGE_SIZE - 1,
+			    addr + seg_len - 1) & PAGE_MASK);
+			pglen = pgend - pgstart + 1;
+
+			if (pglen < 1)
+				continue;
+
+			err = sg_dmamap_append_range(t, map, pgstart,
+			    pglen, flags, boundary);
+			if (err == EFBIG)
+				break;
+			else if (err) {
+				printf("iomap load seg page: %d for "
+				    "va %#"PRIxPADDR" pa %#"PRIxPADDR" (%#"PRIxPADDR" - %#"PRIxPADDR") "
+				    "for %d/0x%x\n",
+				    err, a, pa, pgstart, pgend, pglen, pglen);
+				break;
+			}
+		}
+	}
+	if (err) {
+		sg_dmamap_unload(t, map);
+	} else {
+		spm->spm_origbuf = buf;
+		spm->spm_buftype = X86_DMA_BUFTYPE_LINEAR;
+		spm->spm_proc = p;
+	}
+
+	return (err);
+}
+
+/*
+ * Load an mbuf into our map. we convert it to some bus_dma_segment_ts then
+ * pass it to load_raw.
+ */
+int
+sg_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *mb,
+    int flags)
+{
+	/*
+	 * This code is adapted from sparc64, for very fragmented data
+	 * we may need to adapt the algorithm
+	 */
+	bus_dma_segment_t	 segs[MAX_DMA_SEGS];
+	struct sg_page_map	*spm = map->_dm_cookie;
+	size_t			 len;
+	int			 i, err;
+
+	/*
+	 * Make sure that on error condition we return "no valid mappings".
+	 */
+	map->dm_mapsize = 0;
+	map->dm_nsegs = 0;
+
+	if (mb->m_pkthdr.len > map->_dm_size)
+		return (EINVAL);
+
+	i = 0;
+	len = 0;
+	while (mb) {
+		vaddr_t	vaddr = mtod(mb, vaddr_t);
+		long	buflen = (long)mb->m_len;
+
+		len += buflen;
+		while (buflen > 0 && i < MAX_DMA_SEGS) {
+			paddr_t	pa;
+			long incr;
+
+			incr = min(buflen, NBPG);
+
+			if (pmap_extract(pmap_kernel(), vaddr, &pa) == FALSE)
+				return EINVAL;
+
+			buflen -= incr;
+			vaddr += incr;
+
+			if (i > 0 && pa == (segs[i - 1].ds_addr +
+			    segs[i - 1].ds_len) && ((segs[i - 1].ds_len + incr)
+			    < map->_dm_maxmaxsegsz)) {
+				/* contigious, great! */
+				segs[i - 1].ds_len += incr;
+				continue;
+			}
+			segs[i].ds_addr = pa;
+			segs[i].ds_len = incr;
+			segs[i]._ds_boundary = 0;
+			segs[i]._ds_align = 0;
+			i++;
+		}
+		mb = mb->m_next;
+		if (mb && i >= MAX_DMA_SEGS) {
+			/* our map, it is too big! */
+			return (EFBIG);
+		}
+	}
+
+	err = sg_dmamap_load_raw(t, map, segs, i, (bus_size_t)len, flags);
+
+	if (err == 0) {
+		spm->spm_origbuf = mb;
+		spm->spm_buftype = X86_DMA_BUFTYPE_MBUF;
+	}
+	return (err);
+}
+
+/*
+ * Load a uio into the map. Turn it into segments and call load_raw()
+ */
+int
+sg_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
+    int flags)
+{
+	/*
+	 * loading uios is kinda broken since we can't lock the pages.
+	 * and unlock them at unload. Perhaps page loaning is the answer.
+	 * 'till then we only accept kernel data
+	 */
+	bus_dma_segment_t	 segs[MAX_DMA_SEGS];
+	struct sg_page_map	*spm = map->_dm_cookie;
+	size_t			 len;
+	int			 i, j, err;
+
+	/*
+	 * Make sure that on errror we return "no valid mappings".
+	 */
+	map->dm_mapsize = 0;
+	map->dm_nsegs = 0;
+
+	if (uio->uio_resid > map->_dm_size)
+		return (EINVAL);
+
+	if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace))
+		return (EOPNOTSUPP);
+
+	i = j = 0;
+	len = 0;
+	while (j < uio->uio_iovcnt) {
+		vaddr_t	vaddr = (vaddr_t)uio->uio_iov[j].iov_base;
+		long	buflen = (long)uio->uio_iov[j].iov_len;
+
+		len += buflen;
+		while (buflen > 0 && i < MAX_DMA_SEGS) {
+			paddr_t pa;
+			long incr;
+
+			incr = min(buflen, NBPG);
+			(void)pmap_extract(pmap_kernel(), vaddr, &pa);
+			buflen -= incr;
+			vaddr += incr;
+
+			if (i > 0 && pa == (segs[i - 1].ds_addr +
+			    segs[i -1].ds_len) && ((segs[i - 1].ds_len + incr)
+			    < map->_dm_maxmaxsegsz)) {
+				/* contigious, yay! */
+				segs[i - 1].ds_len += incr;
+				continue;
+			}
+			segs[i].ds_addr = pa;
+			segs[i].ds_len = incr;
+			segs[i]._ds_boundary = 0;
+			segs[i]._ds_align = 0;
+			i++;
+		}
+		j++;
+		if ((uio->uio_iovcnt - j) && i >= MAX_DMA_SEGS) {
+			/* Our map, is it too big! */
+			return (EFBIG);
+		}
+
+	}
+
+	err = sg_dmamap_load_raw(t, map, segs, i, (bus_size_t)len, flags);
+
+	if (err == 0) {
+		spm->spm_origbuf = uio;
+		spm->spm_buftype = X86_DMA_BUFTYPE_UIO;
+	}
+	return (err);
+}
+
+/*
+ * Load a dvmamap from an array of segs.  It calls sg_dmamap_append_range()
+ * or for part of the 2nd pass through the mapping.
+ */
+int
+sg_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
+    bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
+{
+	int i;
+	int left;
+	int err = 0;
+	bus_size_t sgsize;
+	bus_size_t boundary, align;
+	u_long dvmaddr, sgstart, sgend;
+	struct sg_cookie *is = t->_cookie;
+	struct sg_page_map *spm = map->_dm_cookie;
+
+	if (map->dm_nsegs) {
+		/* Already in use?? */
+#ifdef DIAGNOSTIC
+		panic("sg_dmamap_load_raw: map still in use");
+#endif
+		bus_dmamap_unload(t, map);
+	}
+
+	/*
+	 * A boundary presented to bus_dmamem_alloc() takes precedence
+	 * over boundary in the map.
+	 */
+	if ((boundary = segs[0]._ds_boundary) == 0)
+		boundary = map->_dm_boundary;
+
+	align = MAX(MAX(segs[0]._ds_align, map->dm_segs[0]._ds_align),
+	    PAGE_SIZE);
+
+	/*
+	 * Make sure that on error condition we return "no valid mappings".
+	 */
+	map->dm_nsegs = 0;
+
+	sg_iomap_clear_pages(spm);
+	/* Count up the total number of pages we need */
+	for (i = 0, left = size; left > 0 && i < nsegs; i++) {
+		bus_addr_t a, aend;
+		bus_size_t len = segs[i].ds_len;
+		bus_addr_t addr = segs[i].ds_addr;
+		int seg_len = MIN(left, len);
+
+		if (len < 1)
+			continue;
+
+		aend = round_page(addr + seg_len);
+		for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
+
+			err = sg_iomap_insert_page(spm, a);
+			if (err) {
+				printf("iomap insert error: %d for "
+				    "pa %#"PRIxPADDR"\n", err, a);
+				sg_iomap_clear_pages(spm);
+				return (EFBIG);
+			}
+		}
+
+		left -= seg_len;
+	}
+	sgsize = spm->spm_pagecnt * PAGE_SIZE;
+
+	mutex_enter(&is->sg_mtx);
+	if (flags & BUS_DMA_24BIT) {
+		sgstart = MAX(is->sg_ex->ex_start, 0xff000000);
+		sgend = MIN(is->sg_ex->ex_end, 0xffffffff);
+	} else {
+		sgstart = is->sg_ex->ex_start;
+		sgend = is->sg_ex->ex_end;
+	}
+
+	/*
+	 * If our segment size is larger than the boundary we need to
+	 * split the transfer up into little pieces ourselves.
+	 */
+	err = extent_alloc_subregion1(is->sg_ex, sgstart, sgend,
+	    sgsize, align, 0, (sgsize > boundary) ? 0 : boundary,
+	    EX_NOWAIT | EX_BOUNDZERO, (u_long *)&dvmaddr);
+	mutex_exit(&is->sg_mtx);
+
+	if (err != 0) {
+		sg_iomap_clear_pages(spm);
+		return (err);
+	}
+
+	/* Set the active DVMA map */
+	spm->spm_start = dvmaddr;
+	spm->spm_size = sgsize;
+
+	map->dm_mapsize = size;
+
+	sg_iomap_load_map(is, spm, dvmaddr, flags);
+
+	err = sg_dmamap_load_seg(t, is, map, segs, nsegs, flags,
+	    size, boundary);
+
+	if (err) {
+		sg_dmamap_unload(t, map);
+	} else {
+		/* This will be overwritten if mbuf or uio called us */
+		spm->spm_origbuf = segs;
+		spm->spm_buftype = X86_DMA_BUFTYPE_RAW;
+	}
+
+	return (err);
+}
+
+/*
+ * Insert a range of addresses into a loaded map respecting the specified
+ * boundary and alignment restrictions.  The range is specified by its
+ * physical address and length.  The range cannot cross a page boundary.
+ * This code (along with most of the rest of the function in this file)
+ * assumes that the IOMMU page size is equal to PAGE_SIZE.
+ */
+int
+sg_dmamap_append_range(bus_dma_tag_t t, bus_dmamap_t map, paddr_t pa,
+    bus_size_t length, int flags, bus_size_t boundary)
+{
+	struct sg_page_map *spm = map->_dm_cookie;
+	bus_addr_t sgstart, sgend, bd_mask;
+	bus_dma_segment_t *seg = NULL;
+	int i = map->dm_nsegs;
+
+	sgstart = sg_iomap_translate(spm, pa);
+	sgend = sgstart + length - 1;
+
+#ifdef DIAGNOSTIC
+	if (sgstart == 0 || sgstart > sgend) {
+		printf("append range invalid mapping for %#"PRIxPADDR" "
+		    "(%#"PRIxPADDR" - %#"PRIxPADDR")\n", pa, sgstart, sgend);
+		map->dm_nsegs = 0;
+		return (EINVAL);
+	}
+#endif
+
+#ifdef DEBUG
+	if (trunc_page(sgstart) != trunc_page(sgend)) {
+		printf("append range crossing page boundary! "
+		    "pa %#"PRIxPADDR" length %zd/0x%zx sgstart %#"PRIxPADDR" sgend %#"PRIxPADDR"\n",
+		    pa, length, length, sgstart, sgend);
+	}
+#endif
+
+	/*
+	 * We will attempt to merge this range with the previous entry
+	 * (if there is one).
+	 */
+	if (i > 0) {
+		seg = &map->dm_segs[i - 1];
+		if (sgstart == seg->ds_addr + seg->ds_len) {
+			length += seg->ds_len;
+			sgstart = seg->ds_addr;
+			sgend = sgstart + length - 1;
+		} else
+			seg = NULL;
+	}
+
+	if (seg == NULL) {
+		seg = &map->dm_segs[i];
+		if (++i > map->_dm_segcnt) {
+			map->dm_nsegs = 0;
+			return (EFBIG);
+		}
+	}
+
+	/*
+	 * At this point, "i" is the index of the *next* bus_dma_segment_t
+	 * (the segment count, aka map->dm_nsegs) and "seg" points to the
+	 * *current* entry.  "length", "sgstart", and "sgend" reflect what
+	 * we intend to put in "*seg".  No assumptions should be made about
+	 * the contents of "*seg".  Only "boundary" issue can change this
+	 * and "boundary" is often zero, so explicitly test for that case
+	 * (the test is strictly an optimization).
+	 */
+	if (boundary != 0) {
+		bd_mask = ~(boundary - 1);
+
+		while ((sgstart & bd_mask) != (sgend & bd_mask)) {
+			/*
+			 * We are crossing a boundary so fill in the current
+			 * segment with as much as possible, then grab a new
+			 * one.
+			 */
+
+			seg->ds_addr = sgstart;
+			seg->ds_len = boundary - (sgstart & bd_mask);
+
+			sgstart += seg->ds_len; /* sgend stays the same */
+			length -= seg->ds_len;
+
+			seg = &map->dm_segs[i];
+			if (++i > map->_dm_segcnt) {
+				map->dm_nsegs = 0;
+				return (EFBIG);
+			}
+		}
+	}
+
+	seg->ds_addr = sgstart;
+	seg->ds_len = length;
+	map->dm_nsegs = i;
+
+	return (0);
+}
+
+/*
+ * Populate the iomap from a bus_dma_segment_t array.  See note for
+ * sg_dmamap_load() regarding page entry exhaustion of the iomap.
+ * This is less of a problem for load_seg, as the number of pages
+ * is usually similar to the number of segments (nsegs).
+ */
+int
+sg_dmamap_load_seg(bus_dma_tag_t t, struct sg_cookie *is,
+    bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, int flags,
+    bus_size_t size, bus_size_t boundary)
+{
+	int i;
+	int left;
+	int seg;
+
+	/*
+	 * Keep in mind that each segment could span
+	 * multiple pages and that these are not always
+	 * adjacent. The code is no longer adding dvma
+	 * aliases to the IOMMU.  The STC will not cross
+	 * page boundaries anyway and a IOMMU table walk
+	 * vs. what may be a streamed PCI DMA to a ring
+	 * descriptor is probably a wash.  It eases TLB
+	 * pressure and in the worst possible case, it is
+	 * only as bad a non-IOMMUed architecture.  More
+	 * importantly, the code is not quite as hairy.
+	 * (It's bad enough as it is.)
+	 */
+	left = size;
+	seg = 0;
+	for (i = 0; left > 0 && i < nsegs; i++) {
+		bus_addr_t a, aend;
+		bus_size_t len = segs[i].ds_len;
+		bus_addr_t addr = segs[i].ds_addr;
+		int seg_len = MIN(left, len);
+
+		if (len < 1)
+			continue;
+
+		aend = round_page(addr + seg_len);
+		for (a = trunc_page(addr); a < aend; a += PAGE_SIZE) {
+			bus_addr_t pgstart;
+			bus_addr_t pgend;
+			int pglen;
+			int err;
+
+			pgstart = MAX(a, addr);
+			pgend = MIN(a + PAGE_SIZE - 1, addr + seg_len - 1);
+			pglen = pgend - pgstart + 1;
+
+			if (pglen < 1)
+				continue;
+
+			err = sg_dmamap_append_range(t, map, pgstart,
+			    pglen, flags, boundary);
+			if (err == EFBIG)
+				return (err);
+			if (err) {
+				printf("iomap load seg page: %d for "
+				    "pa %#"PRIxPADDR" (%#"PRIxPADDR" - %#"PRIxPADDR" for %d/%x\n",
+				    err, a, pgstart, pgend, pglen, pglen);
+				return (err);
+			}
+
+		}
+
+		left -= seg_len;
+	}
+	return (0);
+}
+
+/*
+ * Unload a dvmamap.
+ */
+void
+sg_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+{
+	struct sg_cookie	*is = t->_cookie;
+	struct sg_page_map	*spm = map->_dm_cookie;
+	bus_addr_t		 dvmaddr = spm->spm_start;
+	bus_size_t		 sgsize = spm->spm_size;
+	int			 error;
+
+	/* Remove the IOMMU entries */
+	sg_iomap_unload_map(is, spm);
+
+	/* Clear the iomap */
+	sg_iomap_clear_pages(spm);
+
+	mutex_enter(&is->sg_mtx);
+	error = extent_free(is->sg_ex, dvmaddr,
+		sgsize, EX_NOWAIT);
+	spm->spm_start = 0;
+	spm->spm_size = 0;
+	mutex_exit(&is->sg_mtx);
+	if (error != 0)
+		printf("warning: %zd of DVMA space lost\n", sgsize);
+
+	spm->spm_buftype = X86_DMA_BUFTYPE_INVALID;
+	spm->spm_origbuf = NULL;
+	spm->spm_proc = NULL;
+	_bus_dmamap_unload(t, map);
+}
+
+/*
+ * Alloc dma safe memory, telling the backend that we're scatter gather
+ * to ease pressure on the vm.
+ *
+ * This assumes that we can map all physical memory.
+ */
+int
+sg_dmamem_alloc(bus_dma_tag_t t, bus_size_t size,
+    bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
+    int nsegs, int *rsegs, int flags)
+{
+	return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
+	    segs, nsegs, rsegs, flags | BUS_DMA_SG, 0, -1));
+}
+
+/*
+ * Create a new iomap.
+ */
+struct sg_page_map *
+sg_iomap_create(int n)
+{
+	struct sg_page_map	*spm;
+
+	/* Safety for heavily fragmented data, such as mbufs */
+	n += 4;
+	if (n < 16)
+		n = 16;
+
+	spm = malloc(sizeof(*spm) + (n - 1) * sizeof(spm->spm_map[0]),
+		M_DMAMAP, M_NOWAIT | M_ZERO);
+	if (spm == NULL)
+		return (NULL);
+
+	/* Initialize the map. */
+	spm->spm_maxpage = n;
+	SPLAY_INIT(&spm->spm_tree);
+
+	return (spm);
+}
+
+/*
+ * Destroy an iomap.
+ */
+void
+sg_iomap_destroy(struct sg_page_map *spm)
+{
+#ifdef DIAGNOSTIC
+	if (spm->spm_pagecnt > 0)
+		printf("sg_iomap_destroy: %d page entries in use\n",
+		    spm->spm_pagecnt);
+#endif
+
+	free(spm, M_DMAMAP);
+}
+
+/*
+ * Utility function used by splay tree to order page entries by pa.
+ */
+static inline int
+iomap_compare(struct sg_page_entry *a, struct sg_page_entry *b)
+{
+	return ((a->spe_pa > b->spe_pa) ? 1 :
+		(a->spe_pa < b->spe_pa) ? -1 : 0);
+}
+
+SPLAY_PROTOTYPE(sg_page_tree, sg_page_entry, spe_node, iomap_compare);
+
+SPLAY_GENERATE(sg_page_tree, sg_page_entry, spe_node, iomap_compare);
+
+/*
+ * Insert a pa entry in the iomap.
+ */
+int
+sg_iomap_insert_page(struct sg_page_map *spm, paddr_t pa)
+{
+	struct sg_page_entry *e;
+
+	if (spm->spm_pagecnt >= spm->spm_maxpage) {
+		struct sg_page_entry spe;
+
+		spe.spe_pa = pa;
+		if (SPLAY_FIND(sg_page_tree, &spm->spm_tree, &spe))
+			return (0);
+
+		return (ENOMEM);
+	}
+
+	e = &spm->spm_map[spm->spm_pagecnt];
+
+	e->spe_pa = pa;
+	e->spe_va = 0;
+
+	e = SPLAY_INSERT(sg_page_tree, &spm->spm_tree, e);
+
+	/* Duplicates are okay, but only count them once. */
+	if (e)
+		return (0);
+
+	++spm->spm_pagecnt;
+
+	return (0);
+}
+
+/*
+ * Locate the iomap by filling in the pa->va mapping and inserting it
+ * into the IOMMU tables.
+ */
+void
+sg_iomap_load_map(struct sg_cookie *sc, struct sg_page_map *spm,
+    bus_addr_t vmaddr, int flags)
+{
+	struct sg_page_entry	*e;
+	int			 i;
+
+	for (i = 0, e = spm->spm_map; i < spm->spm_pagecnt; ++i, ++e) {
+		e->spe_va = vmaddr;
+		sc->bind_page(sc->sg_hdl, e->spe_va, e->spe_pa, flags);
+		vmaddr += PAGE_SIZE;
+	}
+	sc->flush_tlb(sc->sg_hdl);
+}
+
+/*
+ * Remove the iomap from the IOMMU.
+ */
+void
+sg_iomap_unload_map(struct sg_cookie *sc, struct sg_page_map *spm)
+{
+	struct sg_page_entry	*e;
+	int			 i;
+
+	for (i = 0, e = spm->spm_map; i < spm->spm_pagecnt; ++i, ++e)
+		sc->unbind_page(sc->sg_hdl, e->spe_va);
+	sc->flush_tlb(sc->sg_hdl);
+}
+
+/*
+ * Translate a physical address (pa) into a DVMA address.
+ */
+bus_addr_t
+sg_iomap_translate(struct sg_page_map *spm, paddr_t pa)
+{
+	struct sg_page_entry	*e, pe;
+	paddr_t			 offset = pa & PAGE_MASK;
+
+	pe.spe_pa = trunc_page(pa);
+
+	e = SPLAY_FIND(sg_page_tree, &spm->spm_tree, &pe);
+
+	if (e == NULL)
+		return (0);
+
+	return (e->spe_va | offset);
+}
+
+/*
+ * Clear the iomap table and tree.
+ */
+void
+sg_iomap_clear_pages(struct sg_page_map *spm)
+{
+	spm->spm_pagecnt = 0;
+	SPLAY_INIT(&spm->spm_tree);
+}
diff -Naurp old/src/sys/arch/xen/xen/isa_machdep.c new/src/sys/arch/xen/xen/isa_machdep.c
--- old/src/sys/arch/xen/xen/isa_machdep.c	2010-02-06 18:48:54.000000000 +0100
+++ new/src/sys/arch/xen/xen/isa_machdep.c	2011-02-08 11:14:00.000000000 +0100
@@ -97,6 +97,7 @@ __KERNEL_RCSID(0, "$NetBSD: isa_machdep.
 static int _isa_dma_may_bounce(bus_dma_tag_t, bus_dmamap_t, int, int *);
 
 struct x86_bus_dma_tag isa_bus_dma_tag = {
+	NULL,				/* cookie */
 	0,				/* _tag_needs_free */
 	ISA_DMA_BOUNCE_THRESHOLD,	/* _bounce_thresh */
 	0,				/* _bounce_alloc_lo */
diff -Naurp old/src/sys/arch/xen/xen/xpci_xenbus.c new/src/sys/arch/xen/xen/xpci_xenbus.c
--- old/src/sys/arch/xen/xen/xpci_xenbus.c	2010-04-28 21:17:04.000000000 +0200
+++ new/src/sys/arch/xen/xen/xpci_xenbus.c	2011-02-08 11:14:00.000000000 +0100
@@ -91,6 +91,7 @@ CFATTACH_DECL_NEW(xpci_xenbus, sizeof(st
    xpci_xenbus_match, xpci_xenbus_attach, xpci_xenbus_detach, NULL);
 
 struct x86_bus_dma_tag pci_bus_dma_tag = {
+	NULL,				/* cookie */
 	0,			     /* tag_needs_free */
 #if defined(_LP64) || defined(PAE)
 	PCI32_DMA_BOUNCE_THRESHOLD,     /* bounce_thresh */
@@ -121,6 +122,7 @@ struct x86_bus_dma_tag pci_bus_dma_tag =
 
 #ifdef _LP64
 struct x86_bus_dma_tag pci_bus_dma64_tag = {
+	NULL,				/* cookie */
 	0,			     /* tag_needs_free */
 	0,
 	0,
diff -Naurp old/src/sys/conf/files new/src/sys/conf/files
--- old/src/sys/conf/files	2010-11-23 12:14:08.000000000 +0100
+++ new/src/sys/conf/files	2011-02-08 11:14:00.000000000 +0100
@@ -1065,7 +1065,8 @@ file	dev/ic/lan9118.c		smsh
 
 # DRM - Direct Rendering Infrastructure: dev/drm
 define drm {}
-include "external/bsd/drm/conf/files.drm"
+#include "external/bsd/drm/conf/files.drm"
+include "dev/pci/drm/files.drm"
 
 # Definitions for wscons
 # device attributes: display, display with emulator, keyboard, and mouse
diff -Naurp old/src/sys/dev/pci/agp_ali.c new/src/sys/dev/pci/agp_ali.c
--- old/src/sys/dev/pci/agp_ali.c	2010-11-13 14:52:04.000000000 +0100
+++ new/src/sys/dev/pci/agp_ali.c	2011-02-08 11:14:00.000000000 +0100
@@ -54,7 +54,7 @@ struct agp_ali_softc {
 
 static u_int32_t agp_ali_get_aperture(struct agp_softc *);
 static int agp_ali_set_aperture(struct agp_softc *sc, u_int32_t);
-static int agp_ali_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_ali_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_ali_unbind_page(struct agp_softc *, off_t);
 static void agp_ali_flush_tlb(struct agp_softc *);
 
@@ -65,6 +65,7 @@ static struct agp_methods agp_ali_method
 	agp_ali_bind_page,
 	agp_ali_unbind_page,
 	agp_ali_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -214,7 +215,8 @@ agp_ali_set_aperture(struct agp_softc *s
 }
 
 static int
-agp_ali_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_ali_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_ali_softc *asc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agp_amd64.c new/src/sys/dev/pci/agp_amd64.c
--- old/src/sys/dev/pci/agp_amd64.c	2010-11-13 14:52:04.000000000 +0100
+++ new/src/sys/dev/pci/agp_amd64.c	2011-02-08 11:14:00.000000000 +0100
@@ -56,7 +56,7 @@ __KERNEL_RCSID(0, "$NetBSD: agp_amd64.c,
 
 static uint32_t agp_amd64_get_aperture(struct agp_softc *);
 static int agp_amd64_set_aperture(struct agp_softc *, uint32_t);
-static int agp_amd64_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_amd64_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_amd64_unbind_page(struct agp_softc *, off_t);
 static void agp_amd64_flush_tlb(struct agp_softc *);
 
@@ -90,6 +90,7 @@ static struct agp_methods agp_amd64_meth
 	agp_amd64_bind_page,
 	agp_amd64_unbind_page,
 	agp_amd64_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -373,7 +374,8 @@ agp_amd64_set_aperture(struct agp_softc
 }
 
 static int
-agp_amd64_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_amd64_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_amd64_softc *asc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agp_amd.c new/src/sys/dev/pci/agp_amd.c
--- old/src/sys/dev/pci/agp_amd.c	2010-11-13 14:52:04.000000000 +0100
+++ new/src/sys/dev/pci/agp_amd.c	2011-02-08 11:14:00.000000000 +0100
@@ -73,7 +73,7 @@ struct agp_amd_softc {
 
 static u_int32_t agp_amd_get_aperture(struct agp_softc *);
 static int agp_amd_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_amd_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_amd_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_amd_unbind_page(struct agp_softc *, off_t);
 static void agp_amd_flush_tlb(struct agp_softc *);
 
@@ -84,6 +84,7 @@ static struct agp_methods agp_amd_method
 	agp_amd_bind_page,
 	agp_amd_unbind_page,
 	agp_amd_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -303,7 +304,8 @@ agp_amd_set_aperture(struct agp_softc *s
 }
 
 static int
-agp_amd_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_amd_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_amd_softc *asc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agp_apple.c new/src/sys/dev/pci/agp_apple.c
--- old/src/sys/dev/pci/agp_apple.c	2010-11-13 14:52:04.000000000 +0100
+++ new/src/sys/dev/pci/agp_apple.c	2011-02-08 11:14:00.000000000 +0100
@@ -46,7 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: agp_apple.c,
 
 static u_int32_t agp_apple_get_aperture(struct agp_softc *);
 static int agp_apple_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_apple_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_apple_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_apple_unbind_page(struct agp_softc *, off_t);
 static void agp_apple_flush_tlb(struct agp_softc *);
 
@@ -56,6 +56,7 @@ static struct agp_methods agp_apple_meth
 	agp_apple_bind_page,
 	agp_apple_unbind_page,
 	agp_apple_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -154,7 +155,8 @@ agp_apple_set_aperture(struct agp_softc
 }
 
 static int
-agp_apple_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_apple_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_apple_softc *asc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agp.c new/src/sys/dev/pci/agp.c
--- old/src/sys/dev/pci/agp.c	2010-11-13 14:52:04.000000000 +0100
+++ new/src/sys/dev/pci/agp.c	2011-02-08 11:14:00.000000000 +0100
@@ -665,7 +665,7 @@ agp_generic_bind_memory(struct agp_softc
 			AGP_DPF(("binding offset %#lx to pa %#lx\n",
 				(unsigned long)(offset + done + j),
 				(unsigned long)pa));
-			error = AGP_BIND_PAGE(sc, offset + done + j, pa);
+			error = AGP_BIND_PAGE(sc, offset + done + j, pa, 0);
 			if (error) {
 				/*
 				 * Bail out. Reverse all the mappings
diff -Naurp old/src/sys/dev/pci/agp_i810.c new/src/sys/dev/pci/agp_i810.c
--- old/src/sys/dev/pci/agp_i810.c	2011-01-31 00:43:08.000000000 +0100
+++ new/src/sys/dev/pci/agp_i810.c	2011-02-08 11:14:00.000000000 +0100
@@ -56,6 +56,9 @@ __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v
 #define READ4(off)	bus_space_read_4(isc->bst, isc->bsh, off)
 #define WRITE4(off,v)	bus_space_write_4(isc->bst, isc->bsh, off, v)
 
+/* Memory is snooped, must not be accessed through gtt from the cpu. */
+#define	INTEL_COHERENT	0x6
+
 #define CHIP_I810 0	/* i810/i815 */
 #define CHIP_I830 1	/* 830M/845G */
 #define CHIP_I855 2	/* 852GM/855GM/865G */
@@ -66,6 +69,9 @@ __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v
 
 struct agp_i810_softc {
 	u_int32_t initial_aperture;	/* aperture size at startup */
+	bus_dmamap_t scrib_dmamap;
+	bus_dma_segment_t scrib_seg;
+	void *scrib_vaddr;
 	struct agp_gatt *gatt;
 	int chiptype;			/* i810-like or i830 */
 	u_int32_t dcache_size;		/* i810 only */
@@ -81,12 +87,14 @@ struct agp_i810_softc {
 };
 
 /* XXX hack, see below */
+static bool agp_i810_vga_mapped = false;
 static bus_addr_t agp_i810_vga_regbase;
+static bus_space_tag_t agp_i810_vga_bst;
 static bus_space_handle_t agp_i810_vga_bsh;
 
 static u_int32_t agp_i810_get_aperture(struct agp_softc *);
 static int agp_i810_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_i810_unbind_page(struct agp_softc *, off_t);
 static void agp_i810_flush_tlb(struct agp_softc *);
 static int agp_i810_enable(struct agp_softc *, u_int32_t mode);
@@ -103,12 +111,16 @@ static int agp_i810_init(struct agp_soft
 static int agp_i810_write_gtt_entry(struct agp_i810_softc *, off_t,
 				    bus_addr_t);
 
+extern void intagp_dma_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+			    bus_size_t, int);
+
 static struct agp_methods agp_i810_methods = {
 	agp_i810_get_aperture,
 	agp_i810_set_aperture,
 	agp_i810_bind_page,
 	agp_i810_unbind_page,
 	agp_i810_flush_tlb,
+	intagp_dma_sync,
 	agp_i810_enable,
 	agp_i810_alloc_memory,
 	agp_i810_free_memory,
@@ -420,10 +432,17 @@ agp_i810_attach(device_t parent, device_
 	 * XXX horrible hack to allow drm code to use our mapping
 	 * of VGA chip registers
 	 */
+	agp_i810_vga_mapped = true;
 	agp_i810_vga_regbase = mmadr;
+	agp_i810_vga_bst = isc->bst;
 	agp_i810_vga_bsh = isc->bsh;
 
-	return agp_i810_init(sc);
+	error = agp_i810_init(sc);
+	if (error != 0) {
+		free(gatt, M_AGP);
+		agp_generic_detach(sc);
+	}
+	return error;
 }
 
 /*
@@ -431,11 +450,13 @@ agp_i810_attach(device_t parent, device_
  * of VGA chip registers
  */
 int
-agp_i810_borrow(bus_addr_t base, bus_space_handle_t *hdlp)
+agp_i810_borrow(bus_addr_t base, bus_space_tag_t *tagp, bus_space_handle_t *hdlp)
 {
 
-	if (!agp_i810_vga_regbase || base != agp_i810_vga_regbase)
+	if (!agp_i810_vga_mapped || !agp_i810_vga_regbase ||
+	    base != agp_i810_vga_regbase)
 		return 0;
+	*tagp = agp_i810_vga_bst;
 	*hdlp = agp_i810_vga_bsh;
 	return 1;
 }
@@ -444,6 +465,8 @@ static int agp_i810_init(struct agp_soft
 {
 	struct agp_i810_softc *isc;
 	struct agp_gatt *gatt;
+	bus_addr_t tmp;
+	int dummyrseg;
 
 	isc = sc->as_chipc;
 	gatt = isc->gatt;
@@ -462,8 +485,6 @@ static int agp_i810_init(struct agp_soft
 		if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024,
 		    0, &gatt->ag_dmamap, &virtual, &gatt->ag_physical,
 		    &gatt->ag_dmaseg, 1, &dummyseg) != 0) {
-			free(gatt, M_AGP);
-			agp_generic_detach(sc);
 			return ENOMEM;
 		}
 		gatt->ag_virtual = (uint32_t *)virtual;
@@ -495,7 +516,6 @@ static int agp_i810_init(struct agp_soft
 			isc->stolen = 0;
 			aprint_error(
 			    ": unknown memory configuration, disabling\n");
-			agp_generic_detach(sc);
 			return EINVAL;
 		}
 
@@ -550,7 +570,6 @@ static int agp_i810_init(struct agp_soft
 				break;
 			default:
 				aprint_error("Bad PGTBL size\n");
-				agp_generic_detach(sc);
 				return EINVAL;
 			}
 			break;
@@ -564,7 +583,6 @@ static int agp_i810_init(struct agp_soft
 				break;
 			default:
 				aprint_error(": Bad PGTBL size\n");
-				agp_generic_detach(sc);
 				return EINVAL;
 			}
 			break;
@@ -573,7 +591,6 @@ static int agp_i810_init(struct agp_soft
 			break;
 		default:
 			aprint_error(": bad chiptype\n");
-			agp_generic_detach(sc);
 			return EINVAL;
 		}
 
@@ -620,7 +637,6 @@ static int agp_i810_init(struct agp_soft
 		default:
 			aprint_error(
 			    ": unknown memory configuration, disabling\n");
-			agp_generic_detach(sc);
 			return EINVAL;
 		}
 
@@ -667,6 +683,25 @@ static int agp_i810_init(struct agp_soft
 		gatt->ag_physical = pgtblctl & ~1;
 	}
 
+	/* Intel recommends that you have a fake page bound to the gtt always */
+	if (agp_alloc_dmamem(sc->as_dmat, AGP_PAGE_SIZE, 0, &isc->scrib_dmamap,
+	    &isc->scrib_vaddr, &tmp, &isc->scrib_seg, 1, &dummyrseg) != 0) {
+		aprint_error(": can't get scribble page\n");
+		return ENOMEM;
+	}
+
+	tmp = 0;
+	if (isc->chiptype == CHIP_I810) {
+		tmp += isc->dcache_size;
+	} else {
+		tmp += isc->stolen << AGP_PAGE_SHIFT;
+	}
+
+	/* initialise all gtt entries to point to scribble page */
+	for (; tmp < sc->as_apsize; tmp += AGP_PAGE_SIZE)
+		agp_i810_unbind_page(sc, tmp);
+	/* XXX we'll need to restore the GTT contents when we go kms */
+
 	/*
 	 * Make sure the chipset can see everything.
 	 */
@@ -695,6 +730,8 @@ agp_i810_detach(struct agp_softc *sc)
 		pgtblctl &= ~1;
 		WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
 	}
+	agp_free_dmamem(sc->as_dmat, AGP_PAGE_SIZE, isc->scrib_dmamap,
+	    isc->scrib_vaddr, &isc->scrib_seg, 1);
 
 	/* Put the aperture back the way it started. */
 	AGP_SET_APERTURE(sc, isc->initial_aperture);
@@ -831,7 +868,8 @@ agp_i810_set_aperture(struct agp_softc *
 }
 
 static int
-agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_i810_softc *isc = sc->as_chipc;
 
@@ -854,6 +892,13 @@ agp_i810_bind_page(struct agp_softc *sc,
 		}
 	}
 
+	/*
+	 * COHERENT mappings mean set the snoop bit. this should never be
+	 * accessed by the gpu through the gtt.
+	 */
+	if (flags & BUS_DMA_COHERENT)
+		physical |= INTEL_COHERENT;
+
 	return agp_i810_write_gtt_entry(isc, offset, physical | 1);
 }
 
@@ -875,7 +920,8 @@ agp_i810_unbind_page(struct agp_softc *s
 		}
 	}
 
-	return agp_i810_write_gtt_entry(isc, offset, 0);
+	return agp_i810_write_gtt_entry(isc, offset,
+	    isc->scrib_dmamap->dm_segs[0].ds_addr | 1);
 }
 
 /*
@@ -1011,7 +1057,7 @@ agp_i810_bind_memory(struct agp_softc *s
 	if (mem->am_type == 2) {
 		for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
 			agp_i810_bind_page(sc, offset + i,
-			    mem->am_physical + i);
+			    mem->am_physical + i, 0);
 		mem->am_offset = offset;
 		mem->am_is_bound = 1;
 		return 0;
diff -Naurp old/src/sys/dev/pci/agp_intel.c new/src/sys/dev/pci/agp_intel.c
--- old/src/sys/dev/pci/agp_intel.c	2010-11-13 14:52:05.000000000 +0100
+++ new/src/sys/dev/pci/agp_intel.c	2011-02-08 11:14:00.000000000 +0100
@@ -65,7 +65,7 @@ struct agp_intel_softc {
 
 static u_int32_t agp_intel_get_aperture(struct agp_softc *);
 static int agp_intel_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_intel_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_intel_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_intel_unbind_page(struct agp_softc *, off_t);
 static void agp_intel_flush_tlb(struct agp_softc *);
 static int agp_intel_init(struct agp_softc *);
@@ -77,6 +77,7 @@ static struct agp_methods agp_intel_meth
 	agp_intel_bind_page,
 	agp_intel_unbind_page,
 	agp_intel_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -342,7 +343,8 @@ agp_intel_set_aperture(struct agp_softc
 }
 
 static int
-agp_intel_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_intel_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_intel_softc *isc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agp_sis.c new/src/sys/dev/pci/agp_sis.c
--- old/src/sys/dev/pci/agp_sis.c	2010-11-13 14:52:05.000000000 +0100
+++ new/src/sys/dev/pci/agp_sis.c	2011-02-08 11:14:00.000000000 +0100
@@ -54,7 +54,7 @@ struct agp_sis_softc {
 
 static u_int32_t agp_sis_get_aperture(struct agp_softc *);
 static int agp_sis_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_sis_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_sis_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_sis_unbind_page(struct agp_softc *, off_t);
 static void agp_sis_flush_tlb(struct agp_softc *);
 
@@ -64,6 +64,7 @@ static struct agp_methods agp_sis_method
 	agp_sis_bind_page,
 	agp_sis_unbind_page,
 	agp_sis_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -190,7 +191,8 @@ agp_sis_set_aperture(struct agp_softc *s
 }
 
 static int
-agp_sis_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_sis_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_sis_softc *ssc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/agpvar.h new/src/sys/dev/pci/agpvar.h
--- old/src/sys/dev/pci/agpvar.h	2009-05-06 12:34:32.000000000 +0200
+++ new/src/sys/dev/pci/agpvar.h	2011-02-08 11:14:00.000000000 +0100
@@ -103,9 +103,11 @@ struct agp_softc;
 struct agp_methods {
 	u_int32_t (*get_aperture)(struct agp_softc *);
 	int (*set_aperture)(struct agp_softc *, u_int32_t);
-	int (*bind_page)(struct agp_softc *, off_t, bus_addr_t);
+	int (*bind_page)(struct agp_softc *, off_t, bus_addr_t, int);
 	int (*unbind_page)(struct agp_softc *, off_t);
 	void (*flush_tlb)(struct agp_softc *);
+	void (*dma_sync)(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+	    bus_size_t, int);
 	int (*enable)(struct agp_softc *, u_int32_t mode);
 	struct agp_memory *(*alloc_memory)(struct agp_softc *, int, vsize_t);
 	int (*free_memory)(struct agp_softc *, struct agp_memory *);
@@ -115,7 +117,7 @@ struct agp_methods {
 
 #define AGP_GET_APERTURE(sc)	 ((sc)->as_methods->get_aperture(sc))
 #define AGP_SET_APERTURE(sc,a)	 ((sc)->as_methods->set_aperture((sc),(a)))
-#define AGP_BIND_PAGE(sc,o,p)	 ((sc)->as_methods->bind_page((sc),(o),(p)))
+#define AGP_BIND_PAGE(sc,o,p,f)	 ((sc)->as_methods->bind_page((sc),(o),(p),(f)))
 #define AGP_UNBIND_PAGE(sc,o)	 ((sc)->as_methods->unbind_page((sc), (o)))
 #define AGP_FLUSH_TLB(sc)	 ((sc)->as_methods->flush_tlb(sc))
 #define AGP_ENABLE(sc,m)	 ((sc)->as_methods->enable((sc),(m)))
@@ -167,6 +169,7 @@ int agpbusprint(void *, const char *);
  * Functions private to the AGP code.
  */
 void agp_flush_cache(void);
+void agp_flush_cache_range(vaddr_t, vsize_t);
 int agp_find_caps(pci_chipset_tag_t, pcitag_t);
 int agp_map_aperture(struct pci_attach_args *, struct agp_softc *, int);
 struct agp_gatt *agp_alloc_gatt(struct agp_softc *);
@@ -196,6 +199,22 @@ int agp_alloc_dmamem(bus_dma_tag_t, size
 void agp_free_dmamem(bus_dma_tag_t, size_t, bus_dmamap_t, void *,
 		     bus_dma_segment_t *, int) ;
 
+int	agp_bus_dma_init(struct agp_softc *, bus_addr_t, bus_addr_t,
+	    bus_dma_tag_t *);
+void	agp_bus_dma_destroy(struct agp_softc *, bus_dma_tag_t);
+void	agp_bus_dma_set_alignment(bus_dma_tag_t, bus_dmamap_t,
+	    u_long);
+
+struct agp_map;
+
+int	agp_init_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, struct
+	    agp_map **);
+void	agp_destroy_map(struct agp_map *);
+int	agp_map_subregion(struct agp_map *, bus_size_t, bus_size_t,
+	    bus_space_handle_t *);
+void	agp_unmap_subregion(struct agp_map *, bus_space_handle_t,
+	    bus_size_t);
+
 MALLOC_DECLARE(M_AGP);
 
 /*
@@ -268,6 +287,6 @@ void agp_memory_info(void *, void *, str
  * XXX horrible hack to allow drm code to use our mapping
  * of VGA chip registers
  */
-int agp_i810_borrow(bus_addr_t, bus_space_handle_t *);
+int agp_i810_borrow(bus_addr_t, bus_space_tag_t *, bus_space_handle_t *);
 
 #endif /* !_PCI_AGPPRIV_H_ */
diff -Naurp old/src/sys/dev/pci/agp_via.c new/src/sys/dev/pci/agp_via.c
--- old/src/sys/dev/pci/agp_via.c	2010-11-13 14:52:05.000000000 +0100
+++ new/src/sys/dev/pci/agp_via.c	2011-02-08 11:14:00.000000000 +0100
@@ -50,7 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: agp_via.c,v
 
 static u_int32_t agp_via_get_aperture(struct agp_softc *);
 static int agp_via_set_aperture(struct agp_softc *, u_int32_t);
-static int agp_via_bind_page(struct agp_softc *, off_t, bus_addr_t);
+static int agp_via_bind_page(struct agp_softc *, off_t, bus_addr_t, int);
 static int agp_via_unbind_page(struct agp_softc *, off_t);
 static void agp_via_flush_tlb(struct agp_softc *);
 
@@ -60,6 +60,7 @@ static struct agp_methods agp_via_method
 	agp_via_bind_page,
 	agp_via_unbind_page,
 	agp_via_flush_tlb,
+	NULL,
 	agp_generic_enable,
 	agp_generic_alloc_memory,
 	agp_generic_free_memory,
@@ -228,7 +229,8 @@ agp_via_set_aperture(struct agp_softc *s
 }
 
 static int
-agp_via_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
+agp_via_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical,
+    int flags)
 {
 	struct agp_via_softc *asc = sc->as_chipc;
 
diff -Naurp old/src/sys/dev/pci/drm/drm_agpsupport.c new/src/sys/dev/pci/drm/drm_agpsupport.c
--- old/src/sys/dev/pci/drm/drm_agpsupport.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_agpsupport.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,375 @@
+/*-
+ * Copyright 1999 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.
+ *
+ * Author:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *
+ */
+
+/*
+ * Support code for tying the kernel AGP support to DRM drivers and
+ * the DRM's AGP ioctls.
+ */
+
+#include "drmP.h"
+
+struct drm_agp_mem	*drm_agp_lookup_entry(struct drm_device *, void *);
+void			 drm_agp_remove_entry(struct drm_device *,
+			     struct drm_agp_mem *);
+
+int
+drm_agp_info(struct drm_device * dev, struct drm_agp_info *info)
+{
+	struct agp_info	*kern;
+
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+
+	kern = &dev->agp->info;
+#ifndef DRM_NO_AGP
+	agp_get_info(dev->agp->agpdev, kern);
+#endif
+	info->agp_version_major = 1;
+	info->agp_version_minor = 0;
+	info->mode = kern->ai_mode;
+	info->aperture_base = kern->ai_aperture_base;
+	info->aperture_size = kern->ai_aperture_size;
+	info->memory_allowed = kern->ai_memory_allowed;
+	info->memory_used = kern->ai_memory_used;
+	info->id_vendor = kern->ai_devid & 0xffff;
+	info->id_device = kern->ai_devid >> 16;
+
+	return (0);
+}
+
+int
+drm_agp_info_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_info	*info = data;
+
+	return (drm_agp_info(dev, info));
+}
+
+int
+drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	return (drm_agp_acquire(dev));
+}
+
+int
+drm_agp_acquire(struct drm_device *dev)
+{
+#ifndef DRM_NO_AGP
+	int	retcode;
+
+	if (dev->agp == NULL || dev->agp->acquired)
+		return (EINVAL);
+
+	retcode = agp_acquire(dev->agp->agpdev);
+	if (retcode)
+		return (retcode);
+
+	dev->agp->acquired = 1;
+#endif
+	return (0);
+}
+
+int
+drm_agp_release_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	return (drm_agp_release(dev));
+}
+
+int
+drm_agp_release(struct drm_device * dev)
+{
+#ifndef DRM_NO_AGP
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+	agp_release(dev->agp->agpdev);
+	dev->agp->acquired = 0;
+#endif
+	return (0);
+}
+
+int
+drm_agp_enable(struct drm_device *dev, drm_agp_mode_t mode)
+{
+	int	retcode = 0;
+#ifndef DRM_NO_AGP
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+	
+	dev->agp->mode = mode.mode;
+	if ((retcode = agp_enable(dev->agp->agpdev, mode.mode)) == 0)
+		dev->agp->enabled = 1;
+#endif
+	return (retcode);
+}
+
+int
+drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_mode	*mode = data;
+
+	return (drm_agp_enable(dev, *mode));
+}
+
+int
+drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
+{
+#ifndef DRM_NO_AGP
+	struct drm_agp_mem	*entry;
+	void			*handle;
+	struct agp_memory_info	 info;
+	unsigned long		 pages;
+	u_int32_t		 type;
+
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+
+	entry = drm_alloc(sizeof(*entry));
+	if (entry == NULL)
+		return (ENOMEM);
+
+	pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
+	type = (u_int32_t)request->type;
+
+	handle = agp_alloc_memory(dev->agp->agpdev, type,
+	    pages << AGP_PAGE_SHIFT);
+	if (handle == NULL) {
+		drm_free(entry);
+		return (ENOMEM);
+	}
+	
+	entry->handle = handle;
+	entry->bound = 0;
+	entry->pages = pages;
+
+	agp_memory_info(dev->agp->agpdev, entry->handle, &info);
+
+	request->handle = (unsigned long)entry->handle;
+        request->physical = info.ami_physical;
+	DRM_LOCK();
+	TAILQ_INSERT_HEAD(&dev->agp->memory, entry, link);
+	DRM_UNLOCK();
+#endif
+
+	return (0);
+}
+
+int
+drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_buffer	*request = data;
+
+	return (drm_agp_alloc(dev, request));
+}
+
+/*
+ * find entry on agp list. Must be called with dev_lock locked.
+ */
+struct drm_agp_mem *
+drm_agp_lookup_entry(struct drm_device *dev, void *handle)
+{
+	struct drm_agp_mem	*entry;
+
+	TAILQ_FOREACH(entry, &dev->agp->memory, link) {
+		if (entry->handle == handle)
+			break;
+	}
+	return (entry);
+}
+
+int
+drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
+{
+	struct drm_agp_mem	*entry;
+	int			 retcode;
+
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+
+	DRM_LOCK();
+	entry = drm_agp_lookup_entry(dev, (void *)request->handle);
+	if (entry == NULL || !entry->bound) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+
+	retcode =  agp_unbind_memory(dev->agp->agpdev, entry->handle);
+
+	if (retcode == 0)
+		entry->bound = 0;
+	DRM_UNLOCK();
+
+	return (retcode);
+}
+
+int
+drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_binding	*request = data;
+
+	return (drm_agp_unbind(dev, request));
+}
+
+int
+drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
+{
+	struct drm_agp_mem	*entry;
+	int			 retcode, page;
+	
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+
+	DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE);
+
+	DRM_LOCK();
+	entry = drm_agp_lookup_entry(dev, (void *)request->handle);
+	if (entry == NULL || entry->bound) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+
+	page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
+
+	retcode = agp_bind_memory(dev->agp->agpdev, entry->handle,
+	    page * PAGE_SIZE);
+	if (retcode == 0)
+		entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+	DRM_UNLOCK();
+
+	return (retcode);
+}
+
+int
+drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_binding	*request = data;
+
+	return (drm_agp_bind(dev, request));
+}
+
+/*
+ * Remove entry from list and free. Call locked.
+ */
+void
+drm_agp_remove_entry(struct drm_device *dev, struct drm_agp_mem *entry)
+{
+	TAILQ_REMOVE(&dev->agp->memory, entry, link);
+
+	if (entry->bound)
+		agp_unbind_memory(dev->agp->agpdev, entry->handle);
+	agp_free_memory(dev->agp->agpdev, entry->handle);
+	drm_free(entry);
+}
+
+void
+drm_agp_takedown(struct drm_device *dev)
+{
+	struct drm_agp_mem	*entry;
+
+	if (dev->agp == NULL)
+		return;
+
+	/*
+	 * Remove AGP resources, but leave dev->agp intact until
+	 * we detach the device
+	 */
+	DRM_LOCK();
+	while ((entry = TAILQ_FIRST(&dev->agp->memory)) != NULL)
+		drm_agp_remove_entry(dev, entry);
+	DRM_UNLOCK();
+
+	drm_agp_release(dev);
+	dev->agp->enabled  = 0;
+}
+
+int
+drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
+{
+	struct drm_agp_mem	*entry;
+	
+	if (dev->agp == NULL || !dev->agp->acquired)
+		return (EINVAL);
+
+	DRM_LOCK();
+	entry = drm_agp_lookup_entry(dev, (void*)request->handle);
+	if (entry == NULL) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+
+	drm_agp_remove_entry(dev, entry);
+	DRM_UNLOCK();
+   
+	return (0);
+}
+
+int
+drm_agp_free_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_agp_buffer	*request = data;
+
+	return (drm_agp_free(dev, request));
+}
+
+struct drm_agp_head *
+drm_agp_init(void)
+{
+#ifndef DRM_NO_AGP
+	struct agp_softc	*agpdev;
+	struct drm_agp_head	*head = NULL;
+	int		 	 agp_available = 1;
+   
+	agpdev = agp_find_device(0);
+	if (agpdev == NULL)
+		agp_available = 0;
+
+	DRM_DEBUG("agp_available = %d\n", agp_available);
+
+	if (agp_available) {
+		head = drm_calloc(1, sizeof(*head));
+		if (head == NULL)
+			return (NULL);
+		head->agpdev = agpdev;
+		agp_get_info(agpdev, &head->info);
+		head->base = head->info.ai_aperture_base;
+		TAILQ_INIT(&head->memory);
+	}
+	return (head);
+#else
+	return (NULL);
+#endif
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_atomic.h new/src/sys/dev/pci/drm/drm_atomic.h
--- old/src/sys/dev/pci/drm/drm_atomic.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_atomic.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,193 @@
+/**
+ * \file drm_atomic.h
+ * Atomic operations used in the DRM which may or may not be provided by the OS.
+ * 
+ * \author Eric Anholt <anholt@FreeBSD.org>
+ */
+
+/*-
+ * Copyright 2004 Eric Anholt
+ * 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.
+ */
+
+#ifdef __OpenBSD__
+#include <machine/atomic.h>
+#endif
+
+#ifdef __NetBSD__
+#include <sys/atomic.h>
+#endif
+
+/* Many of these implementations are rather fake, but good enough. */
+
+typedef u_int32_t atomic_t;
+
+#if !defined(__NetBSD__)
+
+#ifdef __FreeBSD__
+#define atomic_set(p, v)	(*(p) = (v))
+#define atomic_read(p)		(*(p))
+#define atomic_inc(p)		atomic_add_int(p, 1)
+#define atomic_dec(p)		atomic_subtract_int(p, 1)
+#define atomic_add(n, p)	atomic_add_int(p, n)
+#define atomic_sub(n, p)	atomic_subtract_int(p, n)
+#else /* __FreeBSD__ */
+/* FIXME */
+#define atomic_set(p, v)	(*(p) = (v))
+#define atomic_read(p)		(*(p))
+#define atomic_inc(p)		(*(p) += 1)
+#define atomic_dec(p)		(*(p) -= 1)
+#define atomic_add(n, p)	(*(p) += (n))
+#define atomic_sub(n, p)	(*(p) -= (n))
+/* FIXME */
+#define atomic_add_int(p, v)      *(p) += v
+#define atomic_subtract_int(p, v) *(p) -= v
+#ifdef __OpenBSD__
+#define atomic_set_int(p, bits)		atomic_setbits_int(p,bits)
+#define atomic_clear_int(p, bits)	atomic_clearbits_int(p,bits)
+#else
+#define atomic_set_int(p, bits)   *(p) |= (bits)
+#define atomic_clear_int(p, bits) *(p) &= ~(bits)
+#endif
+#endif /* !__FreeBSD__ */
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 500000)
+#if defined(__i386__) || defined(__amd64__)
+/* The extra atomic functions from 5.0 haven't been merged to 4.x */
+static __inline int
+atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
+{
+	int res = exp;
+
+	__asm __volatile (
+	"	lock ;			"
+	"	cmpxchgl %1,%2 ;	"
+	"       setz	%%al ;		"
+	"	movzbl	%%al,%0 ;	"
+	"1:				"
+	"# atomic_cmpset_int"
+	: "+a" (res)			/* 0 (result) */
+	: "r" (src),			/* 1 */
+	  "m" (*(dst))			/* 2 */
+	: "memory");				 
+
+	return (res);
+}
+#else /* __i386__ */
+static __inline int
+atomic_cmpset_int(__volatile__ u_int *dst, u_int old, u_int new)
+{
+	int s = splhigh();
+	if (*dst==old) {
+		*dst = new;
+		splx(s);
+		return 1;
+	}
+	splx(s);
+	return 0;
+}
+#endif /* !__i386__ */
+#endif /* !__FreeBSD_version || __FreeBSD_version < 500000 */
+
+static __inline atomic_t
+test_and_set_bit(u_int b, volatile void *p)
+{
+	int s = splhigh();
+	unsigned int m = 1<<b;
+	unsigned int r = *(volatile int *)p & m;
+	*(volatile int *)p |= m;
+	splx(s);
+	return r;
+}
+
+#else /* !defined(__NetBSD__) */
+
+#define	atomic_set(p, v)		(*((volatile uint32_t *)p) = (v))
+#define atomic_read(p)		(*(p))
+#define atomic_inc(p)		atomic_inc_uint(p)
+#define atomic_dec(p)		atomic_dec_uint(p)
+#define atomic_add(n, p)	atomic_add_int(p, n)
+#define atomic_sub(n, p)	atomic_add_int(p, -(n))
+
+#define	atomic_set_int(p, bits)		atomic_or_uint(p, bits)
+#define	atomic_clear_int(p, bits)	atomic_and_uint(p, ~(bits))
+#define atomic_setbits_int(p, bits)	atomic_set_int(p, bits)
+#define atomic_clearbits_int(p, bits)	atomic_clear_int(p, bits)
+
+#define	atomic_cmpset_int(p, o, n)					\
+			((old == atomic_cas_uint(p, o, n)) ? 1 : 0)
+
+static __inline atomic_t
+test_and_set_bit(u_int b, volatile void *p)
+{
+	volatile uint32_t *val;
+	uint32_t mask, old;
+
+	val = (volatile uint32_t *)p;
+	mask = 1 << b;
+
+	do {
+		old = *val;
+		if ((old & mask) != 0)
+			break;
+	} while (atomic_cas_uint(val, old, old | mask) != old);
+
+	return old & mask;
+}
+
+#endif /* !defined(__NetBSD__) */
+
+static __inline void
+clear_bit(u_int b, volatile void *p)
+{
+	atomic_clear_int(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f));
+}
+
+static __inline void
+set_bit(u_int b, volatile void *p)
+{
+	atomic_set_int(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f));
+}
+
+static __inline int
+test_bit(u_int b, volatile void *p)
+{
+	return !!(((volatile u_int *)p)[b >> 5] & (1 << (b & 0x1f)));
+}
+
+static __inline int
+find_first_zero_bit(volatile void *p, int max_)
+{
+	int b;
+	volatile u_int *ptr = (volatile u_int *)p;
+
+	for (b = 0; b < max_; b += 32) {
+		if (ptr[b >> 5] != ~0) {
+			for (;;) {
+				if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
+					return b;
+				b++;
+			}
+		}
+	}
+	return max_;
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_bufs.c new/src/sys/dev/pci/drm/drm_bufs.c
--- old/src/sys/dev/pci/drm/drm_bufs.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_bufs.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,1018 @@
+/*-
+ * 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>
+ *
+ */
+
+/** @file drm_bufs.c
+ * Implementation of the ioctls for setup of DRM mappings and DMA buffers.
+ */
+
+#include "sys/types.h"
+#include "dev/pci/pcireg.h"
+
+#include "drmP.h"
+
+int	drm_addbufs_pci(struct drm_device *, struct drm_buf_desc *);
+int	drm_addbufs_sg(struct drm_device *, struct drm_buf_desc *);
+int	drm_addbufs_agp(struct drm_device *, struct drm_buf_desc *);
+
+/*
+ * 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;
+}
+
+struct drm_local_map *
+drm_core_findmap(struct drm_device *dev, unsigned long offset)
+{
+	struct drm_local_map	*map;
+
+	DRM_LOCK();
+	TAILQ_FOREACH(map, &dev->maplist, link) {
+		if (offset == map->ext)
+			break;
+	}
+	DRM_UNLOCK();
+	return (map);
+}
+
+int
+drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size,
+    enum drm_map_type type, enum drm_map_flags flags,
+    struct drm_local_map **map_ptr)
+{
+	struct drm_local_map	*map;
+	int			 align, ret = 0;
+#if 0 /* disabled for now */
+	struct drm_agp_mem	*entry;
+	int			 valid;
+#endif 
+
+	/* 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 ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) {
+		DRM_ERROR("Requested removable map for non-DRM_SHM\n");
+		return EINVAL;
+	}
+	if ((offset & PAGE_MASK) || (size & PAGE_MASK)) {
+		DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n",
+		    offset, size);
+		return EINVAL;
+	}
+	if (offset + size < offset) {
+		DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n",
+		    offset, size);
+		return EINVAL;
+	}
+
+	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset,
+	    size, type);
+
+	/*
+	 * Check if this is just another version of a kernel-allocated map, and
+	 * just hand that back if so.
+	 */
+	DRM_LOCK();
+	if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER ||
+	    type == _DRM_SHM) {
+		TAILQ_FOREACH(map, &dev->maplist, link) {
+			if (map->type == type && (map->offset == offset ||
+			    (map->type == _DRM_SHM &&
+			    map->flags == _DRM_CONTAINS_LOCK))) {
+				DRM_DEBUG("Found kernel map %d\n", type);
+				goto done;
+			}
+		}
+	}
+	DRM_UNLOCK();
+
+	/* Allocate a new map structure, fill it in, and do any type-specific
+	 * initialization necessary.
+	 */
+	map = drm_calloc(1, sizeof(*map));
+	if (map == NULL) {
+		DRM_LOCK();
+		return ENOMEM;
+	}
+
+	map->offset = offset;
+	map->size = size;
+	map->type = type;
+	map->flags = flags;
+
+
+	DRM_LOCK();
+#if !defined(__NetBSD__)
+	ret = extent_alloc(dev->handle_ext, map->size, PAGE_SIZE, 0,
+#else /* !defined(__NetBSD__) */
+	ret = extent_alloc(dev->handle_ext, map->size, PAGE_SIZE,
+#endif /* !defined(__NetBSD__) */
+	    0, EX_NOWAIT, &map->ext);
+	if (ret) {
+		DRM_ERROR("can't find free offset\n");
+		DRM_UNLOCK();
+		drm_free(map);
+		return (ret);
+	}
+	DRM_UNLOCK();
+
+	switch (map->type) {
+	case _DRM_REGISTERS:
+		if (!(map->flags & _DRM_WRITE_COMBINING))
+			break;
+		/* FALLTHROUGH */
+	case _DRM_FRAME_BUFFER:
+		if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0)
+			map->mtrr = 1;
+		break;
+	case _DRM_AGP:
+		/*valid = 0;*/
+		/* In some cases (i810 driver), user space may have already
+		 * added the AGP base itself, because dev->agp->base previously
+		 * only got set during AGP enable.  So, only add the base
+		 * address if the map's offset isn't already within the
+		 * aperture.
+		 */
+		if (map->offset < dev->agp->base ||
+		    map->offset > dev->agp->base +
+		    dev->agp->info.ai_aperture_size - 1) {
+			map->offset += dev->agp->base;
+		}
+		map->mtrr   = dev->agp->mtrr; /* for getmap */
+#if 0 /* disabled for now */
+		/*
+		 * If agp is in control of userspace (some intel drivers for
+		 * example. In which case ignore this loop.
+		 */
+		DRM_LOCK();
+		TAILQ_FOREACH(entry, &dev->agp->memory, link) {
+			DRM_DEBUG("bound = %p, pages = %p, %p\n",
+			    entry->bound, entry->pages,
+			    entry->pages * PAGE_SIZE);
+			if ((map->offset >= entry->bound) &&
+			    (map->offset + map->size <=
+			    entry->bound + entry->pages * PAGE_SIZE)) {
+				valid = 1;
+				break;
+			}
+		}
+		if (!TAILQ_EMPTY(&dev->agp->memory) && !valid) {
+			DRM_UNLOCK();
+			drm_free(map);
+			DRM_ERROR("invalid agp map requested\n");
+			return (EACCES);
+		}
+		DRM_UNLOCK();
+#endif
+		break;
+	case _DRM_SCATTER_GATHER:
+		if (dev->sg == NULL) {
+			drm_free(map);
+			return (EINVAL);
+		}
+		map->offset += dev->sg->handle;
+		break;
+	case _DRM_SHM:
+	case _DRM_CONSISTENT:
+		/*
+		 * Unfortunately, we don't get any alignment specification from
+		 * the caller, so we have to guess. So try to align the bus
+		 * address of the map to its size if possible, otherwise just
+		 * assume PAGE_SIZE alignment.
+		 */
+		align = map->size;
+		if ((align & (align - 1)) != 0)
+			align = PAGE_SIZE;
+		map->dmamem = drm_dmamem_alloc(dev->dmat, map->size, align,
+		    1, map->size, 0, 0);
+		if (map->dmamem == NULL) {
+			drm_free(map);
+			return (ENOMEM);
+		}
+		map->handle = map->dmamem->kva;
+		map->offset = map->dmamem->map->dm_segs[0].ds_addr;
+		if (map->type == _DRM_SHM && map->flags & _DRM_CONTAINS_LOCK) {
+			DRM_LOCK();
+			/* Prevent a 2nd X Server from creating a 2nd lock */
+			if (dev->lock.hw_lock != NULL) {
+				DRM_UNLOCK();
+				drm_dmamem_free(dev->dmat, map->dmamem);
+				drm_free(map);
+				return (EBUSY);
+			}
+			dev->lock.hw_lock = map->handle;
+			DRM_UNLOCK();
+		}
+		break;
+	default:
+		DRM_ERROR("Bad map type %d\n", map->type);
+		drm_free(map);
+		return EINVAL;
+	}
+
+	DRM_LOCK();
+	TAILQ_INSERT_TAIL(&dev->maplist, map, link);
+done:
+	DRM_UNLOCK();
+
+	DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset,
+	    map->size);
+
+	*map_ptr = map;
+
+	return 0;
+}
+
+int
+drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_map		*request = data;
+	struct drm_local_map	*map;
+	int			 err;
+
+	if (!(file_priv->flags & (FREAD|FWRITE)))
+		return EACCES; /* Require read/write */
+
+	err = drm_addmap(dev, request->offset, request->size, request->type,
+	    request->flags, &map);
+	if (err != 0)
+		return err;
+
+	request->offset = map->offset;
+	request->size = map->size;
+	request->type = map->type;
+	request->flags = map->flags;
+	request->mtrr = map->mtrr;
+	request->handle = map->handle;
+
+	request->handle = (void *)map->ext;
+
+	return 0;
+}
+
+void
+drm_rmmap(struct drm_device *dev, struct drm_local_map *map)
+{
+	DRM_LOCK();
+	drm_rmmap_locked(dev, map);
+	DRM_UNLOCK();
+}
+
+
+void
+drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
+{
+	TAILQ_REMOVE(&dev->maplist, map, link);
+
+	switch (map->type) {
+	case _DRM_REGISTERS:
+		/* FALLTHROUGH */
+	case _DRM_FRAME_BUFFER:
+		if (map->mtrr) {
+			int retcode;
+			
+			retcode = drm_mtrr_del(0, map->offset, map->size,
+			    DRM_MTRR_WC);
+			DRM_DEBUG("mtrr_del = %d\n", retcode);
+		}
+		break;
+	case _DRM_AGP:
+		/* FALLTHROUGH */
+	case _DRM_SCATTER_GATHER:
+		break;
+	case _DRM_SHM:
+		/* FALLTHROUGH */
+	case _DRM_CONSISTENT:
+		drm_dmamem_free(dev->dmat, map->dmamem);
+		break;
+	default:
+		DRM_ERROR("Bad map type %d\n", map->type);
+		break;
+	}
+
+	/* NOCOALESCE set, can't fail */
+	extent_free(dev->handle_ext, map->ext, map->size, EX_NOWAIT);
+
+	drm_free(map);
+}
+
+/* Remove a map private from list and deallocate resources if the mapping
+ * isn't in use.
+ */
+
+int
+drm_rmmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_local_map	*map;
+	struct drm_map		*request = data;
+
+	DRM_LOCK();
+	TAILQ_FOREACH(map, &dev->maplist, link) {
+		if (map->handle == request->handle &&
+		    map->flags & _DRM_REMOVABLE)
+			break;
+	}
+
+	/* No match found. */
+	if (map == NULL) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+
+	drm_rmmap_locked(dev, map);
+
+	DRM_UNLOCK();
+
+	return 0;
+}
+
+/*
+ * DMA buffers api.
+ *
+ * The implementation used to be significantly more complicated, but the
+ * complexity has been moved into the drivers as different buffer management
+ * schemes evolved.
+ *
+ * This api is going to die eventually.
+ */
+
+int
+drm_dma_setup(struct drm_device *dev)
+{
+
+	dev->dma = drm_calloc(1, sizeof(*dev->dma));
+	if (dev->dma == NULL)
+		return (ENOMEM);
+
+#if !defined(__NetBSD__)
+	rw_init(&dev->dma->dma_lock, "drmdma");
+#else /* !defined(__NetBSD__) */
+	rw_init(&dev->dma->dma_lock);
+#endif /* !defined(__NetBSD__) */
+
+	return (0);
+}
+
+void
+drm_cleanup_buf(struct drm_device *dev, struct drm_buf_entry *entry)
+{
+	int i;
+
+	if (entry->seg_count) {
+		for (i = 0; i < entry->seg_count; i++)
+			drm_dmamem_free(dev->dmat, entry->seglist[i]);
+		drm_free(entry->seglist);
+
+		entry->seg_count = 0;
+	}
+
+   	if (entry->buf_count) {
+	   	for (i = 0; i < entry->buf_count; i++) {
+			drm_free(entry->buflist[i].dev_private);
+		}
+		drm_free(entry->buflist);
+
+		entry->buf_count = 0;
+	}
+}
+
+void
+drm_dma_takedown(struct drm_device *dev)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	int			 i;
+
+	if (dma == NULL)
+		return;
+
+	/* Clear dma buffers */
+	for (i = 0; i <= DRM_MAX_ORDER; i++)
+		drm_cleanup_buf(dev, &dma->bufs[i]);
+
+	drm_free(dma->buflist);
+	drm_free(dma->pagelist);
+	drm_free(dev->dma);
+	dev->dma = NULL;
+}
+
+
+void
+drm_free_buffer(struct drm_device *dev, struct drm_buf *buf)
+{
+	if (buf == NULL)
+		return;
+
+	buf->pending = 0;
+	buf->file_priv= NULL;
+	buf->used = 0;
+}
+
+void
+drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	int			 i;
+
+	if (dma == NULL)
+		return;
+	for (i = 0; i < dma->buf_count; i++) {
+		if (dma->buflist[i]->file_priv == file_priv)
+				drm_free_buffer(dev, dma->buflist[i]);
+	}
+}
+
+/* Call into the driver-specific DMA handler */
+int
+drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_dma		*d = data;
+	int			 ret = 0;
+
+	if (dev->driver->dma_ioctl == NULL) {
+		DRM_DEBUG("DMA ioctl on driver with no dma handler\n");
+		return (EINVAL);
+	}
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	/* Please don't send us buffers.
+	 */
+	if (d->send_count != 0) {
+		DRM_ERROR("process trying to send %d buffers via drmDMA\n",
+		    d->send_count);
+		return (EINVAL);
+	}
+
+	/* We'll send you buffers.
+	 */
+	if (d->request_count < 0 || d->request_count > dma->buf_count) {
+		DRM_ERROR("Process trying to get %d buffers (of %d max)\n",
+			  d->request_count, dma->buf_count);
+		return (EINVAL);
+	}
+	d->granted_count = 0;
+
+	if (d->request_count)
+		ret = dev->driver->dma_ioctl(dev, d, file_priv);
+	return (ret);
+}
+
+int
+drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_buf_entry	*entry;
+	struct drm_buf		*buf, **temp_buflist;
+	unsigned long		 agp_offset, offset;
+	int			 alignment, count, order, page_order, size;
+	int			 total, byte_count, i;
+#if 0 /* disabled for now */
+	struct drm_agp_mem	*agp_entry;
+	int			 valid;
+#endif
+
+	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);
+
+	/* Make sure buffers are located in AGP memory that we own */
+
+	/* Breaks MGA due to drm_alloc_agp not setting up entries for the
+	 * memory.  Safe to ignore for now because these ioctls are still
+	 * root-only.
+	 */
+#if 0 /* disabled for now */
+	valid = 0;
+	DRM_LOCK();
+	TAILQ_FOREACH(agp_entry, &dev->agp->memory, link) {
+		if ((agp_offset >= agp_entry->bound) &&
+		    (agp_offset + total * count <=
+		    agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+			valid = 1;
+			break;
+		}
+	}
+	if (!TAILQ_EMPTY(&dev->agp->memory) && !valid) {
+		DRM_DEBUG("zone invalid\n");
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+	DRM_UNLOCK();
+#endif
+
+	entry = &dma->bufs[order];
+
+	entry->buflist = drm_calloc(count, sizeof(*entry->buflist));
+	if (entry->buflist == NULL)
+		return ENOMEM;
+
+	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->used = 0;
+
+		buf->offset = (dma->byte_count + offset);
+		buf->bus_address = agp_offset + offset;
+		buf->pending = 0;
+		buf->file_priv = NULL;
+
+		buf->dev_private = drm_calloc(1, dev->driver->buf_priv_size);
+		if (buf->dev_private == NULL) {
+			/* Set count correctly so we free the proper amount. */
+			entry->buf_count = count;
+			drm_cleanup_buf(dev, entry);
+			return ENOMEM;
+		}
+
+		offset += alignment;
+		entry->buf_count++;
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	/* OpenBSD lacks realloc in kernel */
+	temp_buflist = drm_realloc(dma->buflist,
+	    dma->buf_count * sizeof(*dma->buflist),
+	    (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist));
+	if (temp_buflist == NULL) {
+		/* Free the entry because it isn't valid */
+		drm_cleanup_buf(dev, entry);
+		return 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);
+
+	request->count = entry->buf_count;
+	request->size = size;
+
+	dma->flags = _DRM_DMA_USE_AGP;
+
+	return 0;
+}
+
+int
+drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_buf		*buf, **temp_buflist;
+	struct drm_buf_entry	*entry;
+	int			 alignment, byte_count, count, i, order;
+	int			 page_count, page_order, size, total;
+	unsigned long		 offset, *temp_pagelist;
+
+	count = request->count;
+	order = drm_order(request->size);
+	size = 1 << order;
+
+	DRM_DEBUG("count=%d, size=%d (%d), order=%d\n",
+	    request->count, request->size, size, 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;
+
+	entry = &dma->bufs[order];
+
+	entry->buflist = drm_calloc(count, sizeof(*entry->buflist));
+	entry->seglist = drm_calloc(count, sizeof(*entry->seglist));
+
+	/* Keep the original pagelist until we know all the allocations
+	 * have succeeded
+	 */
+	temp_pagelist = drm_calloc((dma->page_count + (count << page_order)),
+	    sizeof(*dma->pagelist));
+
+	if (entry->buflist == NULL || entry->seglist == NULL || 
+	    temp_pagelist == NULL) {
+		drm_free(temp_pagelist);
+		drm_free(entry->seglist);
+		drm_free(entry->buflist);
+		return ENOMEM;
+	}
+
+	memcpy(temp_pagelist, dma->pagelist, dma->page_count * 
+	    sizeof(*dma->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) {
+		struct drm_dmamem *mem = drm_dmamem_alloc(dev->dmat, size,
+		    alignment, 1, size, 0, 0);
+		if (mem == NULL) {
+			/* Set count correctly so we free the proper amount. */
+			entry->buf_count = count;
+			entry->seg_count = count;
+			drm_cleanup_buf(dev, entry);
+			drm_free(temp_pagelist);
+			return ENOMEM;
+		}
+
+		entry->seglist[entry->seg_count++] = mem;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ %p\n", dma->page_count +
+			    page_count, (void *)((vaddr_t)mem->kva + PAGE_SIZE * i));
+			temp_pagelist[dma->page_count + page_count++] = 
+			    (vaddr_t)mem->kva + 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->used = 0;
+			buf->offset = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)((vaddr_t)mem->kva + offset);
+			buf->bus_address = mem->map->dm_segs[0].ds_addr +
+			    offset;
+			buf->pending = 0;
+			buf->file_priv = NULL;
+
+			buf->dev_private = drm_calloc(1,
+			    dev->driver->buf_priv_size);
+			if (buf->dev_private == NULL) {
+				/* Set count so we free the proper amount. */
+				entry->buf_count = count;
+				entry->seg_count = count;
+				drm_cleanup_buf(dev, entry);
+				drm_free(temp_pagelist);
+				return ENOMEM;
+			}
+
+			DRM_DEBUG("buffer %d\n",
+			    entry->buf_count);
+		}
+		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));
+	if (temp_buflist == NULL) {
+		/* Free the entry because it isn't valid */
+		drm_cleanup_buf(dev, entry);
+		drm_free(temp_pagelist);
+		return ENOMEM;
+	}
+	dma->buflist = temp_buflist;
+
+	for (i = 0; i < entry->buf_count; i++)
+		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+
+	/* No allocations failed, so now we can replace the orginal pagelist
+	 * with the new one.
+	 */
+	drm_free(dma->pagelist);
+	dma->pagelist = temp_pagelist;
+
+	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);
+
+	request->count = entry->buf_count;
+	request->size = size;
+
+	return 0;
+
+}
+
+int
+drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_buf_entry	*entry;
+	struct drm_buf		*buf, **temp_buflist;
+	unsigned long		 agp_offset, offset;
+	int			 alignment, byte_count, count, i, order;
+	int			 page_order, size, total;
+
+	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);
+
+	entry = &dma->bufs[order];
+
+	entry->buflist = drm_calloc(count, sizeof(*entry->buflist));
+	if (entry->buflist == NULL)
+		return ENOMEM;
+
+	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->used = 0;
+
+		buf->offset = (dma->byte_count + offset);
+		buf->bus_address = agp_offset + offset;
+		buf->pending = 0;
+		buf->file_priv = NULL;
+
+		buf->dev_private = drm_calloc(1, dev->driver->buf_priv_size);
+		if (buf->dev_private == NULL) {
+			/* Set count correctly so we free the proper amount. */
+			entry->buf_count = count;
+			drm_cleanup_buf(dev, entry);
+			return ENOMEM;
+		}
+
+		DRM_DEBUG("buffer %d\n", entry->buf_count);
+
+		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));
+	if (temp_buflist == NULL) {
+		/* Free the entry because it isn't valid */
+		drm_cleanup_buf(dev, entry);
+		return 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);
+
+	request->count = entry->buf_count;
+	request->size = size;
+
+	dma->flags = _DRM_DMA_USE_SG;
+
+	return 0;
+}
+
+int
+drm_addbufs(struct drm_device *dev, struct drm_buf_desc *request)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	int			 order, ret;
+
+	if (request->count < 0 || request->count > 4096)
+		return (EINVAL);
+	
+	order = drm_order(request->size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
+		return (EINVAL);
+
+	rw_enter_write(&dma->dma_lock);
+
+	/* No more allocations after first buffer-using ioctl. */
+	if (dma->buf_use != 0) {
+		rw_exit_write(&dma->dma_lock);
+		return (EBUSY);
+	}
+	/* No more than one allocation per order */
+	if (dma->bufs[order].buf_count != 0) {
+		rw_exit_write(&dma->dma_lock);
+		return (ENOMEM);
+	}
+
+	if (request->flags & _DRM_AGP_BUFFER)
+		ret = drm_addbufs_agp(dev, request);
+	else if (request->flags & _DRM_SG_BUFFER)
+		ret = drm_addbufs_sg(dev, request);
+	else
+		ret = drm_addbufs_pci(dev, request);
+
+	rw_exit_write(&dma->dma_lock);
+
+	return (ret);
+}
+
+int
+drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_buf_free	*request = data;
+	struct drm_buf		*buf;
+	int			 i, idx, retcode = 0;
+
+	DRM_DEBUG("%d\n", request->count);
+	
+	rw_enter_write(&dma->dma_lock);
+	for (i = 0; i < request->count; i++) {
+		if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) {
+			retcode = EFAULT;
+			break;
+		}
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n", idx,
+			    dma->buf_count - 1);
+			retcode = EINVAL;
+			break;
+		}
+		buf = dma->buflist[idx];
+		if (buf->file_priv != file_priv) {
+			DRM_ERROR("Process %d freeing buffer not owned\n",
+			    DRM_CURRENTPID);
+			retcode = EINVAL;
+			break;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	rw_exit_write(&dma->dma_lock);
+
+	return retcode;
+}
+
+int
+drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_device_dma	*dma = dev->dma;
+	struct drm_buf_map	*request = data;
+	struct vnode		*vn;
+	vaddr_t			 address, vaddr;
+	voff_t			 foff;
+	vsize_t			 size;
+	const int		 zero = 0;
+	int			 i, retcode = 0;
+
+	if (!vfinddev(file_priv->kdev, VCHR, &vn))
+		return EINVAL;
+
+	rw_enter_write(&dma->dma_lock);
+	dev->dma->buf_use++;	/* Can't allocate more after this call */
+	rw_exit_write(&dma->dma_lock);
+
+	if (request->count < dma->buf_count)
+		goto done;
+
+	if ((dev->driver->flags & DRIVER_AGP &&
+	    (dma->flags & _DRM_DMA_USE_AGP)) ||
+	    (dev->driver->flags & DRIVER_SG &&
+	    (dma->flags & _DRM_DMA_USE_SG))) {
+		struct drm_local_map *map = dev->agp_buffer_map;
+
+		if (map == NULL) {
+			DRM_DEBUG("couldn't find agp buffer map\n");
+			retcode = EINVAL;
+			goto done;
+		}
+		size = round_page(map->size);
+		foff = map->ext;
+	} else {
+		size = round_page(dma->byte_count),
+		foff = 0;
+	}
+
+#if !defined(__NetBSD__)
+	vaddr = uvm_map_hint(curproc, VM_PROT_READ | VM_PROT_WRITE);
+	retcode = uvm_mmap(&curproc->p_vmspace->vm_map, &vaddr, size,
+	    UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED,
+	    (caddr_t)vn, foff, curproc->p_rlimit[RLIMIT_MEMLOCK].rlim_cur,
+	    curproc);
+#else /* !defined(__NetBSD__) */
+	vaddr = curproc->p_emul->e_vm_default_addr(curproc,
+	    (vaddr_t)curproc->p_vmspace->vm_daddr, size);
+	retcode = uvm_mmap(&curproc->p_vmspace->vm_map, &vaddr, size,
+	    UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED,
+	    (caddr_t)vn, foff, curproc->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+#endif /* !defined(__NetBSD__) */
+	if (retcode) {
+		DRM_DEBUG("uvm_mmap failed\n");
+		goto done;
+	}
+
+	request->virtual = (void *)vaddr;
+
+	for (i = 0; i < dma->buf_count; i++) {
+		if (DRM_COPY_TO_USER(&request->list[i].idx,
+		    &dma->buflist[i]->idx, sizeof(request->list[0].idx))) {
+			retcode = EFAULT;
+			goto done;
+		}
+		if (DRM_COPY_TO_USER(&request->list[i].total,
+		    &dma->buflist[i]->total, sizeof(request->list[0].total))) {
+			retcode = EFAULT;
+			goto done;
+		}
+		if (DRM_COPY_TO_USER(&request->list[i].used, &zero,
+		    sizeof(zero))) {
+			retcode = EFAULT;
+			goto done;
+		}
+		address = vaddr + dma->buflist[i]->offset; /* *** */
+		if (DRM_COPY_TO_USER(&request->list[i].address, &address,
+		    sizeof(address))) {
+			retcode = EFAULT;
+			goto done;
+		}
+	}
+
+ done:
+	request->count = dma->buf_count;
+
+	DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
+
+	return retcode;
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_context.c new/src/sys/dev/pci/drm/drm_context.c
--- old/src/sys/dev/pci/drm/drm_context.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_context.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,173 @@
+/*-
+ * 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>
+ *
+ */
+
+/** @file drm_context.c
+ * Implementation of the context management ioctls.
+ */
+
+#include "drmP.h"
+
+/* ================================================================
+ * Context bitmap support
+ */
+
+void
+drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
+{
+	if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || 
+	    dev->ctx_bitmap == NULL) {
+		DRM_ERROR("Attempt to free invalid context handle: %d\n",
+		   ctx_handle);
+		return;
+	}
+
+	DRM_LOCK();
+	clear_bit(ctx_handle, dev->ctx_bitmap);
+	DRM_UNLOCK();
+	return;
+}
+
+int
+drm_ctxbitmap_next(struct drm_device *dev)
+{
+	int	bit;
+
+	if (dev->ctx_bitmap == NULL)
+		return (-1);
+
+	DRM_LOCK();
+	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
+	if (bit >= DRM_MAX_CTXBITMAP) {
+		DRM_UNLOCK();
+		return (-1);
+	}
+
+	set_bit(bit, dev->ctx_bitmap);
+	DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
+	DRM_UNLOCK();
+	return (bit);
+}
+
+int
+drm_ctxbitmap_init(struct drm_device *dev)
+{
+	atomic_t	*bitmap;
+	int		 i, temp;
+
+	
+	if ((bitmap = drm_calloc(1, PAGE_SIZE)) == NULL)
+		return (ENOMEM);
+	DRM_LOCK();
+	dev->ctx_bitmap = bitmap;
+	DRM_UNLOCK();
+
+	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+		temp = drm_ctxbitmap_next(dev);
+	   	DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
+	}
+
+	return (0);
+}
+
+void
+drm_ctxbitmap_cleanup(struct drm_device *dev)
+{
+	atomic_t *bitmap;
+
+	DRM_LOCK();
+	bitmap = dev->ctx_bitmap;
+	dev->ctx_bitmap = NULL;
+	DRM_UNLOCK();
+	drm_free(bitmap);
+}
+
+int
+drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_ctx_res	*res = data;
+	struct drm_ctx		 ctx;
+	int			 i;
+
+	if (res->count >= DRM_RESERVED_CONTEXTS) {
+		bzero(&ctx, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			if (DRM_COPY_TO_USER(&res->contexts[i],
+			    &ctx, sizeof(ctx)))
+				return (EFAULT);
+		}
+	}
+	res->count = DRM_RESERVED_CONTEXTS;
+
+	return (0);
+}
+
+int
+drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_ctx	*ctx = data;
+
+	ctx->handle = drm_ctxbitmap_next(dev);
+	if (ctx->handle == DRM_KERNEL_CONTEXT) {
+		/* Skip kernel's context and get a new one. */
+		ctx->handle = drm_ctxbitmap_next(dev);
+	}
+	DRM_DEBUG("%d\n", ctx->handle);
+	if (ctx->handle == -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+		/* Should this return -EBUSY instead? */
+		return (ENOMEM);
+	}
+
+	return (0);
+}
+
+int
+drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_ctx	*ctx = data;
+
+	/* This is 0, because we don't handle any context flags */
+	ctx->flags = 0;
+
+	return (0);
+}
+
+int
+drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_ctx	*ctx = data;
+
+	DRM_DEBUG("%d\n", ctx->handle);
+	if (ctx->handle != DRM_KERNEL_CONTEXT)
+		drm_ctxbitmap_free(dev, ctx->handle);
+
+	return (0);
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_drv.c new/src/sys/dev/pci/drm/drm_drv.c
--- old/src/sys/dev/pci/drm/drm_drv.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_drv.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,1852 @@
+/*-
+ * Copyright 2007-2009 Owain G. Ainsworth <oga@openbsd.org>
+ * Copyright © 2008 Intel Corporation
+ * Copyright 2003 Eric Anholt
+ * 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>
+ *    Daryll Strauss <daryll@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *    Eric Anholt <eric@anholt.net>
+ *    Owain Ainsworth <oga@openbsd.org>
+ *
+ */
+
+/** @file drm_drv.c
+ * The catch-all file for DRM device support, including module setup/teardown,
+ * open/close, and ioctl dispatch.
+ */
+
+#include <sys/param.h>
+#if !defined(__NetBSD__)
+#include <sys/limits.h>
+#else
+#include <sys/syslimits.h>
+#endif
+#include <sys/systm.h>
+#include <uvm/uvm_extern.h>
+
+#include <sys/ttycom.h> /* for TIOCSGRP */
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_sarea.h"
+
+#ifdef DRM_DEBUG_DEFAULT_ON
+int drm_debug_flag = 1;
+#else
+int drm_debug_flag = 0;
+#endif
+
+int	 drm_firstopen(struct drm_device *);
+int	 drm_lastclose(struct drm_device *);
+void	 drm_attach(struct device *, struct device *, void *);
+#if !defined(__NetBSD__)
+int	 drm_probe(struct device *, void *, void *);
+#else /* !defined(__NetBSD__) */
+int	 drm_probe(struct device *, struct cfdata *, void *);
+#endif /* !defined(__NetBSD__) */
+int	 drm_detach(struct device *, int);
+#if !defined(__NetBSD__)
+int	 drm_activate(struct device *, int);
+#else /* !defined(__NetBSD__) */
+int	 drm_activate(struct device *, devact_t);
+#endif /* !defined(__NetBSD__) */
+int	 drmprint(void *, const char *);
+int	 drm_dequeue_event(struct drm_device *, struct drm_file *, size_t,
+	     struct drm_pending_event **);
+
+int	 drm_getunique(struct drm_device *, void *, struct drm_file *);
+int	 drm_version(struct drm_device *, void *, struct drm_file *);
+int	 drm_setversion(struct drm_device *, void *, struct drm_file *);
+int	 drm_getmagic(struct drm_device *, void *, struct drm_file *);
+int	 drm_authmagic(struct drm_device *, void *, struct drm_file *);
+int	 drm_file_cmp(struct drm_file *, struct drm_file *);
+SPLAY_PROTOTYPE(drm_file_tree, drm_file, link, drm_file_cmp);
+
+/* functions used by the per-open handle  code to grab references to object */
+void	 drm_handle_ref(struct drm_obj *);
+void	 drm_handle_unref(struct drm_obj *);
+
+int	 drm_handle_cmp(struct drm_handle *, struct drm_handle *);
+int	 drm_name_cmp(struct drm_obj *, struct drm_obj *);
+int	 drm_fault(struct uvm_faultinfo *, vaddr_t, vm_page_t *, int, int,
+#if !defined(__NetBSD__)
+	     vm_fault_t, vm_prot_t, int);
+#else /* !defined(__NetBSD__) */
+	     vm_prot_t, int);
+#endif /* !defined(__NetBSD__) */
+boolean_t	 drm_flush(struct uvm_object *, voff_t, voff_t, int);
+
+SPLAY_PROTOTYPE(drm_obj_tree, drm_handle, entry, drm_handle_cmp);
+SPLAY_PROTOTYPE(drm_name_tree, drm_obj, entry, drm_name_cmp);
+
+#if defined(__NetBSD__)
+const struct cdevsw drm_cdevsw = {
+	drmopen,
+	drmclose,
+	drmread,
+	nowrite,
+	drmioctl,
+	nostop,
+	notty,
+	drmpoll,
+	drmmmap,
+	nokqfilter,
+	D_TTY | D_NEGOFFSAFE
+};
+#endif /* defined(__NetBSD__) */
+
+/*
+ * attach drm to a pci-based driver.
+ *
+ * This function does all the pci-specific calculations for the 
+ * drm_attach_args.
+ */
+struct device *
+drm_attach_pci(const struct drm_driver_info *driver, struct pci_attach_args *pa,
+    int is_agp, struct device *dev)
+{
+	struct drm_attach_args arg;
+
+	arg.driver = driver;
+	arg.dmat = pa->pa_dmat;
+	arg.bst = pa->pa_memt;
+	arg.irq = pa->pa_intrline;
+	arg.is_agp = is_agp;
+
+	arg.busid_len = 20;
+	arg.busid = malloc(arg.busid_len + 1, M_DRM, M_NOWAIT);
+	if (arg.busid == NULL) {
+		printf("%s: no memory for drm\n", dev->dv_xname);
+		return (NULL);
+	}
+	snprintf(arg.busid, arg.busid_len, "pci:%04x:%02x:%02x.%1x",
+#if !defined(__NetBSD__)
+	    pa->pa_domain, pa->pa_bus, pa->pa_device, pa->pa_function);
+#else /* !defined(__NetBSD__) */
+	    device_unit(device_parent(device_parent(dev))),
+	    pa->pa_bus, pa->pa_device, pa->pa_function);
+#endif /* !defined(__NetBSD__) */
+
+	return (config_found(dev, &arg, drmprint));
+}
+
+int
+drmprint(void *aux, const char *pnp)
+{
+	if (pnp != NULL)
+		printf("drm at %s", pnp);
+	return (UNCONF);
+}
+
+int
+drm_pciprobe(struct pci_attach_args *pa, const struct drm_pcidev *idlist)
+{
+	const struct drm_pcidev *id_entry;
+
+	id_entry = drm_find_description(PCI_VENDOR(pa->pa_id),
+	    PCI_PRODUCT(pa->pa_id), idlist);
+	if (id_entry != NULL)
+		return 1;
+
+	return 0;
+}
+
+int
+#if !defined(__NetBSD__)
+drm_probe(struct device *parent, void *match, void *aux)
+#else /* !defined(__NetBSD__) */
+drm_probe(struct device *parent, struct cfdata *match, void *aux)
+#endif /* !defined(__NetBSD__) */
+{
+	struct drm_attach_args *da = aux;
+
+	return (da->driver != NULL ? 1 : 0);
+}
+
+void
+drm_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct drm_device	*dev = (struct drm_device *)self;
+	struct drm_attach_args	*da = aux;
+
+	dev->dev_private = parent;
+	dev->driver = da->driver;
+
+	dev->dmat = da->dmat;
+	dev->bst = da->bst;
+	dev->irq = da->irq;
+	dev->unique = da->busid;
+	dev->unique_len = da->busid_len;
+
+#if !defined(__NetBSD__)
+	rw_init(&dev->dev_lock, "drmdevlk");
+#else /* !defined(__NetBSD__) */
+	rw_init(&dev->dev_lock);
+#endif /* !defined(__NetBSD__) */
+	mtx_init(&dev->lock.spinlock, IPL_NONE);
+	mtx_init(&dev->event_lock, IPL_TTY);
+#if defined(__NetBSD__)
+	cv_init(&dev->lock.condvar, "drmlkq");
+#endif /* defined(__NetBSD__) */
+
+	TAILQ_INIT(&dev->maplist);
+	SPLAY_INIT(&dev->files);
+
+	if (dev->driver->vblank_pipes != 0 && drm_vblank_init(dev,
+	    dev->driver->vblank_pipes)) {
+		printf(": failed to allocate vblank data\n");
+		goto error;
+	}
+
+	/*
+	 * the dma buffers api is just weird. offset 1Gb to ensure we don't
+	 * conflict with it.
+	 */
+	dev->handle_ext = extent_create("drmext", 1024*1024*1024, LONG_MAX,
+	    M_DRM, NULL, 0, EX_NOWAIT | EX_NOCOALESCE);
+	if (dev->handle_ext == NULL) {
+		DRM_ERROR("Failed to initialise handle extent\n");
+		goto error;
+	}
+
+	if (dev->driver->flags & DRIVER_AGP) {
+		if (da->is_agp)
+			dev->agp = drm_agp_init();
+		if (dev->driver->flags & DRIVER_AGP_REQUIRE &&
+		    dev->agp == NULL) {
+			printf(": couldn't find agp\n");
+			goto error;
+		}
+		if (dev->agp != NULL) {
+			if (drm_mtrr_add(dev->agp->info.ai_aperture_base,
+			    dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0)
+				dev->agp->mtrr = 1;
+		}
+	}
+
+	if (drm_ctxbitmap_init(dev) != 0) {
+		printf(": couldn't allocate memory for context bitmap.\n");
+		goto error;
+	}
+
+	if (dev->driver->flags & DRIVER_GEM) {
+		mtx_init(&dev->obj_name_lock, IPL_NONE);
+		SPLAY_INIT(&dev->name_tree);
+		KASSERT(dev->driver->gem_size >= sizeof(struct drm_obj));
+		/* XXX unique name */
+		pool_init(&dev->objpl, dev->driver->gem_size, 0, 0, 0,
+#if !defined(__NetBSD__)
+		    "drmobjpl", &pool_allocator_nointr);
+#else /* !defined(__NetBSD__) */
+		    "drmobjpl", &pool_allocator_nointr, IPL_NONE);
+#endif /* !defined(__NetBSD__) */
+	}
+
+#if defined(__NetBSD__)
+	(void)pmf_device_register(self, NULL, NULL);
+#endif /* defined(__NetBSD__) */
+
+	printf("\n");
+	return;
+
+error:
+	drm_lastclose(dev);
+}
+
+int
+drm_detach(struct device *self, int flags)
+{
+	struct drm_device *dev = (struct drm_device *)self;
+
+#if defined(__NetBSD__)
+	pmf_device_deregister(self);
+#endif /* defined(__NetBSD__) */
+
+	drm_lastclose(dev);
+
+	drm_ctxbitmap_cleanup(dev);
+
+	extent_destroy(dev->handle_ext);
+
+	drm_vblank_cleanup(dev);
+
+	if (dev->agp && dev->agp->mtrr) {
+		int retcode;
+
+		retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base,
+		    dev->agp->info.ai_aperture_size, DRM_MTRR_WC);
+		DRM_DEBUG("mtrr_del = %d", retcode);
+	}
+
+
+	if (dev->agp != NULL) {
+		drm_free(dev->agp);
+		dev->agp = NULL;
+	}
+
+#if defined(__NetBSD__)
+	if (dev->driver->flags & DRIVER_GEM) {
+		pool_destroy(&dev->objpl);
+		mutex_destroy(&dev->obj_name_lock);
+	}
+	cv_destroy(&dev->lock.condvar);
+	mutex_destroy(&dev->event_lock);
+	mutex_destroy(&dev->lock.spinlock);
+	rw_destroy(&dev->dev_lock);
+#endif /* defined(__NetBSD__) */
+
+	return 0;
+}
+
+int
+#if !defined(__NetBSD__)
+drm_activate(struct device *self, int act)
+#else /* !defined(__NetBSD__) */
+drm_activate(struct device *self, devact_t act)
+#endif /* !defined(__NetBSD__) */
+{
+	switch (act) {
+#if !defined(__NetBSD__)
+	case DVACT_ACTIVATE:
+		break;
+#endif /* !defined(__NetBSD__) */
+
+	case DVACT_DEACTIVATE:
+		/* FIXME */
+		break;
+	}
+	return (0);
+}
+
+#if !defined(__NetBSD__)
+struct cfattach drm_ca = {
+	sizeof(struct drm_device), drm_probe, drm_attach,
+	drm_detach, drm_activate
+};
+
+struct cfdriver drm_cd = {
+	0, "drm", DV_DULL
+};
+#else /* !defined(__NetBSD__) */
+/*
+ * We do not use CFATTACH_DECL_NEW, in order to be compatible with
+ * the rest of the code, which does for instance
+ *	struct drm_device *dev = (struct drm_device *)self;
+ * instead of
+ *	struct drm_device *dev = device_private(self);
+ */
+CFATTACH_DECL(drmdev, sizeof(struct drm_device),
+    drm_probe, drm_attach, drm_detach, drm_activate);
+#endif /* !defined(__NetBSD__) */
+
+const struct drm_pcidev *
+drm_find_description(int vendor, int device, const struct drm_pcidev *idlist)
+{
+	int i = 0;
+	
+	for (i = 0; idlist[i].vendor != 0; i++) {
+		if ((idlist[i].vendor == vendor) &&
+		    (idlist[i].device == device))
+			return &idlist[i];
+	}
+	return NULL;
+}
+
+int
+drm_file_cmp(struct drm_file *f1, struct drm_file *f2)
+{
+	return (f1->minor < f2->minor ? -1 : f1->minor > f2->minor);
+}
+
+SPLAY_GENERATE(drm_file_tree, drm_file, link, drm_file_cmp);
+
+struct drm_file *
+drm_find_file_by_minor(struct drm_device *dev, int minor)
+{
+	struct drm_file	key;
+
+	key.minor = minor;
+	return (SPLAY_FIND(drm_file_tree, &dev->files, &key));
+}
+
+int
+drm_firstopen(struct drm_device *dev)
+{
+	struct drm_local_map	*map;
+	int			 i;
+
+	/* prebuild the SAREA */
+	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
+	    _DRM_CONTAINS_LOCK, &map);
+	if (i != 0)
+		return i;
+
+	if (dev->driver->firstopen)
+		dev->driver->firstopen(dev);
+
+	if (dev->driver->flags & DRIVER_DMA) {
+		if ((i = drm_dma_setup(dev)) != 0)
+			return (i);
+	}
+
+	dev->magicid = 1;
+
+	dev->irq_enabled = 0;
+	dev->if_version = 0;
+
+	dev->buf_pgid = 0;
+
+	DRM_DEBUG("\n");
+
+	return 0;
+}
+
+int
+drm_lastclose(struct drm_device *dev)
+{
+	struct drm_local_map	*map, *mapsave;
+
+	DRM_DEBUG("\n");
+
+	if (dev->driver->lastclose != NULL)
+		dev->driver->lastclose(dev);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+
+	drm_agp_takedown(dev);
+	drm_dma_takedown(dev);
+
+	DRM_LOCK();
+	if (dev->sg != NULL) {
+		struct drm_sg_mem *sg = dev->sg; 
+		dev->sg = NULL;
+
+		DRM_UNLOCK();
+		drm_sg_cleanup(dev, sg);
+		DRM_LOCK();
+	}
+
+	for (map = TAILQ_FIRST(&dev->maplist); map != TAILQ_END(&dev->maplist);
+	    map = mapsave) {
+		mapsave = TAILQ_NEXT(map, link);
+		if ((map->flags & _DRM_DRIVER) == 0)
+			drm_rmmap_locked(dev, map);
+	}
+
+	if (dev->lock.hw_lock != NULL) {
+		dev->lock.hw_lock = NULL; /* SHM removed */
+		dev->lock.file_priv = NULL;
+		mtx_enter(&dev->lock.spinlock);
+#if !defined(__NetBSD__)
+		wakeup(&dev->lock); /* there should be nothing sleeping on it */
+#else /* !defined(__NetBSD__) */
+		cv_broadcast(&dev->lock.condvar);
+#endif /* !defined(__NetBSD__) */
+		mtx_leave(&dev->lock.spinlock);
+	}
+	DRM_UNLOCK();
+
+	return 0;
+}
+
+int
+#if !defined(__NetBSD__)
+drmopen(dev_t kdev, int flags, int fmt, struct proc *p)
+#else /* !defined(__NetBSD__) */
+drmopen(dev_t kdev, int flags, int fmt, struct lwp *p)
+#endif /* !defined(__NetBSD__) */
+{
+	struct drm_device	*dev = NULL;
+	struct drm_file		*file_priv;
+	int			 ret = 0;
+
+	dev = drm_get_device_from_kdev(kdev);
+	if (dev == NULL)
+		return (ENXIO);
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+
+	if (flags & O_EXCL)
+		return (EBUSY); /* No exclusive opens */
+
+	DRM_LOCK();
+	if (dev->open_count++ == 0) {
+		DRM_UNLOCK();
+		if ((ret = drm_firstopen(dev)) != 0)
+			goto err;
+	} else {
+		DRM_UNLOCK();
+	}
+
+	/* always allocate at least enough space for our data */
+	file_priv = drm_calloc(1, max(dev->driver->file_priv_size,
+	    sizeof(*file_priv)));
+	if (file_priv == NULL) {
+		ret = ENOMEM;
+		goto err;
+	}
+
+	file_priv->kdev = kdev;
+	file_priv->flags = flags;
+	file_priv->minor = minor(kdev);
+	TAILQ_INIT(&file_priv->evlist);
+#if defined(__NetBSD__)
+	cv_init(&file_priv->evlist_condvar, "drmread");
+#endif /* defined(__NetBSD__) */
+	file_priv->event_space = 4096; /* 4k for event buffer */
+	DRM_DEBUG("minor = %d\n", file_priv->minor);
+
+	/* for compatibility root is always authenticated */
+	file_priv->authenticated = DRM_SUSER(p);
+
+	if (dev->driver->flags & DRIVER_GEM) {
+		SPLAY_INIT(&file_priv->obj_tree);
+		mtx_init(&file_priv->table_lock, IPL_NONE);
+	}
+
+	if (dev->driver->open) {
+		ret = dev->driver->open(dev, file_priv);
+		if (ret != 0) {
+			goto free_priv;
+		}
+	}
+
+	DRM_LOCK();
+	/* first opener automatically becomes master if root */
+	if (SPLAY_EMPTY(&dev->files) && !DRM_SUSER(p)) {
+		DRM_UNLOCK();
+		ret = EPERM;
+		goto free_priv;
+	}
+
+	file_priv->master = SPLAY_EMPTY(&dev->files);
+
+	SPLAY_INSERT(drm_file_tree, &dev->files, file_priv);
+	DRM_UNLOCK();
+
+	return (0);
+
+free_priv:
+#if defined(__NetBSD__)
+	mutex_destroy(&file_priv->table_lock);
+	cv_destroy(&file_priv->evlist_condvar);
+#endif /* defined(__NetBSD__) */
+	drm_free(file_priv);
+err:
+	DRM_LOCK();
+	--dev->open_count;
+	DRM_UNLOCK();
+	return (ret);
+}
+
+int
+#if !defined(__NetBSD__)
+drmclose(dev_t kdev, int flags, int fmt, struct proc *p)
+#else /* !defined(__NetBSD__) */
+drmclose(dev_t kdev, int flags, int fmt, struct lwp *p)
+#endif /* !defined(__NetBSD__) */
+{
+	struct drm_device		*dev = drm_get_device_from_kdev(kdev);
+	struct drm_file			*file_priv;
+	struct drm_pending_event	*ev, *evtmp;
+	int				 i, retcode = 0;
+
+	if (dev == NULL)
+		return (ENXIO);
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+
+	DRM_LOCK();
+	file_priv = drm_find_file_by_minor(dev, minor(kdev));
+	if (file_priv == NULL) {
+		DRM_ERROR("can't find authenticator\n");
+		retcode = EINVAL;
+		goto done;
+	}
+	DRM_UNLOCK();
+
+	if (dev->driver->close != NULL)
+		dev->driver->close(dev, file_priv);
+
+	DRM_DEBUG("pid = %d, device = %p, open_count = %d\n",
+	    DRM_CURRENTPID, &dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.file_priv == file_priv) {
+		DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
+		    DRM_CURRENTPID,
+		    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+		drm_lock_free(&dev->lock,
+		    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	}
+	if (dev->driver->flags & DRIVER_DMA)
+		drm_reclaim_buffers(dev, file_priv);
+
+	mtx_enter(&dev->event_lock);
+	for (i = 0; i < dev->vblank->vb_num; i++) {
+		struct drmevlist *list = &dev->vblank->vb_crtcs[i].vbl_events;
+		for (ev = TAILQ_FIRST(list); ev != TAILQ_END(list);
+		    ev = evtmp) {
+			evtmp = TAILQ_NEXT(ev, link);
+			if (ev->file_priv == file_priv) {
+				TAILQ_REMOVE(list, ev, link);
+				drm_vblank_put(dev, i);
+				ev->destroy(ev);
+			}
+		}
+	}
+	while ((ev = TAILQ_FIRST(&file_priv->evlist)) != NULL) {
+		TAILQ_REMOVE(&file_priv->evlist, ev, link);
+		ev->destroy(ev);
+	}
+	mtx_leave(&dev->event_lock);
+
+	DRM_LOCK();
+	if (dev->driver->flags & DRIVER_GEM) {
+		struct drm_handle	*han;
+		mtx_enter(&file_priv->table_lock);
+		while ((han = SPLAY_ROOT(&file_priv->obj_tree)) != NULL) {
+			SPLAY_REMOVE(drm_obj_tree, &file_priv->obj_tree, han);
+			drm_handle_unref(han->obj);
+			drm_free(han);
+		}
+		mtx_leave(&file_priv->table_lock);
+	}
+
+	dev->buf_pgid = 0;
+
+	SPLAY_REMOVE(drm_file_tree, &dev->files, file_priv);
+#if defined(__NetBSD__)
+	mutex_destroy(&file_priv->table_lock);
+	cv_destroy(&file_priv->evlist_condvar);
+#endif /* defined(__NetBSD__) */
+	drm_free(file_priv);
+
+done:
+	if (--dev->open_count == 0) {
+		DRM_UNLOCK();
+		retcode = drm_lastclose(dev);
+	} else
+		DRM_UNLOCK();
+
+	return (retcode);
+}
+
+/* drmioctl is called whenever a process performs an ioctl on /dev/drm.
+ */
+int
+drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags, 
+#if !defined(__NetBSD__)
+    struct proc *p)
+#else /* !defined(__NetBSD__) */
+    struct lwp *p)
+#endif /* !defined(__NetBSD__) */
+{
+	struct drm_device *dev = drm_get_device_from_kdev(kdev);
+	struct drm_file *file_priv;
+
+	if (dev == NULL)
+		return ENODEV;
+
+	DRM_LOCK();
+	file_priv = drm_find_file_by_minor(dev, minor(kdev));
+	DRM_UNLOCK();
+	if (file_priv == NULL) {
+		DRM_ERROR("can't find authenticator\n");
+		return EINVAL;
+	}
+
+	++file_priv->ioctl_count;
+
+	DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02lx, dev %p, auth=%d\n",
+	    DRM_CURRENTPID, cmd, DRM_IOCTL_NR(cmd), &dev->device,
+	    file_priv->authenticated);
+
+	switch (cmd) {
+	case FIONBIO:
+	case FIOASYNC:
+		return 0;
+
+	case TIOCSPGRP:
+		dev->buf_pgid = *(int *)data;
+		return 0;
+
+	case TIOCGPGRP:
+		*(int *)data = dev->buf_pgid;
+		return 0;
+	case DRM_IOCTL_VERSION:
+		return (drm_version(dev, data, file_priv));
+	case DRM_IOCTL_GET_UNIQUE:
+		return (drm_getunique(dev, data, file_priv));
+	case DRM_IOCTL_GET_MAGIC:
+		return (drm_getmagic(dev, data, file_priv));
+	case DRM_IOCTL_WAIT_VBLANK:
+		return (drm_wait_vblank(dev, data, file_priv));
+	case DRM_IOCTL_MODESET_CTL:
+		return (drm_modeset_ctl(dev, data, file_priv));
+	case DRM_IOCTL_GEM_CLOSE:
+		return (drm_gem_close_ioctl(dev, data, file_priv));
+
+	/* removed */
+	case DRM_IOCTL_GET_MAP:
+		/* FALLTHROUGH */
+	case DRM_IOCTL_GET_CLIENT:
+		/* FALLTHROUGH */
+	case DRM_IOCTL_GET_STATS:
+		return (EINVAL);
+	/*
+	 * no-oped ioctls, we don't check permissions on them because
+	 * they do nothing. they'll be removed as soon as userland is
+	 * definitely purged
+	 */
+	case DRM_IOCTL_SET_SAREA_CTX:
+	case DRM_IOCTL_BLOCK:
+	case DRM_IOCTL_UNBLOCK:
+	case DRM_IOCTL_MOD_CTX:
+	case DRM_IOCTL_MARK_BUFS:
+	case DRM_IOCTL_FINISH:
+	case DRM_IOCTL_INFO_BUFS:
+	case DRM_IOCTL_SWITCH_CTX:
+	case DRM_IOCTL_NEW_CTX:
+	case DRM_IOCTL_GET_SAREA_CTX:
+		return (0);
+	}
+
+	if (file_priv->authenticated == 1) {
+		switch (cmd) {
+		case DRM_IOCTL_RM_MAP:
+			return (drm_rmmap_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_GET_CTX:
+			return (drm_getctx(dev, data, file_priv));
+		case DRM_IOCTL_RES_CTX:
+			return (drm_resctx(dev, data, file_priv));
+		case DRM_IOCTL_LOCK:
+			return (drm_lock(dev, data, file_priv));
+		case DRM_IOCTL_UNLOCK:
+			return (drm_unlock(dev, data, file_priv));
+		case DRM_IOCTL_MAP_BUFS:
+			return (drm_mapbufs(dev, data, file_priv));
+		case DRM_IOCTL_FREE_BUFS:
+			return (drm_freebufs(dev, data, file_priv));
+		case DRM_IOCTL_DMA:
+			return (drm_dma(dev, data, file_priv));
+		case DRM_IOCTL_AGP_INFO:
+			return (drm_agp_info_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_GEM_FLINK:
+			return (drm_gem_flink_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_GEM_OPEN:
+			return (drm_gem_open_ioctl(dev, data, file_priv));
+
+		}
+	}
+
+	/* master is always root */
+	if (file_priv->master == 1) {
+		switch(cmd) {
+		case DRM_IOCTL_SET_VERSION:
+			return (drm_setversion(dev, data, file_priv));
+		case DRM_IOCTL_IRQ_BUSID:
+			return (drm_irq_by_busid(dev, data, file_priv));
+		case DRM_IOCTL_AUTH_MAGIC:
+			return (drm_authmagic(dev, data, file_priv));
+		case DRM_IOCTL_ADD_MAP:
+			return (drm_addmap_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_ADD_CTX:
+			return (drm_addctx(dev, data, file_priv));
+		case DRM_IOCTL_RM_CTX:
+			return (drm_rmctx(dev, data, file_priv));
+		case DRM_IOCTL_ADD_BUFS:
+			return (drm_addbufs(dev, (struct drm_buf_desc *)data));
+		case DRM_IOCTL_CONTROL:
+			return (drm_control(dev, data, file_priv));
+		case DRM_IOCTL_AGP_ACQUIRE:
+			return (drm_agp_acquire_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_RELEASE:
+			return (drm_agp_release_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_ENABLE:
+			return (drm_agp_enable_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_ALLOC:
+			return (drm_agp_alloc_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_FREE:
+			return (drm_agp_free_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_BIND:
+			return (drm_agp_bind_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_AGP_UNBIND:
+			return (drm_agp_unbind_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_SG_ALLOC:
+			return (drm_sg_alloc_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_SG_FREE:
+			return (drm_sg_free(dev, data, file_priv));
+		case DRM_IOCTL_ADD_DRAW:
+		case DRM_IOCTL_RM_DRAW:
+		case DRM_IOCTL_UPDATE_DRAW:
+			/*
+			 * Support removed from kernel since it's not used.
+			 * just return zero until userland stops calling this
+			 * ioctl.
+			 */
+			return (0);
+		case DRM_IOCTL_SET_UNIQUE:
+		/*
+		 * Deprecated in DRM version 1.1, and will return EBUSY
+		 * when setversion has
+		 * requested version 1.1 or greater.
+		 */
+			return (EBUSY);
+		}
+	}
+	if (dev->driver->ioctl != NULL)
+		return (dev->driver->ioctl(dev, cmd, data, file_priv));
+	else
+		return (EINVAL);
+}
+
+int
+drmread(dev_t kdev, struct uio *uio, int ioflag)
+{
+	struct drm_device		*dev = drm_get_device_from_kdev(kdev);
+	struct drm_file			*file_priv;
+	struct drm_pending_event	*ev;
+	int		 		 error = 0;
+
+	if (dev == NULL)
+		return (ENXIO);
+
+	DRM_LOCK();
+	file_priv = drm_find_file_by_minor(dev, minor(kdev));
+	DRM_UNLOCK();
+	if (file_priv == NULL)
+		return (ENXIO);
+
+	/*
+	 * The semantics are a little weird here. We will wait until we
+	 * have events to process, but as soon as we have events we will
+	 * only deliver as many as we have.
+	 * Note that events are atomic, if the read buffer will not fit in
+	 * a whole event, we won't read any of it out.
+	 */
+	mtx_enter(&dev->event_lock);
+	while (error == 0 && TAILQ_EMPTY(&file_priv->evlist)) {
+		if (ioflag & IO_NDELAY) {
+			mtx_leave(&dev->event_lock);
+			return (EAGAIN);
+		}
+#if !defined(__NetBSD__)
+		error = msleep(&file_priv->evlist, &dev->event_lock,
+		    PWAIT | PCATCH, "drmread", 0);
+#else /* !defined(__NetBSD__) */
+		error = cv_wait_sig(&file_priv->evlist_condvar, &dev->event_lock);
+#endif /* !defined(__NetBSD__) */
+	}
+	if (error) {
+		mtx_leave(&dev->event_lock);
+		return (error);
+	}
+	while (drm_dequeue_event(dev, file_priv, uio->uio_resid, &ev)) {
+		MUTEX_ASSERT_UNLOCKED(&dev->event_lock);
+		/* XXX we always destroy the event on error. */
+		error = uiomove(ev->event, ev->event->length, uio);
+		ev->destroy(ev);
+		if (error)
+			break;
+		mtx_enter(&dev->event_lock);
+	}
+	MUTEX_ASSERT_UNLOCKED(&dev->event_lock);
+
+	return (error);
+}
+
+/*
+ * Deqeue an event from the file priv in question. returning 1 if an
+ * event was found. We take the resid from the read as a parameter because
+ * we will only dequeue and event if the read buffer has space to fit the
+ * entire thing.
+ *
+ * We are called locked, but we will *unlock* the queue on return so that
+ * we may sleep to copyout the event.
+ */
+int
+drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
+    size_t resid, struct drm_pending_event **out)
+{
+	struct drm_pending_event	*ev;
+	int				 gotone = 0;
+
+	MUTEX_ASSERT_LOCKED(&dev->event_lock);
+	if ((ev = TAILQ_FIRST(&file_priv->evlist)) == NULL ||
+	    ev->event->length > resid)
+		goto out;
+
+	TAILQ_REMOVE(&file_priv->evlist, ev, link);
+	file_priv->event_space += ev->event->length;
+	*out = ev;
+	gotone = 1;
+
+out:
+	mtx_leave(&dev->event_lock);
+
+	return (gotone);
+}
+
+/* XXX kqfilter ... */
+int
+#if !defined(__NetBSD__)
+drmpoll(dev_t kdev, int events, struct proc *p)
+#else /* !defined(__NetBSD__) */
+drmpoll(dev_t kdev, int events, struct lwp *p)
+#endif /* !defined(__NetBSD__) */
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct drm_file		*file_priv;
+	int		 	 revents = 0;
+
+	if (dev == NULL)
+		return (POLLERR);
+
+	DRM_LOCK();
+	file_priv = drm_find_file_by_minor(dev, minor(kdev));
+	DRM_UNLOCK();
+	if (file_priv == NULL)
+		return (POLLERR);
+
+	mtx_enter(&dev->event_lock);
+	if (events & (POLLIN | POLLRDNORM)) {
+		if (!TAILQ_EMPTY(&file_priv->evlist))
+			revents |=  events & (POLLIN | POLLRDNORM);
+		else
+			selrecord(p, &file_priv->rsel);
+	}
+	mtx_leave(&dev->event_lock);
+
+	return (revents);
+}
+
+struct drm_local_map *
+drm_getsarea(struct drm_device *dev)
+{
+	struct drm_local_map	*map;
+
+	DRM_LOCK();
+	TAILQ_FOREACH(map, &dev->maplist, link) {
+		if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
+			break;
+	}
+	DRM_UNLOCK();
+	return (map);
+}
+
+paddr_t
+drmmmap(dev_t kdev, off_t offset, int prot)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct drm_local_map	*map;
+	struct drm_file		*file_priv;
+	enum drm_map_type	 type;
+
+	if (dev == NULL)
+		return (-1);
+
+	DRM_LOCK();
+	file_priv = drm_find_file_by_minor(dev, minor(kdev));
+	DRM_UNLOCK();
+	if (file_priv == NULL) {
+		DRM_ERROR("can't find authenticator\n");
+		return (-1);
+	}
+
+	if (!file_priv->authenticated)
+		return (-1);
+
+	if (dev->dma && offset >= 0 && offset < ptoa(dev->dma->page_count)) {
+		struct drm_device_dma *dma = dev->dma;
+		paddr_t	phys = -1;
+
+		rw_enter_write(&dma->dma_lock);
+		if (dma->pagelist != NULL)
+			phys = dma->pagelist[offset >> PAGE_SHIFT];
+		rw_exit_write(&dma->dma_lock);
+
+		return (phys);
+	}
+
+	/*
+	 * A sequential search of a linked list is
+ 	 * fine here because: 1) there will only be
+	 * about 5-10 entries in the list and, 2) a
+	 * DRI client only has to do this mapping
+	 * once, so it doesn't have to be optimized
+	 * for performance, even if the list was a
+	 * bit longer.
+	 */
+	DRM_LOCK();
+	TAILQ_FOREACH(map, &dev->maplist, link) {
+		if (offset >= map->ext &&
+		    offset < map->ext + map->size) {
+			offset -= map->ext;
+			break;
+		}
+	}
+
+	if (map == NULL) {
+		DRM_UNLOCK();
+		DRM_DEBUG("can't find map\n");
+		return (-1);
+	}
+	if (((map->flags & _DRM_RESTRICTED) && file_priv->master == 0)) {
+		DRM_UNLOCK();
+		DRM_DEBUG("restricted map\n");
+		return (-1);
+	}
+	type = map->type;
+	DRM_UNLOCK();
+
+	switch (type) {
+	case _DRM_FRAME_BUFFER:
+	case _DRM_REGISTERS:
+	case _DRM_AGP:
+		return (offset + map->offset);
+		break;
+	/* XXX unify all the bus_dmamem_mmap bits */
+	case _DRM_SCATTER_GATHER:
+		return (bus_dmamem_mmap(dev->dmat, dev->sg->mem->segs,
+		    dev->sg->mem->nsegs, map->offset - dev->sg->handle +
+		    offset, prot, BUS_DMA_NOWAIT));
+	case _DRM_SHM:
+	case _DRM_CONSISTENT:
+		return (bus_dmamem_mmap(dev->dmat, map->dmamem->segs,
+		    map->dmamem->nsegs, offset, prot, BUS_DMA_NOWAIT));
+	default:
+		DRM_ERROR("bad map type %d\n", type);
+		return (-1);	/* This should never happen. */
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Beginning in revision 1.1 of the DRM interface, getunique will return
+ * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
+ * before setunique has been called.  The format for the bus-specific part of
+ * the unique is not defined for any other bus.
+ */
+int
+drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_unique	 *u = data;
+
+	if (u->unique_len >= dev->unique_len) {
+		if (DRM_COPY_TO_USER(u->unique, dev->unique, dev->unique_len))
+			return EFAULT;
+	}
+	u->unique_len = dev->unique_len;
+
+	return 0;
+}
+
+#define DRM_IF_MAJOR	1
+#define DRM_IF_MINOR	2
+
+int
+drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_version	*version_ = data;
+	int			 len;
+
+#define DRM_COPY(name, value)						\
+	len = strlen( value );						\
+	if ( len > name##_len ) len = name##_len;			\
+	name##_len = strlen( value );					\
+	if ( len && name ) {						\
+		if ( DRM_COPY_TO_USER( name, value, len ) )		\
+			return EFAULT;				\
+	}
+
+	version_->version_major = dev->driver->major;
+	version_->version_minor = dev->driver->minor;
+	version_->version_patchlevel = dev->driver->patchlevel;
+
+	DRM_COPY(version_->name, dev->driver->name);
+	DRM_COPY(version_->date, dev->driver->date);
+	DRM_COPY(version_->desc, dev->driver->desc);
+
+	return 0;
+}
+
+int
+drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_set_version	ver, *sv = data;
+	int			if_version;
+
+	/* Save the incoming data, and set the response before continuing
+	 * any further.
+	 */
+	ver = *sv;
+	sv->drm_di_major = DRM_IF_MAJOR;
+	sv->drm_di_minor = DRM_IF_MINOR;
+	sv->drm_dd_major = dev->driver->major;
+	sv->drm_dd_minor = dev->driver->minor;
+
+	/*
+	 * We no longer support interface versions less than 1.1, so error
+	 * out if the xserver is too old. 1.1 always ties the drm to a
+	 * certain busid, this was done on attach
+	 */
+	if (ver.drm_di_major != -1) {
+		if (ver.drm_di_major != DRM_IF_MAJOR || ver.drm_di_minor < 1 ||
+		    ver.drm_di_minor > DRM_IF_MINOR) {
+			return EINVAL;
+		}
+		if_version = DRM_IF_VERSION(ver.drm_di_major, ver.drm_dd_minor);
+		dev->if_version = imax(if_version, dev->if_version);
+	}
+
+	if (ver.drm_dd_major != -1) {
+		if (ver.drm_dd_major != dev->driver->major ||
+		    ver.drm_dd_minor < 0 ||
+		    ver.drm_dd_minor > dev->driver->minor)
+			return EINVAL;
+	}
+
+	return 0;
+}
+
+struct drm_dmamem *
+drm_dmamem_alloc(bus_dma_tag_t dmat, bus_size_t size, bus_size_t alignment,
+    int nsegments, bus_size_t maxsegsz, int mapflags, int loadflags)
+{
+	struct drm_dmamem	*mem;
+	size_t			 strsize;
+	/*
+	 * segs is the last member of the struct since we modify the size 
+	 * to allow extra segments if more than one are allowed.
+	 */
+	strsize = sizeof(*mem) + (sizeof(bus_dma_segment_t) * (nsegments - 1));
+	mem = malloc(strsize, M_DRM, M_NOWAIT | M_ZERO);
+	if (mem == NULL)
+		return (NULL);
+
+	mem->size = size;
+
+	if (bus_dmamap_create(dmat, size, nsegments, maxsegsz, 0,
+	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mem->map) != 0)
+		goto strfree;
+
+	if (bus_dmamem_alloc(dmat, size, alignment, 0, mem->segs, nsegments,
+#if !defined(__NetBSD__)
+	    &mem->nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
+#else /* !defined(__NetBSD__) */
+	    &mem->nsegs, BUS_DMA_NOWAIT) != 0)
+#endif /* !defined(__NetBSD__) */
+		goto destroy;
+
+	if (bus_dmamem_map(dmat, mem->segs, mem->nsegs, size, 
+	    &mem->kva, BUS_DMA_NOWAIT | mapflags) != 0)
+		goto free;
+
+#if defined(__NetBSD__)
+	memset(mem->kva, 0, size);
+#endif /* defined(__NetBSD__) */
+
+	if (bus_dmamap_load(dmat, mem->map, mem->kva, size,
+	    NULL, BUS_DMA_NOWAIT | loadflags) != 0)
+		goto unmap;
+
+	return (mem);
+
+unmap:
+	bus_dmamem_unmap(dmat, mem->kva, size);
+free:
+	bus_dmamem_free(dmat, mem->segs, mem->nsegs);
+destroy:
+	bus_dmamap_destroy(dmat, mem->map);
+strfree:
+	free(mem, M_DRM);
+
+	return (NULL);
+}
+
+void
+drm_dmamem_free(bus_dma_tag_t dmat, struct drm_dmamem *mem)
+{
+	if (mem == NULL)
+		return;
+
+	bus_dmamap_unload(dmat, mem->map);
+	bus_dmamem_unmap(dmat, mem->kva, mem->size);
+	bus_dmamem_free(dmat, mem->segs, mem->nsegs);
+	bus_dmamap_destroy(dmat, mem->map);
+	free(mem, M_DRM);
+}
+
+/**
+ * Called by the client, this returns a unique magic number to be authorized
+ * by the master.
+ *
+ * The master may use its own knowledge of the client (such as the X
+ * connection that the magic is passed over) to determine if the magic number
+ * should be authenticated.
+ */
+int
+drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_auth		*auth = data;
+
+	if (dev->magicid == 0)
+		dev->magicid = 1;
+
+	/* Find unique magic */
+	if (file_priv->magic) {
+		auth->magic = file_priv->magic;
+	} else {
+		DRM_LOCK();
+		file_priv->magic = auth->magic = dev->magicid++;
+		DRM_UNLOCK();
+		DRM_DEBUG("%d\n", auth->magic);
+	}
+
+	DRM_DEBUG("%u\n", auth->magic);
+	return (0);
+}
+
+/**
+ * Marks the client associated with the given magic number as authenticated.
+ */
+int
+drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_file	*p;
+	struct drm_auth	*auth = data;
+	int		 ret = EINVAL;
+
+	DRM_DEBUG("%u\n", auth->magic);
+
+	if (auth->magic == 0)
+		return (ret);
+
+	DRM_LOCK();
+	SPLAY_FOREACH(p, drm_file_tree, &dev->files) {
+		if (p->magic == auth->magic) {
+			p->authenticated = 1;
+			p->magic = 0;
+			ret = 0;
+			break;
+		}
+	}
+	DRM_UNLOCK();
+
+	return (ret);
+}
+
+struct uvm_pagerops drm_pgops = {
+	NULL,
+	drm_ref,
+	drm_unref,
+	drm_fault,
+#if defined(__NetBSD__)
+	NULL,
+#endif /* defined(__NetBSD__) */
+	drm_flush,
+};
+
+
+void
+drm_hold_object_locked(struct drm_obj *obj)
+{
+	while (obj->do_flags & DRM_BUSY) {
+		atomic_setbits_int(&obj->do_flags, DRM_WANTED);
+#if !defined(__NetBSD__)
+		simple_unlock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+#ifdef DRMLOCKDEBUG
+		{
+		int ret = 0;
+		ret = tsleep(obj, PVM, "drm_hold", 3 * hz); /* XXX msleep */
+		if (ret)
+			printf("still waiting for obj %p, owned by %p\n",
+			    obj, obj->holding_proc);
+		}
+#else
+		tsleep(obj, PVM, "drm_hold", 0); /* XXX msleep */
+#endif
+#if !defined(__NetBSD__)
+		simple_lock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_enter(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	}
+#ifdef DRMLOCKDEBUG
+	obj->holding_proc = curproc;
+#endif
+	atomic_setbits_int(&obj->do_flags, DRM_BUSY);
+}
+
+void
+drm_hold_object(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	drm_hold_object_locked(obj);
+#if !defined(__NetBSD__)
+	simple_unlock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+}
+
+int
+drm_try_hold_object(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	/* if the object is free, grab it */
+	if (obj->do_flags & (DRM_BUSY | DRM_WANTED)) {
+#if !defined(__NetBSD__)
+		simple_unlock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+		return (0);
+	}
+	atomic_setbits_int(&obj->do_flags, DRM_BUSY);
+#ifdef DRMLOCKDEBUG
+	obj->holding_proc = curproc;
+#endif
+#if !defined(__NetBSD__)
+	simple_unlock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	return (1);
+}
+
+
+void
+drm_unhold_object_locked(struct drm_obj *obj)
+{
+	if (obj->do_flags & DRM_WANTED)
+		wakeup(obj);
+#ifdef DRMLOCKDEBUG
+	obj->holding_proc = NULL;
+#endif
+	atomic_clearbits_int(&obj->do_flags, DRM_WANTED | DRM_BUSY);	
+}
+
+void
+drm_unhold_object(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	drm_unhold_object_locked(obj);
+#if !defined(__NetBSD__)
+	simple_unlock(&obj->uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+}
+
+void
+drm_ref_locked(struct uvm_object *uobj)
+{
+	uobj->uo_refs++;
+}
+
+void
+drm_ref(struct uvm_object *uobj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	drm_ref_locked(uobj);
+#if !defined(__NetBSD__)
+	simple_unlock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+}
+
+void
+drm_unref(struct uvm_object *uobj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	drm_unref_locked(uobj);
+}
+
+void
+drm_unref_locked(struct uvm_object *uobj)
+{
+	struct drm_obj		*obj = (struct drm_obj *)uobj;
+	struct drm_device	*dev = obj->dev;
+
+again:
+	if (uobj->uo_refs > 1) {
+		uobj->uo_refs--;
+#if !defined(__NetBSD__)
+		simple_unlock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_exit(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+		return;
+	}
+
+	/* inlined version of drm_hold because we want to trylock then sleep */
+	if (obj->do_flags & DRM_BUSY) {
+		atomic_setbits_int(&obj->do_flags, DRM_WANTED);
+#if !defined(__NetBSD__)
+		simple_unlock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_exit(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+		tsleep(obj, PVM, "drm_unref", 0); /* XXX msleep */
+#if !defined(__NetBSD__)
+		simple_lock(&uobj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+		mutex_enter(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+		goto again;
+	}
+#ifdef DRMLOCKDEBUG
+	obj->holding_proc = curproc;
+#endif
+	atomic_setbits_int(&obj->do_flags, DRM_BUSY);
+#if !defined(__NetBSD__)
+	simple_unlock(&obj->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&uobj->vmobjlock);
+#endif /* !defined(__NetBSD__) */
+	/* We own this thing now. it is on no queues, though it may still
+	 * be bound to the aperture (and on the inactive list, in which case
+	 * idling the buffer is what triggered the free. Since we know no one 
+	 * else can grab it now, we can nuke with impunity.
+	 */
+	if (dev->driver->gem_free_object != NULL)
+		dev->driver->gem_free_object(obj);
+
+	uao_detach(obj->uao);
+
+	atomic_dec(&dev->obj_count);
+	atomic_sub(obj->size, &dev->obj_memory);
+	if (obj->do_flags & DRM_WANTED) /* should never happen, not on lists */
+		wakeup(obj);
+#if defined(__NetBSD__)
+	UVM_OBJ_DESTROY(&obj->uobj);
+#endif /* defined(__NetBSD__) */
+	pool_put(&dev->objpl, obj);
+}
+
+/*
+ * convenience function to unreference and unhold an object.
+ */
+void
+drm_unhold_and_unref(struct drm_obj *obj)
+{
+	drm_lock_obj(obj);
+	drm_unhold_object_locked(obj);
+	drm_unref_locked(&obj->uobj);
+}
+
+
+boolean_t	
+drm_flush(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
+{
+	return (TRUE);
+}
+
+
+int
+drm_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr, vm_page_t *pps,
+#if !defined(__NetBSD__)
+    int npages, int centeridx, vm_fault_t fault_type,
+#else /* !defined(__NetBSD__) */
+    int npages, int centeridx,
+#endif /* !defined(__NetBSD__) */
+    vm_prot_t access_type, int flags)
+{
+	struct vm_map_entry *entry = ufi->entry;
+	struct uvm_object *uobj = entry->object.uvm_obj;
+	struct drm_obj *obj = (struct drm_obj *)uobj;
+	struct drm_device *dev = obj->dev;
+	int ret;
+	UVMHIST_FUNC("udv_fault"); UVMHIST_CALLED(maphist);
+	UVMHIST_LOG(maphist,"  flags=%ld", flags,0,0,0);
+
+	/*
+	 * we do not allow device mappings to be mapped copy-on-write
+	 * so we kill any attempt to do so here.
+	 */
+	
+	if (UVM_ET_ISCOPYONWRITE(entry)) {
+		UVMHIST_LOG(maphist, "<- failed -- COW entry (etype=0x%lx)", 
+		    entry->etype, 0,0,0);
+		uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj, NULL);
+		return(VM_PAGER_ERROR);
+	}
+
+	/* Call down into driver to do the magic */
+	ret = dev->driver->gem_fault(obj, ufi, entry->offset + (vaddr -
+	    entry->start), vaddr, pps, npages, centeridx,
+	    access_type, flags);
+	return (ret);
+}
+
+/*
+ * Code to support memory managers based on the GEM (Graphics
+ * Execution Manager) api.
+ */
+struct drm_obj *
+drm_gem_object_alloc(struct drm_device *dev, size_t size)
+{
+	struct drm_obj	*obj;
+
+	KASSERT((size & (PAGE_SIZE -1)) == 0);
+
+#if !defined(__NetBSD__)
+	if ((obj = pool_get(&dev->objpl, PR_WAITOK | PR_ZERO)) == NULL)
+		return (NULL);
+#else /* !defined(__NetBSD__) */
+	if ((obj = pool_get(&dev->objpl, PR_WAITOK)) == NULL)
+		return (NULL);
+	memset(obj, 0, dev->objpl.pr_size);
+#endif /* !defined(__NetBSD__) */
+
+	obj->dev = dev;
+
+	/* uao create can't fail in the 0 case, it just sleeps */
+	obj->uao = uao_create(size, 0);
+	obj->size = size;
+#if !defined(__NetBSD__)
+	uvm_objinit(&obj->uobj, &drm_pgops, 1);
+#else /* !defined(__NetBSD__) */
+	UVM_OBJ_INIT(&obj->uobj, &drm_pgops, 1);
+#endif /* !defined(__NetBSD__) */
+
+	if (dev->driver->gem_init_object != NULL &&
+	    dev->driver->gem_init_object(obj) != 0) {
+		uao_detach(obj->uao);
+#if defined(__NetBSD__)
+		UVM_OBJ_DESTROY(&obj->uobj);
+#endif /* defined(__NetBSD__) */
+		pool_put(&dev->objpl, obj);
+		return (NULL);
+	}
+	atomic_inc(&dev->obj_count);
+	atomic_add(obj->size, &dev->obj_memory);
+	return (obj);
+}
+
+int
+drm_handle_create(struct drm_file *file_priv, struct drm_obj *obj,
+    int *handlep)
+{
+	struct drm_handle	*han;
+
+	if ((han = drm_calloc(1, sizeof(*han))) == NULL)
+		return (ENOMEM);
+
+	han->obj = obj;
+	mtx_enter(&file_priv->table_lock);
+again:
+	*handlep = han->handle = ++file_priv->obj_id;
+	/*
+	 * Make sure we have no duplicates. this'll hurt once we wrap, 0 is
+	 * reserved.
+	 */
+	if (han->handle == 0 || SPLAY_INSERT(drm_obj_tree,
+	    &file_priv->obj_tree, han))
+		goto again;
+	mtx_leave(&file_priv->table_lock);
+	
+	drm_handle_ref(obj);
+	return (0);
+}
+
+struct drm_obj *
+drm_gem_object_lookup(struct drm_device *dev, struct drm_file *file_priv,
+    int handle)
+{
+	struct drm_obj		*obj;
+	struct drm_handle	*han, search;
+
+	search.handle = handle;
+
+	mtx_enter(&file_priv->table_lock);
+	han = SPLAY_FIND(drm_obj_tree, &file_priv->obj_tree, &search);
+	if (han == NULL) {
+		mtx_leave(&file_priv->table_lock);
+		return (NULL);
+	}
+
+	obj = han->obj;
+	drm_ref(&obj->uobj);
+	mtx_leave(&file_priv->table_lock);
+
+	return (obj);
+}
+
+int
+drm_gem_close_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_gem_close	*args = data;
+	struct drm_handle	*han, find;
+	struct drm_obj		*obj;
+
+	if ((dev->driver->flags & DRIVER_GEM) == 0)
+		return (ENODEV);
+
+	find.handle = args->handle;
+	mtx_enter(&file_priv->table_lock);
+	han = SPLAY_FIND(drm_obj_tree, &file_priv->obj_tree, &find);
+	if (han == NULL) {
+		mtx_leave(&file_priv->table_lock);
+		return (EINVAL);
+	}
+
+	obj = han->obj;
+	SPLAY_REMOVE(drm_obj_tree, &file_priv->obj_tree, han);
+	mtx_leave(&file_priv->table_lock);
+
+	drm_free(han);
+
+	DRM_LOCK();
+	drm_handle_unref(obj);
+	DRM_UNLOCK();
+
+	return (0);
+}
+
+int
+drm_gem_flink_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_gem_flink	*args = data;
+	struct drm_obj		*obj;
+
+	if (!(dev->driver->flags & DRIVER_GEM))
+		return (ENODEV);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+
+	mtx_enter(&dev->obj_name_lock);
+	if (!obj->name) {
+again:
+		obj->name = ++dev->obj_name; 
+		/* 0 is reserved, make sure we don't clash. */
+		if (obj->name == 0 || SPLAY_INSERT(drm_name_tree,
+		    &dev->name_tree, obj))
+			goto again;
+		/* name holds a reference to the object */
+		drm_ref(&obj->uobj);
+	}
+	mtx_leave(&dev->obj_name_lock);
+
+	args->name = (uint64_t)obj->name;
+
+	drm_unref(&obj->uobj);
+
+	return (0);
+}
+
+int
+drm_gem_open_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_gem_open	*args = data;
+	struct drm_obj		*obj, search;
+	int			 ret, handle;
+
+	if (!(dev->driver->flags & DRIVER_GEM))
+		return (ENODEV);
+
+	search.name = args->name;
+	mtx_enter(&dev->obj_name_lock);
+	obj = SPLAY_FIND(drm_name_tree, &dev->name_tree, &search);
+	if (obj != NULL)
+		drm_ref(&obj->uobj);
+	mtx_leave(&dev->obj_name_lock);
+	if (obj == NULL)
+		return (ENOENT);
+
+	/* this gives our reference to the handle */
+	ret = drm_handle_create(file_priv, obj, &handle);
+	if (ret) {
+		drm_unref(&obj->uobj);
+		return (ret);
+	}
+
+	args->handle = handle;
+	args->size = obj->size;
+
+        return (0);
+}
+
+/*
+ * grab a reference for a per-open handle. 
+ * The object contains a handlecount too because if all handles disappear we
+ * need to also remove the global name (names initially are per open unless the
+ * flink ioctl is called.
+ */
+void
+drm_handle_ref(struct drm_obj *obj)
+{
+	/* we are given the reference from the caller, so just
+	 * crank handlecount.
+	 */
+	obj->handlecount++;
+}
+
+/*
+ * Remove the reference owned by a per-open handle. If we're the last one,
+ * remove the reference from flink, too.
+ */
+void
+drm_handle_unref(struct drm_obj *obj)
+{
+	/* do this first in case this is the last reference */
+	if (--obj->handlecount == 0) {
+		struct drm_device	*dev = obj->dev;
+
+		mtx_enter(&dev->obj_name_lock);
+		if (obj->name) {
+			SPLAY_REMOVE(drm_name_tree, &dev->name_tree, obj);
+			obj->name = 0;
+			mtx_leave(&dev->obj_name_lock);
+			/* name held a reference to object */
+			drm_unref(&obj->uobj);
+		} else {
+			mtx_leave(&dev->obj_name_lock);
+		}
+	}
+	drm_unref(&obj->uobj);
+}
+
+/*
+ * Helper function to load a uvm anonymous object into a dmamap, to be used
+ * for binding to a translation-table style sg mechanism (e.g. agp, or intel
+ * gtt).
+ *
+ * For now we ignore maxsegsz.
+ */
+int
+drm_gem_load_uao(bus_dma_tag_t dmat, bus_dmamap_t map, struct uvm_object *uao,
+    bus_size_t size, int flags, bus_dma_segment_t **segp)
+{
+	bus_dma_segment_t	*segs;
+	struct vm_page		*pg;
+	struct pglist		 plist;
+	u_long			 npages = size >> PAGE_SHIFT, i = 0;
+	int			 ret;
+
+	TAILQ_INIT(&plist);
+
+	/*
+	 * This is really quite ugly, but nothing else would need
+	 * bus_dmamap_load_uao() yet.
+	 */
+	segs = malloc(npages * sizeof(*segs), M_DRM, M_WAITOK | M_ZERO);
+	if (segs == NULL)
+		return (ENOMEM);
+
+	/* This may sleep, no choice in the matter */
+	if (uvm_objwire(uao, 0, size, &plist) != 0) {
+		ret = ENOMEM;
+		goto free;
+	}
+
+#if !defined(__NetBSD__)
+	TAILQ_FOREACH(pg, &plist, pageq) {
+#else /* !defined(__NetBSD__) */
+	TAILQ_FOREACH(pg, &plist, pageq.queue) {
+#endif /* !defined(__NetBSD__) */
+		paddr_t pa = VM_PAGE_TO_PHYS(pg);
+		
+		if (i > 0 && pa == (segs[i - 1].ds_addr +
+		    segs[i - 1].ds_len)) {
+			/* contiguous, yay */
+			segs[i - 1].ds_len += PAGE_SIZE;
+			continue;
+		}
+		segs[i].ds_addr = pa;
+		segs[i].ds_len = PAGE_SIZE;
+		if (i++ > npages)
+			break;
+	}
+	/* this should be impossible */
+	if (pg != TAILQ_END(&pageq)) {
+		ret = EINVAL;
+		goto unwire;
+	}
+
+	if ((ret = bus_dmamap_load_raw(dmat, map, segs, i, size, flags)) != 0)
+		goto unwire;
+
+	*segp = segs;
+
+	return (0);
+
+unwire:
+	uvm_objunwire(uao, 0, size);
+free:
+	free(segs, M_DRM);
+	return (ret);
+}
+
+int
+drm_handle_cmp(struct drm_handle *a, struct drm_handle *b)
+{
+	return (a->handle < b->handle ? -1 : a->handle > b->handle);
+}
+
+int
+drm_name_cmp(struct drm_obj *a, struct drm_obj *b)
+{
+	return (a->name < b->name ? -1 : a->name > b->name);
+}
+
+SPLAY_GENERATE(drm_obj_tree, drm_handle, entry, drm_handle_cmp);
+
+SPLAY_GENERATE(drm_name_tree, drm_obj, entry, drm_name_cmp);
diff -Naurp old/src/sys/dev/pci/drm/drm.h new/src/sys/dev/pci/drm/drm.h
--- old/src/sys/dev/pci/drm/drm.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,1011 @@
+/**
+ * \file drm.h
+ * Header for the Direct Rendering Manager
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * \par Acknowledgments:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg.
+ */
+
+/*
+ * Copyright 1999 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.
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#ifndef __user
+#define __user
+#endif
+
+#ifdef __GNUC__
+# define DEPRECATED  __attribute__ ((deprecated))
+#else
+# define DEPRECATED
+#endif
+
+#include <sys/ioccom.h>
+#define DRM_IOCTL_NR(n)		((n) & 0xff)
+#define DRM_IOC_VOID		IOC_VOID
+#define DRM_IOC_READ		IOC_OUT
+#define DRM_IOC_WRITE		IOC_IN
+#define DRM_IOC_READWRITE	IOC_INOUT
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+
+#define DRM_MAJOR       88
+#define DRM_MAX_MINOR   15
+
+#define DRM_NAME	"drm"	  /**< Name in kernel, /dev, and /proc */
+#define DRM_MIN_ORDER	5	  /**< At least 2^5 bytes = 32 bytes */
+#define DRM_MAX_ORDER	22	  /**< Up to 2^22 bytes = 4MB */
+#define DRM_RAM_PERCENT 10	  /**< How much system ram can we lock? */
+
+#define _DRM_LOCK_HELD	0x80000000U /**< Hardware lock is held */
+#define _DRM_LOCK_CONT	0x40000000U /**< Hardware lock is contended */
+#define _DRM_LOCK_IS_HELD(lock)	   ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock)	   ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+#include <sys/types.h>
+typedef unsigned long drm_handle_t;	/**< To mapped regions */
+typedef unsigned int drm_context_t;	/**< GLXContext handle */
+typedef unsigned int drm_drawable_t;
+typedef unsigned int drm_magic_t;	/**< Magic for authentication */
+
+/**
+ * Cliprect.
+ *
+ * \warning: If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well
+ *
+ * \note KW: Actually it's illegal to change either for
+ * backwards-compatibility reasons.
+ */
+struct drm_clip_rect {
+	unsigned short x1;
+	unsigned short y1;
+	unsigned short x2;
+	unsigned short y2;
+};
+
+/**
+ * Texture region,
+ */
+struct drm_tex_region {
+	unsigned char next;
+	unsigned char prev;
+	unsigned char in_use;
+	unsigned char padding;
+	unsigned int age;
+};
+
+/**
+ * Hardware lock.
+ *
+ * The lock structure is a simple cache-line aligned integer.  To avoid
+ * processor bus contention on a multiprocessor system, there should not be any
+ * other data stored in the same cache line.
+ */
+struct drm_hw_lock {
+	__volatile__ unsigned int lock;		/**< lock variable */
+	char padding[60];			/**< Pad to cache line */
+};
+
+/**
+ * DRM_IOCTL_VERSION ioctl argument type.
+ *
+ * \sa drmGetVersion().
+ */
+struct drm_version {
+	int version_major;	  /**< Major version */
+	int version_minor;	  /**< Minor version */
+	int version_patchlevel;	  /**< Patch level */
+	size_t name_len;	  /**< Length of name buffer */
+	char __user *name;	  /**< Name of driver */
+	size_t date_len;	  /**< Length of date buffer */
+	char __user *date;	  /**< User-space buffer to hold date */
+	size_t desc_len;	  /**< Length of desc buffer */
+	char __user *desc;	  /**< User-space buffer to hold desc */
+};
+
+/**
+ * DRM_IOCTL_GET_UNIQUE ioctl argument type.
+ *
+ * \sa drmGetBusid() and drmSetBusId().
+ */
+struct drm_unique {
+	size_t unique_len;	  /**< Length of unique */
+	char __user *unique;		  /**< Unique name for driver instantiation */
+};
+
+struct drm_list {
+	int count;		  /**< Length of user-space structures */
+	struct drm_version __user *version;
+};
+
+struct drm_block {
+	int unused;
+};
+
+/**
+ * DRM_IOCTL_CONTROL ioctl argument type.
+ *
+ * \sa drmCtlInstHandler() and drmCtlUninstHandler().
+ */
+struct drm_control {
+	enum {
+		DRM_ADD_COMMAND,
+		DRM_RM_COMMAND,
+		DRM_INST_HANDLER,
+		DRM_UNINST_HANDLER
+	} func;
+	int irq;
+};
+
+/**
+ * Type of memory to map.
+ */
+enum drm_map_type {
+	_DRM_FRAME_BUFFER = 0,	  /**< WC (no caching), no core dump */
+	_DRM_REGISTERS = 1,	  /**< no caching, no core dump */
+	_DRM_SHM = 2,		  /**< shared, cached */
+	_DRM_AGP = 3,		  /**< AGP/GART */
+	_DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
+	_DRM_CONSISTENT = 5,	  /**< Consistent memory for PCI DMA */
+};
+
+/**
+ * Memory mapping flags.
+ */
+enum drm_map_flags {
+	_DRM_RESTRICTED = 0x01,	     /**< Cannot be mapped to user-virtual */
+	_DRM_READ_ONLY = 0x02,
+	_DRM_LOCKED = 0x04,	     /**< shared, cached, locked */
+	_DRM_KERNEL = 0x08,	     /**< kernel requires access */
+	_DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
+	_DRM_CONTAINS_LOCK = 0x20,   /**< SHM page that contains lock */
+	_DRM_REMOVABLE = 0x40,	     /**< Removable mapping */
+	_DRM_DRIVER = 0x80	     /**< Managed by driver */
+};
+
+struct drm_ctx_priv_map {
+	unsigned int ctx_id;	 /**< Context requesting private mapping */
+	void *handle;		 /**< Handle of map */
+};
+
+/**
+ * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
+ * argument type.
+ *
+ * \sa drmAddMap().
+ */
+struct drm_map {
+	unsigned long offset;	 /**< Requested physical address (0 for SAREA)*/
+	unsigned long size;	 /**< Requested physical size (bytes) */
+	enum drm_map_type type;	 /**< Type of memory to map */
+	enum drm_map_flags flags;	 /**< Flags */
+	void *handle;		 /**< User-space: "Handle" to pass to mmap() */
+				 /**< Kernel-space: kernel-virtual address */
+	int mtrr;		 /**< MTRR slot used */
+	/*   Private data */
+};
+
+/**
+ * DRM_IOCTL_GET_CLIENT ioctl argument type.
+ */
+struct drm_client {
+	int idx;		/**< Which client desired? */
+	int auth;		/**< Is client authenticated? */
+	unsigned long pid;	/**< Process ID */
+	unsigned long uid;	/**< User ID */
+	unsigned long magic;	/**< Magic */
+	unsigned long iocs;	/**< Ioctl count */
+};
+
+enum drm_stat_type {
+	_DRM_STAT_LOCK,
+	_DRM_STAT_OPENS,
+	_DRM_STAT_CLOSES,
+	_DRM_STAT_IOCTLS,
+	_DRM_STAT_LOCKS,
+	_DRM_STAT_UNLOCKS,
+	_DRM_STAT_VALUE,	/**< Generic value */
+	_DRM_STAT_BYTE,		/**< Generic byte counter (1024bytes/K) */
+	_DRM_STAT_COUNT,	/**< Generic non-byte counter (1000/k) */
+
+	_DRM_STAT_IRQ,		/**< IRQ */
+	_DRM_STAT_PRIMARY,	/**< Primary DMA bytes */
+	_DRM_STAT_SECONDARY,	/**< Secondary DMA bytes */
+	_DRM_STAT_DMA,		/**< DMA */
+	_DRM_STAT_SPECIAL,	/**< Special DMA (e.g., priority or polled) */
+	_DRM_STAT_MISSED	/**< Missed DMA opportunity */
+	    /* Add to the *END* of the list */
+};
+
+/**
+ * DRM_IOCTL_GET_STATS ioctl argument type.
+ */
+struct drm_stats {
+	unsigned long count;
+	struct {
+		unsigned long value;
+		enum drm_stat_type type;
+	} data[15];
+};
+
+/**
+ * Hardware locking flags.
+ */
+enum drm_lock_flags {
+	_DRM_LOCK_READY = 0x01,	     /**< Wait until hardware is ready for DMA */
+	_DRM_LOCK_QUIESCENT = 0x02,  /**< Wait until hardware quiescent */
+	_DRM_LOCK_FLUSH = 0x04,	     /**< Flush this context's DMA queue first */
+	_DRM_LOCK_FLUSH_ALL = 0x08,  /**< Flush all DMA queues first */
+	/* These *HALT* flags aren't supported yet
+	   -- they will be used to support the
+	   full-screen DGA-like mode. */
+	_DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
+	_DRM_HALT_CUR_QUEUES = 0x20  /**< Halt all current queues */
+};
+
+/**
+ * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
+ *
+ * \sa drmGetLock() and drmUnlock().
+ */
+struct drm_lock {
+	int context;
+	enum drm_lock_flags flags;
+};
+
+/**
+ * DMA flags
+ *
+ * \warning
+ * These values \e must match xf86drm.h.
+ *
+ * \sa drm_dma.
+ */
+enum drm_dma_flags {
+	/* Flags for DMA buffer dispatch */
+	_DRM_DMA_BLOCK = 0x01,	      /**<
+				       * Block until buffer dispatched.
+				       *
+				       * \note The buffer may not yet have
+				       * been processed by the hardware --
+				       * getting a hardware lock with the
+				       * hardware quiescent will ensure
+				       * that the buffer has been
+				       * processed.
+				       */
+	_DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */
+	_DRM_DMA_PRIORITY = 0x04,     /**< High priority dispatch */
+
+	/* Flags for DMA buffer request */
+	_DRM_DMA_WAIT = 0x10,	      /**< Wait for free buffers */
+	_DRM_DMA_SMALLER_OK = 0x20,   /**< Smaller-than-requested buffers OK */
+	_DRM_DMA_LARGER_OK = 0x40     /**< Larger-than-requested buffers OK */
+};
+
+/**
+ * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
+ *
+ * \sa drmAddBufs().
+ */
+struct drm_buf_desc {
+	int count;		 /**< Number of buffers of this size */
+	int size;		 /**< Size in bytes */
+	int low_mark;		 /**< Low water mark */
+	int high_mark;		 /**< High water mark */
+	enum {
+		_DRM_PAGE_ALIGN = 0x01,	/**< Align on page boundaries for DMA */
+		_DRM_AGP_BUFFER = 0x02,	/**< Buffer is in AGP space */
+		_DRM_SG_BUFFER  = 0x04,	/**< Scatter/gather memory buffer */
+		_DRM_FB_BUFFER  = 0x08, /**< Buffer is in frame buffer */
+		_DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */
+	} flags;
+	unsigned long agp_start; /**<
+				  * Start address of where the AGP buffers are
+				  * in the AGP aperture
+				  */
+};
+
+/**
+ * DRM_IOCTL_INFO_BUFS ioctl argument type.
+ */
+struct drm_buf_info {
+	int count;		  /**< Number of buffers described in list */
+	struct drm_buf_desc __user *list; /**< List of buffer descriptions */
+};
+
+/**
+ * DRM_IOCTL_FREE_BUFS ioctl argument type.
+ */
+struct drm_buf_free {
+	int count;
+	int __user *list;
+};
+
+/**
+ * Buffer information
+ *
+ * \sa drm_buf_map.
+ */
+struct drm_buf_pub {
+	int idx;		       /**< Index into the master buffer list */
+	int total;		       /**< Buffer size */
+	int used;		       /**< Amount of buffer in use (for DMA) */
+	void __user *address;	       /**< Address of buffer */
+};
+
+/**
+ * DRM_IOCTL_MAP_BUFS ioctl argument type.
+ */
+struct drm_buf_map {
+	int count;		/**< Length of the buffer list */
+	void __user *virtual;		/**< Mmap'd area in user-virtual */
+	struct drm_buf_pub __user *list;	/**< Buffer information */
+};
+
+/**
+ * DRM_IOCTL_DMA ioctl argument type.
+ *
+ * Indices here refer to the offset into the buffer list in drm_buf_get.
+ *
+ * \sa drmDMA().
+ */
+struct drm_dma {
+	int context;			  /**< Context handle */
+	int send_count;			  /**< Number of buffers to send */
+	int __user *send_indices;	  /**< List of handles to buffers */
+	int __user *send_sizes;		  /**< Lengths of data to send */
+	enum drm_dma_flags flags;	  /**< Flags */
+	int request_count;		  /**< Number of buffers requested */
+	int request_size;		  /**< Desired size for buffers */
+	int __user *request_indices;	  /**< Buffer information */
+	int __user *request_sizes;
+	int granted_count;		  /**< Number of buffers granted */
+};
+
+enum drm_ctx_flags {
+	_DRM_CONTEXT_PRESERVED = 0x01,
+	_DRM_CONTEXT_2DONLY = 0x02
+};
+
+/**
+ * DRM_IOCTL_ADD_CTX ioctl argument type.
+ *
+ * \sa drmCreateContext() and drmDestroyContext().
+ */
+struct drm_ctx {
+	drm_context_t handle;
+	enum drm_ctx_flags flags;
+};
+
+/**
+ * DRM_IOCTL_RES_CTX ioctl argument type.
+ */
+struct drm_ctx_res {
+	int count;
+	struct drm_ctx __user *contexts;
+};
+
+/**
+ * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
+ */
+struct drm_draw {
+	drm_drawable_t handle;
+};
+
+/**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+	DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+struct drm_update_draw {
+	drm_drawable_t handle;
+	unsigned int type;
+	unsigned int num;
+	unsigned long long data;
+};
+
+/**
+ * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
+ */
+struct drm_auth {
+	drm_magic_t magic;
+};
+
+/**
+ * DRM_IOCTL_IRQ_BUSID ioctl argument type.
+ *
+ * \sa drmGetInterruptFromBusID().
+ */
+struct drm_irq_busid {
+	int irq;	/**< IRQ number */
+	int busnum;	/**< bus number */
+	int devnum;	/**< device number */
+	int funcnum;	/**< function number */
+};
+
+enum drm_vblank_seq_type {
+	_DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
+	_DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+	_DRM_VBLANK_EVENT = 0x4000000,   /**< Send event instead of blocking */
+	_DRM_VBLANK_FLIP = 0x8000000,	/**< Scheduled buffer swap should flip */
+	_DRM_VBLANK_NEXTONMISS = 0x10000000,	/**< If missed, wait for next vblank */
+	_DRM_VBLANK_SECONDARY = 0x20000000,	/**< Secondary display controller */
+	_DRM_VBLANK_SIGNAL = 0x40000000	/**< Send signal instead of blocking */
+};
+
+#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
+				_DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)
+
+struct drm_wait_vblank_request {
+	enum drm_vblank_seq_type type;
+	unsigned int sequence;
+	unsigned long signal;
+};
+
+struct drm_wait_vblank_reply {
+	enum drm_vblank_seq_type type;
+	unsigned int sequence;
+	long tval_sec;
+	long tval_usec;
+};
+
+/**
+ * DRM_IOCTL_WAIT_VBLANK ioctl argument type.
+ *
+ * \sa drmWaitVBlank().
+ */
+union drm_wait_vblank {
+	struct drm_wait_vblank_request request;
+	struct drm_wait_vblank_reply reply;
+};
+
+#define _DRM_PRE_MODESET 1
+#define _DRM_POST_MODESET 2
+
+/**
+ * DRM_IOCTL_MODESET_CTL ioctl argument type
+ *
+ * \sa drmModesetCtl().
+ */
+struct drm_modeset_ctl {
+	uint32_t crtc;
+	uint32_t cmd;
+};
+
+/**
+ * DRM_IOCTL_AGP_ENABLE ioctl argument type.
+ *
+ * \sa drmAgpEnable().
+ */
+struct drm_agp_mode {
+	unsigned long mode;	/**< AGP mode */
+};
+
+/**
+ * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
+ *
+ * \sa drmAgpAlloc() and drmAgpFree().
+ */
+struct drm_agp_buffer {
+	unsigned long size;	/**< In bytes -- will round to page boundary */
+	unsigned long handle;	/**< Used for binding / unbinding */
+	unsigned long type;	/**< Type of memory to allocate */
+	unsigned long physical;	/**< Physical used by i810 */
+};
+
+/**
+ * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
+ *
+ * \sa drmAgpBind() and drmAgpUnbind().
+ */
+struct drm_agp_binding {
+	unsigned long handle;	/**< From drm_agp_buffer */
+	unsigned long offset;	/**< In bytes -- will round to page boundary */
+};
+
+/**
+ * DRM_IOCTL_AGP_INFO ioctl argument type.
+ *
+ * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
+ * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
+ * drmAgpVendorId() and drmAgpDeviceId().
+ */
+struct drm_agp_info {
+	int agp_version_major;
+	int agp_version_minor;
+	unsigned long mode;
+	unsigned long aperture_base;	/* physical address */
+	unsigned long aperture_size;	/* bytes */
+	unsigned long memory_allowed;	/* bytes */
+	unsigned long memory_used;
+
+	/* PCI information */
+	unsigned short id_vendor;
+	unsigned short id_device;
+};
+
+/**
+ * DRM_IOCTL_SG_ALLOC ioctl argument type.
+ */
+struct drm_scatter_gather {
+	unsigned long size;	/**< In bytes -- will round to page boundary */
+	unsigned long handle;	/**< Used for mapping / unmapping */
+};
+
+/**
+ * DRM_IOCTL_SET_VERSION ioctl argument type.
+ */
+struct drm_set_version {
+	int drm_di_major;
+	int drm_di_minor;
+	int drm_dd_major;
+	int drm_dd_minor;
+};
+
+/* DRM_IOCTL_GEM_CLOSE ioctl argument type */
+struct drm_gem_close {
+	/* Handle of the object to be closed. */
+	uint32_t handle;
+	uint32_t pad;
+};
+
+/* DRM_IOCTL_GEM_FLINK ioctl argument type */
+struct drm_gem_flink {
+	/* Handle for the object being named */
+	uint32_t handle;
+
+	/* Returned global name */
+	uint32_t name;
+};
+
+/* DRM_IOCTL_GEM_OPEN ioctl argument type */
+struct drm_gem_open {
+	/* Name of object being opened */
+	uint32_t name;
+
+	/* Returned handle for the object */
+	uint32_t handle;
+
+	/* Returned size of the object */
+	uint64_t size;
+};
+
+/*
+ * Modesetting interface defines and types.
+ * Be warned that OpenBSD does not support these ioctls at the moment,
+ * and that a different approach may be chosen in the future.
+ */
+#define DRM_DISPLAY_INFO_LEN	32
+#define DRM_CONNECTOR_NAME_LEN	32
+#define DRM_DISPLAY_MODE_LEN	32
+#define DRM_PROP_NAME_LEN	32
+
+#define DRM_MODE_TYPE_BUILTIN	(1<<0)
+#define DRM_MODE_TYPE_CLOCK_C	((1<<1) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_CRTC_C	((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_PREFERRED	(1<<3)
+#define DRM_MODE_TYPE_DEFAULT	(1<<4)
+#define DRM_MODE_TYPE_USERDEF	(1<<5)
+#define DRM_MODE_TYPE_DRIVER	(1<<6)
+
+/* Video mode flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_FLAG_PHSYNC	(1<<0)
+#define DRM_MODE_FLAG_NHSYNC	(1<<1)
+#define DRM_MODE_FLAG_PVSYNC	(1<<2)
+#define DRM_MODE_FLAG_NVSYNC	(1<<3)
+#define DRM_MODE_FLAG_INTERLACE	(1<<4)
+#define DRM_MODE_FLAG_DBLSCAN	(1<<5)
+#define DRM_MODE_FLAG_CSYNC	(1<<6)
+#define DRM_MODE_FLAG_PCSYNC	(1<<7)
+#define DRM_MODE_FLAG_NCSYNC	(1<<8)
+#define DRM_MODE_FLAG_HSKEW	(1<<9) /* hskew provided */
+#define DRM_MODE_FLAG_BCAST	(1<<10)
+#define DRM_MODE_FLAG_PIXMUX	(1<<11)
+#define DRM_MODE_FLAG_DBLCLK	(1<<12)
+#define DRM_MODE_FLAG_CLKDIV2	(1<<13)
+
+/* DPMS flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_DPMS_ON	0
+#define DRM_MODE_DPMS_STANDBY	1
+#define DRM_MODE_DPMS_SUSPEND	2
+#define DRM_MODE_DPMS_OFF	3
+
+/* Scaling mode options */
+#define DRM_MODE_SCALE_NON_GPU		0
+#define DRM_MODE_SCALE_FULLSCREEN	1
+#define DRM_MODE_SCALE_NO_SCALE		2
+#define DRM_MODE_SCALE_ASPECT		3
+
+/* Dithering mode options */
+#define DRM_MODE_DITHERING_OFF	0
+#define DRM_MODE_DITHERING_ON	1
+
+struct drm_mode_modeinfo {
+	uint32_t clock;
+	uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
+	uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+	uint32_t vrefresh; /* vertical refresh * 1000 */
+
+	uint32_t flags;
+	uint32_t type;
+	char name[DRM_DISPLAY_MODE_LEN];
+};
+
+struct drm_mode_card_res {
+	uint64_t fb_id_ptr;
+	uint64_t crtc_id_ptr;
+	uint64_t connector_id_ptr;
+	uint64_t encoder_id_ptr;
+	uint32_t count_fbs;
+	uint32_t count_crtcs;
+	uint32_t count_connectors;
+	uint32_t count_encoders;
+	uint32_t min_width, max_width;
+	uint32_t min_height, max_height;
+};
+
+struct drm_mode_crtc {
+	uint64_t set_connectors_ptr;
+	uint32_t count_connectors;
+
+	uint32_t crtc_id; /**< Id */
+	uint32_t fb_id; /**< Id of framebuffer */
+
+	uint32_t x, y; /**< Position on the frameuffer */
+
+	uint32_t gamma_size;
+	uint32_t mode_valid;
+	struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_ENCODER_NONE	0
+#define DRM_MODE_ENCODER_DAC	1
+#define DRM_MODE_ENCODER_TMDS	2
+#define DRM_MODE_ENCODER_LVDS	3
+#define DRM_MODE_ENCODER_TVDAC	4
+
+struct drm_mode_get_encoder {
+	uint32_t encoder_id;
+	uint32_t encoder_type;
+
+	uint32_t crtc_id; /**< Id of crtc */
+
+	uint32_t possible_crtcs;
+	uint32_t possible_clones;
+};
+
+/* This is for connectors with multiple signal types. */
+/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
+#define DRM_MODE_SUBCONNECTOR_Automatic	0
+#define DRM_MODE_SUBCONNECTOR_Unknown	0
+#define DRM_MODE_SUBCONNECTOR_DVID	3
+#define DRM_MODE_SUBCONNECTOR_DVIA	4
+#define DRM_MODE_SUBCONNECTOR_Composite	5
+#define DRM_MODE_SUBCONNECTOR_SVIDEO	6
+#define DRM_MODE_SUBCONNECTOR_Component	8
+
+#define DRM_MODE_CONNECTOR_Unknown	0
+#define DRM_MODE_CONNECTOR_VGA		1
+#define DRM_MODE_CONNECTOR_DVII		2
+#define DRM_MODE_CONNECTOR_DVID		3
+#define DRM_MODE_CONNECTOR_DVIA		4
+#define DRM_MODE_CONNECTOR_Composite	5
+#define DRM_MODE_CONNECTOR_SVIDEO	6
+#define DRM_MODE_CONNECTOR_LVDS		7
+#define DRM_MODE_CONNECTOR_Component	8
+#define DRM_MODE_CONNECTOR_9PinDIN	9
+#define DRM_MODE_CONNECTOR_DisplayPort	10
+#define DRM_MODE_CONNECTOR_HDMIA	11
+#define DRM_MODE_CONNECTOR_HDMIB	12
+
+struct drm_mode_get_connector {
+
+	uint64_t encoders_ptr;
+	uint64_t modes_ptr;
+	uint64_t props_ptr;
+	uint64_t prop_values_ptr;
+
+	uint32_t count_modes;
+	uint32_t count_props;
+	uint32_t count_encoders;
+
+	uint32_t encoder_id; /**< Current Encoder */
+	uint32_t connector_id; /**< Id */
+	uint32_t connector_type;
+	uint32_t connector_type_id;
+
+	uint32_t connection;
+	uint32_t mm_width, mm_height; /**< HxW in millimeters */
+	uint32_t subpixel;
+};
+
+#define DRM_MODE_PROP_PENDING	(1<<0)
+#define DRM_MODE_PROP_RANGE	(1<<1)
+#define DRM_MODE_PROP_IMMUTABLE	(1<<2)
+#define DRM_MODE_PROP_ENUM	(1<<3) /* enumerated type with text strings */
+#define DRM_MODE_PROP_BLOB	(1<<4)
+
+struct drm_mode_property_enum {
+	uint64_t value;
+	char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_mode_get_property {
+	uint64_t values_ptr; /* values and blob lengths */
+	uint64_t enum_blob_ptr; /* enum and blob id ptrs */
+
+	uint32_t prop_id;
+	uint32_t flags;
+	char name[DRM_PROP_NAME_LEN];
+
+	uint32_t count_values;
+	uint32_t count_enum_blobs;
+};
+
+struct drm_mode_connector_set_property {
+	uint64_t value;
+	uint32_t prop_id;
+	uint32_t connector_id;
+};
+
+struct drm_mode_get_blob {
+	uint32_t blob_id;
+	uint32_t length;
+	uint64_t data;
+};
+
+struct drm_mode_fb_cmd {
+	uint32_t fb_id;
+	uint32_t width, height;
+	uint32_t pitch;
+	uint32_t bpp;
+	uint32_t depth;
+	/* driver specific handle */
+	uint32_t handle;
+};
+
+struct drm_mode_mode_cmd {
+	uint32_t connector_id;
+	struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_CURSOR_BO	(1<<0)
+#define DRM_MODE_CURSOR_MOVE	(1<<1)
+
+/*
+ * depending on the value in flags different members are used.
+ *
+ * CURSOR_BO uses
+ *    crtc
+ *    width
+ *    height
+ *    handle - if 0 turns the cursor of
+ *
+ * CURSOR_MOVE uses
+ *    crtc
+ *    x
+ *    y
+ */
+struct drm_mode_cursor {
+	uint32_t flags;
+	uint32_t crtc_id;
+	int32_t x;
+	int32_t y;
+	uint32_t width;
+	uint32_t height;
+	/* driver specific handle */
+	uint32_t handle;
+};
+
+struct drm_mode_crtc_lut {
+	uint32_t crtc_id;
+	uint32_t gamma_size;
+
+	/* pointers to arrays */
+	uint64_t red;
+	uint64_t green;
+	uint64_t blue;
+};
+
+#define DRM_IOCTL_BASE			'd'
+#define DRM_IO(nr)			_IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,type)		_IOR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOW(nr,type)		_IOW(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOWR(nr,type)		_IOWR(DRM_IOCTL_BASE,nr,type)
+
+#define DRM_IOCTL_VERSION		DRM_IOWR(0x00, struct drm_version)
+#define DRM_IOCTL_GET_UNIQUE		DRM_IOWR(0x01, struct drm_unique)
+#define DRM_IOCTL_GET_MAGIC		DRM_IOR( 0x02, struct drm_auth)
+#define DRM_IOCTL_IRQ_BUSID		DRM_IOWR(0x03, struct drm_irq_busid)
+#define DRM_IOCTL_GET_MAP               DRM_IOWR(0x04, struct drm_map)
+#define DRM_IOCTL_GET_CLIENT            DRM_IOWR(0x05, struct drm_client)
+#define DRM_IOCTL_GET_STATS             DRM_IOR( 0x06, struct drm_stats)
+#define DRM_IOCTL_SET_VERSION		DRM_IOWR(0x07, struct drm_set_version)
+#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0x08, struct drm_modeset_ctl)
+#define DRM_IOCTL_GEM_CLOSE		DRM_IOW (0x09, struct drm_gem_close)
+#define DRM_IOCTL_GEM_FLINK		DRM_IOWR(0x0a, struct drm_gem_flink)
+#define DRM_IOCTL_GEM_OPEN		DRM_IOWR(0x0b, struct drm_gem_open)
+
+#define DRM_IOCTL_SET_UNIQUE		DRM_IOW( 0x10, struct drm_unique)
+#define DRM_IOCTL_AUTH_MAGIC		DRM_IOW( 0x11, struct drm_auth)
+#define DRM_IOCTL_BLOCK			DRM_IOWR(0x12, struct drm_block)
+#define DRM_IOCTL_UNBLOCK		DRM_IOWR(0x13, struct drm_block)
+#define DRM_IOCTL_CONTROL		DRM_IOW( 0x14, struct drm_control)
+#define DRM_IOCTL_ADD_MAP		DRM_IOWR(0x15, struct drm_map)
+#define DRM_IOCTL_ADD_BUFS		DRM_IOWR(0x16, struct drm_buf_desc)
+#define DRM_IOCTL_MARK_BUFS		DRM_IOW( 0x17, struct drm_buf_desc)
+#define DRM_IOCTL_INFO_BUFS		DRM_IOWR(0x18, struct drm_buf_info)
+#define DRM_IOCTL_MAP_BUFS		DRM_IOWR(0x19, struct drm_buf_map)
+#define DRM_IOCTL_FREE_BUFS		DRM_IOW( 0x1a, struct drm_buf_free)
+
+#define DRM_IOCTL_RM_MAP		DRM_IOW( 0x1b, struct drm_map)
+
+#define DRM_IOCTL_SET_SAREA_CTX		DRM_IOW( 0x1c, struct drm_ctx_priv_map)
+#define DRM_IOCTL_GET_SAREA_CTX		DRM_IOWR(0x1d, struct drm_ctx_priv_map)
+
+#define DRM_IOCTL_ADD_CTX		DRM_IOWR(0x20, struct drm_ctx)
+#define DRM_IOCTL_RM_CTX		DRM_IOWR(0x21, struct drm_ctx)
+#define DRM_IOCTL_MOD_CTX		DRM_IOW( 0x22, struct drm_ctx)
+#define DRM_IOCTL_GET_CTX		DRM_IOWR(0x23, struct drm_ctx)
+#define DRM_IOCTL_SWITCH_CTX		DRM_IOW( 0x24, struct drm_ctx)
+#define DRM_IOCTL_NEW_CTX		DRM_IOW( 0x25, struct drm_ctx)
+#define DRM_IOCTL_RES_CTX		DRM_IOWR(0x26, struct drm_ctx_res)
+#define DRM_IOCTL_ADD_DRAW		DRM_IOWR(0x27, struct drm_draw)
+#define DRM_IOCTL_RM_DRAW		DRM_IOWR(0x28, struct drm_draw)
+#define DRM_IOCTL_DMA			DRM_IOWR(0x29, struct drm_dma)
+#define DRM_IOCTL_LOCK			DRM_IOW( 0x2a, struct drm_lock)
+#define DRM_IOCTL_UNLOCK		DRM_IOW( 0x2b, struct drm_lock)
+#define DRM_IOCTL_FINISH		DRM_IOW( 0x2c, struct drm_lock)
+
+#define DRM_IOCTL_AGP_ACQUIRE		DRM_IO(  0x30)
+#define DRM_IOCTL_AGP_RELEASE		DRM_IO(  0x31)
+#define DRM_IOCTL_AGP_ENABLE		DRM_IOW( 0x32, struct drm_agp_mode)
+#define DRM_IOCTL_AGP_INFO		DRM_IOR( 0x33, struct drm_agp_info)
+#define DRM_IOCTL_AGP_ALLOC		DRM_IOWR(0x34, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_FREE		DRM_IOW( 0x35, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_BIND		DRM_IOW( 0x36, struct drm_agp_binding)
+#define DRM_IOCTL_AGP_UNBIND		DRM_IOW( 0x37, struct drm_agp_binding)
+
+#define DRM_IOCTL_SG_ALLOC		DRM_IOWR(0x38, struct drm_scatter_gather)
+#define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, struct drm_scatter_gather)
+
+#define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, union drm_wait_vblank)
+
+#define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, struct drm_update_draw)
+
+#define DRM_IOCTL_MODE_GETRESOURCES	DRM_IOWR(0xA0, struct drm_mode_card_res)
+#define DRM_IOCTL_MODE_GETCRTC		DRM_IOWR(0xA1, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_SETCRTC		DRM_IOWR(0xA2, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_CURSOR		DRM_IOWR(0xA3, struct drm_mode_cursor)
+#define DRM_IOCTL_MODE_GETGAMMA		DRM_IOWR(0xA4, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_SETGAMMA		DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_GETENCODER	DRM_IOWR(0xA6, struct drm_mode_get_encoder)
+#define DRM_IOCTL_MODE_GETCONNECTOR	DRM_IOWR(0xA7, struct drm_mode_get_connector)
+#define DRM_IOCTL_MODE_ATTACHMODE	DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_DETACHMODE	DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+
+#define DRM_IOCTL_MODE_GETPROPERTY	DRM_IOWR(0xAA, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_SETPROPERTY	DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
+#define DRM_IOCTL_MODE_GETPROPBLOB	DRM_IOWR(0xAC, struct drm_mode_get_blob)
+#define DRM_IOCTL_MODE_GETFB		DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_ADDFB		DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_RMFB		DRM_IOWR(0xAF, unsigned int)
+
+/**
+ * Device specific ioctls should only be in their respective headers
+ * The device specific ioctl range is from 0x40 to 0x99.
+ * Generic IOCTLS restart at 0xA0.
+ *
+ * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
+ * drmCommandReadWrite().
+ */
+#define DRM_COMMAND_BASE                0x40
+#define DRM_COMMAND_END                 0xA0
+
+/**
+ * Header for events written back to userspace on the drm fd.  The
+ * type defines the type of event, the length specifies the total
+ * length of the event (including the header), and user_data is
+ * typically a 64 bit value passed with the ioctl that triggered the
+ * event.  A read on the drm fd will always only return complete
+ * events, that is, if for example the read buffer is 100 bytes, and
+ * there are two 64 byte events pending, only one will be returned.
+ *
+ * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and
+ * up are chipset specific.
+ */
+struct drm_event {
+	u_int32_t	 type;
+	u_int32_t	 length;
+};
+
+#define DRM_EVENT_VBLANK 0x01
+#define DRM_EVENT_FLIP_COMPLETE 0x02
+
+struct drm_event_vblank {
+	struct drm_event	 base;
+	u_int64_t		 user_data;
+	u_int32_t		 tv_sec;
+	u_int32_t		 tv_usec;
+	u_int32_t		 sequence;
+	u_int32_t		 reserved;
+};
+
+/* typedef area */
+#ifndef __KERNEL__
+typedef struct drm_clip_rect drm_clip_rect_t;
+typedef struct drm_tex_region drm_tex_region_t;
+typedef struct drm_hw_lock drm_hw_lock_t;
+typedef struct drm_version drm_version_t;
+typedef struct drm_unique drm_unique_t;
+typedef struct drm_list drm_list_t;
+typedef struct drm_block drm_block_t;
+typedef struct drm_control drm_control_t;
+typedef enum drm_map_type drm_map_type_t;
+typedef enum drm_map_flags drm_map_flags_t;
+typedef struct drm_ctx_priv_map drm_ctx_priv_map_t;
+typedef struct drm_map drm_map_t;
+typedef struct drm_client drm_client_t;
+typedef enum drm_stat_type drm_stat_type_t;
+typedef struct drm_stats drm_stats_t;
+typedef enum drm_lock_flags drm_lock_flags_t;
+typedef struct drm_lock drm_lock_t;
+typedef enum drm_dma_flags drm_dma_flags_t;
+typedef struct drm_buf_desc drm_buf_desc_t;
+typedef struct drm_buf_info drm_buf_info_t;
+typedef struct drm_buf_free drm_buf_free_t;
+typedef struct drm_buf_pub drm_buf_pub_t;
+typedef struct drm_buf_map drm_buf_map_t;
+typedef struct drm_dma drm_dma_t;
+typedef union drm_wait_vblank drm_wait_vblank_t;
+typedef struct drm_agp_mode drm_agp_mode_t;
+typedef enum drm_ctx_flags drm_ctx_flags_t;
+typedef struct drm_ctx drm_ctx_t;
+typedef struct drm_ctx_res drm_ctx_res_t;
+typedef struct drm_draw drm_draw_t;
+typedef struct drm_update_draw drm_update_draw_t;
+typedef struct drm_auth drm_auth_t;
+typedef struct drm_irq_busid drm_irq_busid_t;
+typedef enum drm_vblank_seq_type drm_vblank_seq_type_t;
+
+typedef struct drm_agp_buffer drm_agp_buffer_t;
+typedef struct drm_agp_binding drm_agp_binding_t;
+typedef struct drm_agp_info drm_agp_info_t;
+typedef struct drm_scatter_gather drm_scatter_gather_t;
+typedef struct drm_set_version drm_set_version_t;
+#endif
+
+#endif
diff -Naurp old/src/sys/dev/pci/drm/drm_irq.c new/src/sys/dev/pci/drm/drm_irq.c
--- old/src/sys/dev/pci/drm/drm_irq.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_irq.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,517 @@
+/*-
+ * Copyright 2003 Eric Anholt
+ * 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
+ * ERIC ANHOLT 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:
+ *    Eric Anholt <anholt@FreeBSD.org>
+ *
+ */
+
+/** @file drm_irq.c
+ * Support code for handling setup/teardown of interrupt handlers and
+ * handing interrupt handlers off to the drivers.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+
+void		drm_update_vblank_count(struct drm_device *, int);
+void		vblank_disable(void *);
+int		drm_queue_vblank_event(struct drm_device *, int,
+		    union drm_wait_vblank *, struct drm_file *);
+void		drm_handle_vblank_events(struct drm_device *, int);
+
+#ifdef DRM_VBLANK_DEBUG
+#define DPRINTF(x...)	do { printf(x); } while(/* CONSTCOND */ 0)
+#else
+#define DPRINTF(x...)	do { } while(/* CONSTCOND */ 0)
+#endif
+
+int
+drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_irq_busid	*irq = data;
+
+	/*
+	 * This is only ever called by root as part of a stupid interface.
+	 * just hand over the irq without checking the busid. If all clients
+	 * can be forced to use interface 1.2 then this can die.
+	 */
+	irq->irq = dev->irq;
+
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n", irq->busnum, irq->devnum,
+	    irq->funcnum, irq->irq);
+
+	return 0;
+}
+
+int
+drm_irq_install(struct drm_device *dev)
+{
+	int	ret;
+
+	if (dev->irq == 0 || dev->dev_private == NULL)
+		return (EINVAL);
+
+	DRM_DEBUG("irq=%d\n", dev->irq);
+
+	DRM_LOCK();
+	if (dev->irq_enabled) {
+		DRM_UNLOCK();
+		return (EBUSY);
+	}
+	dev->irq_enabled = 1;
+	DRM_UNLOCK();
+
+	if ((ret = dev->driver->irq_install(dev)) != 0)
+		goto err;
+
+	return (0);
+err:
+	DRM_LOCK();
+	dev->irq_enabled = 0;
+	DRM_UNLOCK();
+	return (ret);
+}
+
+int
+drm_irq_uninstall(struct drm_device *dev)
+{
+	int i;
+
+	DRM_LOCK();
+	if (!dev->irq_enabled) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+
+	dev->irq_enabled = 0;
+	DRM_UNLOCK();
+
+	/*
+	 * Ick. we're about to turn of vblanks, so make sure anyone waiting
+	 * on them gets woken up. Also make sure we update state correctly
+	 * so that we can continue refcounting correctly.
+	 */
+	if (dev->vblank != NULL) {
+		mtx_enter(&dev->vblank->vb_lock);
+		for (i = 0; i < dev->vblank->vb_num; i++) {
+#if !defined(__NetBSD__)
+			wakeup(&dev->vblank->vb_crtcs[i]);
+#else /* !defined(__NetBSD__) */
+			cv_broadcast(&dev->vblank->vb_crtcs[i].condvar);
+#endif /* !defined(__NetBSD__) */
+			dev->vblank->vb_crtcs[i].vbl_enabled = 0;
+			dev->vblank->vb_crtcs[i].vbl_last =
+			    dev->driver->get_vblank_counter(dev, i);
+		}
+		mtx_leave(&dev->vblank->vb_lock);
+	}
+
+	DRM_DEBUG("irq=%d\n", dev->irq);
+
+	dev->driver->irq_uninstall(dev);
+
+	return (0);
+}
+
+int
+drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_control	*ctl = data;
+
+	/* Handle drivers who used to require IRQ setup no longer does. */
+	if (!(dev->driver->flags & DRIVER_IRQ))
+		return (0);
+
+	switch (ctl->func) {
+	case DRM_INST_HANDLER:
+		if (dev->if_version < DRM_IF_VERSION(1, 2) &&
+		    ctl->irq != dev->irq)
+			return (EINVAL);
+		return (drm_irq_install(dev));
+	case DRM_UNINST_HANDLER:
+		return (drm_irq_uninstall(dev));
+	default:
+		return (EINVAL);
+	}
+}
+
+void
+vblank_disable(void *arg)
+{
+	struct drm_device	*dev = (struct drm_device*)arg;
+	struct drm_vblank_info	*vbl = dev->vblank;
+	struct drm_vblank	*crtc;
+	int			 i;
+
+	mtx_enter(&vbl->vb_lock);
+	for (i = 0; i < vbl->vb_num; i++) {
+		crtc = &vbl->vb_crtcs[i];
+
+		if (crtc->vbl_refs == 0 && crtc->vbl_enabled) {
+			DPRINTF("%s: disabling crtc %d\n", __func__, i);
+			crtc->vbl_last =
+			    dev->driver->get_vblank_counter(dev, i);
+			dev->driver->disable_vblank(dev, i);
+			crtc->vbl_enabled = 0;
+		}
+	}
+	mtx_leave(&vbl->vb_lock);
+}
+
+void
+drm_vblank_cleanup(struct drm_device *dev)
+{
+#if defined(__NetBSD__)
+	int	i;
+#endif /* defined(__NetBSD__) */
+
+	if (dev->vblank == NULL)
+		return; /* not initialised */
+
+	timeout_del(&dev->vblank->vb_disable_timer);
+#if defined(__NetBSD__)
+	callout_destroy(&dev->vblank->vb_disable_timer);
+#endif /* defined(__NetBSD__) */
+
+	vblank_disable(dev);
+
+#if defined(__NetBSD__)
+	for (i = 0; i < dev->vblank->vb_num; i++)
+		cv_destroy(&dev->vblank->vb_crtcs[i].condvar);
+	mutex_destroy(&dev->vblank->vb_lock);
+#endif /* defined(__NetBSD__) */
+
+	drm_free(dev->vblank);
+	dev->vblank = NULL;
+}
+
+int
+drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+	int	i;
+
+	dev->vblank = malloc(sizeof(*dev->vblank) + (num_crtcs *
+	    sizeof(struct drm_vblank)), M_DRM,  M_WAITOK | M_CANFAIL | M_ZERO);
+	if (dev->vblank == NULL)
+		return (ENOMEM);
+
+	dev->vblank->vb_num = num_crtcs;
+	mtx_init(&dev->vblank->vb_lock, IPL_TTY);
+	timeout_set(&dev->vblank->vb_disable_timer, vblank_disable, dev);
+	for (i = 0; i < num_crtcs; i++)
+		TAILQ_INIT(&dev->vblank->vb_crtcs[i].vbl_events);
+#if defined(__NetBSD__)
+	for (i = 0; i < num_crtcs; i++)
+		cv_init(&dev->vblank->vb_crtcs[i].condvar, "drmvblq");
+#endif /* defined(__NetBSD__) */
+
+	return (0);
+}
+
+u_int32_t
+drm_vblank_count(struct drm_device *dev, int crtc)
+{
+	return (dev->vblank->vb_crtcs[crtc].vbl_count);
+}
+
+void
+drm_update_vblank_count(struct drm_device *dev, int crtc)
+{
+	u_int32_t	cur_vblank, diff;
+
+	/*
+	 * Interrupt was disabled prior to this call, so deal with counter wrap
+	 * note that we may have lost a full vb_max events if
+	 * the register is small or the interrupts were off for a long time.
+	 */
+	cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+	diff = cur_vblank - dev->vblank->vb_crtcs[crtc].vbl_last;
+	if (cur_vblank < dev->vblank->vb_crtcs[crtc].vbl_last)
+		diff += dev->vblank->vb_max;
+
+	dev->vblank->vb_crtcs[crtc].vbl_count += diff;
+}
+
+int
+drm_vblank_get(struct drm_device *dev, int crtc)
+{
+	struct drm_vblank_info	*vbl = dev->vblank;
+	int			 ret = 0;
+
+	if (dev->irq_enabled == 0)
+		return (EINVAL);
+
+	mtx_enter(&vbl->vb_lock);
+	DPRINTF("%s: %d refs = %d\n", __func__, crtc,
+	    vbl->vb_crtcs[crtc].vbl_refs);
+	vbl->vb_crtcs[crtc].vbl_refs++;
+	if (vbl->vb_crtcs[crtc].vbl_refs == 1 &&
+	    vbl->vb_crtcs[crtc].vbl_enabled == 0) {
+		if ((ret = dev->driver->enable_vblank(dev, crtc)) == 0) {
+			vbl->vb_crtcs[crtc].vbl_enabled = 1;
+			drm_update_vblank_count(dev, crtc);
+		} else {
+			vbl->vb_crtcs[crtc].vbl_refs--;
+		}
+
+	}
+	mtx_leave(&vbl->vb_lock);
+
+	return (ret);
+}
+
+void
+drm_vblank_put(struct drm_device *dev, int crtc)
+{
+	mtx_enter(&dev->vblank->vb_lock);
+	/* Last user schedules disable */
+	DPRINTF("%s: %d  refs = %d\n", __func__, crtc,
+	    dev->vblank->vb_crtcs[crtc].vbl_refs);
+	KASSERT(dev->vblank->vb_crtcs[crtc].vbl_refs > 0);
+	if (--dev->vblank->vb_crtcs[crtc].vbl_refs == 0)
+		timeout_add_sec(&dev->vblank->vb_disable_timer, 5);
+	mtx_leave(&dev->vblank->vb_lock);
+}
+
+int
+drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_modeset_ctl	*modeset = data;
+	struct drm_vblank	*vbl;
+	int			 crtc, ret = 0;
+
+	/* not initialised yet, just noop */
+	if (dev->vblank == NULL)
+		return (0);
+
+	crtc = modeset->crtc;
+	if (crtc >= dev->vblank->vb_num)
+		return (EINVAL);
+
+	vbl = &dev->vblank->vb_crtcs[crtc];
+
+	/*
+	 * If interrupts are enabled/disabled between calls to this ioctl then
+	 * it can get nasty. So just grab a reference so that the interrupts
+	 * keep going through the modeset
+	 */
+	switch (modeset->cmd) {
+	case _DRM_PRE_MODESET:
+		DPRINTF("%s: pre modeset on %d\n", __func__, crtc);
+		if (vbl->vbl_inmodeset == 0) {
+			mtx_enter(&dev->vblank->vb_lock);
+			vbl->vbl_inmodeset = 0x1;
+			mtx_leave(&dev->vblank->vb_lock);
+			if (drm_vblank_get(dev, crtc) == 0)
+				vbl->vbl_inmodeset |= 0x2;
+		}
+		break;
+	case _DRM_POST_MODESET:
+		DPRINTF("%s: post modeset on %d\n", __func__, crtc);
+		if (vbl->vbl_inmodeset) {
+			if (vbl->vbl_inmodeset & 0x2)
+				drm_vblank_put(dev, crtc);
+			vbl->vbl_inmodeset = 0;
+		}
+		break;
+	default:
+		ret = EINVAL;
+		break;
+	}
+
+	return (ret);
+}
+
+int
+drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct timeval		 now;
+	union drm_wait_vblank	*vblwait = data;
+	int			 ret, flags, crtc, seq;
+
+	if (!dev->irq_enabled || dev->vblank == NULL ||
+	    vblwait->request.type & _DRM_VBLANK_SIGNAL)
+		return (EINVAL);
+
+	flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
+	crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+
+	if (crtc >= dev->vblank->vb_num)
+		return (EINVAL);
+
+	if ((ret = drm_vblank_get(dev, crtc)) != 0)
+		return (ret);
+	seq = drm_vblank_count(dev, crtc);
+
+	if (vblwait->request.type & _DRM_VBLANK_RELATIVE) {
+		vblwait->request.sequence += seq;
+		vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
+	}
+
+	flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
+	if ((flags & _DRM_VBLANK_NEXTONMISS) &&
+	    (seq - vblwait->request.sequence) <= (1<<23)) {
+		vblwait->request.sequence = seq + 1;
+	}
+
+	if (flags & _DRM_VBLANK_EVENT)
+		return (drm_queue_vblank_event(dev, crtc, vblwait, file_priv));
+
+	DPRINTF("%s: %d waiting on %d, current %d\n", __func__, crtc,
+	     vblwait->request.sequence, drm_vblank_count(dev, crtc));
+	DRM_WAIT_ON(ret, &dev->vblank->vb_crtcs[crtc], &dev->vblank->vb_lock,
+	    3 * hz, "drmvblq", ((drm_vblank_count(dev, crtc) -
+	    vblwait->request.sequence) <= (1 << 23)) || dev->irq_enabled == 0);
+
+	microtime(&now);
+	vblwait->reply.tval_sec = now.tv_sec;
+	vblwait->reply.tval_usec = now.tv_usec;
+	vblwait->reply.sequence = drm_vblank_count(dev, crtc);
+	DPRINTF("%s: %d done waiting, seq = %d\n", __func__, crtc,
+	    vblwait->reply.sequence);
+
+	drm_vblank_put(dev, crtc);
+	return (ret);
+}
+
+int
+drm_queue_vblank_event(struct drm_device *dev, int crtc,
+    union drm_wait_vblank *vblwait, struct drm_file *file_priv)
+{
+	struct drm_pending_vblank_event	*vev;
+	struct timeval			 now;
+	u_int				 seq;
+
+
+	vev = drm_calloc(1, sizeof(*vev));
+	if (vev == NULL)
+		return (ENOMEM);
+
+	vev->event.base.type = DRM_EVENT_VBLANK;
+	vev->event.base.length = sizeof(vev->event);
+	vev->event.user_data = vblwait->request.signal;
+	vev->base.event = &vev->event.base;
+	vev->base.file_priv = file_priv;
+	vev->base.destroy = (void (*) (struct drm_pending_event *))drm_free;
+
+	microtime(&now);
+
+	mtx_enter(&dev->event_lock);
+	if (file_priv->event_space < sizeof(vev->event)) {
+		mtx_leave(&dev->event_lock);
+		drm_free(vev);
+		return (ENOMEM);
+	}
+
+
+	seq = drm_vblank_count(dev, crtc);
+	file_priv->event_space -= sizeof(vev->event);
+
+	DPRINTF("%s: queueing event %d on crtc %d\n", __func__, seq, crtc);
+
+	if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
+	    (seq - vblwait->request.sequence) <= (1 << 23)) {
+		vblwait->request.sequence = seq + 1;
+		vblwait->reply.sequence = vblwait->request.sequence;
+	}
+
+	vev->event.sequence = vblwait->request.sequence;
+	if ((seq - vblwait->request.sequence) <= (1 << 23)) {
+		vev->event.tv_sec = now.tv_sec;
+		vev->event.tv_usec = now.tv_usec;
+		DPRINTF("%s: already passed, dequeuing: crtc %d, value %d\n",
+		    __func__, crtc, seq);
+		drm_vblank_put(dev, crtc);
+		TAILQ_INSERT_TAIL(&file_priv->evlist, &vev->base, link);
+#if !defined(__NetBSD__)
+		wakeup(&file_priv->evlist);
+#else /* !defined(__NetBSD__) */
+		cv_broadcast(&file_priv->evlist_condvar);
+#endif /* !defined(__NetBSD__) */
+		selwakeup(&file_priv->rsel);
+	} else {
+		TAILQ_INSERT_TAIL(&dev->vblank->vb_crtcs[crtc].vbl_events,
+		    &vev->base, link);
+	}
+	mtx_leave(&dev->event_lock);
+
+	return (0);
+}
+
+void
+drm_handle_vblank_events(struct drm_device *dev, int crtc)
+{
+	struct drmevlist		*list;
+	struct drm_pending_event	*ev, *tmp;
+	struct drm_pending_vblank_event	*vev;
+	struct timeval			 now;
+	u_int				 seq;
+
+	list = &dev->vblank->vb_crtcs[crtc].vbl_events;
+	microtime(&now);
+	seq = drm_vblank_count(dev, crtc);
+
+	mtx_enter(&dev->event_lock);
+	for (ev = TAILQ_FIRST(list); ev != TAILQ_END(list); ev = tmp) {
+		tmp = TAILQ_NEXT(ev, link);
+
+		vev = (struct drm_pending_vblank_event *)ev;
+
+		if ((seq - vev->event.sequence) > (1 << 23))
+			continue;
+		DPRINTF("%s: got vblank event on crtc %d, value %d\n",
+		    __func__, crtc, seq);
+		
+		vev->event.sequence = seq;
+		vev->event.tv_sec = now.tv_sec;
+		vev->event.tv_usec = now.tv_usec;
+		drm_vblank_put(dev, crtc);
+		TAILQ_REMOVE(list, ev, link);
+		TAILQ_INSERT_TAIL(&ev->file_priv->evlist, ev, link);
+#if !defined(__NetBSD__)
+		wakeup(&ev->file_priv->evlist);
+#else /* !defined(__NetBSD__) */
+		cv_broadcast(&ev->file_priv->evlist_condvar);
+#endif /* !defined(__NetBSD__) */
+		selwakeup(&ev->file_priv->rsel);
+	}
+	mtx_leave(&dev->event_lock);
+}
+
+void
+drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+	/*
+	 * XXX if we had proper atomic operations this mutex wouldn't
+	 * XXX need to be held.
+	 */
+	mtx_enter(&dev->vblank->vb_lock);
+	dev->vblank->vb_crtcs[crtc].vbl_count++;
+#if !defined(__NetBSD__)
+	wakeup(&dev->vblank->vb_crtcs[crtc]);
+#else /* !defined(__NetBSD__) */
+	cv_broadcast(&dev->vblank->vb_crtcs[crtc].condvar);
+#endif /* !defined(__NetBSD__) */
+	mtx_leave(&dev->vblank->vb_lock);
+	drm_handle_vblank_events(dev, crtc);
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_lock.c new/src/sys/dev/pci/drm/drm_lock.c
--- old/src/sys/dev/pci/drm/drm_lock.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_lock.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,170 @@
+/*-
+ * Copyright 1999 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>
+ *
+ */
+
+/** @file drm_lock.c
+ * Implementation of the ioctls and other support code for dealing with the
+ * hardware lock.
+ *
+ * The DRM hardware lock is a shared structure between the kernel and userland.
+ *
+ * On uncontended access where the new context was the last context, the
+ * client may take the lock without dropping down into the kernel, using atomic
+ * compare-and-set.
+ *
+ * If the client finds during compare-and-set that it was not the last owner
+ * of the lock, it calls the DRM lock ioctl, which may sleep waiting for the
+ * lock, and may have side-effects of kernel-managed context switching.
+ *
+ * When the client releases the lock, if the lock is marked as being contended
+ * by another client, then the DRM unlock ioctl is called so that the
+ * contending client may be woken up.
+ */
+
+#include "drmP.h"
+
+int
+drm_lock_take(struct drm_lock_data *lock_data, unsigned int context)
+{
+	volatile unsigned int	*lock = &lock_data->hw_lock->lock;
+	unsigned int		 old, new;
+
+	do {
+		old = *lock;
+		if (old & _DRM_LOCK_HELD)
+			new = old | _DRM_LOCK_CONT;
+		else
+			new = context | _DRM_LOCK_HELD;
+	} while (!atomic_cmpset_int(lock, old, new));
+
+	if (_DRM_LOCKING_CONTEXT(old) == context && _DRM_LOCK_IS_HELD(old)) {
+		if (context != DRM_KERNEL_CONTEXT)
+			DRM_ERROR("%d holds heavyweight lock\n", context);
+		return (0);
+	}
+	/* If the lock wasn't held before, it's ours */
+	return (!_DRM_LOCK_IS_HELD(old));
+}
+
+int
+drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
+{
+	volatile unsigned int	*lock = &lock_data->hw_lock->lock;
+	unsigned int		 old, new;
+
+	mtx_enter(&lock_data->spinlock);
+	lock_data->file_priv = NULL;
+	do {
+		old  = *lock;
+		new  = 0;
+	} while (!atomic_cmpset_int(lock, old, new));
+	mtx_leave(&lock_data->spinlock);
+
+	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+		DRM_ERROR("%d freed heavyweight lock held by %d\n",
+			  context, _DRM_LOCKING_CONTEXT(old));
+		return 1;
+	}
+	mtx_enter(&lock_data->spinlock);
+#if !defined(__NetBSD__)
+	wakeup(lock_data);
+#else /* !defined(__NetBSD__) */
+	cv_broadcast(&lock_data->condvar);
+#endif /* !defined(__NetBSD__) */
+	mtx_leave(&lock_data->spinlock);
+	return 0;
+}
+
+int
+drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+        struct drm_lock	*lock = data;
+        int		 ret = 0;
+
+        if (lock->context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+		    DRM_CURRENTPID, lock->context);
+                return EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+	    lock->context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
+	    lock->flags);
+
+	mtx_enter(&dev->lock.spinlock);
+	for (;;) {
+		if (drm_lock_take(&dev->lock, lock->context)) {
+			dev->lock.file_priv = file_priv;
+			break;  /* Got lock */
+		}
+
+		/* Contention */
+#if !defined(__NetBSD__)
+		ret = msleep(&dev->lock, &dev->lock.spinlock,
+		    PZERO | PCATCH, "drmlkq", 0);
+#else /* !defined(__NetBSD__) */
+		ret = cv_wait_sig(&dev->lock.condvar, &dev->lock.spinlock);
+#endif /* !defined(__NetBSD__) */
+		if (ret != 0)
+			break;
+	}
+	mtx_leave(&dev->lock.spinlock);
+	DRM_DEBUG("%d %s\n", lock->context, ret ? "interrupted" : "has lock");
+
+	if (ret != 0)
+		return ret;
+
+	/* XXX: Add signal blocking here */
+
+	return 0;
+}
+
+int
+drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_lock	*lock = data;
+
+	if (lock->context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+		    DRM_CURRENTPID, lock->context);
+		return EINVAL;
+	}
+	/* Check that the context unlock being requested actually matches
+	 * who currently holds the lock.
+	 */
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context)
+		return EINVAL;
+
+	if (drm_lock_free(&dev->lock, lock->context)) {
+		DRM_ERROR("\n");
+	}
+
+	return 0;
+}
diff -Naurp old/src/sys/dev/pci/drm/drm_memory.c new/src/sys/dev/pci/drm/drm_memory.c
--- old/src/sys/dev/pci/drm/drm_memory.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_memory.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,191 @@
+/*-
+ *Copyright 1999 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>
+ *
+ */
+
+/** @file drm_memory.c
+ * Wrappers for kernel memory allocation routines, and MTRR management support.
+ *
+ * This file previously implemented a memory consumption tracking system using
+ * the "area" argument for various different types of allocations, but that
+ * has been stripped out for now.
+ */
+
+#include "drmP.h"
+
+#if defined(__NetBSD__)
+MALLOC_DEFINE(M_DRM, "drm", "Direct Rendering Management");
+#endif /* defined(__NetBSD__) */
+
+void*
+drm_alloc(size_t size)
+{
+	return (malloc(size, M_DRM, M_NOWAIT));
+}
+
+void *
+drm_calloc(size_t nmemb, size_t size)
+{
+	if (nmemb == 0 || SIZE_MAX / nmemb < size)
+		return (NULL);
+	else
+		return malloc(size * nmemb, M_DRM, M_NOWAIT | M_ZERO);
+}
+
+void *
+drm_realloc(void *oldpt, size_t oldsize, size_t size)
+{
+	void *pt;
+
+	pt = malloc(size, M_DRM, M_NOWAIT);
+	if (pt == NULL)
+		return NULL;
+	if (oldpt && oldsize) {
+		memcpy(pt, oldpt, min(oldsize, size));
+		free(oldpt, M_DRM);
+	}
+	return pt;
+}
+
+void
+drm_free(void *pt)
+{
+	if (pt != NULL)
+		free(pt, M_DRM);
+}
+
+/* Inline replacements for DRM_IOREMAP macros */
+void
+drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
+{
+	DRM_DEBUG("offset: 0x%lx size: 0x%lx type: %d\n", map->offset, map->size,
+	    map->type);
+
+	/* default to failure. */
+	map->handle = 0;
+
+	if (map->type == _DRM_AGP || map->type == _DRM_FRAME_BUFFER) {
+	/*
+	 * there can be multiple agp maps in the same BAR, agp also
+	 * quite possibly isn't the same as the vga device, just try
+	 * to map it.
+	 */
+		DRM_DEBUG("AGP map\n");
+		map->bst = dev->bst;
+		if (bus_space_map(map->bst, map->offset,
+		    map->size, BUS_SPACE_MAP_LINEAR |
+		    BUS_SPACE_MAP_PREFETCHABLE, &map->bsh)) {
+			DRM_ERROR("ioremap fail\n");
+			return;
+		}
+		/* handles are still supposed to be kernel virtual addresses */
+		map->handle = bus_space_vaddr(map->bst, map->bsh);
+	}
+}
+
+void
+drm_core_ioremapfree(struct drm_local_map *map)
+{
+	if (map->handle && map->size && (map->type == _DRM_AGP ||
+	    map->type == _DRM_FRAME_BUFFER)) {
+		bus_space_unmap(map->bst, map->bsh, map->size);
+		map->handle = 0;
+	}
+}
+
+#if !defined(__NetBSD__)
+int
+drm_mtrr_add(unsigned long offset, size_t size, int flags)
+{
+#ifndef DRM_NO_MTRR
+	int act;
+	struct mem_range_desc mrdesc;
+
+	mrdesc.mr_base = offset;
+	mrdesc.mr_len = size;
+	mrdesc.mr_flags = flags;
+	act = MEMRANGE_SET_UPDATE;
+	strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
+	return mem_range_attr_set(&mrdesc, &act);
+#else
+	return 0;
+#endif
+}
+
+int
+drm_mtrr_del(int handle, unsigned long offset, size_t size, int flags)
+{
+#ifndef DRM_NO_MTRR
+	int act;
+	struct mem_range_desc mrdesc;
+
+	mrdesc.mr_base = offset;
+	mrdesc.mr_len = size;
+	mrdesc.mr_flags = flags;
+	act = MEMRANGE_SET_REMOVE;
+	strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
+	return mem_range_attr_set(&mrdesc, &act);
+#else
+	return 0;
+#endif
+}
+#else /* !defined(__NetBSD__) */
+int
+drm_mtrr_add(unsigned long offset, size_t size, int flags)
+{
+#ifdef MTRR_GETSET_KERNEL
+	struct mtrr mtrrmap;
+	int one = 1;
+
+	mtrrmap.base = offset;
+	mtrrmap.len = size;
+	mtrrmap.type = flags;
+	mtrrmap.flags = MTRR_VALID;
+	return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
+#else
+	return 0;
+#endif
+}
+
+int
+drm_mtrr_del(int handle, unsigned long offset, size_t size, int flags)
+{
+#ifdef MTRR_GETSET_KERNEL
+	struct mtrr mtrrmap;
+	int one = 1;
+
+	mtrrmap.base = offset;
+	mtrrmap.len = size;
+	mtrrmap.type = flags;
+	mtrrmap.flags = 0;
+	return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
+#else
+	return 0;
+#endif
+}
+#endif /* !defined(__NetBSD__) */
diff -Naurp old/src/sys/dev/pci/drm/drmP.h new/src/sys/dev/pci/drm/drmP.h
--- old/src/sys/dev/pci/drm/drmP.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drmP.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,912 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ */
+/*-
+ * Copyright 1999 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>
+ *
+ */
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#if defined(_KERNEL) || defined(__KERNEL__)
+
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/resource.h>
+#include <sys/resourcevar.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/signalvar.h>
+#include <sys/poll.h>
+#include <sys/tree.h>
+#include <sys/endian.h>
+#include <sys/mman.h>
+#include <sys/stdint.h>
+#include <sys/agpio.h>
+#if !defined(__NetBSD__)
+#include <sys/memrange.h>
+#else /* !defined(__NetBSD__) */
+#if defined(__i386__) || defined(__x86_64__)
+#include <machine/mtrr.h>
+#endif
+#endif /* !defined(__NetBSD__) */
+#include <sys/extent.h>
+#include <sys/vnode.h>
+
+#if defined(__NetBSD__)
+#include <sys/condvar.h>
+#include <sys/kauth.h>
+#include <sys/select.h>
+#endif /* defined(__NetBSD__) */
+
+#include <uvm/uvm.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/agpvar.h>
+#include <dev/pci/vga_pcivar.h>
+#include <machine/param.h>
+#include <machine/bus.h>
+
+#if defined(__NetBSD__)
+MALLOC_DECLARE(M_DRM);
+
+/* OpenBSD queue(3) compatibility definitions. */
+#define TAILQ_END(head)		NULL
+
+/* OpenBSD UVM pager compatibility definitions. */
+#define VM_PAGER_OK		0
+#define VM_PAGER_ERROR		EIO
+#define VM_PAGER_REFAULT	ERESTART
+
+/* OpenBSD UVM object compatibility definitions. */
+#define uvm_objwire(uobj, start, end, plist)				\
+	uobj_wirepages(uobj, start, end, plist)
+#define uvm_objunwire(uobj, start, end)					\
+	uobj_unwirepages(uobj, start, end)
+
+/* OpenBSD mutex(9) compatibility definitions. */
+#define mtx_init(mtx, lvl)	mutex_init(mtx, MUTEX_DEFAULT, lvl)
+#define mtx_enter(mtx)		mutex_enter(mtx)
+#define mtx_leave(mtx)		mutex_exit(mtx)
+
+#define MUTEX_ASSERT_LOCKED(mtx)	(KASSERT(mutex_owned(mtx)))
+#define MUTEX_ASSERT_UNLOCKED(mtx)	(KASSERT(!(mutex_owned(mtx))))
+
+/* OpenBSD rwlock(9) compatibility definitions. */
+#define rw_enter_write(rwl)	rw_enter(rwl, RW_WRITER)
+#define rw_exit_write(rwl)	rw_exit(rwl)
+#define rw_enter_read(rwl)	rw_enter(rwl, RW_READER)
+#define rw_exit_read(rwl)	rw_exit(rwl)
+
+/* OpenBSD timeout(9) compatibility definitions. */
+static __inline void
+timeout_set(callout_t *cs, void (*func)(void *), void *arg)
+{
+	callout_init(cs, 0);
+	callout_setfunc(cs, func, arg);
+}
+static __inline void
+timeout_del(callout_t *cs)
+{
+	(void)callout_stop(cs);
+}
+static __inline void
+timeout_add_sec(callout_t *cs, int sec)
+{
+	long long ticks;
+
+	ticks = (long long)hz * sec;
+	if (ticks > INT_MAX)
+		ticks = INT_MAX;
+
+	callout_schedule(cs, (int)ticks);
+}
+static __inline void
+timeout_add_msec(callout_t *cs, int msec)
+{
+	long long ticks;
+
+	ticks = (long long)msec * 1000 / tick;
+	if (ticks > INT_MAX)
+		ticks = INT_MAX;
+
+	callout_schedule(cs, (int)ticks);
+}
+
+/* OpenBSD selrecord/selwakeup compatibility definitions. */
+#define selwakeup(sip)		selnotify(sip, 0, 0)
+
+/* OpenBSD types compatibility definitions. */
+typedef void *			caddr_t;
+typedef struct vm_page *	vm_page_t;
+#endif /* defined(__NetBSD__) */
+
+#include "drm.h"
+#include "drm_atomic.h"
+
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+				/* Internal types and structures */
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
+
+#define __OS_HAS_AGP	1
+
+#define DRM_CURRENTPID		curproc->p_pid
+#define DRM_LOCK()		rw_enter_write(&dev->dev_lock)
+#define DRM_UNLOCK()		rw_exit_write(&dev->dev_lock)
+#define DRM_READLOCK()		rw_enter_read(&dev->dev_lock)
+#define DRM_READUNLOCK()	rw_exit_read(&dev->dev_lock)
+#define DRM_MAXUNITS		8
+
+#if !defined(__NetBSD__)
+
+/* D_CLONE only supports one device, this will be fixed eventually */
+#define drm_get_device_from_kdev(_kdev)	\
+	(drm_cd.cd_ndevs > 0 ? drm_cd.cd_devs[0] : NULL)
+#if 0
+#define drm_get_device_from_kdev(_kdev)			\
+	(minor(_kdev) < drm_cd.cd_ndevs) ? drm_cd.cd_devs[minor(_kdev)] : NULL
+#endif
+
+/* DRM_SUSER returns true if the user is superuser */
+#define DRM_SUSER(p)		(suser(p, p->p_acflag) == 0)
+#define DRM_MTRR_WC		MDF_WRITECOMBINE
+
+#define PAGE_ALIGN(addr)	(((addr) + PAGE_MASK) & ~PAGE_MASK)
+
+extern struct cfdriver drm_cd;
+
+#else /* !defined(__NetBSD__) */
+
+/* D_CLONE only supports one device, this will be fixed eventually */
+#define drm_get_device_from_kdev(_kdev)	\
+	device_private(drmdev_cd.cd_ndevs > 0 ? drmdev_cd.cd_devs[0] : NULL)
+
+#define DRM_SUSER(l)		(kauth_cred_getsvuid((l)->l_cred) == 0)
+
+#ifdef MTRR_TYPE_WC
+#define DRM_MTRR_WC		MTRR_TYPE_WC
+#else
+#define DRM_MTRR_WC		0
+#endif
+
+#define PAGE_ALIGN(addr)	round_page(addr)
+
+extern struct cfdriver drmdev_cd;
+
+#endif /* !defined(__NetBSD__) */
+
+typedef u_int64_t u64;
+typedef u_int32_t u32;
+typedef u_int16_t u16;
+typedef u_int8_t u8;
+
+/* DRM_READMEMORYBARRIER() prevents reordering of reads.
+ * DRM_WRITEMEMORYBARRIER() prevents reordering of writes.
+ * DRM_MEMORYBARRIER() prevents reordering of reads and writes.
+ */
+#if defined(__i386__)
+#define DRM_READMEMORYBARRIER()		__asm __volatile( \
+					"lock; addl $0,0(%%esp)" : : : "memory");
+#define DRM_WRITEMEMORYBARRIER()	__asm __volatile("" : : : "memory");
+#define DRM_MEMORYBARRIER()		__asm __volatile( \
+					"lock; addl $0,0(%%esp)" : : : "memory");
+#elif defined(__alpha__)
+#define DRM_READMEMORYBARRIER()		alpha_mb();
+#define DRM_WRITEMEMORYBARRIER()	alpha_wmb();
+#define DRM_MEMORYBARRIER()		alpha_mb();
+#elif defined(__amd64__)
+#define DRM_READMEMORYBARRIER()		__asm __volatile( \
+					"lock; addl $0,0(%%rsp)" : : : "memory");
+#define DRM_WRITEMEMORYBARRIER()	__asm __volatile("" : : : "memory");
+#define DRM_MEMORYBARRIER()		__asm __volatile( \
+					"lock; addl $0,0(%%rsp)" : : : "memory");
+#endif
+
+#define	DRM_COPY_TO_USER(user, kern, size)	copyout(kern, user, size)
+#define	DRM_COPY_FROM_USER(kern, user, size)	copyin(user, kern, size)
+#define le32_to_cpu(x) letoh32(x)
+#define cpu_to_le32(x) htole32(x)
+
+#define DRM_UDELAY(udelay)	DELAY(udelay)
+
+#define LOCK_TEST_WITH_RETURN(dev, file_priv)				\
+do {									\
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||		\
+	     dev->lock.file_priv != file_priv) {			\
+		DRM_ERROR("%s called without lock held\n",		\
+			   __FUNCTION__);				\
+		return EINVAL;						\
+	}								\
+} while (0)
+
+#if !defined(__NetBSD__)
+#define DRM_WAIT_ON(ret, queue, lock,  timeout, msg, condition ) do {	\
+	mtx_enter(lock);						\
+	while ((ret) == 0) {						\
+		if (condition)						\
+			break;						\
+		ret = msleep((queue), (lock), PZERO | PCATCH,		\
+		    (msg), (timeout));					\
+	}								\
+	mtx_leave(lock);						\
+} while (/* CONSTCOND */ 0)
+#else /* !defined(__NetBSD__) */
+#define DRM_WAIT_ON(ret, queue, lock,  timeout, msg, condition ) do {	\
+	mtx_enter(lock);						\
+	while ((ret) == 0) {						\
+		if (condition)						\
+			break;						\
+		ret = cv_timedwait_sig((queue.condvar), (lock),		\
+		    (timeout));						\
+	}								\
+	mtx_leave(lock);						\
+} while (/* CONSTCOND */ 0)
+#endif /* !defined(__NetBSD__) */
+
+#define DRM_ERROR(fmt, arg...) \
+	printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt,		\
+	    curproc->p_pid, __func__ , ## arg)
+
+
+#define DRM_INFO(fmt, arg...)  printf("%s: " fmt, dev_priv->dev.dv_xname, ## arg)
+
+#ifdef DRMDEBUG
+#undef DRM_DEBUG
+#define DRM_DEBUG(fmt, arg...) do {					\
+	if (drm_debug_flag)						\
+		printf("[" DRM_NAME ":pid%d:%s] " fmt, curproc->p_pid,	\
+			__func__ , ## arg);				\
+} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...) do { } while(/* CONSTCOND */ 0)
+#endif
+
+struct drm_pcidev {
+	int vendor;
+	int device;
+	long driver_private;
+};
+
+struct drm_file;
+struct drm_device;
+
+struct drm_buf {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	unsigned long	  offset;      /* Byte offset (used internally)	     */
+	void 		  *address;    /* KVA of buffer			     */
+	unsigned long	  bus_address; /* Bus address of buffer		     */
+	__volatile__ int  pending;     /* On hardware DMA queue		     */
+	struct drm_file   *file_priv;  /* Unique identifier of holding process */
+	void		  *dev_private;  /* Per-buffer private storage       */
+};
+
+struct drm_dmamem {
+	bus_dmamap_t		map;
+	caddr_t			kva;
+	bus_size_t		size;
+	int			nsegs;
+	bus_dma_segment_t	segs[1];
+};
+
+struct drm_buf_entry {
+	struct drm_dmamem	**seglist;
+	struct drm_buf		*buflist;
+	int			 buf_count;
+	int			 buf_size;
+	int			 page_order;
+	int			 seg_count;
+};
+
+struct drm_pending_event {
+	TAILQ_ENTRY(drm_pending_event)	 link;
+	struct drm_event		*event;
+	struct drm_file			*file_priv;
+	void				(*destroy)(struct drm_pending_event *);
+};
+
+struct drm_pending_vblank_event {
+	struct drm_pending_event	base;
+	struct drm_event_vblank		event;
+};
+
+TAILQ_HEAD(drmevlist, drm_pending_event);
+
+struct drm_file {
+	SPLAY_HEAD(drm_obj_tree, drm_handle)	 obj_tree;
+	struct drmevlist			 evlist;
+#if !defined(__NetBSD__)
+	struct mutex				 table_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t				 table_lock;
+	kcondvar_t				 evlist_condvar;
+#endif /* !defined(__NetBSD__) */
+	struct selinfo				 rsel;
+	SPLAY_ENTRY(drm_file)			 link;
+	int					 authenticated;
+	unsigned long				 ioctl_count;
+	dev_t					 kdev;
+	drm_magic_t				 magic;
+	int					 event_space;
+	int					 flags;
+	int					 master;
+	int					 minor;
+	u_int					 obj_id; /*next gem id*/
+};
+
+struct drm_lock_data {
+#if !defined(__NetBSD__)
+	struct mutex		 spinlock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 spinlock;
+	kcondvar_t		 condvar;
+#endif /* !defined(__NetBSD__) */
+	struct drm_hw_lock	*hw_lock;	/* Hardware lock */
+	/* Unique identifier of holding process (NULL is kernel) */
+	struct drm_file		*file_priv;
+};
+
+/* This structure, in the struct drm_device, is always initialized while
+ * the device is open.  dev->dma_lock protects the incrementing of
+ * dev->buf_use, which when set marks that no further bufs may be allocated
+ * until device teardown occurs (when the last open of the device has closed).
+ * The high/low watermarks of bufs are only touched by the X Server, and thus
+ * not concurrently accessed, so no locking is needed.
+ */
+struct drm_device_dma {
+#if !defined(__NetBSD__)
+	struct rwlock	 	 dma_lock;
+#else /* !defined(__NetBSD__) */
+	krwlock_t	 	 dma_lock;
+#endif /* !defined(__NetBSD__) */
+	struct drm_buf_entry	 bufs[DRM_MAX_ORDER+1];
+	struct drm_buf		**buflist;	/* Vector of pointers info bufs*/
+	unsigned long		*pagelist;
+	unsigned long		 byte_count;
+	int			 buf_use;	/* Buffers used no more alloc */
+	int			 buf_count;
+	int			 page_count;
+	int			 seg_count;
+	enum {
+		_DRM_DMA_USE_AGP = 0x01,
+		_DRM_DMA_USE_SG  = 0x02
+	} flags;
+};
+
+struct drm_agp_mem {
+	void               *handle;
+	unsigned long      bound; /* address */
+	int                pages;
+	TAILQ_ENTRY(drm_agp_mem) link;
+};
+
+struct drm_agp_head {
+	struct agp_softc			*agpdev;
+	const char				*chipset;
+	TAILQ_HEAD(agp_memlist, drm_agp_mem)	 memory;
+	struct agp_info				 info;
+	unsigned long				 base;
+	unsigned long				 mode;
+	unsigned long				 page_mask;
+	int					 acquired;
+	int					 cant_use_aperture;
+	int					 enabled;
+   	int					 mtrr;
+};
+
+struct drm_sg_mem {
+	struct drm_dmamem	*mem;
+	unsigned long		 handle;
+};
+
+struct drm_local_map {
+	TAILQ_ENTRY(drm_local_map)	 link;	/* Link for map list */
+	struct drm_dmamem		*dmamem;/* Handle to DMA mem */
+	void				*handle;/* KVA, if mapped */
+	bus_space_tag_t			 bst;	/* Tag for mapped pci mem */
+	bus_space_handle_t		 bsh;	/* Handle to mapped pci mem */
+	u_long				 ext;	/* extent for mmap */
+	u_long				 offset;/* Physical address */
+	u_long				 size;	/* Physical size (bytes) */
+	int				 mtrr;	/* Boolean: MTRR used */
+	enum drm_map_flags		 flags;	/* Flags */
+	enum drm_map_type		 type;	/* Type of memory mapped */
+};
+
+struct drm_vblank_info {
+#if !defined(__NetBSD__)
+	struct mutex		 vb_lock;		/* VBLANK data lock */
+	struct timeout		 vb_disable_timer;	/* timer for disable */
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 vb_lock;		/* VBLANK data lock */
+	callout_t		 vb_disable_timer;	/* timer for disable */
+#endif /* !defined(__NetBSD__) */
+	int			 vb_num;		/* number of crtcs */
+	u_int32_t		 vb_max;		/* counter reg size */
+	struct drm_vblank {
+		struct drmevlist vbl_events;		/* vblank events */
+		u_int32_t	 vbl_last;		/* Last recieved */
+		u_int32_t	 vbl_count;		/* interrupt no. */
+		int		 vbl_refs;		/* Number of users */
+		int		 vbl_enabled;		/* Enabled? */
+		int		 vbl_inmodeset;		/* in a modeset? */
+#if defined(__NetBSD__)
+		kcondvar_t	 condvar;
+#endif /* defined(__NetBSD__) */
+	}			 vb_crtcs[1];
+};
+
+/* Heap implementation for radeon and i915 legacy */
+TAILQ_HEAD(drm_heap, drm_mem);
+
+struct drm_mem {
+	TAILQ_ENTRY(drm_mem)	 link;
+	struct drm_file		*file_priv; /* NULL: free, other: real files */
+	int			 start;
+	int			 size;
+};
+
+/* location of GART table */
+#define DRM_ATI_GART_MAIN 1
+#define DRM_ATI_GART_FB   2
+
+#define DRM_ATI_GART_PCI  1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP  3
+#define DRM_ATI_GART_R600 4
+
+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) -1)
+#define upper_32_bits(_val) ((u_int32_t)(((_val) >> 16) >> 16))
+
+struct drm_ati_pcigart_info {
+	union pcigart_table {
+		struct fb_gart {
+			bus_space_tag_t		 bst;
+			bus_space_handle_t	 bsh;
+		}	fb;
+		struct mem_gart {
+			struct drm_dmamem	*mem;
+			u_int32_t		*addr;
+		}	dma;
+	}			 tbl;
+	bus_addr_t		 bus_addr;
+	bus_addr_t		 table_mask;
+	bus_size_t		 table_size;
+	int			 gart_table_location;
+	int			 gart_reg_if;
+};
+
+/*
+ *  Locking protocol:
+ * All drm object are uvm objects, as such they have a reference count and
+ * a lock. On the other hand, operations carries out by the drm may involve
+ * sleeping (waiting for rendering to finish, say), while you wish to have
+ * mutual exclusion on an object. For this reason, all drm-related operations
+ * on drm objects must acquire the DRM_BUSY flag on the object as the first
+ * thing that they do. If the BUSY flag is already on the object, set DRM_WANTED
+ * and sleep until the other locker is done with it. When the BUSY flag is 
+ * acquired then only that flag and a reference is required to do most 
+ * operations on the drm_object. The uvm object is still bound by uvm locking
+ * protocol.
+ *
+ * Subdrivers (radeon, intel, etc) may have other locking requirement, these
+ * requirements will be detailed in those drivers.
+ */
+struct drm_obj {
+	struct uvm_object		 uobj;
+	SPLAY_ENTRY(drm_obj)	 	 entry;
+	struct drm_device		*dev;
+	struct uvm_object		*uao;
+
+	size_t				 size;
+	int				 name;
+	int				 handlecount;
+/* any flags over 0x00000010 are device specific */
+#define	DRM_BUSY	0x00000001
+#define	DRM_WANTED	0x00000002
+	u_int				 do_flags;
+#ifdef DRMLOCKDEBUG			/* to tell owner */
+	struct proc			*holding_proc;
+#endif
+	uint32_t			 read_domains;
+	uint32_t			 write_domain;
+
+	uint32_t			 pending_read_domains;
+	uint32_t			 pending_write_domain;
+};
+
+struct drm_handle {
+	SPLAY_ENTRY(drm_handle)	 entry;
+	struct drm_obj		*obj;
+	uint32_t		 handle;
+};
+
+struct drm_driver_info {
+	int	(*firstopen)(struct drm_device *);
+	int	(*open)(struct drm_device *, struct drm_file *);
+	int	(*ioctl)(struct drm_device*, u_long, caddr_t,
+		    struct drm_file *);
+	void	(*close)(struct drm_device *, struct drm_file *);
+	void	(*lastclose)(struct drm_device *);
+	int	(*dma_ioctl)(struct drm_device *, struct drm_dma *,
+		    struct drm_file *);
+	int	(*irq_install)(struct drm_device *);
+	void	(*irq_uninstall)(struct drm_device *);
+	int	vblank_pipes;
+	u_int32_t (*get_vblank_counter)(struct drm_device *, int);
+	int	(*enable_vblank)(struct drm_device *, int);
+	void	(*disable_vblank)(struct drm_device *, int);
+	/*
+	 * driver-specific constructor for gem objects to set up private data.
+	 * returns 0 on success.
+	 */
+	int	(*gem_init_object)(struct drm_obj *);
+	void	(*gem_free_object)(struct drm_obj *);
+	int	(*gem_fault)(struct drm_obj *, struct uvm_faultinfo *, off_t,
+		    vaddr_t, vm_page_t *, int, int, vm_prot_t, int);
+
+	size_t	gem_size;
+	size_t	buf_priv_size;
+	size_t	file_priv_size;
+
+	int	major;
+	int	minor;
+	int	patchlevel;
+	const char *name;		/* Simple driver name		   */
+	const char *desc;		/* Longer driver name		   */
+	const char *date;		/* Date of last major changes.	   */
+
+#define DRIVER_AGP		0x1
+#define DRIVER_AGP_REQUIRE	0x2
+#define DRIVER_MTRR		0x4
+#define DRIVER_DMA		0x8
+#define DRIVER_PCI_DMA		0x10
+#define DRIVER_SG		0x20
+#define DRIVER_IRQ		0x40
+#define DRIVER_GEM		0x80
+
+	u_int	flags;
+};
+
+/** 
+ * DRM device functions structure
+ */
+struct drm_device {
+	struct device	  device; /* softc is an extension of struct device */
+
+	const struct drm_driver_info *driver;
+
+	bus_dma_tag_t			dmat;
+	bus_space_tag_t			bst;
+
+	char		  *unique;	/* Unique identifier: e.g., busid  */
+	int		  unique_len;	/* Length of unique field	   */
+	
+	int		  if_version;	/* Highest interface version set */
+				/* Locks */
+#if !defined(__NetBSD__)
+	struct rwlock	  dev_lock;	/* protects everything else */
+#else /* !defined(__NetBSD__) */
+	krwlock_t	  dev_lock;	/* protects everything else */
+#endif /* !defined(__NetBSD__) */
+
+				/* Usage Counters */
+	int		  open_count;	/* Outstanding files open	   */
+
+				/* Authentication */
+	SPLAY_HEAD(drm_file_tree, drm_file)	files;
+	drm_magic_t	  magicid;
+
+	/* Linked list of mappable regions. Protected by dev_lock */
+	struct extent				*handle_ext;
+	TAILQ_HEAD(drm_map_list, drm_local_map)	 maplist;
+
+
+	struct drm_lock_data  lock;	/* Information on hardware lock	*/
+
+				/* DMA queues (contexts) */
+	struct drm_device_dma  *dma;		/* Optional pointer for DMA support */
+
+				/* Context support */
+	int		  irq;		/* Interrupt used by board	   */
+	int		  irq_enabled;	/* True if the irq handler is enabled */
+
+	/* VBLANK support */
+	struct drm_vblank_info	*vblank;		/* One per ctrc */
+#if !defined(__NetBSD__)
+	struct mutex		 event_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 event_lock;
+#endif /* !defined(__NetBSD__) */
+
+	pid_t			 buf_pgid;
+
+	struct drm_agp_head	*agp;
+	struct drm_sg_mem	*sg;  /* Scatter gather memory */
+	atomic_t		*ctx_bitmap;
+	void			*dev_private;
+	struct drm_local_map	*agp_buffer_map;
+
+	/* GEM info */
+#if !defined(__NetBSD__)
+	struct mutex		 obj_name_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 obj_name_lock;
+#endif /* !defined(__NetBSD__) */
+	atomic_t		 obj_count;
+	u_int			 obj_name;
+	atomic_t		 obj_memory;
+	atomic_t		 pin_count;
+	atomic_t		 pin_memory;
+	atomic_t		 gtt_count;
+	atomic_t		 gtt_memory;
+	uint32_t		 gtt_total;
+	uint32_t		 invalidate_domains;
+	uint32_t		 flush_domains;
+	SPLAY_HEAD(drm_name_tree, drm_obj)	name_tree;
+	struct pool				objpl;
+};
+
+struct drm_attach_args {
+	const struct drm_driver_info	*driver;
+	char				*busid;
+	bus_dma_tag_t			 dmat;
+	bus_space_tag_t			 bst;
+	size_t				 busid_len;
+	int				 is_agp;
+	u_int8_t			 irq;
+};
+
+extern int	drm_debug_flag;
+
+/* Device setup support (drm_drv.c) */
+int	drm_pciprobe(struct pci_attach_args *, const struct drm_pcidev * );
+struct device	*drm_attach_pci(const struct drm_driver_info *, 
+		     struct pci_attach_args *, int, struct device *);
+dev_type_ioctl(drmioctl);
+dev_type_read(drmread);
+dev_type_poll(drmpoll);
+dev_type_open(drmopen);
+dev_type_close(drmclose);
+dev_type_mmap(drmmmap);
+struct drm_local_map	*drm_getsarea(struct drm_device *);
+struct drm_dmamem	*drm_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
+			     int, bus_size_t, int, int);
+void			 drm_dmamem_free(bus_dma_tag_t, struct drm_dmamem *);
+
+const struct drm_pcidev	*drm_find_description(int , int ,
+			     const struct drm_pcidev *);
+
+/* File operations helpers (drm_fops.c) */
+struct drm_file	*drm_find_file_by_minor(struct drm_device *, int);
+
+/* Memory management support (drm_memory.c) */
+void	*drm_alloc(size_t);
+void	*drm_calloc(size_t, size_t);
+void	*drm_realloc(void *, size_t, size_t);
+void	 drm_free(void *);
+
+/* XXX until we get PAT support */
+#define drm_core_ioremap_wc drm_core_ioremap
+void	drm_core_ioremap(struct drm_local_map *, struct drm_device *);
+void	drm_core_ioremapfree(struct drm_local_map *);
+
+int	drm_mtrr_add(unsigned long, size_t, int);
+int	drm_mtrr_del(int, unsigned long, size_t, int);
+
+/* Heap interface (DEPRECATED) */
+int		 drm_init_heap(struct drm_heap *, int, int);
+struct drm_mem	*drm_alloc_block(struct drm_heap *, int, int,
+		     struct drm_file *);
+int		 drm_mem_free(struct drm_heap *, int, struct drm_file *);
+void		 drm_mem_release(struct drm_heap *, struct drm_file *);
+void		 drm_mem_takedown(struct drm_heap *);
+
+/* Context management (DRI1, deprecated) */
+int	drm_ctxbitmap_init(struct drm_device *);
+void	drm_ctxbitmap_cleanup(struct drm_device *);
+void	drm_ctxbitmap_free(struct drm_device *, int);
+int	drm_ctxbitmap_next(struct drm_device *);
+
+/* Locking IOCTL support (drm_lock.c) */
+int	drm_lock_take(struct drm_lock_data *, unsigned int);
+int	drm_lock_free(struct drm_lock_data *, unsigned int);
+
+/* Buffer management and DMA support (drm_bufs.c) */
+int	drm_order(unsigned long);
+struct drm_local_map *drm_core_findmap(struct drm_device *, unsigned long);
+int	drm_rmmap_ioctl(struct drm_device *, void *, struct drm_file *);
+void	drm_rmmap(struct drm_device *, struct drm_local_map *);
+void	drm_rmmap_locked(struct drm_device *, struct drm_local_map *);
+int	drm_addmap_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_addmap(struct drm_device *, unsigned long, unsigned long,
+	    enum drm_map_type, enum drm_map_flags, struct drm_local_map **);
+int	drm_addbufs(struct drm_device *, struct drm_buf_desc *);
+int	drm_freebufs(struct drm_device *, void *, struct drm_file *);
+int	drm_mapbufs(struct drm_device *, void *, struct drm_file *);
+int	drm_dma(struct drm_device *, void *, struct drm_file *);
+int	drm_dma_setup(struct drm_device *);
+void	drm_dma_takedown(struct drm_device *);
+void	drm_cleanup_buf(struct drm_device *, struct drm_buf_entry *);
+void	drm_free_buffer(struct drm_device *, struct drm_buf *);
+void	drm_reclaim_buffers(struct drm_device *, struct drm_file *);
+
+/* IRQ support (drm_irq.c) */
+int	drm_irq_install(struct drm_device *);
+int	drm_irq_uninstall(struct drm_device *);
+void	drm_vblank_cleanup(struct drm_device *);
+int	drm_vblank_init(struct drm_device *, int);
+u_int32_t drm_vblank_count(struct drm_device *, int);
+int	drm_vblank_get(struct drm_device *, int);
+void	drm_vblank_put(struct drm_device *, int);
+int	drm_modeset_ctl(struct drm_device *, void *, struct drm_file *);
+void	drm_handle_vblank(struct drm_device *, int);
+
+/* AGP/PCI Express/GART support (drm_agpsupport.c) */
+struct drm_agp_head *drm_agp_init(void);
+void	drm_agp_takedown(struct drm_device *);
+int	drm_agp_acquire(struct drm_device *);
+int	drm_agp_release(struct drm_device *);
+int	drm_agp_info(struct drm_device *, struct drm_agp_info *);
+int	drm_agp_enable(struct drm_device *, struct drm_agp_mode);
+void	*drm_agp_allocate_memory(size_t, u32);
+int	drm_agp_free_memory(void *);
+int	drm_agp_bind_memory(void *, off_t);
+int	drm_agp_unbind_memory(void *);
+int	drm_agp_alloc(struct drm_device *, struct drm_agp_buffer *);
+int	drm_agp_free(struct drm_device *, struct drm_agp_buffer *);
+int	drm_agp_bind(struct drm_device *, struct drm_agp_binding *);
+int	drm_agp_unbind(struct drm_device *, struct drm_agp_binding *);
+
+/* Scatter Gather Support (drm_scatter.c) */
+void	drm_sg_cleanup(struct drm_device *, struct drm_sg_mem *);
+int	drm_sg_alloc(struct drm_device *, struct drm_scatter_gather *);
+
+/* ATI PCIGART support (ati_pcigart.c) */
+int	drm_ati_pcigart_init(struct drm_device *,
+	    struct drm_ati_pcigart_info *);
+int	drm_ati_pcigart_cleanup(struct drm_device *,
+	    struct drm_ati_pcigart_info *);
+
+/* Locking IOCTL support (drm_drv.c) */
+int	drm_lock(struct drm_device *, void *, struct drm_file *);
+int	drm_unlock(struct drm_device *, void *, struct drm_file *);
+
+/* Context IOCTL support (drm_context.c) */
+int	drm_resctx(struct drm_device *, void *, struct drm_file *);
+int	drm_addctx(struct drm_device *, void *, struct drm_file *);
+int	drm_getctx(struct drm_device *, void *, struct drm_file *);
+int	drm_rmctx(struct drm_device *, void *, struct drm_file *);
+
+/* IRQ support (drm_irq.c) */
+int	drm_control(struct drm_device *, void *, struct drm_file *);
+int	drm_wait_vblank(struct drm_device *, void *, struct drm_file *);
+int	drm_irq_by_busid(struct drm_device *, void *, struct drm_file *);
+
+/* AGP/GART support (drm_agpsupport.c) */
+int	drm_agp_acquire_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_release_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_enable_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_info_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_alloc_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_free_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_unbind_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_agp_bind_ioctl(struct drm_device *, void *, struct drm_file *);
+
+/* Scatter Gather Support (drm_scatter.c) */
+int	drm_sg_alloc_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_sg_free(struct drm_device *, void *, struct drm_file *);
+
+struct drm_obj *drm_gem_object_alloc(struct drm_device *, size_t);
+void	 drm_unref(struct uvm_object *);
+void	 drm_ref(struct uvm_object *);
+void	 drm_unref_locked(struct uvm_object *);
+void	 drm_ref_locked(struct uvm_object *);
+void	drm_hold_object_locked(struct drm_obj *);
+void	drm_hold_object(struct drm_obj *);
+void	drm_unhold_object_locked(struct drm_obj *);
+void	drm_unhold_object(struct drm_obj *);
+int	drm_try_hold_object(struct drm_obj *);
+void	drm_unhold_and_unref(struct drm_obj *);
+int	drm_handle_create(struct drm_file *, struct drm_obj *, int *);
+struct drm_obj *drm_gem_object_lookup(struct drm_device *,
+			    struct drm_file *, int );
+int	drm_gem_close_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_gem_flink_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_gem_open_ioctl(struct drm_device *, void *, struct drm_file *);
+int	drm_gem_load_uao(bus_dma_tag_t, bus_dmamap_t, struct uvm_object *,
+	    bus_size_t, int, bus_dma_segment_t **);
+
+static __inline void
+drm_gem_object_reference(struct drm_obj *obj)
+{
+	drm_ref(&obj->uobj);
+}
+
+static __inline void
+drm_gem_object_unreference(struct drm_obj *obj)
+{
+	drm_unref(&obj->uobj);
+}
+
+static __inline void 
+drm_lock_obj(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	simple_lock(&obj->uobj);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+}
+
+static __inline void 
+drm_unlock_obj(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	simple_unlock(&obj->uobj);
+#else /* !defined(__NetBSD__) */
+	mutex_exit(&obj->uobj.vmobjlock);
+#endif /* !defined(__NetBSD__) */
+}
+#ifdef DRMLOCKDEBUG
+
+#define DRM_ASSERT_HELD(obj)		\
+	KASSERT(obj->do_flags & DRM_BUSY && obj->holding_proc == curproc)
+#if !defined(__NetBSD__)
+#define DRM_OBJ_ASSERT_LOCKED(obj) /* XXX mutexes */
+#else /* !defined(__NetBSD__) */
+#define DRM_OBJ_ASSERT_LOCKED(obj) KASSERT(mutex_owned(&obj->uobj.vmobjlock))
+#endif /* !defined(__NetBSD__) */
+#define DRM_ASSERT_LOCKED(lock) MUTEX_ASSERT_LOCKED(lock)
+#else
+
+#define DRM_ASSERT_HELD(obj)
+#define DRM_OBJ_ASSERT_LOCKED(obj)
+#define DRM_ASSERT_LOCKED(lock) 
+
+#endif
+
+
+#endif /* __KERNEL__ */
+#endif /* _DRM_P_H_ */
diff -Naurp old/src/sys/dev/pci/drm/drm_sarea.h new/src/sys/dev/pci/drm/drm_sarea.h
--- old/src/sys/dev/pci/drm/drm_sarea.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_sarea.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,84 @@
+/**
+ * \file drm_sarea.h
+ * \brief SAREA definitions
+ *
+ * \author Michel D�zer <michel@daenzer.net>
+ */
+
+/*
+ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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
+ * TUNGSTEN GRAPHICS 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.
+ */
+
+#ifndef _DRM_SAREA_H_
+#define _DRM_SAREA_H_
+
+#include "drm.h"
+
+/* SAREA area needs to be at least a page */
+#if defined(__alpha__)
+#define SAREA_MAX                       0x2000
+#elif defined(__ia64__)
+#define SAREA_MAX                       0x10000	/* 64kB */
+#else
+/* Intel 830M driver needs at least 8k SAREA */
+#define SAREA_MAX                       0x2000UL
+#endif
+
+/** Maximum number of drawables in the SAREA */
+#define SAREA_MAX_DRAWABLES		256
+
+#define SAREA_DRAWABLE_CLAIMED_ENTRY    0x80000000
+
+/** SAREA drawable */
+struct drm_sarea_drawable {
+	unsigned int stamp;
+	unsigned int flags;
+};
+
+/** SAREA frame */
+struct drm_sarea_frame {
+	unsigned int x;
+	unsigned int y;
+	unsigned int width;
+	unsigned int height;
+	unsigned int fullscreen;
+};
+
+/** SAREA */
+struct drm_sarea {
+    /** first thing is always the DRM locking structure */
+	struct drm_hw_lock lock;
+    /** \todo Use readers/writer lock for drm_sarea::drawable_lock */
+	struct drm_hw_lock drawable_lock;
+	struct drm_sarea_drawable drawableTable[SAREA_MAX_DRAWABLES];	/**< drawables */
+	struct drm_sarea_frame frame;	/**< frame */
+	drm_context_t dummy_context;
+};
+
+#ifndef __KERNEL__
+typedef struct drm_sarea_drawable drm_sarea_drawable_t;
+typedef struct drm_sarea_frame drm_sarea_frame_t;
+typedef struct drm_sarea drm_sarea_t;
+#endif
+
+#endif				/* _DRM_SAREA_H_ */
diff -Naurp old/src/sys/dev/pci/drm/drm_scatter.c new/src/sys/dev/pci/drm/drm_scatter.c
--- old/src/sys/dev/pci/drm/drm_scatter.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/drm_scatter.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,118 @@
+/*-
+ * 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
+ * PRECISION INSIGHT 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:
+ *   Gareth Hughes <gareth@valinux.com>
+ *   Eric Anholt <anholt@FreeBSD.org>
+ *
+ */
+
+/*
+ * Allocation of memory for scatter-gather mappings by the graphics chip.
+ *
+ * The memory allocated here is then made into an aperture in the card
+ * by drm_ati_pcigart_init().
+ */
+#include "drmP.h"
+
+void
+drm_sg_cleanup(struct drm_device *dev, struct drm_sg_mem *entry)
+{
+	if (entry == NULL)
+		return;
+
+	drm_dmamem_free(dev->dmat, entry->mem);
+	drm_free(entry);
+}
+
+int
+drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather *request)
+{
+	struct drm_sg_mem	*entry;
+	bus_size_t		 size;
+	unsigned long		 pages;
+
+	if (dev->sg != NULL)
+		return (EINVAL);
+
+	entry = drm_calloc(1, sizeof(*entry));
+        if (entry == NULL)
+                return (ENOMEM);
+
+	pages = round_page(request->size) / PAGE_SIZE;
+	size = pages << PAGE_SHIFT;
+
+	DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
+
+	if ((entry->mem = drm_dmamem_alloc(dev->dmat, size, PAGE_SIZE, pages,
+	    PAGE_SIZE, 0, 0)) == NULL)
+		return (ENOMEM);
+
+	request->handle = entry->handle = (unsigned long)entry->mem->kva;
+	DRM_DEBUG("sg alloc handle  = %08lx\n", entry->handle);
+
+	DRM_LOCK();
+	if (dev->sg) {
+		DRM_UNLOCK();
+		drm_sg_cleanup(dev, entry);
+		return EINVAL;
+	}
+	dev->sg = entry;
+	DRM_UNLOCK();
+
+	return (0);
+}
+
+int
+drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_scatter_gather	*request = data;
+	int				 ret;
+
+	DRM_DEBUG("\n");
+
+	ret = drm_sg_alloc(dev, request);
+	return ret;
+}
+
+int
+drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_scatter_gather	*request = data;
+	struct drm_sg_mem		*entry;
+
+	DRM_LOCK();
+	entry = dev->sg;
+	dev->sg = NULL;
+	DRM_UNLOCK();
+
+	if (entry == NULL || entry->handle != request->handle)
+		return EINVAL;
+
+	DRM_DEBUG("sg free virtual  = 0x%lx\n", entry->handle);
+
+	drm_sg_cleanup(dev, entry);
+
+	return 0;
+}
diff -Naurp old/src/sys/dev/pci/drm/files.drm new/src/sys/dev/pci/drm/files.drm
--- old/src/sys/dev/pci/drm/files.drm	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/files.drm	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,20 @@
+# $NetBSD: files.drm,v 1.2 2007/03/28 11:29:37 jmcneill Exp $
+# $OpenBSD: files.drm,v 1.20 2010/05/25 17:15:49 oga Exp $
+
+# direct rendering modules
+define drmbase {}
+device drmdev: drmbase
+attach drmdev at drmbase
+file   dev/pci/drm/drm_agpsupport.c    drmdev
+file   dev/pci/drm/drm_bufs.c          drmdev
+file   dev/pci/drm/drm_context.c       drmdev
+file   dev/pci/drm/drm_drv.c           drmdev	needs-flag
+file   dev/pci/drm/drm_irq.c           drmdev
+file   dev/pci/drm/drm_lock.c          drmdev
+file   dev/pci/drm/drm_memory.c        drmdev
+file   dev/pci/drm/drm_scatter.c       drmdev
+
+device	inteldrm: drmbase
+attach	inteldrm at drm
+file	dev/pci/drm/i915_drv.c		inteldrm
+file	dev/pci/drm/i915_irq.c		inteldrm
diff -Naurp old/src/sys/dev/pci/drm/i915_drm.h new/src/sys/dev/pci/drm/i915_drm.h
--- old/src/sys/dev/pci/drm/i915_drm.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/i915_drm.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,657 @@
+/*
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS 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.
+ *
+ */
+
+#ifndef _I915_DRM_H_
+#define _I915_DRM_H_
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints.
+ */
+
+#include "drm.h"
+
+/* Each region is a minimum of 16k, and there are at most 255 of them.
+ */
+#define I915_NR_TEX_REGIONS 255	/* table size 2k - maximum due to use
+				 * of chars for next/prev indices */
+#define I915_LOG_MIN_TEX_REGION_SIZE 14
+
+typedef struct _drm_i915_init {
+	enum {
+		I915_INIT_DMA = 0x01,
+		I915_CLEANUP_DMA = 0x02,
+		I915_RESUME_DMA = 0x03
+	} func;
+	unsigned int mmio_offset;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits;
+	unsigned int back_pitch;
+	unsigned int depth_pitch;
+	unsigned int cpp;
+	unsigned int chipset;
+} drm_i915_init_t;
+
+typedef struct drm_i915_sarea {
+	struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1];
+	int last_upload;	/* last time texture was uploaded */
+	int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int ctxOwner;		/* last context to upload state */
+	int texAge;
+	int pf_enabled;		/* is pageflipping allowed? */
+	int pf_active;
+	int pf_current_page;	/* which buffer is being displayed? */
+	int perf_boxes;		/* performance boxes to be displayed */
+	int width, height;      /* screen size in pixels */
+
+	drm_handle_t front_handle;
+	int front_offset;
+	int front_size;
+
+	drm_handle_t back_handle;
+	int back_offset;
+	int back_size;
+
+	drm_handle_t depth_handle;
+	int depth_offset;
+	int depth_size;
+
+	drm_handle_t tex_handle;
+	int tex_offset;
+	int tex_size;
+	int log_tex_granularity;
+	int pitch;
+	int rotation;           /* 0, 90, 180 or 270 */
+	int rotated_offset;
+	int rotated_size;
+	int rotated_pitch;
+	int virtualX, virtualY;
+
+	unsigned int front_tiled;
+	unsigned int back_tiled;
+	unsigned int depth_tiled;
+	unsigned int rotated_tiled;
+	unsigned int rotated2_tiled;
+
+	int planeA_x;
+	int planeA_y;
+	int planeA_w;
+	int planeA_h;
+	int planeB_x;
+	int planeB_y;
+	int planeB_w;
+	int planeB_h;
+
+	/* Triple buffering */
+	drm_handle_t third_handle;
+	int third_offset;
+	int third_size;
+	unsigned int third_tiled;
+
+	/* buffer object handles for the static buffers.  May change
+	 * over the lifetime of the client, though it doesn't in our current
+	 * implementation.
+	 */
+	unsigned int front_bo_handle;
+	unsigned int back_bo_handle;
+	unsigned int third_bo_handle;
+	unsigned int depth_bo_handle;
+} drm_i915_sarea_t;
+
+/* Flags for perf_boxes
+ */
+#define I915_BOX_RING_EMPTY    0x1
+#define I915_BOX_FLIP          0x2
+#define I915_BOX_WAIT          0x4
+#define I915_BOX_TEXTURE_LOAD  0x8
+#define I915_BOX_LOST_CONTEXT  0x10
+
+/* I915 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_I915_INIT		0x00
+#define DRM_I915_FLUSH		0x01
+#define DRM_I915_FLIP		0x02
+#define DRM_I915_BATCHBUFFER	0x03
+#define DRM_I915_IRQ_EMIT	0x04
+#define DRM_I915_IRQ_WAIT	0x05
+#define DRM_I915_GETPARAM	0x06
+#define DRM_I915_SETPARAM	0x07
+#define DRM_I915_ALLOC		0x08
+#define DRM_I915_FREE		0x09
+#define DRM_I915_INIT_HEAP	0x0a
+#define DRM_I915_CMDBUFFER	0x0b
+#define DRM_I915_DESTROY_HEAP	0x0c
+#define DRM_I915_SET_VBLANK_PIPE	0x0d
+#define DRM_I915_GET_VBLANK_PIPE	0x0e
+#define DRM_I915_VBLANK_SWAP	0x0f
+#define DRM_I915_HWS_ADDR	0x11
+#define DRM_I915_GEM_INIT	0x13
+#define DRM_I915_GEM_EXECBUFFER	0x14
+#define DRM_I915_GEM_PIN	0x15
+#define DRM_I915_GEM_UNPIN	0x16
+#define DRM_I915_GEM_BUSY	0x17
+#define DRM_I915_GEM_THROTTLE	0x18
+#define DRM_I915_GEM_ENTERVT	0x19
+#define DRM_I915_GEM_LEAVEVT	0x1a
+#define DRM_I915_GEM_CREATE	0x1b
+#define DRM_I915_GEM_PREAD	0x1c
+#define DRM_I915_GEM_PWRITE	0x1d
+#define DRM_I915_GEM_MMAP	0x1e
+#define DRM_I915_GEM_SET_DOMAIN	0x1f
+#define DRM_I915_GEM_SW_FINISH	0x20
+#define DRM_I915_GEM_SET_TILING	0x21
+#define DRM_I915_GEM_GET_TILING	0x22
+#define DRM_I915_GEM_GET_APERTURE	0x23
+#define DRM_I915_GEM_EXECBUFFER2	0x24
+#define DRM_I915_GEM_MADVISE	0x25
+
+#define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
+#define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
+#define DRM_IOCTL_I915_FLIP		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP)
+#define DRM_IOCTL_I915_BATCHBUFFER	DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
+#define DRM_IOCTL_I915_IRQ_EMIT         DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
+#define DRM_IOCTL_I915_IRQ_WAIT         DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
+#define DRM_IOCTL_I915_GETPARAM         DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, drm_i915_getparam_t)
+#define DRM_IOCTL_I915_SETPARAM         DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SETPARAM, drm_i915_setparam_t)
+#define DRM_IOCTL_I915_ALLOC            DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_ALLOC, drm_i915_mem_alloc_t)
+#define DRM_IOCTL_I915_FREE             DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t)
+#define DRM_IOCTL_I915_INIT_HEAP        DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
+#define DRM_IOCTL_I915_CMDBUFFER	DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
+#define DRM_IOCTL_I915_DESTROY_HEAP	DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
+#define DRM_IOCTL_I915_SET_VBLANK_PIPE	DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_GET_VBLANK_PIPE	DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_VBLANK_SWAP	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+#define DRM_IOCTL_I915_HWS_ADDR		DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, drm_i915_hws_addr_t)
+#define DRM_IOCTL_I915_GEM_INIT		DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
+#define DRM_IOCTL_I915_GEM_EXECBUFFER	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
+#define DRM_IOCTL_I915_GEM_EXECBUFFER2	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
+#define DRM_IOCTL_I915_GEM_PIN		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
+#define DRM_IOCTL_I915_GEM_UNPIN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
+#define DRM_IOCTL_I915_GEM_BUSY		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
+#define DRM_IOCTL_I915_GEM_THROTTLE	DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
+#define DRM_IOCTL_I915_GEM_ENTERVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
+#define DRM_IOCTL_I915_GEM_LEAVEVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
+#define DRM_IOCTL_I915_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_PREAD	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
+#define DRM_IOCTL_I915_GEM_PWRITE	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
+#define DRM_IOCTL_I915_GEM_MMAP		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
+#define DRM_IOCTL_I915_GEM_SET_DOMAIN	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
+#define DRM_IOCTL_I915_GEM_SW_FINISH	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish)
+#define DRM_IOCTL_I915_GEM_SET_TILING	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
+#define DRM_IOCTL_I915_GEM_GET_TILING	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
+#define DRM_IOCTL_I915_GEM_GET_APERTURE	DRM_IOR  (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
+#define DRM_IOCTL_I915_GEM_MADVISE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
+
+/* Allow drivers to submit batchbuffers directly to hardware, relying
+ * on the security mechanisms provided by hardware.
+ */
+typedef struct drm_i915_batchbuffer {
+	int start;		/* agp offset */
+	int used;		/* nr bytes in use */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+	int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO */
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+	struct drm_clip_rect __user *cliprects;	/* pointer to userspace cliprects */
+} drm_i915_batchbuffer_t;
+
+/* As above, but pass a pointer to userspace buffer which can be
+ * validated by the kernel prior to sending to hardware.
+ */
+typedef struct _drm_i915_cmdbuffer {
+	char __user *buf;	/* pointer to userspace command buffer */
+	int sz;			/* nr bytes in buf */
+	int DR1;		/* hw flags for GFX_OP_DRAWRECT_INFO */
+	int DR4;		/* window origin for GFX_OP_DRAWRECT_INFO */
+	int num_cliprects;	/* mulitpass with multiple cliprects? */
+	struct drm_clip_rect __user *cliprects;	/* pointer to userspace cliprects */
+} drm_i915_cmdbuffer_t;
+
+/* Userspace can request & wait on irq's:
+ */
+typedef struct drm_i915_irq_emit {
+	int __user *irq_seq;
+} drm_i915_irq_emit_t;
+
+typedef struct drm_i915_irq_wait {
+	int irq_seq;
+} drm_i915_irq_wait_t;
+
+/* Ioctl to query kernel params:
+ */
+#define I915_PARAM_IRQ_ACTIVE            1
+#define I915_PARAM_ALLOW_BATCHBUFFER     2
+#define I915_PARAM_LAST_DISPATCH         3
+#define I915_PARAM_CHIPSET_ID            4
+#define I915_PARAM_HAS_GEM		 5
+#define I915_PARAM_NUM_FENCES_AVAIL      6
+#define I915_PARAM_HAS_EXECBUF2          9
+
+typedef struct drm_i915_getparam {
+	int param;
+	int __user *value;
+} drm_i915_getparam_t;
+
+/* Ioctl to set kernel params:
+ */
+#define I915_SETPARAM_USE_MI_BATCHBUFFER_START            1
+#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
+#define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
+#define I915_SETPARAM_NUM_USED_FENCES                     4
+
+typedef struct drm_i915_setparam {
+	int param;
+	int value;
+} drm_i915_setparam_t;
+
+/* A memory manager for regions of shared memory:
+ */
+#define I915_MEM_REGION_AGP 1
+
+typedef struct drm_i915_mem_alloc {
+	int region;
+	int alignment;
+	int size;
+	int __user *region_offset;	/* offset from start of fb or agp */
+} drm_i915_mem_alloc_t;
+
+typedef struct drm_i915_mem_free {
+	int region;
+	int region_offset;
+} drm_i915_mem_free_t;
+
+typedef struct drm_i915_mem_init_heap {
+	int region;
+	int size;
+	int start;
+} drm_i915_mem_init_heap_t;
+
+/* Allow memory manager to be torn down and re-initialized (eg on
+ * rotate):
+ */
+typedef struct drm_i915_mem_destroy_heap {
+	int region;
+} drm_i915_mem_destroy_heap_t;
+
+/* Allow X server to configure which pipes to monitor for vblank signals
+ */
+#define	DRM_I915_VBLANK_PIPE_A	1
+#define	DRM_I915_VBLANK_PIPE_B	2
+
+typedef struct drm_i915_vblank_pipe {
+	int pipe;
+} drm_i915_vblank_pipe_t;
+
+/* Schedule buffer swap at given vertical blank:
+ */
+typedef struct drm_i915_vblank_swap {
+	drm_drawable_t drawable;
+	enum drm_vblank_seq_type seqtype;
+	unsigned int sequence;
+} drm_i915_vblank_swap_t;
+
+typedef struct drm_i915_hws_addr {
+	uint64_t addr;
+} drm_i915_hws_addr_t;
+
+struct drm_i915_gem_init {
+	/**
+	 * Beginning offset in the GTT to be managed by the DRM memory
+	 * manager.
+	 */
+	uint64_t gtt_start;
+	/**
+	 * Ending offset in the GTT to be managed by the DRM memory
+	 * manager.
+	 */
+	uint64_t gtt_end;
+};
+
+struct drm_i915_gem_create {
+	/**
+	 * Requested size for the object.
+	 *
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	uint64_t size;
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	uint32_t handle;
+	uint32_t pad;
+};
+
+struct drm_i915_gem_pread {
+	/** Handle for the object being read. */
+	uint32_t handle;
+	uint32_t pad;
+	/** Offset into the object to read from */
+	uint64_t offset;
+	/** Length of data to read */
+	uint64_t size;
+	/**
+	 * Pointer to write the data into.
+	 *
+	 * This is a fixed-size type for 32/64 compatibility.
+	 */
+	uint64_t data_ptr;
+};
+
+struct drm_i915_gem_pwrite {
+	/** Handle for the object being written to. */
+	uint32_t handle;
+	uint32_t pad;
+	/** Offset into the object to write to */
+	uint64_t offset;
+	/** Length of data to write */
+	uint64_t size;
+	/**
+	 * Pointer to read the data from.
+	 *
+	 * This is a fixed-size type for 32/64 compatibility.
+	 */
+	uint64_t data_ptr;
+};
+
+struct drm_i915_gem_mmap {
+	/** Handle for the object being mapped. */
+	uint32_t handle;
+	uint32_t pad;
+	/** Offset in the object to map. */
+	uint64_t offset;
+	/**
+	 * Length of data to map.
+	 *
+	 * The value will be page-aligned.
+	 */
+	uint64_t size;
+	/**
+	 * Returned pointer the data was mapped at.
+	 *
+	 * This is a fixed-size type for 32/64 compatibility.
+	 */
+	uint64_t addr_ptr;
+};
+
+struct drm_i915_gem_set_domain {
+	/** Handle for the object */
+	uint32_t handle;
+
+	/** New read domains */
+	uint32_t read_domains;
+
+	/** New write domain */
+	uint32_t write_domain;
+};
+
+struct drm_i915_gem_sw_finish {
+	/** Handle for the object */
+	uint32_t handle;
+};
+
+struct drm_i915_gem_relocation_entry {
+	/**
+	 * Handle of the buffer being pointed to by this relocation entry.
+	 *
+	 * It's appealing to make this be an index into the mm_validate_entry
+	 * list to refer to the buffer, but this allows the driver to create
+	 * a relocation list for state buffers and not re-write it per
+	 * exec using the buffer.
+	 */
+	uint32_t target_handle;
+
+	/**
+	 * Value to be added to the offset of the target buffer to make up
+	 * the relocation entry.
+	 */
+	uint32_t delta;
+
+	/** Offset in the buffer the relocation entry will be written into */
+	uint64_t offset;
+
+	/**
+	 * Offset value of the target buffer that the relocation entry was last
+	 * written as.
+	 *
+	 * If the buffer has the same offset as last time, we can skip syncing
+	 * and writing the relocation.  This value is written back out by
+	 * the execbuffer ioctl when the relocation is written.
+	 */
+	uint64_t presumed_offset;
+
+	/**
+	 * Target memory domains read by this operation.
+	 */
+	uint32_t read_domains;
+
+	/**
+	 * Target memory domains written by this operation.
+	 *
+	 * Note that only one domain may be written by the whole
+	 * execbuffer operation, so that where there are conflicts,
+	 * the application will get -EINVAL back.
+	 */
+	uint32_t write_domain;
+};
+
+/** @{
+ * Intel memory domains
+ *
+ * Most of these just align with the various caches in
+ * the system and are used to flush and invalidate as
+ * objects end up cached in different domains.
+ */
+/** CPU cache */
+#define I915_GEM_DOMAIN_CPU		0x00000001
+/** Render cache, used by 2D and 3D drawing */
+#define I915_GEM_DOMAIN_RENDER		0x00000002
+/** Sampler cache, used by texture engine */
+#define I915_GEM_DOMAIN_SAMPLER		0x00000004
+/** Command queue, used to load batch buffers */
+#define I915_GEM_DOMAIN_COMMAND		0x00000008
+/** Instruction cache, used by shader programs */
+#define I915_GEM_DOMAIN_INSTRUCTION	0x00000010
+/** Vertex address cache */
+#define I915_GEM_DOMAIN_VERTEX		0x00000020
+/** GTT domain - aperture and scanout */
+#define I915_GEM_DOMAIN_GTT		0x00000040
+/** @} */
+
+struct drm_i915_gem_exec_object2 {
+	/**
+	 * User's handle for a buffer to be bound into the GTT for this
+	 * operation.
+	 */
+	u_int32_t handle;
+
+	/** Number of relocations to be performed on this buffer */
+	u_int32_t relocation_count;
+	/**
+	 * Pointer to array of struct drm_i915_gem_relocation_entry containing
+	 * the relocations to be performed in this buffer.
+	 */
+	u_int64_t relocs_ptr;
+
+	/** Required alignment in graphics aperture */
+	u_int64_t alignment;
+
+	/**
+	 * Returned value of the updated offset of the object, for future
+	 * presumed_offset writes.
+	 */
+	u_int64_t offset;
+
+#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
+	u_int64_t flags;
+	u_int64_t rsvd1;
+	u_int64_t rsvd2;
+};
+
+struct drm_i915_gem_execbuffer2 {
+	/**
+	 * List of gem_exec_object2 structs
+	 */
+	u_int64_t buffers_ptr;
+	u_int32_t buffer_count;
+
+	/** Offset in the batchbuffer to start execution from. */
+	u_int32_t batch_start_offset;
+	/** Bytes used in batchbuffer from batch_start_offset */
+	u_int32_t batch_len;
+	u_int64_t flags; /* currently unused */
+	u_int64_t rsvd1;
+	u_int64_t rsvd2;
+};
+
+struct drm_i915_gem_pin {
+	/** Handle of the buffer to be pinned. */
+	uint32_t handle;
+	uint32_t pad;
+
+	/** alignment required within the aperture */
+	uint64_t alignment;
+
+	/** Returned GTT offset of the buffer. */
+	uint64_t offset;
+};
+
+struct drm_i915_gem_unpin {
+	/** Handle of the buffer to be unpinned. */
+	uint32_t handle;
+	uint32_t pad;
+};
+
+struct drm_i915_gem_busy {
+	/** Handle of the buffer to check for busy */
+	uint32_t handle;
+
+	/** Return busy status (1 if busy, 0 if idle) */
+	uint32_t busy;
+};
+
+#define I915_TILING_NONE	0
+#define I915_TILING_X		1
+#define I915_TILING_Y		2
+
+#define I915_BIT_6_SWIZZLE_NONE		0
+#define I915_BIT_6_SWIZZLE_9		1
+#define I915_BIT_6_SWIZZLE_9_10		2
+#define I915_BIT_6_SWIZZLE_9_11		3
+#define I915_BIT_6_SWIZZLE_9_10_11	4
+/* Not seen by userland */
+#define I915_BIT_6_SWIZZLE_UNKNOWN	5
+/* Seen by userland. */
+#define I915_BIT_6_SWIZZLE_9_17		6
+#define I915_BIT_6_SWIZZLE_9_10_17	7
+
+struct drm_i915_gem_set_tiling {
+	/** Handle of the buffer to have its tiling state updated */
+	uint32_t handle;
+
+	/**
+	 * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+	 * I915_TILING_Y).
+	 *
+	 * This value is to be set on request, and will be updated by the
+	 * kernel on successful return with the actual chosen tiling layout.
+	 *
+	 * The tiling mode may be demoted to I915_TILING_NONE when the system
+	 * has bit 6 swizzling that can't be managed correctly by GEM.
+	 *
+	 * Buffer contents become undefined when changing tiling_mode.
+	 */
+	uint32_t tiling_mode;
+
+	/**
+	 * Stride in bytes for the object when in I915_TILING_X or
+	 * I915_TILING_Y.
+	 */
+	uint32_t stride;
+
+	/**
+	 * Returned address bit 6 swizzling required for CPU access through
+	 * mmap mapping.
+	 */
+	uint32_t swizzle_mode;
+};
+
+struct drm_i915_gem_get_tiling {
+	/** Handle of the buffer to get tiling state for. */
+	uint32_t handle;
+
+	/**
+	 * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+	 * I915_TILING_Y).
+	 */
+	uint32_t tiling_mode;
+
+	/**
+	 * Returned address bit 6 swizzling required for CPU access through
+	 * mmap mapping.
+	 */
+	uint32_t swizzle_mode;
+};
+
+struct drm_i915_gem_get_aperture {
+	/** Total size of the aperture used by i915_gem_execbuffer, in bytes */
+	uint64_t aper_size;
+
+	/**
+	 * Available space in the aperture used by i915_gem_execbuffer, in
+	 * bytes
+	 */
+	uint64_t aper_available_size;
+};
+
+#define I915_MADV_WILLNEED 0
+#define I915_MADV_DONTNEED 1
+#define __I915_MADV_PURGED 2 /* internal state */
+
+struct drm_i915_gem_madvise {
+	/** Handle of the buffer to change the backing store advice */
+	u_int32_t handle;
+
+	/* Advice: either the buffer will be needed again in the near future,
+	 *         or wont be and could be discarded under memory pressure.
+	 */
+	u_int32_t madv;
+
+	/** Whether the backing store still exists. */
+	u_int32_t retained;
+};
+
+#endif				/* _I915_DRM_H_ */
diff -Naurp old/src/sys/dev/pci/drm/i915_drv.c new/src/sys/dev/pci/drm/i915_drv.c
--- old/src/sys/dev/pci/drm/i915_drv.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/i915_drv.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,6500 @@
+/*
+ * Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*-
+ * Copyright © 2008 Intel Corporation
+ * Copyright 2003 Tungsten Graphics, 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:
+ *    Gareth Hughes <gareth@valinux.com>
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#if !defined(__NetBSD__)
+#include <machine/pmap.h>
+#else /* !defined(__NetBSD__) */
+#include <uvm/uvm_pmap.h>
+#endif /* !defined(__NetBSD__) */
+
+#include <sys/queue.h>
+#if !defined(__NetBSD__)
+#include <sys/workq.h>
+#else
+#include <sys/pool.h>
+#include <sys/workqueue.h>
+#endif
+#if 0
+#	define INTELDRM_WATCH_COHERENCY
+#	define WATCH_INACTIVE
+#endif
+
+#define I915_GEM_GPU_DOMAINS	(~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+
+#if !defined(__NetBSD__)
+int	inteldrm_probe(struct device *, void *, void *);
+#else /* !defined(__NetBSD__) */
+int	inteldrm_probe(struct device *, struct cfdata *, void *);
+#endif /* !defined(__NetBSD__) */
+void	inteldrm_attach(struct device *, struct device *, void *);
+int	inteldrm_detach(struct device *, int);
+#if !defined(__NetBSD__)
+int	inteldrm_activate(struct device *, int);
+#else /* !defined(__NetBSD__) */
+static bool	inteldrm_suspend(struct device *, const pmf_qual_t *);
+static bool	inteldrm_resume(struct device *, const pmf_qual_t *);
+#endif /* !defined(__NetBSD__) */
+int	inteldrm_ioctl(struct drm_device *, u_long, caddr_t, struct drm_file *);
+int	inteldrm_doioctl(struct drm_device *, u_long, caddr_t, struct drm_file *);
+int	inteldrm_intr(void *);
+void	inteldrm_error(struct inteldrm_softc *);
+int	inteldrm_ironlake_intr(void *);
+void	inteldrm_lastclose(struct drm_device *);
+
+void	inteldrm_wrap_ring(struct inteldrm_softc *);
+int	inteldrm_gmch_match(struct pci_attach_args *);
+void	inteldrm_chipset_flush(struct inteldrm_softc *);
+void	inteldrm_timeout(void *);
+void	inteldrm_hangcheck(void *);
+void	inteldrm_hung(void *, void *);
+void	inteldrm_965_reset(struct inteldrm_softc *, u_int8_t);
+int	inteldrm_fault(struct drm_obj *, struct uvm_faultinfo *, off_t,
+	    vaddr_t, vm_page_t *, int, int, vm_prot_t, int );
+void	inteldrm_wipe_mappings(struct drm_obj *);
+void	inteldrm_purge_obj(struct drm_obj *);
+void	inteldrm_set_max_obj_size(struct inteldrm_softc *);
+void	inteldrm_quiesce(struct inteldrm_softc *);
+
+/* For reset and suspend */
+int	inteldrm_save_state(struct inteldrm_softc *);
+int	inteldrm_restore_state(struct inteldrm_softc *);
+int	inteldrm_save_display(struct inteldrm_softc *);
+int	inteldrm_restore_display(struct inteldrm_softc *);
+void	i915_save_vga(struct inteldrm_softc *);
+void	i915_restore_vga(struct inteldrm_softc *);
+void	i915_save_modeset_reg(struct inteldrm_softc *);
+void	i915_restore_modeset_reg(struct inteldrm_softc *);
+u_int8_t	i915_read_indexed(struct inteldrm_softc *, u_int16_t,
+		    u_int16_t, u_int8_t);
+void	i915_write_indexed(struct inteldrm_softc *, u_int16_t,
+	    u_int16_t, u_int8_t, u_int8_t);
+void	i915_write_ar(struct inteldrm_softc *, u_int16_t, u_int8_t,
+	    u_int8_t, u_int16_t);
+u_int8_t	i915_read_ar(struct inteldrm_softc *, u_int16_t,
+		    u_int8_t, u_int16_t);
+void	i915_save_palette(struct inteldrm_softc *, enum pipe);
+void	i915_restore_palette(struct inteldrm_softc *, enum pipe);
+
+void	i915_alloc_ifp(struct inteldrm_softc *, struct pci_attach_args *);
+void	i965_alloc_ifp(struct inteldrm_softc *, struct pci_attach_args *);
+
+void	inteldrm_detect_bit_6_swizzle(struct inteldrm_softc *,
+	    struct pci_attach_args *);
+
+#if !defined(__NetBSD__)
+int	inteldrm_setup_mchbar(struct inteldrm_softc *,
+	    struct pci_attach_args *);
+void	inteldrm_teardown_mchbar(struct inteldrm_softc *,
+	    struct pci_attach_args *, int);
+#else /* !defined(__NetBSD__) */
+int	inteldrm_setup_mchbar(struct inteldrm_softc *,
+	    struct pci_attach_args *, bus_space_handle_t *);
+void	inteldrm_teardown_mchbar(struct inteldrm_softc *,
+	    struct pci_attach_args *, int, bus_space_handle_t);
+#endif /* !defined(__NetBSD__) */
+
+/* Ioctls */
+int	inteldrm_getparam(struct inteldrm_softc *dev_priv, void *data);
+int	inteldrm_setparam(struct inteldrm_softc *dev_priv, void *data);
+int	i915_gem_init_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_create_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_pread_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_pwrite_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_set_domain_ioctl(struct drm_device *, void *,
+	    struct drm_file *);
+int	i915_gem_execbuffer2(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_pin_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_unpin_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_busy_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_entervt_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_leavevt_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_get_aperture_ioctl(struct drm_device *, void *,
+	    struct drm_file *);
+int	i915_gem_set_tiling(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_get_tiling(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_gtt_map_ioctl(struct drm_device *, void *, struct drm_file *);
+int	i915_gem_madvise_ioctl(struct drm_device *, void *, struct drm_file *);
+
+/* GEM memory manager functions */
+int	i915_gem_init_object(struct drm_obj *);
+void	i915_gem_free_object(struct drm_obj *);
+int	i915_gem_object_pin(struct drm_obj *, uint32_t, int);
+void	i915_gem_object_unpin(struct drm_obj *);
+void	i915_gem_retire_requests(struct inteldrm_softc *);
+void	i915_gem_retire_request(struct inteldrm_softc *,
+	    struct inteldrm_request *);
+void	i915_gem_retire_work_handler(void *, void*);
+int	i915_gem_idle(struct inteldrm_softc *);
+void	i915_gem_object_move_to_active(struct drm_obj *);
+void	i915_gem_object_move_off_active(struct drm_obj *);
+void	i915_gem_object_move_to_inactive(struct drm_obj *);
+void	i915_gem_object_move_to_inactive_locked(struct drm_obj *);
+uint32_t	i915_add_request(struct inteldrm_softc *);
+void	inteldrm_process_flushing(struct inteldrm_softc *, u_int32_t);
+void	i915_move_to_tail(struct inteldrm_obj *, struct i915_gem_list *);
+void	i915_list_remove(struct inteldrm_obj *);
+int	i915_gem_init_hws(struct inteldrm_softc *);
+void	i915_gem_cleanup_hws(struct inteldrm_softc *);
+int	i915_gem_init_ringbuffer(struct inteldrm_softc *);
+int	inteldrm_start_ring(struct inteldrm_softc *);
+void	i915_gem_cleanup_ringbuffer(struct inteldrm_softc *);
+int	i915_gem_ring_throttle(struct drm_device *, struct drm_file *);
+int	i915_gem_evict_inactive(struct inteldrm_softc *, int);
+int	i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *,
+	    u_int32_t, struct drm_i915_gem_relocation_entry **);
+int	i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *,
+	    u_int32_t, struct drm_i915_gem_relocation_entry *);
+void	i915_dispatch_gem_execbuffer(struct drm_device *,
+	    struct drm_i915_gem_execbuffer2 *, uint64_t);
+void	i915_gem_object_set_to_gpu_domain(struct drm_obj *);
+int	i915_gem_object_pin_and_relocate(struct drm_obj *,
+	    struct drm_file *, struct drm_i915_gem_exec_object2 *,
+	    struct drm_i915_gem_relocation_entry *);
+int	i915_gem_object_bind_to_gtt(struct drm_obj *, bus_size_t, int);
+int	i915_wait_request(struct inteldrm_softc *, uint32_t, int);
+u_int32_t	i915_gem_flush(struct inteldrm_softc *, uint32_t, uint32_t);
+int	i915_gem_object_unbind(struct drm_obj *, int);
+
+struct drm_obj	*i915_gem_find_inactive_object(struct inteldrm_softc *,
+		     size_t);
+
+int	i915_gem_evict_everything(struct inteldrm_softc *, int);
+int	i915_gem_evict_something(struct inteldrm_softc *, size_t, int);
+int	i915_gem_object_set_to_gtt_domain(struct drm_obj *, int, int);
+int	i915_gem_object_set_to_cpu_domain(struct drm_obj *, int, int);
+int	i915_gem_object_flush_gpu_write_domain(struct drm_obj *, int, int, int);
+int	i915_gem_get_fence_reg(struct drm_obj *, int);
+int	i915_gem_object_put_fence_reg(struct drm_obj *, int);
+bus_size_t	i915_gem_get_gtt_alignment(struct drm_obj *);
+
+bus_size_t	i915_get_fence_size(struct inteldrm_softc *, bus_size_t);
+int	i915_tiling_ok(struct drm_device *, int, int, int);
+int	i915_gem_object_fence_offset_ok(struct drm_obj *, int);
+void	i965_write_fence_reg(struct inteldrm_fence *);
+void	i915_write_fence_reg(struct inteldrm_fence *);
+void	i830_write_fence_reg(struct inteldrm_fence *);
+void	i915_gem_bit_17_swizzle(struct drm_obj *);
+void	i915_gem_save_bit_17_swizzle(struct drm_obj *);
+int	inteldrm_swizzle_page(struct vm_page *page);
+
+/* Debug functions, mostly called from ddb */
+void	i915_gem_seqno_info(int);
+void	i915_interrupt_info(int);
+void	i915_gem_fence_regs_info(int);
+void	i915_hws_info(int);
+void	i915_batchbuffer_info(int);
+void	i915_ringbuffer_data(int);
+void	i915_ringbuffer_info(int);
+#ifdef WATCH_INACTIVE
+void inteldrm_verify_inactive(struct inteldrm_softc *, char *, int);
+#else
+#define inteldrm_verify_inactive(dev,file,line)
+#endif
+
+static const struct drm_pcidev inteldrm_pciidlist[] = {
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82830M_IGD,
+	    CHIP_I830|CHIP_M|CHIP_GEN2},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82845G_IGD,
+	    CHIP_I845G|CHIP_GEN2},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82855GM_IGD,
+	    CHIP_I85X|CHIP_M|CHIP_GEN2},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82865G_IGD,
+	    CHIP_I865G|CHIP_GEN2},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915G_IGD_1,
+	    CHIP_I915G|CHIP_I9XX|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7221_IGD,
+	    CHIP_I915G|CHIP_I9XX|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82915GM_IGD_1,
+	    CHIP_I915GM|CHIP_I9XX|CHIP_M|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945G_IGD_1,
+	    CHIP_I945G|CHIP_I9XX|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GM_IGD_1,
+	    CHIP_I945GM|CHIP_I9XX|CHIP_M|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82945GME_IGD_1,
+	    CHIP_I945GM|CHIP_I9XX|CHIP_M|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82946GZ_IGD_1,
+	    CHIP_I965|CHIP_I9XX|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G35_IGD_1,
+	    CHIP_I965|CHIP_I9XX|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q965_IGD_1,
+	    CHIP_I965|CHIP_I9XX|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G965_IGD_1,
+	    CHIP_I965|CHIP_I9XX|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82GM965_IGD_1,
+	    CHIP_I965GM|CHIP_I965|CHIP_I9XX|CHIP_M|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82GME965_IGD_1,
+	    CHIP_I965|CHIP_I9XX|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G33_IGD_1,
+	    CHIP_G33|CHIP_I9XX|CHIP_HWS|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q35_IGD_1,
+	    CHIP_G33|CHIP_I9XX|CHIP_HWS|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q33_IGD_1,
+	    CHIP_G33|CHIP_I9XX|CHIP_HWS|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82GM45_IGD_1,
+	    CHIP_G4X|CHIP_GM45|CHIP_I965|CHIP_I9XX|CHIP_M|CHIP_HWS|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, 0x2E02,
+	    CHIP_G4X|CHIP_I965|CHIP_I9XX|CHIP_HWS|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82Q45_IGD_1,
+	    CHIP_G4X|CHIP_I965|CHIP_I9XX|CHIP_HWS|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G45_IGD_1,
+	    CHIP_G4X|CHIP_I965|CHIP_I9XX|CHIP_HWS|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82G41_IGD_1,
+	    CHIP_G4X|CHIP_I965|CHIP_I9XX|CHIP_HWS|CHIP_GEN4},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PINEVIEW_IGC_1,
+	    CHIP_G33|CHIP_PINEVIEW|CHIP_M|CHIP_I9XX|CHIP_HWS|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PINEVIEW_M_IGC_1,
+	    CHIP_G33|CHIP_PINEVIEW|CHIP_M|CHIP_I9XX|CHIP_HWS|CHIP_GEN3},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_CLARKDALE_IGD,
+	    CHIP_IRONLAKE|CHIP_IRONLAKE_D|CHIP_I965|CHIP_I9XX|CHIP_HWS},
+	{PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ARRANDALE_IGD,
+	    CHIP_IRONLAKE|CHIP_M|CHIP_IRONLAKE_M|CHIP_I965|CHIP_I9XX|CHIP_HWS},
+	{0, 0, 0}
+};
+
+static const struct drm_driver_info inteldrm_driver = {
+	.buf_priv_size		= 1,	/* No dev_priv */
+	.file_priv_size		= sizeof(struct inteldrm_file),
+	.ioctl			= inteldrm_ioctl,
+	.lastclose		= inteldrm_lastclose,
+	.vblank_pipes		= 2,
+	.get_vblank_counter	= i915_get_vblank_counter,
+	.enable_vblank		= i915_enable_vblank,
+	.disable_vblank		= i915_disable_vblank,
+	.irq_install		= i915_driver_irq_install,
+	.irq_uninstall		= i915_driver_irq_uninstall,
+
+	.gem_init_object	= i915_gem_init_object,
+	.gem_free_object	= i915_gem_free_object,
+	.gem_fault		= inteldrm_fault,
+	.gem_size		= sizeof(struct inteldrm_obj),
+
+	.name			= DRIVER_NAME,
+	.desc			= DRIVER_DESC,
+	.date			= DRIVER_DATE,
+	.major			= DRIVER_MAJOR,
+	.minor			= DRIVER_MINOR,
+	.patchlevel		= DRIVER_PATCHLEVEL,
+
+	.flags			= DRIVER_AGP | DRIVER_AGP_REQUIRE |
+				    DRIVER_MTRR | DRIVER_IRQ | DRIVER_GEM,
+};
+
+int
+#if !defined(__NetBSD__)
+inteldrm_probe(struct device *parent, void *match, void *aux)
+#else /* !defined(__NetBSD__) */
+inteldrm_probe(struct device *parent, struct cfdata *match, void *aux)
+#endif /* !defined(__NetBSD__) */
+{
+	return (drm_pciprobe((struct pci_attach_args *)aux,
+	    inteldrm_pciidlist));
+}
+
+/*
+ * We're intel IGD, bus 0 function 0 dev 0 should be the GMCH, so it should
+ * be Intel
+ */
+int
+inteldrm_gmch_match(struct pci_attach_args *pa)
+{
+	if (pa->pa_bus == 0 && pa->pa_device == 0 && pa->pa_function == 0 &&
+	    PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
+	    PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
+	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
+		return (1);
+	return (0);
+}
+
+#if defined(__NetBSD__)
+
+/*
+ * Task work queue.  Implements OpenBSD's workq_add_task(9) API.
+ */
+
+struct workq {
+	struct pool		 wq_pool;
+	struct workqueue	*wq_queue;
+};
+
+typedef void (*workq_fn)(void *, void *);
+
+struct workq_task {
+	struct work		 wqt_work;
+	workq_fn		 wqt_func;
+	void			*wqt_arg1;
+	void			*wqt_arg2;
+};
+
+#define WQ_WAITOK	(1<<0)
+
+static void
+workq_worker(struct work *wk, void *arg)
+{
+	struct workq_task	*wqt = (struct workq_task *)wk;
+	struct pool		*wpl = arg;
+
+	KASSERT(wqt != NULL && wpl != NULL);
+	KASSERT(wk == &wqt->wqt_work);
+
+	wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
+
+	pool_put(wpl, wqt);
+}
+
+static struct workq *
+workq_create(const char *name, int maxqs, int ipl)
+{
+	struct workq		*wq;
+
+	wq = malloc(sizeof(*wq), M_DRM, M_NOWAIT);
+	if (wq == NULL)
+		return NULL;
+
+	if (workqueue_create(&wq->wq_queue, name, workq_worker,
+	    &wq->wq_pool, PRI_BIO, ipl, 0)) {
+		free(wq, M_DRM);
+		return NULL;
+	}
+
+	pool_init(&wq->wq_pool, sizeof(struct workq_task), 0, 0, 0,
+	    name, NULL, IPL_HIGH);
+
+	return wq;
+}
+
+static int
+workq_add_task(struct workq *wq, int flags, workq_fn func, void *a1, void *a2)
+{
+	struct workq_task	*wqt;
+
+	KASSERT(wq != NULL);
+
+	wqt = pool_get(&wq->wq_pool, (flags & WQ_WAITOK) ?
+	    PR_WAITOK : PR_NOWAIT);
+	if (wqt == NULL)
+		return ENOMEM;
+
+	wqt->wqt_func = func;
+	wqt->wqt_arg1 = a1;
+	wqt->wqt_arg2 = a2;
+
+	workqueue_enqueue(wq->wq_queue, &wqt->wqt_work, NULL);
+
+	return 0;
+}
+
+#endif /* defined(__NetBSD__) */
+
+void
+inteldrm_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct inteldrm_softc	*dev_priv = (struct inteldrm_softc *)self;
+	struct pci_attach_args	*pa = aux, bpa;
+#if !defined(__NetBSD__)
+	struct vga_pci_bar	*bar;
+#else /* !defined(__NetBSD__) */
+	bus_addr_t		 vb_base;
+#endif /* !defined(__NetBSD__) */
+	struct drm_device	*dev;
+	const struct drm_pcidev	*id_entry;
+	int			 i;
+
+	id_entry = drm_find_description(PCI_VENDOR(pa->pa_id),
+	    PCI_PRODUCT(pa->pa_id), inteldrm_pciidlist);
+	dev_priv->flags = id_entry->driver_private;
+	dev_priv->pci_device = PCI_PRODUCT(pa->pa_id);
+
+	dev_priv->pc = pa->pa_pc;
+	dev_priv->tag = pa->pa_tag;
+	dev_priv->dmat = pa->pa_dmat;
+	dev_priv->bst = pa->pa_memt;
+
+#if !defined(__NetBSD__)
+	/* we need to use this api for now due to sharing with intagp */
+	bar = vga_pci_bar_info((struct vga_pci_softc *)parent,
+	    (IS_I9XX(dev_priv) ? 0 : 1));
+	if (bar == NULL) {
+		printf(": can't get BAR info\n");
+		return;
+	}
+
+	dev_priv->regs = vga_pci_bar_map((struct vga_pci_softc *)parent,
+	    bar->addr, 0, 0);
+	if (dev_priv->regs == NULL) {
+#else /* !defined(__NetBSD__) */
+	vb_base = vga_bar_base(parent, (IS_I9XX(dev_priv) ? 0 : 1));
+	/* XXX horrible kludge: agp might have mapped it */
+	if (!agp_i810_borrow(vb_base, &dev_priv->regs->bst,
+	    &dev_priv->regs->bsh)) {
+#endif /* !defined(__NetBSD__) */
+		printf(": can't map mmio space\n");
+		return;
+	}
+
+	if (pci_intr_map(pa, &dev_priv->ih) != 0) {
+		printf(": couldn't map interrupt\n");
+		return;
+	}
+
+	/*
+	 * set up interrupt handler, note that we don't switch the interrupt
+	 * on until the X server talks to us, kms will change this.
+	 */
+	dev_priv->irqh = pci_intr_establish(dev_priv->pc, dev_priv->ih, IPL_TTY,
+	    (HAS_PCH_SPLIT(dev_priv) ? inteldrm_ironlake_intr : inteldrm_intr),
+#if !defined(__NetBSD__)
+	    dev_priv, dev_priv->dev.dv_xname);
+#else /* !defined(__NetBSD__) */
+	    dev_priv);
+#endif /* !defined(__NetBSD__) */
+	if (dev_priv->irqh == NULL) {
+		printf(": couldn't  establish interrupt\n");
+		return;
+	}
+
+	/* Unmask the interrupts that we always want on. */
+	if (HAS_PCH_SPLIT(dev_priv)) {
+		dev_priv->irq_mask_reg = ~PCH_SPLIT_DISPLAY_INTR_FIX;
+		/* masked for now, turned on on demand */
+		dev_priv->gt_irq_mask_reg = ~PCH_SPLIT_RENDER_INTR_FIX;
+		dev_priv->pch_irq_mask_reg = ~PCH_SPLIT_HOTPLUG_INTR_FIX;
+	} else {
+		dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
+	}
+
+	dev_priv->workq = workq_create("intelrel", 1, IPL_TTY);
+	if (dev_priv->workq == NULL) {
+		printf("couldn't create workq\n");
+		return;
+	}
+
+	/* GEM init */
+	TAILQ_INIT(&dev_priv->mm.active_list);
+	TAILQ_INIT(&dev_priv->mm.flushing_list);
+	TAILQ_INIT(&dev_priv->mm.inactive_list);
+	TAILQ_INIT(&dev_priv->mm.gpu_write_list);
+	TAILQ_INIT(&dev_priv->mm.request_list);
+	TAILQ_INIT(&dev_priv->mm.fence_list);
+	timeout_set(&dev_priv->mm.retire_timer, inteldrm_timeout, dev_priv);
+	timeout_set(&dev_priv->mm.hang_timer, inteldrm_hangcheck, dev_priv);
+	dev_priv->mm.next_gem_seqno = 1;
+	dev_priv->mm.suspended = 1;
+
+	/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
+	if (IS_GEN3(dev_priv)) {
+		u_int32_t tmp = I915_READ(MI_ARB_STATE);
+		if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) {
+			/*
+			 * arb state is a masked write, so set bit + bit
+			 * in mask
+			 */
+			tmp = MI_ARB_C3_LP_WRITE_ENABLE |
+			    (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT);
+			I915_WRITE(MI_ARB_STATE, tmp);
+		}
+	}
+
+	/* For the X server, in kms mode this will not be needed */
+	dev_priv->fence_reg_start = 3;
+
+	if (IS_I965G(dev_priv) || IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+	    IS_G33(dev_priv))
+		dev_priv->num_fence_regs = 16;
+	else
+		dev_priv->num_fence_regs = 8;
+	/* Initialise fences to zero, else on some macs we'll get corruption */
+	if (IS_I965G(dev_priv)) {
+		for (i = 0; i < 16; i++)
+			I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
+	} else {
+		for (i = 0; i < 8; i++)
+			I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+		if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+		    IS_G33(dev_priv))
+			for (i = 0; i < 8; i++)
+				I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+	}
+
+	if (pci_find_device(&bpa, inteldrm_gmch_match) == 0) {
+		printf(": can't find GMCH\n");
+		return;
+	}
+
+	/* Set up the IFP for chipset flushing */
+	if (dev_priv->flags & (CHIP_I915G|CHIP_I915GM|CHIP_I945G|CHIP_I945GM)) {
+		i915_alloc_ifp(dev_priv, &bpa);
+	} else if (IS_I965G(dev_priv) || IS_G33(dev_priv)) {
+		i965_alloc_ifp(dev_priv, &bpa);
+	} else {
+		int nsegs;
+		/*
+		 * I8XX has no flush page mechanism, we fake it by writing until
+		 * the cache is empty. allocate a page to scribble on
+		 */
+		dev_priv->ifp.i8xx.kva = NULL;
+		if (bus_dmamem_alloc(pa->pa_dmat, PAGE_SIZE, 0, 0,
+		    &dev_priv->ifp.i8xx.seg, 1, &nsegs, BUS_DMA_WAITOK) == 0) {
+			if (bus_dmamem_map(pa->pa_dmat, &dev_priv->ifp.i8xx.seg,
+			    1, PAGE_SIZE, &dev_priv->ifp.i8xx.kva, 0) != 0) {
+				bus_dmamem_free(pa->pa_dmat,
+				    &dev_priv->ifp.i8xx.seg, nsegs);
+				dev_priv->ifp.i8xx.kva = NULL;
+			}
+		}
+	}
+
+	inteldrm_detect_bit_6_swizzle(dev_priv, &bpa);
+	/* Init HWS */
+	if (!I915_NEED_GFX_HWS(dev_priv)) {
+		if (i915_init_phys_hws(dev_priv, pa->pa_dmat) != 0) {
+			printf(": couldn't alloc HWS page\n");
+			return;
+		}
+	}
+
+	printf(": %s\n", pci_intr_string(pa->pa_pc, dev_priv->ih));
+
+	mtx_init(&dev_priv->user_irq_lock, IPL_TTY);
+	mtx_init(&dev_priv->list_lock, IPL_NONE);
+	mtx_init(&dev_priv->request_lock, IPL_NONE);
+	mtx_init(&dev_priv->fence_lock, IPL_NONE);
+#if defined(__NetBSD__)
+	cv_init(&dev_priv->condvar, "gemwt");
+#endif /* defined(__NetBSD__) */
+
+	/* All intel chipsets need to be treated as agp, so just pass one */
+	dev_priv->drmdev = drm_attach_pci(&inteldrm_driver, pa, 1, self);
+
+	dev = (struct drm_device *)dev_priv->drmdev;
+
+	/*
+	 * XXX [GS] I'm not sure about what the following does.  It seems
+	 * related to the use of write combining.  But x86_mem_add_mapping
+	 * already does it in NetBSD since BUS_SPACE_MAP_PREFETCHABLE will
+	 * be used in agp_map_subregion.
+	 *
+	 * XXX [GS] See OpenBSD's uvm_page_physload_flags which differs
+	 * from NetBSD's uvm_page_physload.
+	 */
+#if !defined(__NetBSD__)
+	/* XXX would be a lot nicer to get agp info before now */
+	uvm_page_physload_flags(atop(dev->agp->base), atop(dev->agp->base +
+	    dev->agp->info.ai_aperture_size), atop(dev->agp->base),
+	    atop(dev->agp->base + dev->agp->info.ai_aperture_size), 0,
+	    PHYSLOAD_DEVICE);
+	/* array of vm pages that physload introduced. */
+	dev_priv->pgs = PHYS_TO_VM_PAGE(dev->agp->base);
+	KASSERT(dev_priv->pgs != NULL);
+	/*
+	 * XXX mark all pages write combining so user mmaps get the right
+	 * bits. We really need a proper MI api for doing this, but for now
+	 * this allows us to use PAT where available.
+	 */
+	for (i = 0; i < atop(dev->agp->info.ai_aperture_size); i++)
+		atomic_setbits_int(&(dev_priv->pgs[i].pg_flags), PG_PMAP_WC);
+#endif /* !defined(__NetBSD__) */
+	if (agp_init_map(dev_priv->bst, dev->agp->base,
+	    dev->agp->info.ai_aperture_size, BUS_SPACE_MAP_LINEAR |
+	    BUS_SPACE_MAP_PREFETCHABLE, &dev_priv->agph))
+		panic("can't map aperture");
+
+#if defined(__NetBSD__)
+	(void)pmf_device_register(self, inteldrm_suspend, inteldrm_resume);
+#endif /* defined(__NetBSD__) */
+}
+
+int
+inteldrm_detach(struct device *self, int flags)
+{
+	struct inteldrm_softc *dev_priv = (struct inteldrm_softc *)self;
+
+#if defined(__NetBSD__)
+	pmf_device_deregister(self);
+#endif /* defined(__NetBSD__) */
+
+	timeout_del(&dev_priv->mm.retire_timer);
+	timeout_del(&dev_priv->mm.hang_timer);
+#if defined(__NetBSD__)
+	callout_destroy(&dev_priv->mm.retire_timer);
+	callout_destroy(&dev_priv->mm.hang_timer);
+#endif /* defined(__NetBSD__) */
+
+	agp_destroy_map(dev_priv->agph);
+
+	/* this will quiesce any dma that's going on and kill the timeouts. */
+	if (dev_priv->drmdev != NULL) {
+		config_detach(dev_priv->drmdev, flags);
+		dev_priv->drmdev = NULL;
+	}
+
+	if (!I915_NEED_GFX_HWS(dev_priv) && dev_priv->hws_dmamem) {
+		drm_dmamem_free(dev_priv->dmat, dev_priv->hws_dmamem);
+		dev_priv->hws_dmamem = NULL;
+		/* Need to rewrite hardware status page */
+		I915_WRITE(HWS_PGA, 0x1ffff000);
+		dev_priv->hw_status_page = NULL;
+	}
+
+	if (IS_I9XX(dev_priv) && dev_priv->ifp.i9xx.valid) {
+#if !defined(__NetBSD__)
+		bus_space_unmap(dev_priv->ifp.i9xx.bst, dev_priv->ifp.i9xx.bsh,
+#else /* !defined(__NetBSD__) */
+		bus_space_free(dev_priv->ifp.i9xx.bst, dev_priv->ifp.i9xx.bsh,
+#endif /* !defined(__NetBSD__) */
+		    PAGE_SIZE);
+	} else if (dev_priv->flags & (CHIP_I830 | CHIP_I845G | CHIP_I85X |
+	    CHIP_I865G) && dev_priv->ifp.i8xx.kva != NULL) {
+		bus_dmamem_unmap(dev_priv->dmat, dev_priv->ifp.i8xx.kva,
+		     PAGE_SIZE);
+		bus_dmamem_free(dev_priv->dmat, &dev_priv->ifp.i8xx.seg, 1);
+	}
+
+	pci_intr_disestablish(dev_priv->pc, dev_priv->irqh);
+
+#if defined(__NetBSD__)
+	cv_destroy(&dev_priv->condvar);
+	mutex_destroy(&dev_priv->fence_lock);
+	mutex_destroy(&dev_priv->request_lock);
+	mutex_destroy(&dev_priv->list_lock);
+	mutex_destroy(&dev_priv->user_irq_lock);
+#endif /* defined(__NetBSD__) */
+
+	/* XXX Destroy the task queue dev_priv->workq. */
+
+#if !defined(__NetBSD__)
+	if (dev_priv->regs != NULL)
+		vga_pci_bar_unmap(dev_priv->regs);
+#endif /* !defined(__NetBSD__) */
+
+	return (0);
+}
+
+#if !defined(__NetBSD__)
+int
+inteldrm_activate(struct device *arg, int act)
+{
+	struct inteldrm_softc	*dev_priv = (struct inteldrm_softc *)arg;
+
+	switch (act) {
+	case DVACT_QUIESCE:
+		inteldrm_quiesce(dev_priv);
+		break;
+	case DVACT_SUSPEND:
+		inteldrm_save_state(dev_priv);
+		break;
+	case DVACT_RESUME:
+		inteldrm_restore_state(dev_priv);
+		/* entrypoints can stop sleeping now */
+		atomic_clearbits_int(&dev_priv->sc_flags, INTELDRM_QUIET);
+		wakeup(&dev_priv->flags);
+		break;
+	}
+
+	return (0);
+}
+#else /* !defined(__NetBSD__) */
+static bool
+inteldrm_suspend(struct device *arg, const pmf_qual_t *qual)
+{
+	struct inteldrm_softc	*dev_priv = (struct inteldrm_softc *)arg;
+
+	inteldrm_quiesce(dev_priv);
+	inteldrm_save_state(dev_priv);
+
+	return true;
+}
+
+static bool
+inteldrm_resume(struct device *arg, const pmf_qual_t *qual)
+{
+	struct inteldrm_softc	*dev_priv = (struct inteldrm_softc *)arg;
+
+	inteldrm_restore_state(dev_priv);
+	/* entrypoints can stop sleeping now */
+	atomic_clearbits_int(&dev_priv->sc_flags, INTELDRM_QUIET);
+	wakeup(&dev_priv->flags);
+
+	return true;
+}
+#endif /* !defined(__NetBSD__) */
+
+#if !defined(__NetBSD__)
+struct cfattach inteldrm_ca = {
+	sizeof(struct inteldrm_softc), inteldrm_probe, inteldrm_attach,
+	inteldrm_detach, inteldrm_activate
+};
+
+struct cfdriver inteldrm_cd = {
+	0, "inteldrm", DV_DULL
+};
+#else /* !defined(__NetBSD__) */
+/*
+ * We do not use CFATTACH_DECL_NEW, in order to be compatible with
+ * the rest of the code (see similar comment in drm_drv.c).
+ */
+CFATTACH_DECL(inteldrm, sizeof(struct inteldrm_softc),
+    inteldrm_probe, inteldrm_attach, inteldrm_detach, NULL);
+#endif /* !defined(__NetBSD__) */
+
+int
+inteldrm_ioctl(struct drm_device *dev, u_long cmd, caddr_t data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	int			 error = 0;
+
+	while ((dev_priv->sc_flags & INTELDRM_QUIET) && error == 0)
+		error = tsleep(&dev_priv->flags, PCATCH, "intelioc", 0);
+	if (error)
+		return (error);
+	dev_priv->entries++;
+
+	error = inteldrm_doioctl(dev, cmd, data, file_priv);
+
+	dev_priv->entries--;
+	if (dev_priv->sc_flags & INTELDRM_QUIET)
+		wakeup(&dev_priv->entries);
+	return (error);
+}
+
+int
+inteldrm_doioctl(struct drm_device *dev, u_long cmd, caddr_t data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	if (file_priv->authenticated == 1) {
+		switch (cmd) {
+		case DRM_IOCTL_I915_GETPARAM:
+			return (inteldrm_getparam(dev_priv, data));
+		case DRM_IOCTL_I915_GEM_EXECBUFFER2:
+			return (i915_gem_execbuffer2(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_BUSY:
+			return (i915_gem_busy_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_THROTTLE:
+			return (i915_gem_ring_throttle(dev, file_priv));
+		case DRM_IOCTL_I915_GEM_MMAP:
+			return (i915_gem_gtt_map_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_CREATE:
+			return (i915_gem_create_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_PREAD:
+			return (i915_gem_pread_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_PWRITE:
+			return (i915_gem_pwrite_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_SET_DOMAIN:
+			return (i915_gem_set_domain_ioctl(dev, data,
+			    file_priv));
+		case DRM_IOCTL_I915_GEM_SET_TILING:
+			return (i915_gem_set_tiling(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_GET_TILING:
+			return (i915_gem_get_tiling(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_GET_APERTURE:
+			return (i915_gem_get_aperture_ioctl(dev, data,
+			    file_priv));
+		case DRM_IOCTL_I915_GEM_MADVISE:
+			return (i915_gem_madvise_ioctl(dev, data, file_priv));
+		default:
+			break;
+		}
+	}
+
+	if (file_priv->master == 1) {
+		switch (cmd) {
+		case DRM_IOCTL_I915_SETPARAM:
+			return (inteldrm_setparam(dev_priv, data));
+		case DRM_IOCTL_I915_GEM_INIT:
+			return (i915_gem_init_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_ENTERVT:
+			return (i915_gem_entervt_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_LEAVEVT:
+			return (i915_gem_leavevt_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_PIN:
+			return (i915_gem_pin_ioctl(dev, data, file_priv));
+		case DRM_IOCTL_I915_GEM_UNPIN:
+			return (i915_gem_unpin_ioctl(dev, data, file_priv));
+		}
+	}
+	return (EINVAL);
+}
+
+int
+inteldrm_ironlake_intr(void *arg)
+{
+	struct inteldrm_softc	*dev_priv = arg;
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	u_int32_t		 de_iir, gt_iir, de_ier, pch_iir;
+	int			 ret = 0;
+
+	de_ier = I915_READ(DEIER);
+	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+	(void)I915_READ(DEIER);
+
+	de_iir = I915_READ(DEIIR);
+	gt_iir = I915_READ(GTIIR);
+	pch_iir = I915_READ(SDEIIR);
+
+	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
+		goto done;
+	ret = 1;
+
+	if (gt_iir & GT_USER_INTERRUPT) {
+		mtx_enter(&dev_priv->user_irq_lock);
+#if !defined(__NetBSD__)
+		wakeup(dev_priv);
+#else /* !defined(__NetBSD__) */
+		cv_broadcast(&dev_priv->condvar);
+#endif /* !defined(__NetBSD__) */
+		mtx_leave(&dev_priv->user_irq_lock);
+		dev_priv->mm.hang_cnt = 0;
+		timeout_add_msec(&dev_priv->mm.hang_timer, 750);
+	}
+	if (gt_iir & GT_MASTER_ERROR)
+		inteldrm_error(dev_priv);
+
+	if (de_iir & DE_PIPEA_VBLANK)
+		drm_handle_vblank(dev, 0);
+	if (de_iir & DE_PIPEB_VBLANK)
+		drm_handle_vblank(dev, 1);
+
+	/* should clear PCH hotplug event before clearing CPU irq */
+	I915_WRITE(SDEIIR, pch_iir);
+	I915_WRITE(GTIIR, gt_iir);
+	I915_WRITE(DEIIR, de_iir);
+
+done:
+	I915_WRITE(DEIER, de_ier);
+	(void)I915_READ(DEIER);
+
+	return (ret);
+}
+
+int
+inteldrm_intr(void *arg)
+{
+	struct inteldrm_softc	*dev_priv = arg;
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	u_int32_t		 iir, pipea_stats = 0, pipeb_stats = 0;
+
+	/* we're not set up, don't poke the hw */
+	if (dev_priv->hw_status_page == NULL)
+		return (0);
+	/*
+	 * lock is to protect from writes to PIPESTAT and IMR from other cores.
+	 */
+	mtx_enter(&dev_priv->user_irq_lock);
+	iir = I915_READ(IIR);
+	if (iir == 0) {
+		mtx_leave(&dev_priv->user_irq_lock);
+		return (0);
+	}
+
+	/*
+	 * Clear the PIPE(A|B)STAT regs before the IIR
+	 */
+	if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+		pipea_stats = I915_READ(PIPEASTAT);
+		I915_WRITE(PIPEASTAT, pipea_stats);
+	}
+	if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+		pipeb_stats = I915_READ(PIPEBSTAT);
+		I915_WRITE(PIPEBSTAT, pipeb_stats);
+	}
+	if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+		inteldrm_error(dev_priv);
+
+	I915_WRITE(IIR, iir);
+	(void)I915_READ(IIR); /* Flush posted writes */
+
+	if (iir & I915_USER_INTERRUPT) {
+#if !defined(__NetBSD__)
+		wakeup(dev_priv);
+#else /* !defined(__NetBSD__) */
+		cv_broadcast(&dev_priv->condvar);
+#endif /* !defined(__NetBSD__) */
+		dev_priv->mm.hang_cnt = 0;
+		timeout_add_msec(&dev_priv->mm.hang_timer, 750);
+	}
+
+	mtx_leave(&dev_priv->user_irq_lock);
+
+	if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS)
+		drm_handle_vblank(dev, 0);
+
+	if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS)
+		drm_handle_vblank(dev, 1);
+
+	return (1);
+}
+
+u_int32_t
+inteldrm_read_hws(struct inteldrm_softc *dev_priv, int reg)
+{
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	struct inteldrm_obj	*obj_priv;
+	bus_dma_tag_t		 tag;
+	bus_dmamap_t		 map;
+	u_int32_t		 val;
+
+	if (I915_NEED_GFX_HWS(dev_priv)) {
+		obj_priv = (struct inteldrm_obj *)dev_priv->hws_obj;
+		map = obj_priv->dmamap;
+		tag = dev_priv->agpdmat;
+	} else {
+		map = dev_priv->hws_dmamem->map;
+		tag = dev->dmat;
+	}
+
+	bus_dmamap_sync(tag, map, 0, PAGE_SIZE, BUS_DMASYNC_POSTREAD);
+
+	val = ((volatile u_int32_t *)(dev_priv->hw_status_page))[reg];
+	bus_dmamap_sync(tag, map, 0, PAGE_SIZE, BUS_DMASYNC_PREREAD);
+
+	return (val);
+}
+
+/*
+ * These five ring manipulation functions are protected by dev->dev_lock.
+ */
+int
+inteldrm_wait_ring(struct inteldrm_softc *dev_priv, int n)
+{
+	struct inteldrm_ring	*ring = &dev_priv->ring;
+	u_int32_t		 acthd_reg, acthd, last_acthd, last_head;
+	int			 i;
+
+	acthd_reg = IS_I965G(dev_priv) ? ACTHD_I965 : ACTHD;
+	last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+	last_acthd = I915_READ(acthd_reg);
+
+	/* ugh. Could really do with a proper, resettable timer here. */
+	for (i = 0; i < 100000; i++) {
+		ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+		acthd = I915_READ(acthd_reg);
+		ring->space = ring->head - (ring->tail + 8);
+
+		INTELDRM_VPRINTF("%s: head: %x tail: %x space: %x\n", __func__,
+			ring->head, ring->tail, ring->space);
+		if (ring->space < 0)
+			ring->space += ring->size;
+		if (ring->space >= n)
+			return (0);
+
+		/* Only timeout if the ring isn't chewing away on something */
+		if (ring->head != last_head || acthd != last_acthd)
+			i = 0;
+
+		last_head = ring->head;
+		last_acthd = acthd;
+		delay(10);
+	}
+
+	return (EBUSY);
+}
+
+void
+inteldrm_wrap_ring(struct inteldrm_softc *dev_priv)
+{
+	u_int32_t	rem;;
+
+	rem = dev_priv->ring.size - dev_priv->ring.tail;
+	if (dev_priv->ring.space < rem &&
+	    inteldrm_wait_ring(dev_priv, rem) != 0)
+			return; /* XXX */
+
+	dev_priv->ring.space -= rem;
+
+	bus_space_set_region_4(dev_priv->bst, dev_priv->ring.bsh,
+	    dev_priv->ring.woffset, MI_NOOP, rem / 4);
+
+	dev_priv->ring.tail = 0;
+}
+
+void
+inteldrm_begin_ring(struct inteldrm_softc *dev_priv, int ncmd)
+{
+	int	bytes = 4 * ncmd;
+
+	INTELDRM_VPRINTF("%s: %d\n", __func__, ncmd);
+	if (dev_priv->ring.tail + bytes > dev_priv->ring.size)
+		inteldrm_wrap_ring(dev_priv);
+	if (dev_priv->ring.space < bytes)
+		inteldrm_wait_ring(dev_priv, bytes);
+	dev_priv->ring.woffset = dev_priv->ring.tail;
+	dev_priv->ring.tail += bytes;
+	dev_priv->ring.tail &= dev_priv->ring.size - 1;
+	dev_priv->ring.space -= bytes;
+}
+
+void
+inteldrm_out_ring(struct inteldrm_softc *dev_priv, u_int32_t cmd)
+{
+	INTELDRM_VPRINTF("%s: %x\n", __func__, cmd);
+	bus_space_write_4(dev_priv->bst, dev_priv->ring.bsh,
+	    dev_priv->ring.woffset, cmd);
+	/*
+	 * don't need to deal with wrap here because we padded
+	 * the ring out if we would wrap
+	 */
+	dev_priv->ring.woffset += 4;
+}
+
+void
+inteldrm_advance_ring(struct inteldrm_softc *dev_priv)
+{
+	INTELDRM_VPRINTF("%s: %x, %x\n", __func__, dev_priv->ring.wspace,
+	    dev_priv->ring.woffset);
+	DRM_MEMORYBARRIER();
+	I915_WRITE(PRB0_TAIL, dev_priv->ring.tail);
+}
+
+void
+inteldrm_update_ring(struct inteldrm_softc *dev_priv)
+{
+	struct inteldrm_ring	*ring = &dev_priv->ring;
+
+	ring->head = (I915_READ(PRB0_HEAD) & HEAD_ADDR);
+	ring->tail = (I915_READ(PRB0_TAIL) & TAIL_ADDR);
+	ring->space = ring->head - (ring->tail + 8);
+	if (ring->space < 0)
+		ring->space += ring->size;
+	INTELDRM_VPRINTF("%s: head: %x tail: %x space: %x\n", __func__,
+		ring->head, ring->tail, ring->space);
+}
+
+/*
+ * Sets up the hardware status page for devices that need a physical address
+ * in the register.
+ */
+int
+i915_init_phys_hws(struct inteldrm_softc *dev_priv, bus_dma_tag_t dmat)
+{
+	/* Program Hardware Status Page */
+	if ((dev_priv->hws_dmamem = drm_dmamem_alloc(dmat, PAGE_SIZE,
+	    PAGE_SIZE, 1, PAGE_SIZE, 0, BUS_DMA_READ)) == NULL) {
+		return (ENOMEM);
+	}
+
+	dev_priv->hw_status_page = dev_priv->hws_dmamem->kva;
+
+	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+
+	bus_dmamap_sync(dmat, dev_priv->hws_dmamem->map, 0, PAGE_SIZE,
+	    BUS_DMASYNC_PREREAD);
+	I915_WRITE(HWS_PGA, dev_priv->hws_dmamem->map->dm_segs[0].ds_addr);
+	DRM_DEBUG("Enabled hardware status page\n");
+	return (0);
+}
+
+void
+i915_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
+{
+	bus_addr_t	addr;
+	u_int32_t	reg;
+
+	dev_priv->ifp.i9xx.valid = true;
+	dev_priv->ifp.i9xx.bst = bpa->pa_memt;
+
+	reg = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR);
+	if (reg & 0x1) {
+		addr = (bus_addr_t)reg;
+		addr &= ~0x1;
+		/* XXX extents ... need data on whether bioses alloc or not. */
+		if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
+		    &dev_priv->ifp.i9xx.bsh) != 0)
+			goto nope;
+		return;
+#if !defined(__NetBSD__)
+	} else if (bpa->pa_memex == NULL || extent_alloc(bpa->pa_memex,
+	    PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) || bus_space_map(bpa->pa_memt,
+	    addr, PAGE_SIZE, 0, &dev_priv->ifp.i9xx.bsh))
+#else /* !defined(__NetBSD__) */
+	} else if (bus_space_alloc(bpa->pa_memt, 0, 0xffffffff,
+	    PAGE_SIZE, PAGE_SIZE, 0, 0, &addr, &dev_priv->ifp.i9xx.bsh))
+#endif /* !defined(__NetBSD__) */
+		goto nope;
+
+	pci_conf_write(bpa->pa_pc, bpa->pa_tag, I915_IFPADDR, addr | 0x1);
+
+	return;
+
+nope:
+	dev_priv->ifp.i9xx.valid = false;
+	printf(": no ifp ");
+}
+
+void
+i965_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
+{
+	bus_addr_t	addr;
+	u_int32_t	lo, hi;
+
+	dev_priv->ifp.i9xx.valid = true;
+	dev_priv->ifp.i9xx.bst = bpa->pa_memt;
+
+	hi = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4);
+	lo = pci_conf_read(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR);
+	if (lo & 0x1) {
+		addr = (((u_int64_t)hi << 32) | lo);
+		addr &= ~0x1;
+		/* XXX extents ... need data on whether bioses alloc or not. */
+		if (bus_space_map(bpa->pa_memt, addr, PAGE_SIZE, 0,
+		    &dev_priv->ifp.i9xx.bsh) != 0)
+			goto nope;
+		return;
+#if !defined(__NetBSD__)
+	} else if (bpa->pa_memex == NULL || extent_alloc(bpa->pa_memex,
+	    PAGE_SIZE, PAGE_SIZE, 0, 0, 0, &addr) || bus_space_map(bpa->pa_memt,
+	    addr, PAGE_SIZE, 0, &dev_priv->ifp.i9xx.bsh))
+#else /* !defined(__NetBSD__) */
+	} else if (bus_space_alloc(bpa->pa_memt, 0, 0xffffffff,
+	    PAGE_SIZE, PAGE_SIZE, 0, 0, &addr, &dev_priv->ifp.i9xx.bsh))
+#endif /* !defined(__NetBSD__) */
+		goto nope;
+
+	pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR + 4,
+	    upper_32_bits(addr));
+	pci_conf_write(bpa->pa_pc, bpa->pa_tag, I965_IFPADDR,
+	    (addr & 0xffffffff) | 0x1);
+
+	return;
+
+nope:
+	dev_priv->ifp.i9xx.valid = false;
+	printf(": no ifp ");
+}
+
+void
+inteldrm_chipset_flush(struct inteldrm_softc *dev_priv)
+{
+	/*
+	 * Write to this flush page flushes the chipset write cache.
+	 * The write will return when it is done.
+	 */
+	if (IS_I9XX(dev_priv)) {
+	    if (dev_priv->ifp.i9xx.valid)
+		bus_space_write_4(dev_priv->ifp.i9xx.bst,
+		    dev_priv->ifp.i9xx.bsh, 0, 1);
+	} else {
+		/*
+		 * I8XX don't have a flush page mechanism, but do have the
+		 * cache. Do it the bruteforce way. we write 1024 byes into
+		 * the cache, then clflush them out so they'll kick the stuff
+		 * we care about out of the chipset cache.
+		 */
+		if (dev_priv->ifp.i8xx.kva != NULL) {
+			memset(dev_priv->ifp.i8xx.kva, 0, 1024);
+			agp_flush_cache_range((vaddr_t)dev_priv->ifp.i8xx.kva,
+			    1024);
+		}
+	}
+}
+
+void
+inteldrm_lastclose(struct drm_device *dev)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+#if !defined(__NetBSD__)
+	struct vm_page		*p;
+#endif /* !defined(__NetBSD__) */
+	int			 ret;
+
+	ret = i915_gem_idle(dev_priv);
+	if (ret)
+		DRM_ERROR("failed to idle hardware: %d\n", ret);
+
+	if (dev_priv->agpdmat != NULL) {
+		/*
+		 * make sure we nuke everything, we may have mappings that we've
+		 * unrefed, but uvm has a reference to them for maps. Make sure
+		 * they get unbound and any accesses will segfault.
+		 * XXX only do ones in GEM.
+		 */
+#if !defined(__NetBSD__)
+		for (p = dev_priv->pgs; p < dev_priv->pgs +
+		    (dev->agp->info.ai_aperture_size / PAGE_SIZE); p++)
+			pmap_page_protect(p, VM_PROT_NONE);
+#endif /* !defined(__NetBSD__) */
+		agp_bus_dma_destroy(dev->agp->agpdev,
+		    dev_priv->agpdmat);
+	}
+	dev_priv->agpdmat = NULL;
+}
+
+int
+inteldrm_getparam(struct inteldrm_softc *dev_priv, void *data)
+{
+	drm_i915_getparam_t	*param = data;
+	int			 value;
+
+	switch (param->param) {
+	case I915_PARAM_CHIPSET_ID:
+		value = dev_priv->pci_device;
+		break;
+	case I915_PARAM_HAS_GEM:
+		value = 1;
+		break;
+	case I915_PARAM_NUM_FENCES_AVAIL:
+		value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
+		break;
+	case I915_PARAM_HAS_EXECBUF2:
+		value = 1;
+		break;
+	default:
+		DRM_DEBUG("Unknown parameter %d\n", param->param);
+		return (EINVAL);
+	}
+	return (copyout(&value, param->value, sizeof(int)));
+}
+
+int
+inteldrm_setparam(struct inteldrm_softc *dev_priv, void *data)
+{
+	drm_i915_setparam_t	*param = data;
+
+	switch (param->param) {
+	case I915_SETPARAM_NUM_USED_FENCES:
+		if (param->value > dev_priv->num_fence_regs ||
+		    param->value < 0)
+			return EINVAL;
+		/* Userspace can use first N regs */
+		dev_priv->fence_reg_start = param->value;
+		break;
+	default:
+		DRM_DEBUG("unknown parameter %d\n", param->param);
+		return (EINVAL);
+	}
+
+	return 0;
+}
+
+
+int
+i915_gem_init_ioctl(struct drm_device *dev, void *data,
+		    struct drm_file *file_priv)
+{
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_i915_gem_init	*args = data;
+
+	DRM_LOCK();
+
+	if (args->gtt_start >= args->gtt_end ||
+	    args->gtt_end > dev->agp->info.ai_aperture_size ||
+	    (args->gtt_start & PAGE_MASK) != 0 ||
+	    (args->gtt_end & PAGE_MASK) != 0) {
+		DRM_UNLOCK();
+		return (EINVAL);
+	}
+	/*
+	 * putting stuff in the last page of the aperture can cause nasty
+	 * problems with prefetch going into unassigned memory. Since we put
+	 * a scratch page on all unused aperture pages, just leave the last
+	 * page as a spill to prevent gpu hangs.
+	 */
+	if (args->gtt_end == dev->agp->info.ai_aperture_size)
+		args->gtt_end -= 4096;
+
+	if (agp_bus_dma_init(dev->agp->agpdev,
+	    dev->agp->base + args->gtt_start, dev->agp->base + args->gtt_end,
+	    &dev_priv->agpdmat) != 0) {
+		DRM_UNLOCK();
+		return (ENOMEM);
+	}
+
+	dev->gtt_total = (uint32_t)(args->gtt_end - args->gtt_start);
+	inteldrm_set_max_obj_size(dev_priv);
+
+	DRM_UNLOCK();
+
+	return 0;
+}
+
+void
+inteldrm_set_max_obj_size(struct inteldrm_softc *dev_priv)
+{
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+
+	/*
+	 * Allow max obj size up to the size where ony 2 would fit the
+	 * aperture, but some slop exists due to alignment etc
+	 */
+	dev_priv->max_gem_obj_size = (dev->gtt_total -
+	    atomic_read(&dev->pin_memory)) * 3 / 4 / 2;
+
+}
+
+int
+i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_i915_gem_get_aperture	*args = data;
+
+	/* we need a write lock here to make sure we get the right value */
+	DRM_LOCK();
+	args->aper_size = dev->gtt_total;
+	args->aper_available_size = (args->aper_size -
+	    atomic_read(&dev->pin_memory));
+	DRM_UNLOCK();
+
+	return (0);
+}
+
+/**
+ * Creates a new mm object and returns a handle to it.
+ */
+int
+i915_gem_create_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_i915_gem_create	*args = data;
+	struct drm_obj			*obj;
+	int				 handle, ret;
+
+	args->size = round_page(args->size);
+	/*
+	 * XXX to avoid copying between 2 objs more than half the aperture size
+	 * we don't allow allocations that are that big. This will be fixed
+	 * eventually by intelligently falling back to cpu reads/writes in
+	 * such cases. (linux allows this but does cpu maps in the ddx instead).
+	 */
+	if (args->size > dev_priv->max_gem_obj_size)
+		return (EFBIG);
+
+	/* Allocate the new object */
+	obj = drm_gem_object_alloc(dev, args->size);
+	if (obj == NULL)
+		return (ENOMEM);
+
+	/* we give our reference to the handle */
+	ret = drm_handle_create(file_priv, obj, &handle);
+
+	if (ret == 0)
+		args->handle = handle;
+	else
+		drm_unref(&obj->uobj);
+
+	return (ret);
+}
+
+/**
+ * Reads data from the object referenced by handle.
+ *
+ * On error, the contents of *data are undefined.
+ */
+int
+i915_gem_pread_ioctl(struct drm_device *dev, void *data,
+		     struct drm_file *file_priv)
+{
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_i915_gem_pread	*args = data;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	char				*vaddr;
+	bus_space_handle_t		 bsh;
+	bus_size_t			 bsize;
+	voff_t				 offset;
+	int				 ret;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	DRM_READLOCK();
+	drm_hold_object(obj);
+
+	/*
+	 * Bounds check source.
+	 */
+	if (args->offset > obj->size || args->size > obj->size ||
+	    args->offset + args->size > obj->size) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	ret = i915_gem_object_pin(obj, 0, 1);
+	if (ret) {
+		goto out;
+	}
+	ret = i915_gem_object_set_to_gtt_domain(obj, 0, 1);
+	if (ret)
+		goto unpin;
+
+	obj_priv = (struct inteldrm_obj *)obj;
+	offset = obj_priv->gtt_offset + args->offset;
+
+	bsize = round_page(offset + args->size) - trunc_page(offset);
+
+	if ((ret = agp_map_subregion(dev_priv->agph,
+	    trunc_page(offset), bsize, &bsh)) != 0)
+		goto unpin;
+	vaddr = bus_space_vaddr(dev->bst, bsh);
+	if (vaddr == NULL) {
+		ret = EFAULT;
+		goto unmap;
+	}
+
+	ret = copyout(vaddr + (offset & PAGE_MASK),
+	    (char *)(uintptr_t)args->data_ptr, args->size);
+
+unmap:
+	agp_unmap_subregion(dev_priv->agph, bsh, bsize);
+unpin:
+	i915_gem_object_unpin(obj);
+out:
+	drm_unhold_and_unref(obj);
+	DRM_READUNLOCK();
+
+	return (ret);
+}
+
+
+/**
+ * Writes data to the object referenced by handle.
+ *
+ * On error, the contents of the buffer that were to be modified are undefined.
+ */
+int
+i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_i915_gem_pwrite	*args = data;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	char				*vaddr;
+	bus_space_handle_t		 bsh;
+	bus_size_t			 bsize;
+	off_t				 offset;
+	int				 ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	DRM_READLOCK();
+	drm_hold_object(obj);
+
+	/* Bounds check destination. */
+	if (args->offset > obj->size || args->size > obj->size ||
+	    args->offset + args->size > obj->size) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	ret = i915_gem_object_pin(obj, 0, 1);
+	if (ret) {
+		goto out;
+	}
+	ret = i915_gem_object_set_to_gtt_domain(obj, 1, 1);
+	if (ret)
+		goto unpin;
+
+	obj_priv = (struct inteldrm_obj *)obj;
+	offset = obj_priv->gtt_offset + args->offset;
+	bsize = round_page(offset + args->size) - trunc_page(offset);
+
+	if ((ret = agp_map_subregion(dev_priv->agph,
+	    trunc_page(offset), bsize, &bsh)) != 0)
+		goto unpin;
+	vaddr = bus_space_vaddr(dev_priv->bst, bsh);
+	if (vaddr == NULL) {
+		ret = EFAULT;
+		goto unmap;
+	}
+
+	ret = copyin((char *)(uintptr_t)args->data_ptr,
+	    vaddr + (offset & PAGE_MASK), args->size);
+
+
+unmap:
+	agp_unmap_subregion(dev_priv->agph, bsh, bsize);
+unpin:
+	i915_gem_object_unpin(obj);
+out:
+	drm_unhold_and_unref(obj);
+	DRM_READUNLOCK();
+
+	return (ret);
+}
+
+/**
+ * Called when user space prepares to use an object with the CPU, either through
+ * the mmap ioctl's mapping or a GTT mapping.
+ */
+int
+i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file_priv)
+{
+	struct drm_i915_gem_set_domain	*args = data;
+	struct drm_obj			*obj;
+	u_int32_t			 read_domains = args->read_domains;
+	u_int32_t			 write_domain = args->write_domain;
+	int				 ret;
+
+	/*
+	 * Only handle setting domains to types we allow the cpu to see.
+	 * while linux allows the CPU domain here, we only allow GTT since that
+	 * is all that we let userland near.
+	 * Also sanity check that having something in the write domain implies
+	 * it's in the read domain, and only that read domain.
+	 */
+	if ((write_domain | read_domains)  & ~I915_GEM_DOMAIN_GTT ||
+	    (write_domain != 0 && read_domains != write_domain))
+		return (EINVAL);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	drm_hold_object(obj);
+
+	ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0, 1);
+
+	drm_unhold_and_unref(obj);
+	/*
+	 * Silently promote `you're not bound, there was nothing to do'
+	 * to success, since the client was just asking us to make sure
+	 * everything was done.
+	 */
+	return ((ret == EINVAL) ? 0 : ret);
+}
+
+int
+i915_gem_gtt_map_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_i915_gem_mmap	*args = data;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	vaddr_t				 addr;
+	voff_t				 offset;
+	vsize_t				 end, nsize;
+	int				 ret;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+
+	/* Since we are doing purely uvm-related operations here we do
+	 * not need to hold the object, a reference alone is sufficient
+	 */
+	obj_priv = (struct inteldrm_obj *)obj;
+
+	/* Check size. Also ensure that the object is not purgeable */
+	if (args->size == 0 || args->offset > obj->size || args->size >
+	    obj->size || (args->offset + args->size) > obj->size ||
+	    i915_obj_purgeable(obj_priv)) {
+		ret = EINVAL;
+		goto done;
+	}
+
+	end = round_page(args->offset + args->size);
+	offset = trunc_page(args->offset);
+	nsize = end - offset;
+
+	/*
+	 * We give our reference from object_lookup to the mmap, so only
+	 * must free it in the case that the map fails.
+	 */
+#if !defined(__NetBSD__)
+	addr = uvm_map_hint(curproc, VM_PROT_READ | VM_PROT_WRITE);
+	ret = uvm_map_p(&curproc->p_vmspace->vm_map, &addr, nsize, &obj->uobj,
+	    offset, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+	    UVM_INH_SHARE, UVM_ADV_RANDOM, 0), curproc);
+#else /* !defined(__NetBSD__) */
+	addr = curproc->p_emul->e_vm_default_addr(curproc,
+	    (vaddr_t)curproc->p_vmspace->vm_daddr, nsize);
+	ret = uvm_map(&curproc->p_vmspace->vm_map, &addr, nsize, &obj->uobj,
+	    offset, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+	    UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
+#endif /* !defined(__NetBSD__) */
+
+done:
+	if (ret == 0)
+		args->addr_ptr = (uint64_t) addr + (args->offset & PAGE_MASK);
+	else
+		drm_unref(&obj->uobj);
+
+	return (ret);
+}
+
+/* called locked */
+void
+i915_gem_object_move_to_active(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct inteldrm_fence	*reg;
+	u_int32_t		 seqno = dev_priv->mm.next_gem_seqno;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->request_lock);
+	MUTEX_ASSERT_LOCKED(&dev_priv->list_lock);
+
+	/* Add a reference if we're newly entering the active list. */
+	if (!inteldrm_is_active(obj_priv)) {
+		drm_ref(&obj->uobj);
+		atomic_setbits_int(&obj->do_flags, I915_ACTIVE);
+	}
+
+	if (inteldrm_needs_fence(obj_priv)) {
+		reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+		reg->last_rendering_seqno = seqno;
+	}
+	if (obj->write_domain)
+		obj_priv->last_write_seqno = seqno;
+
+	/* Move from whatever list we were on to the tail of execution. */
+	i915_move_to_tail(obj_priv, &dev_priv->mm.active_list);
+	obj_priv->last_rendering_seqno = seqno;
+}
+
+void
+i915_gem_object_move_off_active(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct inteldrm_fence	*reg;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->list_lock);
+	DRM_OBJ_ASSERT_LOCKED(obj);
+
+	obj_priv->last_rendering_seqno = 0;
+	/* if we have a fence register, then reset the seqno */
+	if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
+		reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+		reg->last_rendering_seqno = 0;
+	}
+	if (obj->write_domain == 0)
+		obj_priv->last_write_seqno = 0;
+}
+
+/* If you call this on an object that you have held, you must have your own
+ * reference, not just the reference from the active list.
+ */
+void
+i915_gem_object_move_to_inactive(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	mtx_enter(&dev_priv->list_lock);
+	drm_lock_obj(obj);
+	/* unlocks list lock and object lock */
+	i915_gem_object_move_to_inactive_locked(obj);
+}
+
+/* called locked */
+void
+i915_gem_object_move_to_inactive_locked(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->list_lock);
+	DRM_OBJ_ASSERT_LOCKED(obj);
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+	if (obj_priv->pin_count != 0)
+		i915_list_remove(obj_priv);
+	else
+		i915_move_to_tail(obj_priv, &dev_priv->mm.inactive_list);
+
+	i915_gem_object_move_off_active(obj);
+	atomic_clearbits_int(&obj->do_flags, I915_FENCED_EXEC);
+
+	KASSERT((obj->do_flags & I915_GPU_WRITE) == 0);
+	/* unlock because this unref could recurse */
+	mtx_leave(&dev_priv->list_lock);
+	if (inteldrm_is_active(obj_priv)) {
+		atomic_clearbits_int(&obj->do_flags,
+		    I915_ACTIVE);
+		drm_unref_locked(&obj->uobj);
+	} else {
+		drm_unlock_obj(obj);
+	}
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+}
+
+void
+inteldrm_purge_obj(struct drm_obj *obj)
+{
+	DRM_ASSERT_HELD(obj);
+	/*
+	 * may sleep. We free here instead of deactivate (which
+	 * the madvise() syscall would do) because in this case
+	 * (userland bo cache and GL_APPLE_object_purgeable objects in
+	 * OpenGL) the pages are defined to be freed if they were cleared
+	 * so kill them and free up the memory
+	 */
+#if !defined(__NetBSD__)
+	simple_lock(&obj->uao->vmobjlock);
+	obj->uao->pgops->pgo_flush(obj->uao, 0, obj->size,
+	    PGO_ALLPAGES | PGO_FREE);
+	simple_unlock(&obj->uao->vmobjlock);
+#else /* !defined(__NetBSD__) */
+	mutex_enter(&obj->uao->vmobjlock);
+	obj->uao->pgops->pgo_put(obj->uao, 0, obj->size,
+	    PGO_ALLPAGES | PGO_FREE);
+	/* the mutex is already released (cf. uao_put in uvm_aobj.c) */
+	KASSERT(!mutex_owned(&obj->uao->vmobjlock));
+#endif /* !defined(__NetBSD__) */
+
+	/*
+	 * If flush failed, it may have halfway through, so just
+	 * always mark as purged
+	 */
+	atomic_setbits_int(&obj->do_flags, I915_PURGED);
+}
+
+void
+inteldrm_process_flushing(struct inteldrm_softc *dev_priv,
+    u_int32_t flush_domains)
+{
+	struct inteldrm_obj		*obj_priv, *next;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->request_lock);
+	mtx_enter(&dev_priv->list_lock);
+	for (obj_priv = TAILQ_FIRST(&dev_priv->mm.gpu_write_list);
+	    obj_priv != TAILQ_END(&dev_priv->mm.gpu_write_list);
+	    obj_priv = next) {
+		struct drm_obj *obj = &(obj_priv->obj);
+
+		next = TAILQ_NEXT(obj_priv, write_list);
+
+		if ((obj->write_domain & flush_domains)) {
+			TAILQ_REMOVE(&dev_priv->mm.gpu_write_list,
+			    obj_priv, write_list);
+			atomic_clearbits_int(&obj->do_flags,
+			     I915_GPU_WRITE);
+			i915_gem_object_move_to_active(obj);
+			obj->write_domain = 0;
+			/* if we still need the fence, update LRU */
+			if (inteldrm_needs_fence(obj_priv)) {
+				KASSERT(obj_priv->fence_reg !=
+				    I915_FENCE_REG_NONE);
+				/* we have a fence, won't sleep, can't fail
+				 * since we have the fence we no not need
+				 * to have the object held
+				 */
+				i915_gem_get_fence_reg(obj, 1);
+			}
+
+		}
+	}
+	mtx_leave(&dev_priv->list_lock);
+}
+
+/**
+ * Creates a new sequence number, emitting a write of it to the status page
+ * plus an interrupt, which will trigger and interrupt if they are currently
+ * enabled.
+ *
+ * Must be called with struct_lock held.
+ *
+ * Returned sequence numbers are nonzero on success.
+ */
+uint32_t
+i915_add_request(struct inteldrm_softc *dev_priv)
+{
+	struct inteldrm_request	*request;
+	uint32_t		 seqno;
+	int			 was_empty;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->request_lock);
+
+	request = drm_calloc(1, sizeof(*request));
+	if (request == NULL) {
+		printf("%s: failed to allocate request\n", __func__);
+		return 0;
+	}
+
+	/* Grab the seqno we're going to make this request be, and bump the
+	 * next (skipping 0 so it can be the reserved no-seqno value).
+	 */
+	seqno = dev_priv->mm.next_gem_seqno;
+	dev_priv->mm.next_gem_seqno++;
+	if (dev_priv->mm.next_gem_seqno == 0)
+		dev_priv->mm.next_gem_seqno++;
+
+	BEGIN_LP_RING(4);
+	OUT_RING(MI_STORE_DWORD_INDEX);
+	OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+	OUT_RING(seqno);
+
+	OUT_RING(MI_USER_INTERRUPT);
+	ADVANCE_LP_RING();
+
+	DRM_DEBUG("%d\n", seqno);
+
+	/* XXX request timing for throttle */
+	request->seqno = seqno;
+	was_empty = TAILQ_EMPTY(&dev_priv->mm.request_list);
+	TAILQ_INSERT_TAIL(&dev_priv->mm.request_list, request, list);
+
+	if (dev_priv->mm.suspended == 0) {
+		if (was_empty)
+			timeout_add_sec(&dev_priv->mm.retire_timer, 1);
+		/* XXX was_empty? */
+		timeout_add_msec(&dev_priv->mm.hang_timer, 750);
+	}
+	return seqno;
+}
+
+/**
+ * Moves buffers associated only with the given active seqno from the active
+ * to inactive list, potentially freeing them.
+ *
+ * called with and sleeps with the drm_lock.
+ */
+void
+i915_gem_retire_request(struct inteldrm_softc *dev_priv,
+    struct inteldrm_request *request)
+{
+	struct inteldrm_obj	*obj_priv;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->request_lock);
+	mtx_enter(&dev_priv->list_lock);
+	/* Move any buffers on the active list that are no longer referenced
+	 * by the ringbuffer to the flushing/inactive lists as appropriate.  */
+	while ((obj_priv  = TAILQ_FIRST(&dev_priv->mm.active_list)) != NULL) {
+		struct drm_obj *obj = &obj_priv->obj;
+
+		/* If the seqno being retired doesn't match the oldest in the
+		 * list, then the oldest in the list must still be newer than
+		 * this seqno.
+		 */
+		if (obj_priv->last_rendering_seqno != request->seqno)
+			break;
+
+		drm_lock_obj(obj);
+		/*
+		 * If we're now clean and can be read from, move inactive,
+		 * else put on the flushing list to signify that we're not
+		 * available quite yet.
+		 */
+		if (obj->write_domain != 0) {
+			KASSERT(inteldrm_is_active(obj_priv));
+			i915_move_to_tail(obj_priv,
+			    &dev_priv->mm.flushing_list);
+			i915_gem_object_move_off_active(obj);
+			drm_unlock_obj(obj);
+		} else {
+			/* unlocks object for us and drops ref */
+			i915_gem_object_move_to_inactive_locked(obj);
+			mtx_enter(&dev_priv->list_lock);
+		}
+	}
+	mtx_leave(&dev_priv->list_lock);
+}
+
+/**
+ * This function clears the request list as sequence numbers are passed.
+ */
+void
+i915_gem_retire_requests(struct inteldrm_softc *dev_priv)
+{
+	struct inteldrm_request	*request;
+	uint32_t		 seqno;
+
+	if (dev_priv->hw_status_page == NULL)
+		return;
+
+	seqno = i915_get_gem_seqno(dev_priv);
+
+	mtx_enter(&dev_priv->request_lock);
+	while ((request = TAILQ_FIRST(&dev_priv->mm.request_list)) != NULL) {
+		if (i915_seqno_passed(seqno, request->seqno) ||
+		    dev_priv->mm.wedged) {
+			TAILQ_REMOVE(&dev_priv->mm.request_list, request, list);
+			i915_gem_retire_request(dev_priv, request);
+			mtx_leave(&dev_priv->request_lock);
+
+			drm_free(request);
+			mtx_enter(&dev_priv->request_lock);
+		} else
+			break;
+	}
+	mtx_leave(&dev_priv->request_lock);
+}
+
+void
+i915_gem_retire_work_handler(void *arg1, void *unused)
+{
+	struct inteldrm_softc	*dev_priv = arg1;
+
+	i915_gem_retire_requests(dev_priv);
+	if (!TAILQ_EMPTY(&dev_priv->mm.request_list))
+		timeout_add_sec(&dev_priv->mm.retire_timer, 1);
+}
+
+/**
+ * Waits for a sequence number to be signaled, and cleans up the
+ * request and object lists appropriately for that event.
+ *
+ * Called locked, sleeps with it.
+ */
+int
+i915_wait_request(struct inteldrm_softc *dev_priv, uint32_t seqno,
+    int interruptible)
+{
+	int ret = 0;
+
+	/* Check first because poking a wedged chip is bad. */
+	if (dev_priv->mm.wedged)
+		return (EIO);
+
+	if (seqno == dev_priv->mm.next_gem_seqno) {
+		mtx_enter(&dev_priv->request_lock);
+		seqno = i915_add_request(dev_priv);
+		mtx_leave(&dev_priv->request_lock);
+		if (seqno == 0)
+			return (ENOMEM);
+	}
+
+	if (!i915_seqno_passed(i915_get_gem_seqno(dev_priv), seqno)) {
+		mtx_enter(&dev_priv->user_irq_lock);
+		i915_user_irq_get(dev_priv);
+		while (ret == 0) {
+			if (i915_seqno_passed(i915_get_gem_seqno(dev_priv),
+			    seqno) || dev_priv->mm.wedged)
+				break;
+#if !defined(__NetBSD__)
+			ret = msleep(dev_priv, &dev_priv->user_irq_lock,
+			    PZERO | (interruptible ? PCATCH : 0), "gemwt", 0);
+#else /* !defined(__NetBSD__) */
+			if (interruptible)
+				ret = cv_wait_sig(&dev_priv->condvar,
+				    &dev_priv->user_irq_lock);
+			else
+				cv_wait(&dev_priv->condvar,
+				    &dev_priv->user_irq_lock);
+#endif /* !defined(__NetBSD__) */
+		}
+		i915_user_irq_put(dev_priv);
+		mtx_leave(&dev_priv->user_irq_lock);
+	}
+	if (dev_priv->mm.wedged)
+		ret = EIO;
+
+	/* Directly dispatch request retiring.  While we have the work queue
+	 * to handle this, the waiter on a request often wants an associated
+	 * buffer to have made it to the inactive list, and we would need
+	 * a separate wait queue to handle that.
+	 */
+	if (ret == 0)
+		i915_gem_retire_requests(dev_priv);
+
+	return (ret);
+}
+
+/*
+ * flush and invalidate the provided domains
+ * if we have successfully queued a gpu flush, then we return a seqno from
+ * the request. else (failed or just cpu flushed)  we return 0.
+ */
+u_int32_t
+i915_gem_flush(struct inteldrm_softc *dev_priv, uint32_t invalidate_domains,
+    uint32_t flush_domains)
+{
+	uint32_t	cmd;
+	int		ret = 0;
+
+	if (flush_domains & I915_GEM_DOMAIN_CPU)
+		inteldrm_chipset_flush(dev_priv);
+	if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0) 
+		return (0);
+	/*
+	 * read/write caches:
+	 *
+	 * I915_GEM_DOMAIN_RENDER is always invalidated, but is
+	 * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
+	 * also flushed at 2d versus 3d pipeline switches.
+	 *
+	 * read-only caches:
+	 *
+	 * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
+	 * MI_READ_FLUSH is set, and is always flushed on 965.
+	 *
+	 * I915_GEM_DOMAIN_COMMAND may not exist?
+	 *
+	 * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
+	 * invalidated when MI_EXE_FLUSH is set.
+	 *
+	 * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
+	 * invalidated with every MI_FLUSH.
+	 *
+	 * TLBs:
+	 *
+	 * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
+	 * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
+	 * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
+	 * are flushed at any MI_FLUSH.
+	 */
+
+	cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+	if ((invalidate_domains | flush_domains) &
+	    I915_GEM_DOMAIN_RENDER)
+		cmd &= ~MI_NO_WRITE_FLUSH;
+	/*
+	 * On the 965, the sampler cache always gets flushed
+	 * and this bit is reserved.
+	 */
+	if (!IS_I965G(dev_priv) &&
+	    invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+		cmd |= MI_READ_FLUSH;
+	if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+		cmd |= MI_EXE_FLUSH;
+
+	mtx_enter(&dev_priv->request_lock);
+	BEGIN_LP_RING(2);
+	OUT_RING(cmd);
+	OUT_RING(MI_NOOP);
+	ADVANCE_LP_RING();
+
+	/* if this is a gpu flush, process the results */
+	if (flush_domains & I915_GEM_GPU_DOMAINS) {
+		inteldrm_process_flushing(dev_priv, flush_domains);
+		ret = i915_add_request(dev_priv);
+	}
+	mtx_leave(&dev_priv->request_lock);
+
+	return (ret);
+}
+
+/**
+ * Unbinds an object from the GTT aperture.
+ *
+ * XXX track dirty and pass down to uvm (note, DONTNEED buffers are clean).
+ */
+int
+i915_gem_object_unbind(struct drm_obj *obj, int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 ret = 0;
+
+	DRM_ASSERT_HELD(obj);
+	/*
+	 * if it's already unbound, or we've already done lastclose, just
+	 * let it happen. XXX does this fail to unwire?
+	 */
+	if (obj_priv->dmamap == NULL || dev_priv->agpdmat == NULL)
+		return 0;
+
+	if (obj_priv->pin_count != 0) {
+		DRM_ERROR("Attempting to unbind pinned buffer\n");
+		return (EINVAL);
+	}
+
+	KASSERT(!i915_obj_purged(obj_priv));
+
+	/* Move the object to the CPU domain to ensure that
+	 * any possible CPU writes while it's not in the GTT
+	 * are flushed when we go to remap it. This will
+	 * also ensure that all pending GPU writes are finished
+	 * before we unbind.
+	 */
+	ret = i915_gem_object_set_to_cpu_domain(obj, 1, interruptible);
+	if (ret)
+		return ret;
+
+	KASSERT(!inteldrm_is_active(obj_priv));
+
+	/* if it's purgeable don't bother dirtying the pages */
+	if (i915_obj_purgeable(obj_priv))
+		atomic_clearbits_int(&obj->do_flags, I915_DIRTY);
+	/*
+	 * unload the map, then unwire the backing object.
+	 */
+	i915_gem_save_bit_17_swizzle(obj);
+	bus_dmamap_unload(dev_priv->agpdmat, obj_priv->dmamap);
+	uvm_objunwire(obj->uao, 0, obj->size);
+	/* XXX persistent dmamap worth the memory? */
+	bus_dmamap_destroy(dev_priv->agpdmat, obj_priv->dmamap);
+	obj_priv->dmamap = NULL;
+	free(obj_priv->dma_segs, M_DRM);
+	obj_priv->dma_segs = NULL;
+	/* XXX this should change whether we tell uvm the page is dirty */
+	atomic_clearbits_int(&obj->do_flags, I915_DIRTY);
+
+	obj_priv->gtt_offset = 0;
+	atomic_dec(&dev->gtt_count);
+	atomic_sub(obj->size, &dev->gtt_memory);
+
+	/* Remove ourselves from any LRU list if present. */
+	i915_list_remove((struct inteldrm_obj *)obj);
+
+	if (i915_obj_purgeable(obj_priv))
+		inteldrm_purge_obj(obj);
+
+	return (0);
+}
+
+int
+i915_gem_evict_something(struct inteldrm_softc *dev_priv, size_t min_size,
+    int interruptible)
+{
+	struct drm_obj		*obj;
+	struct inteldrm_request	*request;
+	struct inteldrm_obj	*obj_priv;
+	u_int32_t		 seqno;
+	int			 ret = 0, write_domain = 0;
+
+	for (;;) {
+		i915_gem_retire_requests(dev_priv);
+
+		/* If there's an inactive buffer available now, grab it
+		 * and be done.
+		 */
+		obj = i915_gem_find_inactive_object(dev_priv, min_size);
+		if (obj != NULL) {
+			obj_priv = (struct inteldrm_obj *)obj;
+			/* find inactive object returns the object with a
+			 * reference for us, and held
+			 */
+			KASSERT(obj_priv->pin_count == 0);
+			KASSERT(!inteldrm_is_active(obj_priv));
+			DRM_ASSERT_HELD(obj);
+
+			/* Wait on the rendering and unbind the buffer. */
+			ret = i915_gem_object_unbind(obj, interruptible);
+			drm_unhold_and_unref(obj);
+			return (ret);
+		}
+
+		/* If we didn't get anything, but the ring is still processing
+		 * things, wait for one of those things to finish and hopefully
+		 * leave us a buffer to evict.
+		 */
+		mtx_enter(&dev_priv->request_lock);
+		if ((request = TAILQ_FIRST(&dev_priv->mm.request_list))
+		    != NULL) {
+			seqno = request->seqno;
+			mtx_leave(&dev_priv->request_lock);
+
+			ret = i915_wait_request(dev_priv, seqno, interruptible);
+			if (ret)
+				return (ret);
+
+			continue;
+		}
+		mtx_leave(&dev_priv->request_lock);
+
+		/* If we didn't have anything on the request list but there
+		 * are buffers awaiting a flush, emit one and try again.
+		 * When we wait on it, those buffers waiting for that flush
+		 * will get moved to inactive.
+		 */
+		mtx_enter(&dev_priv->list_lock);
+		TAILQ_FOREACH(obj_priv, &dev_priv->mm.flushing_list, list) {
+			obj = &obj_priv->obj;
+			if (obj->size >= min_size) {
+				write_domain = obj->write_domain;
+				break;
+			}
+			obj = NULL;
+		}
+		mtx_leave(&dev_priv->list_lock);
+
+		if (write_domain) {
+			if (i915_gem_flush(dev_priv, write_domain,
+			    write_domain) == 0)
+				return (ENOMEM);
+			continue;
+		}
+
+		/*
+		 * If we didn't do any of the above, there's no single buffer
+		 * large enough to swap out for the new one, so just evict
+		 * everything and start again. (This should be rare.)
+		 */
+		if (!TAILQ_EMPTY(&dev_priv->mm.inactive_list))
+			return (i915_gem_evict_inactive(dev_priv,
+			    interruptible));
+		else
+			return (i915_gem_evict_everything(dev_priv,
+			    interruptible));
+	}
+	/* NOTREACHED */
+}
+
+struct drm_obj *
+i915_gem_find_inactive_object(struct inteldrm_softc *dev_priv,
+    size_t min_size)
+{
+	struct drm_obj		*obj, *best = NULL, *first = NULL;
+	struct inteldrm_obj	*obj_priv;
+
+	/*
+	 * We don't need references to the object as long as we hold the list
+	 * lock, they won't disappear until we release the lock.
+	 */
+	mtx_enter(&dev_priv->list_lock);
+	TAILQ_FOREACH(obj_priv, &dev_priv->mm.inactive_list, list) {
+		obj = &obj_priv->obj;
+		if (obj->size >= min_size) {
+			if ((!inteldrm_is_dirty(obj_priv) ||
+			    i915_obj_purgeable(obj_priv)) &&
+			    (best == NULL || obj->size < best->size)) {
+				best = obj;
+				if (best->size == min_size)
+					break;
+			}
+		}
+		if (first == NULL)
+			first = obj;
+	}
+	if (best == NULL)
+		best = first;
+	if (best) {
+		drm_ref(&best->uobj);
+		/*
+		 * if we couldn't grab it, we may as well fail and go
+		 * onto the next step for the sake of simplicity.
+		 */
+		if (drm_try_hold_object(best) == 0) {
+			drm_unref(&best->uobj);
+			best = NULL;
+		}
+	}
+	mtx_leave(&dev_priv->list_lock);
+	return (best);
+}
+
+int
+i915_gem_evict_everything(struct inteldrm_softc *dev_priv, int interruptible)
+{
+	u_int32_t	seqno;
+	int		ret;
+
+	if (TAILQ_EMPTY(&dev_priv->mm.inactive_list) &&
+	    TAILQ_EMPTY(&dev_priv->mm.flushing_list) &&
+	    TAILQ_EMPTY(&dev_priv->mm.active_list))
+		return (ENOSPC);
+
+	seqno = i915_gem_flush(dev_priv, I915_GEM_GPU_DOMAINS,
+	    I915_GEM_GPU_DOMAINS);
+	if (seqno == 0)
+		return (ENOMEM);
+
+	if ((ret = i915_wait_request(dev_priv, seqno, interruptible)) != 0 ||
+	    (ret = i915_gem_evict_inactive(dev_priv, interruptible)) != 0)
+		return (ret);
+
+	/*
+	 * All lists should be empty because we flushed the whole queue, then
+	 * we evicted the whole shebang, only pinned objects are still bound.
+	 */
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.inactive_list));
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.flushing_list));
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.active_list));
+
+	return (0);
+}
+/*
+ * return required GTT alignment for an object, taking into account potential
+ * fence register needs
+ */
+bus_size_t
+i915_gem_get_gtt_alignment(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	bus_size_t		 start, i;
+
+	/*
+	 * Minimum alignment is 4k (GTT page size), but fence registers may
+	 * modify this
+	 */
+	if (IS_I965G(dev_priv) || obj_priv->tiling_mode == I915_TILING_NONE)
+		return (4096);
+
+	/*
+	 * Older chips need to be aligned to the size of the smallest fence
+	 * register that can contain the object.
+	 */
+	if (IS_I9XX(dev_priv))
+		start = 1024 * 1024;
+	else
+		start = 512 * 1024;
+
+	for (i = start; i < obj->size; i <<= 1)
+		;
+
+	return (i);
+}
+
+void
+i965_write_fence_reg(struct inteldrm_fence *reg)
+{
+	struct drm_obj		*obj = reg->obj;
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 regnum = obj_priv->fence_reg;
+	u_int64_t		 val;
+
+	val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+		    0xfffff000) << 32;
+	val |= obj_priv->gtt_offset & 0xfffff000;
+	val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
+	if (obj_priv->tiling_mode == I915_TILING_Y)
+		val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+	val |= I965_FENCE_REG_VALID;
+
+	I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val);
+}
+
+void
+i915_write_fence_reg(struct inteldrm_fence *reg)
+{
+	struct drm_obj		*obj = reg->obj;
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	bus_size_t		 fence_reg;
+	u_int32_t		 val;
+	u_int32_t		 pitch_val;
+	int			 regnum = obj_priv->fence_reg;
+	int			 tile_width;
+
+	if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
+	    (obj_priv->gtt_offset & (obj->size - 1))) {
+		DRM_ERROR("object 0x%jx not 1M or size (0x%zx) aligned\n",
+		    (uintmax_t)obj_priv->gtt_offset, obj->size);
+		return;
+	}
+
+	if (obj_priv->tiling_mode == I915_TILING_Y &&
+	    HAS_128_BYTE_Y_TILING(dev_priv))
+		tile_width = 128;
+	else
+		tile_width = 512;
+
+	/* Note: pitch better be a power of two tile widths */
+	pitch_val = obj_priv->stride / tile_width;
+	pitch_val = ffs(pitch_val) - 1;
+
+	/* XXX print more */
+	if ((obj_priv->tiling_mode == I915_TILING_Y &&
+	    HAS_128_BYTE_Y_TILING(dev_priv) &&
+	    pitch_val > I830_FENCE_MAX_PITCH_VAL) ||
+	    pitch_val > I915_FENCE_MAX_PITCH_VAL)
+		printf("%s: invalid pitch provided", __func__);
+
+	val = obj_priv->gtt_offset;
+	if (obj_priv->tiling_mode == I915_TILING_Y)
+		val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+	val |= I915_FENCE_SIZE_BITS(obj->size);
+	val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+	val |= I830_FENCE_REG_VALID;
+
+	if (regnum < 8)
+		fence_reg = FENCE_REG_830_0 + (regnum * 4);
+	else
+		fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4);
+	I915_WRITE(fence_reg, val);
+}
+
+void
+i830_write_fence_reg(struct inteldrm_fence *reg)
+{
+	struct drm_obj		*obj = reg->obj;
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 regnum = obj_priv->fence_reg;
+	u_int32_t		 pitch_val, val;
+
+	if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) ||
+	    (obj_priv->gtt_offset & (obj->size - 1))) {
+		DRM_ERROR("object 0x%08jx not 512K or size aligned 0x%zx\n",
+		    (uintmax_t)obj_priv->gtt_offset, obj->size);
+		return;
+	}
+
+	pitch_val = ffs(obj_priv->stride / 128) - 1;
+
+	val = obj_priv->gtt_offset;
+	if (obj_priv->tiling_mode == I915_TILING_Y)
+		val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+	val |= I830_FENCE_SIZE_BITS(obj->size);
+	val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+	val |= I830_FENCE_REG_VALID;
+
+	I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
+
+}
+
+/*
+ * i915_gem_get_fence_reg - set up a fence reg for an object
+ *
+ * When mapping objects through the GTT, userspace wants to be able to write
+ * to them without having to worry about swizzling if the object is tiled.
+ *
+ * This function walks the fence regs looking for a free one, stealing one
+ * if it can't find any.
+ *
+ * It then sets up the reg based on the object's properties: address, pitch
+ * and tiling format.
+ */
+int
+i915_gem_get_fence_reg(struct drm_obj *obj, int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct inteldrm_obj	*old_obj_priv = NULL;
+	struct drm_obj		*old_obj = NULL;
+	struct inteldrm_fence	*reg = NULL;
+	int			 i, ret, avail;
+
+	/* If our fence is getting used, just update our place in the LRU */
+	if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
+		mtx_enter(&dev_priv->fence_lock);
+		reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+
+		TAILQ_REMOVE(&dev_priv->mm.fence_list, reg, list);
+		TAILQ_INSERT_TAIL(&dev_priv->mm.fence_list, reg, list);
+		mtx_leave(&dev_priv->fence_lock);
+		return (0);
+	}
+
+	DRM_ASSERT_HELD(obj);
+	switch (obj_priv->tiling_mode) {
+	case I915_TILING_NONE:
+		DRM_ERROR("allocating a fence for non-tiled object?\n");
+		break;
+	case I915_TILING_X:
+		if (obj_priv->stride == 0)
+			return (EINVAL);
+		if (obj_priv->stride & (512 - 1))
+			DRM_ERROR("object 0x%08jx is X tiled but has non-512B"
+			    " pitch\n", (uintmax_t)obj_priv->gtt_offset);
+		break;
+	case I915_TILING_Y:
+		if (obj_priv->stride == 0)
+			return (EINVAL);
+		if (obj_priv->stride & (128 - 1))
+			DRM_ERROR("object 0x%08jx is Y tiled but has non-128B"
+			    " pitch\n", (uintmax_t)obj_priv->gtt_offset);
+		break;
+	}
+
+again:
+	/* First try to find a free reg */
+	avail = 0;
+	mtx_enter(&dev_priv->fence_lock);
+	for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+		reg = &dev_priv->fence_regs[i];
+		if (reg->obj == NULL)
+			break;
+
+		old_obj_priv = (struct inteldrm_obj *)reg->obj;
+		if (old_obj_priv->pin_count == 0)
+			avail++;
+	}
+
+	/* None available, try to steal one or wait for a user to finish */
+	if (i == dev_priv->num_fence_regs) {
+		if (avail == 0) {
+			mtx_leave(&dev_priv->fence_lock);
+			return (ENOMEM);
+		}
+
+		TAILQ_FOREACH(reg, &dev_priv->mm.fence_list,
+		    list) {
+			old_obj = reg->obj;
+			old_obj_priv = (struct inteldrm_obj *)old_obj;
+
+			if (old_obj_priv->pin_count)
+				continue;
+
+			/* Ref it so that wait_rendering doesn't free it under
+			 * us. if we can't hold it, it may change state soon
+			 * so grab the next one.
+			 */
+			drm_ref(&old_obj->uobj);
+			if (drm_try_hold_object(old_obj) == 0) {
+				drm_unref(&old_obj->uobj);
+				continue;
+			}
+
+			break;
+		}
+		mtx_leave(&dev_priv->fence_lock);
+
+		/* if we tried all of them, give it another whirl. we failed to
+		 * get a hold this go round.
+		 */
+		if (reg == NULL)
+			goto again;
+
+		ret = i915_gem_object_put_fence_reg(old_obj, interruptible);
+		drm_unhold_and_unref(old_obj);
+		if (ret != 0)
+			return (ret);
+		/* we should have freed one up now, so relock and re-search */
+		goto again;
+	}
+
+	/*
+	 * Here we will either have found a register in the first
+	 * loop, or we will have waited for one and in the second case
+	 * and thus have grabbed the object in question, freed the register
+	 * then redone the second loop (having relocked the fence list).
+	 * Therefore at this point it is impossible to have a null value
+	 * in reg.
+	 */
+	KASSERT(reg != NULL);
+
+	obj_priv->fence_reg = i;
+	reg->obj = obj;
+	TAILQ_INSERT_TAIL(&dev_priv->mm.fence_list, reg, list);
+
+	if (IS_I965G(dev_priv))
+		i965_write_fence_reg(reg);
+	else if (IS_I9XX(dev_priv))
+		i915_write_fence_reg(reg);
+	else
+		i830_write_fence_reg(reg);
+	mtx_leave(&dev_priv->fence_lock);
+
+	return 0;
+}
+
+int
+i915_gem_object_put_fence_reg(struct drm_obj *obj, int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct inteldrm_fence	*reg;
+	int			 ret;
+
+	DRM_ASSERT_HELD(obj);
+	if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
+		return (0);
+
+	/*
+	 * If the last execbuffer we did on the object needed a fence then
+	 * we must emit a flush.
+	 */
+	if (inteldrm_needs_fence(obj_priv)) {
+		ret = i915_gem_object_flush_gpu_write_domain(obj, 1,
+		    interruptible, 0);
+		if (ret != 0)
+			return (ret);
+	}
+
+	/* if rendering is queued up that depends on the fence, wait for it */
+	reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+	if (reg->last_rendering_seqno != 0) {
+		ret = i915_wait_request(dev_priv, reg->last_rendering_seqno,
+		    interruptible);
+		if (ret != 0)
+			return (ret);
+	}
+
+	/* tiling changed, must wipe userspace mappings */
+	if ((obj->write_domain | obj->read_domains) & I915_GEM_DOMAIN_GTT) {
+		inteldrm_wipe_mappings(obj);
+		if (obj->write_domain == I915_GEM_DOMAIN_GTT)
+			obj->write_domain = 0;
+	}
+
+	mtx_enter(&dev_priv->fence_lock);
+	if (IS_I965G(dev_priv)) {
+		I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
+	} else {
+		u_int32_t fence_reg;
+
+		if (obj_priv->fence_reg < 8)
+			fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4;
+		else
+			fence_reg = FENCE_REG_945_8 +
+			    (obj_priv->fence_reg - 8) * 4;
+		I915_WRITE(fence_reg , 0);
+	}
+
+	reg->obj = NULL;
+	TAILQ_REMOVE(&dev_priv->mm.fence_list, reg, list);
+	obj_priv->fence_reg = I915_FENCE_REG_NONE;
+	mtx_leave(&dev_priv->fence_lock);
+	atomic_clearbits_int(&obj->do_flags, I915_FENCE_INVALID);
+
+	return (0);
+}
+
+int
+inteldrm_fault(struct drm_obj *obj, struct uvm_faultinfo *ufi, off_t offset,
+    vaddr_t vaddr, vm_page_t *pps, int npages, int centeridx,
+    vm_prot_t access_type, int flags)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	paddr_t			 paddr;
+	int			 lcv, ret;
+	int			 write = !!(access_type & VM_PROT_WRITE);
+	vm_prot_t		 mapprot;
+	boolean_t		 locked = TRUE;
+
+#if defined(__NetBSD__)
+	UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist);
+#endif /* defined(__NetBSD__) */
+
+	/* Are we about to suspend?, if so wait until we're done */
+	if (dev_priv->sc_flags & INTELDRM_QUIET) {
+		/* we're about to sleep, unlock the map etc */
+		uvmfault_unlockall(ufi, NULL, &obj->uobj, NULL);
+		while (dev_priv->sc_flags & INTELDRM_QUIET)
+			tsleep(&dev_priv->flags, 0, "intelflt", 0);
+		dev_priv->entries++;
+		/*
+		 * relock so we're in the same state we would be in if we
+		 * were not quiesced before
+		 */
+		locked = uvmfault_relock(ufi);
+		if (locked) {
+			drm_lock_obj(obj);
+		} else {
+			dev_priv->entries--;
+			if (dev_priv->sc_flags & INTELDRM_QUIET)
+				wakeup(&dev_priv->entries);
+			return (VM_PAGER_REFAULT);
+		}
+	} else {
+		dev_priv->entries++;
+	}
+
+#if !defined(__NetBSD__)
+	if (rw_enter(&dev->dev_lock, RW_NOSLEEP | RW_READ) != 0) {
+#else /* !defined(__NetBSD__) */
+	if (rw_tryenter(&dev->dev_lock, RW_READER) == 0) {
+#endif /* !defined(__NetBSD__) */
+		uvmfault_unlockall(ufi, NULL, &obj->uobj, NULL);
+		DRM_READLOCK();
+		locked = uvmfault_relock(ufi);
+		if (locked)
+			drm_lock_obj(obj);
+	}
+	if (locked)
+		drm_hold_object_locked(obj);
+	else { /* obj already unlocked */
+		dev_priv->entries--;
+		if (dev_priv->sc_flags & INTELDRM_QUIET)
+			wakeup(&dev_priv->entries);
+		return (VM_PAGER_REFAULT);
+	}
+
+	/* we have a hold set on the object now, we can unlock so that we can
+	 * sleep in binding and flushing.
+	 */
+	drm_unlock_obj(obj);
+
+	if (obj_priv->dmamap != NULL &&
+	    (obj_priv->gtt_offset & (i915_gem_get_gtt_alignment(obj) - 1) ||
+	    (!i915_gem_object_fence_offset_ok(obj, obj_priv->tiling_mode)))) {
+		/*
+		 * pinned objects are defined to have a sane alignment which can
+		 * not change.
+		 */
+		KASSERT(obj_priv->pin_count == 0);
+		if ((ret = i915_gem_object_unbind(obj, 0)))
+			goto error;
+	}
+
+	if (obj_priv->dmamap == NULL) {
+		ret = i915_gem_object_bind_to_gtt(obj, 0, 0);
+		if (ret) {
+			printf("%s: failed to bind\n", __func__);
+			goto error;
+		}
+		i915_gem_object_move_to_inactive(obj);
+	}
+
+	/*
+	 * We could only do this on bind so allow for map_buffer_range
+	 * unsynchronised objects (where buffer suballocation
+	 * is done by the GL application), however it gives coherency problems
+	 * normally.
+	 */
+	ret = i915_gem_object_set_to_gtt_domain(obj, write, 0);
+	if (ret) {
+		printf("%s: failed to set to gtt (%d)\n",
+		    __func__, ret);
+		goto error;
+	}
+
+	mapprot = ufi->entry->protection;
+	/*
+	 * if it's only a read fault, we only put ourselves into the gtt
+	 * read domain, so make sure we fault again and set ourselves to write.
+	 * this prevents us needing userland to do domain management and get
+	 * it wrong, and makes us fully coherent with the gpu re mmap.
+	 */
+	if (write == 0)
+		mapprot &= ~VM_PROT_WRITE;
+	/* XXX try and  be more efficient when we do this */
+	for (lcv = 0 ; lcv < npages ; lcv++, offset += PAGE_SIZE,
+	    vaddr += PAGE_SIZE) {
+		if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx)
+			continue;
+
+		if (pps[lcv] == PGO_DONTCARE)
+			continue;
+
+		paddr = dev->agp->base + obj_priv->gtt_offset + offset;
+
+		UVMHIST_LOG(maphist,
+		    "  MAPPING: device: pm=%p, va=0x%lx, pa=0x%lx, at=%ld",
+		    ufi->orig_map->pmap, vaddr, (u_long)paddr, mapprot);
+		if (pmap_enter(ufi->orig_map->pmap, vaddr, paddr,
+		    mapprot, PMAP_CANFAIL | mapprot) != 0) {
+			drm_unhold_object(obj);
+			uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap,
+			    NULL, NULL);
+			DRM_READUNLOCK();
+			dev_priv->entries--;
+			if (dev_priv->sc_flags & INTELDRM_QUIET)
+				wakeup(&dev_priv->entries);
+			uvm_wait("intelflt");
+			return (VM_PAGER_REFAULT);
+		}
+	}
+error:
+	drm_unhold_object(obj);
+	uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, NULL, NULL);
+	DRM_READUNLOCK();
+	dev_priv->entries--;
+	if (dev_priv->sc_flags & INTELDRM_QUIET)
+		wakeup(&dev_priv->entries);
+	pmap_update(ufi->orig_map->pmap);
+	if (ret == EIO) {
+		/*
+		 * EIO means we're wedged, so upon resetting the gpu we'll
+		 * be alright and can refault. XXX only on resettable chips.
+		 */
+		ret = VM_PAGER_REFAULT;
+	} else if (ret) {
+		ret = VM_PAGER_ERROR;
+	} else {
+		ret = VM_PAGER_OK;
+	}
+	return (ret);
+}
+
+void
+inteldrm_wipe_mappings(struct drm_obj *obj)
+{
+#if !defined(__NetBSD__)
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct vm_page		*pg;
+#endif /* !defined(__NetBSD__) */
+
+	DRM_ASSERT_HELD(obj);
+	/* make sure any writes hit the bus before we do whatever change
+	 * that prompted us to kill the mappings.
+	 */
+	DRM_MEMORYBARRIER();
+	/* nuke all our mappings. XXX optimise. */
+#if !defined(__NetBSD__)
+	for (pg = &dev_priv->pgs[atop(obj_priv->gtt_offset)]; pg !=
+	    &dev_priv->pgs[atop(obj_priv->gtt_offset + obj->size)]; pg++)
+		pmap_page_protect(pg, VM_PROT_NONE);
+#endif /* !defined(__NetBSD__) */
+}
+
+/**
+ * Finds free space in the GTT aperture and binds the object there.
+ */
+int
+i915_gem_object_bind_to_gtt(struct drm_obj *obj, bus_size_t alignment,
+    int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 ret;
+
+	DRM_ASSERT_HELD(obj);
+	if (dev_priv->agpdmat == NULL)
+		return (EINVAL);
+	if (alignment == 0) {
+		alignment = i915_gem_get_gtt_alignment(obj);
+	} else if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) {
+		DRM_ERROR("Invalid object alignment requested %ju\n",
+		    (uintmax_t)alignment);
+		return (EINVAL);
+	}
+
+	/* Can't bind a purgeable buffer */
+	if (i915_obj_purgeable(obj_priv)) {
+		printf("tried to bind purgeable buffer");
+		return (EINVAL);
+	}
+
+	if ((ret = bus_dmamap_create(dev_priv->agpdmat, obj->size, 1,
+	    obj->size, 0, BUS_DMA_WAITOK, &obj_priv->dmamap)) != 0) {
+		DRM_ERROR("Failed to create dmamap\n");
+		return (ret);
+	}
+	agp_bus_dma_set_alignment(dev_priv->agpdmat, obj_priv->dmamap,
+	    alignment);
+
+ search_free:
+	/*
+	 * the helper function wires the uao then binds it to the aperture for
+	 * us, so all we have to do is set up the dmamap then load it.
+	 */
+	ret = drm_gem_load_uao(dev_priv->agpdmat, obj_priv->dmamap, obj->uao,
+	    obj->size, BUS_DMA_WAITOK | obj_priv->dma_flags,
+	    &obj_priv->dma_segs);
+	/* XXX NOWAIT? */
+	if (ret != 0) {
+		/* If the gtt is empty and we're still having trouble
+		 * fitting our object in, we're out of memory.
+		 */
+		if (TAILQ_EMPTY(&dev_priv->mm.inactive_list) &&
+		    TAILQ_EMPTY(&dev_priv->mm.flushing_list) &&
+		    TAILQ_EMPTY(&dev_priv->mm.active_list)) {
+			DRM_ERROR("GTT full, but LRU list empty\n");
+			goto error;
+		}
+
+		ret = i915_gem_evict_something(dev_priv, obj->size,
+		    interruptible);
+		if (ret != 0)
+			goto error;
+		goto search_free;
+	}
+	i915_gem_bit_17_swizzle(obj);
+
+	obj_priv->gtt_offset = obj_priv->dmamap->dm_segs[0].ds_addr -
+	    dev->agp->base;
+
+	atomic_inc(&dev->gtt_count);
+	atomic_add(obj->size, &dev->gtt_memory);
+
+	/* Assert that the object is not currently in any GPU domain. As it
+	 * wasn't in the GTT, there shouldn't be any way it could have been in
+	 * a GPU cache
+	 */
+	KASSERT((obj->read_domains & I915_GEM_GPU_DOMAINS) == 0);
+	KASSERT((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0);
+
+	return (0);
+
+error:
+	bus_dmamap_destroy(dev_priv->agpdmat, obj_priv->dmamap);
+	obj_priv->dmamap = NULL;
+	obj_priv->gtt_offset = 0;
+	return (ret);
+}
+
+/*
+ * Flush the GPU write domain for the object if dirty, then wait for the
+ * rendering to complete. When this returns it is safe to unbind from the
+ * GTT or access from the CPU.
+ */
+int
+i915_gem_object_flush_gpu_write_domain(struct drm_obj *obj, int pipelined,
+    int interruptible, int write)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	u_int32_t		 seqno;
+	int			 ret = 0;
+
+	DRM_ASSERT_HELD(obj);
+	if ((obj->write_domain & I915_GEM_GPU_DOMAINS) != 0) {
+		/*
+		 * Queue the GPU write cache flushing we need.
+		 * This call will move stuff form the flushing list to the
+		 * active list so all we need to is wait for it.
+		 */
+		(void)i915_gem_flush(dev_priv, 0, obj->write_domain);
+		KASSERT(obj->write_domain == 0);
+	}
+
+	/* wait for queued rendering so we know it's flushed and bo is idle */
+	if (pipelined == 0 && inteldrm_is_active(obj_priv)) {
+		if (write) {
+			seqno = obj_priv->last_rendering_seqno;
+		} else {
+			seqno = obj_priv->last_write_seqno;
+		}
+		ret =  i915_wait_request(dev_priv, seqno, interruptible);
+	}
+	return (ret);
+}
+
+/*
+ * Moves a single object to the GTT and possibly write domain.
+ *
+ * This function returns when the move is complete, including waiting on
+ * flushes to occur.
+ */
+int
+i915_gem_object_set_to_gtt_domain(struct drm_obj *obj, int write,
+    int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 ret;
+
+	DRM_ASSERT_HELD(obj);
+	/* Not valid to be called on unbound objects. */
+	if (obj_priv->dmamap == NULL)
+		return (EINVAL);
+	/* Wait on any GPU rendering and flushing to occur. */
+	if ((ret = i915_gem_object_flush_gpu_write_domain(obj, 0,
+	    interruptible, write)) != 0)
+		return (ret);
+
+	if (obj->write_domain == I915_GEM_DOMAIN_CPU) {
+		/* clflush the pages, and flush chipset cache */
+		bus_dmamap_sync(dev_priv->agpdmat, obj_priv->dmamap, 0,
+		    obj->size, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+		inteldrm_chipset_flush(dev_priv);
+		obj->write_domain = 0;
+	}
+
+	/* We're accessing through the gpu, so grab a new fence register or
+	 * update the LRU.
+	 */
+	if (obj->do_flags & I915_FENCE_INVALID) {
+		ret = i915_gem_object_put_fence_reg(obj, interruptible);
+		if (ret)
+			return (ret);
+	}
+	if (obj_priv->tiling_mode != I915_TILING_NONE)
+		ret = i915_gem_get_fence_reg(obj, interruptible);
+
+	/*
+	 * If we're writing through the GTT domain then the CPU and GPU caches
+	 * will need to be invalidated at next use.
+	 * It should now be out of any other write domains and we can update
+	 * to the correct ones
+	 */
+	KASSERT((obj->write_domain & ~I915_GEM_DOMAIN_GTT) == 0);
+	if (write) {
+		obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_GTT;
+		atomic_setbits_int(&obj->do_flags, I915_DIRTY);
+	} else {
+		obj->read_domains |= I915_GEM_DOMAIN_GTT;
+	}
+
+	return (ret);
+}
+
+/*
+ * Moves a single object to the CPU read and possibly write domain.
+ *
+ * This function returns when the move is complete, including waiting on
+ * flushes to return.
+ */
+int
+i915_gem_object_set_to_cpu_domain(struct drm_obj *obj, int write,
+    int interruptible)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 ret;
+
+	DRM_ASSERT_HELD(obj);
+	/* Wait on any GPU rendering and flushing to occur. */
+	if ((ret = i915_gem_object_flush_gpu_write_domain(obj, 0,
+	    interruptible, write)) != 0)
+		return (ret);
+
+	if (obj->write_domain == I915_GEM_DOMAIN_GTT ||
+	    (write && obj->read_domains & I915_GEM_DOMAIN_GTT)) {
+		/*
+		 * No actual flushing is required for the GTT write domain.
+		 * Writes to it immeditately go to main memory as far as we
+		 * know, so there's no chipset flush. It also doesn't land
+		 * in render cache.
+		 */
+		inteldrm_wipe_mappings(obj);
+		if (obj->write_domain == I915_GEM_DOMAIN_GTT)
+			obj->write_domain = 0;
+	}
+
+	/* remove the fence register since we're not using it anymore */
+	if ((ret = i915_gem_object_put_fence_reg(obj, interruptible)) != 0)
+		return (ret);
+
+	/* Flush the CPU cache if it's still invalid. */
+	if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) {
+		bus_dmamap_sync(dev_priv->agpdmat, obj_priv->dmamap, 0,
+		    obj->size, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+		obj->read_domains |= I915_GEM_DOMAIN_CPU;
+	}
+
+	/*
+	 * It should now be out of any other write domain, and we can update
+	 * the domain value for our changes.
+	 */
+	KASSERT((obj->write_domain & ~I915_GEM_DOMAIN_CPU) == 0);
+
+	/*
+	 * If we're writing through the CPU, then the GPU read domains will
+	 * need to be invalidated at next use.
+	 */
+	if (write)
+		obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+
+	return (0);
+}
+
+/*
+ * Set the next domain for the specified object. This
+ * may not actually perform the necessary flushing/invaliding though,
+ * as that may want to be batched with other set_domain operations
+ *
+ * This is (we hope) the only really tricky part of gem. The goal
+ * is fairly simple -- track which caches hold bits of the object
+ * and make sure they remain coherent. A few concrete examples may
+ * help to explain how it works. For shorthand, we use the notation
+ * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the
+ * a pair of read and write domain masks.
+ *
+ * Case 1: the batch buffer
+ *
+ *	1. Allocated
+ *	2. Written by CPU
+ *	3. Mapped to GTT
+ *	4. Read by GPU
+ *	5. Unmapped from GTT
+ *	6. Freed
+ *
+ *	Let's take these a step at a time
+ *
+ *	1. Allocated
+ *		Pages allocated from the kernel may still have
+ *		cache contents, so we set them to (CPU, CPU) always.
+ *	2. Written by CPU (using pwrite)
+ *		The pwrite function calls set_domain (CPU, CPU) and
+ *		this function does nothing (as nothing changes)
+ *	3. Mapped by GTT
+ *		This function asserts that the object is not
+ *		currently in any GPU-based read or write domains
+ *	4. Read by GPU
+ *		i915_gem_execbuffer calls set_domain (COMMAND, 0).
+ *		As write_domain is zero, this function adds in the
+ *		current read domains (CPU+COMMAND, 0).
+ *		flush_domains is set to CPU.
+ *		invalidate_domains is set to COMMAND
+ *		clflush is run to get data out of the CPU caches
+ *		then i915_dev_set_domain calls i915_gem_flush to
+ *		emit an MI_FLUSH and drm_agp_chipset_flush
+ *	5. Unmapped from GTT
+ *		i915_gem_object_unbind calls set_domain (CPU, CPU)
+ *		flush_domains and invalidate_domains end up both zero
+ *		so no flushing/invalidating happens
+ *	6. Freed
+ *		yay, done
+ *
+ * Case 2: The shared render buffer
+ *
+ *	1. Allocated
+ *	2. Mapped to GTT
+ *	3. Read/written by GPU
+ *	4. set_domain to (CPU,CPU)
+ *	5. Read/written by CPU
+ *	6. Read/written by GPU
+ *
+ *	1. Allocated
+ *		Same as last example, (CPU, CPU)
+ *	2. Mapped to GTT
+ *		Nothing changes (assertions find that it is not in the GPU)
+ *	3. Read/written by GPU
+ *		execbuffer calls set_domain (RENDER, RENDER)
+ *		flush_domains gets CPU
+ *		invalidate_domains gets GPU
+ *		clflush (obj)
+ *		MI_FLUSH and drm_agp_chipset_flush
+ *	4. set_domain (CPU, CPU)
+ *		flush_domains gets GPU
+ *		invalidate_domains gets CPU
+ *		flush_gpu_write (obj) to make sure all drawing is complete.
+ *		This will include an MI_FLUSH to get the data from GPU
+ *		to memory
+ *		clflush (obj) to invalidate the CPU cache
+ *		Another MI_FLUSH in i915_gem_flush (eliminate this somehow?)
+ *	5. Read/written by CPU
+ *		cache lines are loaded and dirtied
+ *	6. Read written by GPU
+ *		Same as last GPU access
+ *
+ * Case 3: The constant buffer
+ *
+ *	1. Allocated
+ *	2. Written by CPU
+ *	3. Read by GPU
+ *	4. Updated (written) by CPU again
+ *	5. Read by GPU
+ *
+ *	1. Allocated
+ *		(CPU, CPU)
+ *	2. Written by CPU
+ *		(CPU, CPU)
+ *	3. Read by GPU
+ *		(CPU+RENDER, 0)
+ *		flush_domains = CPU
+ *		invalidate_domains = RENDER
+ *		clflush (obj)
+ *		MI_FLUSH
+ *		drm_agp_chipset_flush
+ *	4. Updated (written) by CPU again
+ *		(CPU, CPU)
+ *		flush_domains = 0 (no previous write domain)
+ *		invalidate_domains = 0 (no new read domains)
+ *	5. Read by GPU
+ *		(CPU+RENDER, 0)
+ *		flush_domains = CPU
+ *		invalidate_domains = RENDER
+ *		clflush (obj)
+ *		MI_FLUSH
+ *		drm_agp_chipset_flush
+ */
+void
+i915_gem_object_set_to_gpu_domain(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	u_int32_t		 invalidate_domains = 0;
+	u_int32_t		 flush_domains = 0;
+
+	DRM_ASSERT_HELD(obj);
+	KASSERT((obj->pending_read_domains & I915_GEM_DOMAIN_CPU) == 0);
+	KASSERT(obj->pending_write_domain != I915_GEM_DOMAIN_CPU);
+	/*
+	 * If the object isn't moving to a new write domain,
+	 * let the object stay in multiple read domains
+	 */
+	if (obj->pending_write_domain == 0)
+		obj->pending_read_domains |= obj->read_domains;
+	else
+		atomic_setbits_int(&obj->do_flags, I915_DIRTY);
+
+	/*
+	 * Flush the current write domain if
+	 * the new read domains don't match. Invalidate
+	 * any read domains which differ from the old
+	 * write domain
+	 */
+	if (obj->write_domain &&
+	    obj->write_domain != obj->pending_read_domains) {
+		flush_domains |= obj->write_domain;
+		invalidate_domains |= obj->pending_read_domains &
+		    ~obj->write_domain;
+	}
+	/*
+	 * Invalidate any read caches which may have
+	 * stale data. That is, any new read domains.
+	 */
+	invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
+	/* clflush the cpu now, gpu caches get queued. */
+	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
+		bus_dmamap_sync(dev_priv->agpdmat, obj_priv->dmamap, 0,
+		    obj->size, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+	}
+	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) {
+		inteldrm_wipe_mappings(obj);
+	}
+
+	/* The actual obj->write_domain will be updated with
+	 * pending_write_domain after we emit the accumulated flush for all of
+	 * the domain changes in execuffer (which clears object's write
+	 * domains). So if we have a current write domain that we aren't
+	 * changing, set pending_write_domain to it.
+	 */
+	if (flush_domains == 0 && obj->pending_write_domain == 0 &&
+	    (obj->pending_read_domains == obj->write_domain ||
+	    obj->write_domain == 0))
+		obj->pending_write_domain = obj->write_domain;
+	obj->read_domains = obj->pending_read_domains;
+	obj->pending_read_domains = 0;
+
+	dev->invalidate_domains |= invalidate_domains;
+	dev->flush_domains |= flush_domains;
+}
+
+/**
+ * Pin an object to the GTT and evaluate the relocations landing in it.
+ */
+int
+i915_gem_object_pin_and_relocate(struct drm_obj *obj,
+    struct drm_file *file_priv, struct drm_i915_gem_exec_object2 *entry,
+    struct drm_i915_gem_relocation_entry *relocs)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct drm_obj		*target_obj;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	bus_space_handle_t	 bsh;
+	int			 i, ret, needs_fence;
+
+	DRM_ASSERT_HELD(obj);
+	needs_fence = ((entry->flags & EXEC_OBJECT_NEEDS_FENCE) &&
+	    obj_priv->tiling_mode != I915_TILING_NONE);
+	if (needs_fence)
+		atomic_setbits_int(&obj->do_flags, I915_EXEC_NEEDS_FENCE);
+
+	/* Choose the GTT offset for our buffer and put it there. */
+	ret = i915_gem_object_pin(obj, (u_int32_t)entry->alignment,
+	    needs_fence);
+	if (ret)
+		return ret;
+
+	entry->offset = obj_priv->gtt_offset;
+
+	/* Apply the relocations, using the GTT aperture to avoid cache
+	 * flushing requirements.
+	 */
+	for (i = 0; i < entry->relocation_count; i++) {
+		struct drm_i915_gem_relocation_entry *reloc = &relocs[i];
+		struct inteldrm_obj *target_obj_priv;
+		uint32_t reloc_val, reloc_offset;
+
+		target_obj = drm_gem_object_lookup(obj->dev, file_priv,
+		    reloc->target_handle);
+		/* object must have come before us in the list */
+		if (target_obj == NULL) {
+			i915_gem_object_unpin(obj);
+			return (EBADF);
+		}
+		if ((target_obj->do_flags & I915_IN_EXEC) == 0) {
+			printf("%s: object not already in execbuffer\n",
+			__func__);
+			ret = EBADF;
+			goto err;
+		}
+
+		target_obj_priv = (struct inteldrm_obj *)target_obj;
+
+		/* The target buffer should have appeared before us in the
+		 * exec_object list, so it should have a GTT space bound by now.
+		 */
+		if (target_obj_priv->dmamap == 0) {
+			DRM_ERROR("No GTT space found for object %d\n",
+				  reloc->target_handle);
+			ret = EINVAL;
+			goto err;
+		}
+
+		/* must be in one write domain and one only */
+		if (reloc->write_domain & (reloc->write_domain - 1)) {
+			ret = EINVAL;
+			goto err;
+		}
+		if (reloc->read_domains & I915_GEM_DOMAIN_CPU ||
+		    reloc->write_domain & I915_GEM_DOMAIN_CPU) {
+			DRM_ERROR("relocation with read/write CPU domains: "
+			    "obj %p target %d offset %d "
+			    "read %08x write %08x", obj,
+			    reloc->target_handle, (int)reloc->offset,
+			    reloc->read_domains, reloc->write_domain);
+			ret = EINVAL;
+			goto err;
+		}
+
+		if (reloc->write_domain && target_obj->pending_write_domain &&
+		    reloc->write_domain != target_obj->pending_write_domain) {
+			DRM_ERROR("Write domain conflict: "
+				  "obj %p target %d offset %d "
+				  "new %08x old %08x\n",
+				  obj, reloc->target_handle,
+				  (int) reloc->offset,
+				  reloc->write_domain,
+				  target_obj->pending_write_domain);
+			ret = EINVAL;
+			goto err;
+		}
+
+		target_obj->pending_read_domains |= reloc->read_domains;
+		target_obj->pending_write_domain |= reloc->write_domain;
+
+
+		if (reloc->offset > obj->size - 4) {
+			DRM_ERROR("Relocation beyond object bounds: "
+				  "obj %p target %d offset %d size %d.\n",
+				  obj, reloc->target_handle,
+				  (int) reloc->offset, (int) obj->size);
+			ret = EINVAL;
+			goto err;
+		}
+		if (reloc->offset & 3) {
+			DRM_ERROR("Relocation not 4-byte aligned: "
+				  "obj %p target %d offset %d.\n",
+				  obj, reloc->target_handle,
+				  (int) reloc->offset);
+			ret = EINVAL;
+			goto err;
+		}
+
+		if (reloc->delta > target_obj->size) {
+			DRM_ERROR("reloc larger than target\n");
+			ret = EINVAL;
+			goto err;
+		}
+
+		/* Map the page containing the relocation we're going to
+		 * perform.
+		 */
+		reloc_offset = obj_priv->gtt_offset + reloc->offset;
+		reloc_val = target_obj_priv->gtt_offset + reloc->delta;
+
+		if (target_obj_priv->gtt_offset == reloc->presumed_offset) {
+			drm_gem_object_unreference(target_obj);
+			 continue;
+		}
+
+		ret = i915_gem_object_set_to_gtt_domain(obj, 1, 1);
+		if (ret != 0)
+			goto err;
+
+		if ((ret = agp_map_subregion(dev_priv->agph,
+		    trunc_page(reloc_offset), PAGE_SIZE, &bsh)) != 0) {
+			DRM_ERROR("map failed...\n");
+			goto err;
+		}
+
+		bus_space_write_4(dev_priv->bst, bsh, reloc_offset & PAGE_MASK,
+		     reloc_val);
+
+		reloc->presumed_offset = target_obj_priv->gtt_offset;
+
+		agp_unmap_subregion(dev_priv->agph, bsh, PAGE_SIZE);
+		drm_gem_object_unreference(target_obj);
+	}
+
+	return 0;
+
+err:
+	/* we always jump to here mid-loop */
+	drm_gem_object_unreference(target_obj);
+	i915_gem_object_unpin(obj);
+	return (ret);
+}
+
+/** Dispatch a batchbuffer to the ring
+ */
+void
+i915_dispatch_gem_execbuffer(struct drm_device *dev,
+    struct drm_i915_gem_execbuffer2 *exec, uint64_t exec_offset)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	uint32_t		 exec_start, exec_len;
+
+	MUTEX_ASSERT_LOCKED(&dev_priv->request_lock);
+	exec_start = (uint32_t)exec_offset + exec->batch_start_offset;
+	exec_len = (uint32_t)exec->batch_len;
+
+	if (IS_I830(dev_priv) || IS_845G(dev_priv)) {
+		BEGIN_LP_RING(6);
+		OUT_RING(MI_BATCH_BUFFER);
+		OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+		OUT_RING(exec_start + exec_len - 4);
+		OUT_RING(MI_NOOP);
+	} else {
+		BEGIN_LP_RING(4);
+		if (IS_I965G(dev_priv)) {
+			OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) |
+			    MI_BATCH_NON_SECURE_I965);
+			OUT_RING(exec_start);
+		} else {
+			OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+			OUT_RING(exec_start | MI_BATCH_NON_SECURE);
+		}
+	}
+
+	/*
+	 * Ensure that the commands in the batch buffer are
+	 * finished before the interrupt fires (from a subsequent request
+	 * added). We get back a seqno representing the execution of the
+	 * current buffer, which we can wait on.  We would like to mitigate
+	 * these interrupts, likely by only creating seqnos occasionally
+	 * (so that we have *some* interrupts representing completion of
+	 * buffers that we can wait on when trying to clear up gtt space).
+	 */
+	OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH);
+	OUT_RING(MI_NOOP);
+	ADVANCE_LP_RING();
+	/*
+	 * move to active associated all previous buffers with the seqno
+	 * that this call will emit. so we don't need the return. If it fails
+	 * then the next seqno will take care of it.
+	 */
+	(void)i915_add_request(dev_priv);
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+}
+
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
+int
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+{
+#if 0
+	struct inteldrm_file	*intel_file = (struct inteldrm_file *)file_priv;
+	u_int32_t		 seqno;
+#endif
+	int			 ret = 0;
+
+	return ret;
+}
+
+int
+i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *exec_list,
+    u_int32_t buffer_count, struct drm_i915_gem_relocation_entry **relocs)
+{
+	u_int32_t	reloc_count = 0, reloc_index = 0, i;
+	int		ret;
+
+	*relocs = NULL;
+	for (i = 0; i < buffer_count; i++) {
+		if (reloc_count + exec_list[i].relocation_count < reloc_count)
+			return (EINVAL);
+		reloc_count += exec_list[i].relocation_count;
+	}
+
+	if (reloc_count == 0)
+		return (0);
+
+	if (SIZE_MAX / reloc_count < sizeof(**relocs))
+		return (EINVAL);
+	*relocs = drm_alloc(reloc_count * sizeof(**relocs));
+	for (i = 0; i < buffer_count; i++) {
+		if ((ret = copyin((void *)(uintptr_t)exec_list[i].relocs_ptr,
+		    &(*relocs)[reloc_index], exec_list[i].relocation_count *
+		    sizeof(**relocs))) != 0) {
+			drm_free(*relocs);
+			*relocs = NULL;
+			return (ret);
+		}
+		reloc_index += exec_list[i].relocation_count;
+	}
+
+	return (0);
+}
+
+int
+i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list,
+    u_int32_t buffer_count, struct drm_i915_gem_relocation_entry *relocs)
+{
+	u_int32_t	reloc_count = 0, i;
+	int		ret = 0;
+
+	if (relocs == NULL)
+		return (0);
+
+	for (i = 0; i < buffer_count; i++) {
+		if ((ret = copyout(&relocs[reloc_count],
+		    (void *)(uintptr_t)exec_list[i].relocs_ptr,
+		    exec_list[i].relocation_count * sizeof(*relocs))) != 0)
+			break;
+		reloc_count += exec_list[i].relocation_count;
+	}
+
+	drm_free(relocs);
+
+	return (ret);
+}
+
+int
+i915_gem_execbuffer2(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc			*dev_priv = dev->dev_private;
+	struct drm_i915_gem_execbuffer2		*args = data;
+	struct drm_i915_gem_exec_object2	*exec_list = NULL;
+	struct drm_i915_gem_relocation_entry	*relocs = NULL;
+	struct inteldrm_obj			*obj_priv, *batch_obj_priv;
+	struct drm_obj				**object_list = NULL;
+	struct drm_obj				*batch_obj, *obj;
+	size_t					 oflow;
+	int					 ret, ret2, i;
+	int					 pinned = 0, pin_tries;
+	uint32_t				 reloc_index;
+
+	/*
+	 * Check for valid execbuffer offset. We can do this early because
+	 * bound object are always page aligned, so only the start offset
+	 * matters. Also check for integer overflow in the batch offset and size
+	 */
+	 if ((args->batch_start_offset | args->batch_len) & 0x7 ||
+	    args->batch_start_offset + args->batch_len < args->batch_len ||
+	    args->batch_start_offset + args->batch_len <
+	    args->batch_start_offset)
+		return (EINVAL);
+
+	if (args->buffer_count < 1) {
+		DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
+		return (EINVAL);
+	}
+	/* Copy in the exec list from userland, check for overflow */
+	oflow = SIZE_MAX / args->buffer_count;
+	if (oflow < sizeof(*exec_list) || oflow < sizeof(*object_list))
+		return (EINVAL);
+	exec_list = drm_alloc(sizeof(*exec_list) * args->buffer_count);
+	object_list = drm_alloc(sizeof(*object_list) * args->buffer_count);
+	if (exec_list == NULL || object_list == NULL) {
+		ret = ENOMEM;
+		goto pre_mutex_err;
+	}
+	ret = copyin((void *)(uintptr_t)args->buffers_ptr, exec_list,
+	    sizeof(*exec_list) * args->buffer_count);
+	if (ret != 0)
+		goto pre_mutex_err;
+
+	ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
+	    &relocs);
+	if (ret != 0)
+		goto pre_mutex_err;
+
+	DRM_LOCK();
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	/* XXX check these before we copyin... but we do need the lock */
+	if (dev_priv->mm.wedged) {
+		ret = EIO;
+		goto unlock;
+	}
+
+	if (dev_priv->mm.suspended) {
+		ret = EBUSY;
+		goto unlock;
+	}
+
+	/* Look up object handles */
+	for (i = 0; i < args->buffer_count; i++) {
+		object_list[i] = drm_gem_object_lookup(dev, file_priv,
+		    exec_list[i].handle);
+		obj = object_list[i];
+		if (obj == NULL) {
+			DRM_ERROR("Invalid object handle %d at index %d\n",
+				   exec_list[i].handle, i);
+			ret = EBADF;
+			goto err;
+		}
+		if (obj->do_flags & I915_IN_EXEC) {
+			DRM_ERROR("Object %p appears more than once in object_list\n",
+			    object_list[i]);
+			ret = EBADF;
+			goto err;
+		}
+		atomic_setbits_int(&obj->do_flags, I915_IN_EXEC);
+	}
+
+	/* Pin and relocate */
+	for (pin_tries = 0; ; pin_tries++) {
+		ret = pinned = 0;
+		reloc_index = 0;
+
+		for (i = 0; i < args->buffer_count; i++) {
+			object_list[i]->pending_read_domains = 0;
+			object_list[i]->pending_write_domain = 0;
+			drm_hold_object(object_list[i]);
+			ret = i915_gem_object_pin_and_relocate(object_list[i],
+			    file_priv, &exec_list[i], &relocs[reloc_index]);
+			if (ret) {
+				drm_unhold_object(object_list[i]);
+				break;
+			}
+			pinned++;
+			reloc_index += exec_list[i].relocation_count;
+		}
+		/* success */
+		if (ret == 0)
+			break;
+
+		/* error other than GTT full, or we've already tried again */
+		if (ret != ENOSPC || pin_tries >= 1)
+			goto err;
+
+		/*
+		 * unpin all of our buffers and unhold them so they can be
+		 * unbound so we can try and refit everything in the aperture.
+		 */
+		for (i = 0; i < pinned; i++) {
+			i915_gem_object_unpin(object_list[i]);
+			drm_unhold_object(object_list[i]);
+		}
+		pinned = 0;
+		/* evict everyone we can from the aperture */
+		ret = i915_gem_evict_everything(dev_priv, 1);
+		if (ret)
+			goto err;
+	}
+
+	/* If we get here all involved objects are referenced, pinned, relocated
+	 * and held. Now we can finish off the exec processing.
+	 *
+	 * First, set the pending read domains for the batch buffer to
+	 * command.
+	 */
+	batch_obj = object_list[args->buffer_count - 1];
+	batch_obj_priv = (struct inteldrm_obj *)batch_obj;
+	if (args->batch_start_offset + args->batch_len > batch_obj->size ||
+	    batch_obj->pending_write_domain) {
+		ret = EINVAL;
+		goto err;
+	}
+	batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	/*
+	 * Zero the global flush/invalidate flags. These will be modified as
+	 * new domains are computed for each object
+	 */
+	dev->invalidate_domains = 0;
+	dev->flush_domains = 0;
+
+	/* Compute new gpu domains and update invalidate/flush */
+	for (i = 0; i < args->buffer_count; i++)
+		i915_gem_object_set_to_gpu_domain(object_list[i]);
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	/* flush and invalidate any domains that need them. */
+	(void)i915_gem_flush(dev_priv, dev->invalidate_domains,
+	    dev->flush_domains);
+
+	/*
+	 * update the write domains, and fence/gpu write accounting information.
+	 * Also do the move to active list here. The lazy seqno accounting will
+	 * make sure that they have the correct seqno. If the add_request
+	 * fails, then we will wait for a later batch (or one added on the
+	 * wait), which will waste some time, but if we're that low on memory
+	 * then we could fail in much worse ways.
+	 */
+	mtx_enter(&dev_priv->request_lock); /* to prevent races on next_seqno */
+	mtx_enter(&dev_priv->list_lock);
+	for (i = 0; i < args->buffer_count; i++) {
+		obj = object_list[i];
+		obj_priv = (struct inteldrm_obj *)obj;
+		drm_lock_obj(obj);
+
+		obj->write_domain = obj->pending_write_domain;
+		/*
+		 * if we have a write domain, add us to the gpu write list
+		 * else we can remove the bit because it has been flushed.
+		 */
+		if (obj->do_flags & I915_GPU_WRITE)
+			TAILQ_REMOVE(&dev_priv->mm.gpu_write_list, obj_priv,
+			     write_list);
+		if (obj->write_domain) {
+			TAILQ_INSERT_TAIL(&dev_priv->mm.gpu_write_list,
+			    obj_priv, write_list);
+			atomic_setbits_int(&obj->do_flags, I915_GPU_WRITE);
+		} else {
+			atomic_clearbits_int(&obj->do_flags,
+			     I915_GPU_WRITE);
+		}
+		/* if this batchbuffer needs a fence, then the object is
+		 * counted as fenced exec. else any outstanding fence waits
+		 * will just wait on the fence last_seqno.
+		 */
+		if (inteldrm_exec_needs_fence(obj_priv)) {
+			atomic_setbits_int(&obj->do_flags,
+			    I915_FENCED_EXEC);
+		} else {
+			atomic_clearbits_int(&obj->do_flags,
+			    I915_FENCED_EXEC);
+		}
+
+		drm_unlock_obj(obj);
+		i915_gem_object_move_to_active(object_list[i]);
+	}
+	mtx_leave(&dev_priv->list_lock);
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	/* Exec the batchbuffer */
+	/*
+	 * XXX make sure that this may never fail by preallocating the request.
+	 */
+	i915_dispatch_gem_execbuffer(dev, args, batch_obj_priv->gtt_offset);
+	mtx_leave(&dev_priv->request_lock);
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	ret = copyout(exec_list, (void *)(uintptr_t)args->buffers_ptr,
+	    sizeof(*exec_list) * args->buffer_count);
+
+err:
+	for (i = 0; i < args->buffer_count; i++) {
+		if (object_list[i] == NULL)
+			break;
+
+		atomic_clearbits_int(&object_list[i]->do_flags, I915_IN_EXEC |
+		    I915_EXEC_NEEDS_FENCE);
+		if (i < pinned) {
+			i915_gem_object_unpin(object_list[i]);
+			drm_unhold_and_unref(object_list[i]);
+		} else {
+			drm_unref(&object_list[i]->uobj);
+		}
+	}
+
+unlock:
+	DRM_UNLOCK();
+
+pre_mutex_err:
+	/* update userlands reloc state. */
+	ret2 = i915_gem_put_relocs_to_user(exec_list,
+	    args->buffer_count, relocs);
+	if (ret2 != 0 && ret == 0)
+		ret = ret2;
+
+	drm_free(object_list);
+	drm_free(exec_list);
+
+	return ret;
+}
+
+int
+i915_gem_object_pin(struct drm_obj *obj, uint32_t alignment, int needs_fence)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	int			 ret;
+
+	DRM_ASSERT_HELD(obj);
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+	/*
+	 * if already bound, but alignment is unsuitable, unbind so we can
+	 * fix it. Similarly if we have constraints due to fence registers,
+	 * adjust if needed. Note that if we are already pinned we may as well
+	 * fail because whatever depends on this alignment will render poorly
+	 * otherwise, so just fail the pin (with a printf so we can fix a
+	 * wrong userland).
+	 */
+	if (obj_priv->dmamap != NULL &&
+	    ((alignment && obj_priv->gtt_offset & (alignment - 1)) ||
+	    obj_priv->gtt_offset & (i915_gem_get_gtt_alignment(obj) - 1) ||
+	    !i915_gem_object_fence_offset_ok(obj, obj_priv->tiling_mode))) {
+		/* if it is already pinned we sanitised the alignment then */
+		KASSERT(obj_priv->pin_count == 0);
+		if ((ret = i915_gem_object_unbind(obj, 1)))
+			return (ret);
+	}
+
+	if (obj_priv->dmamap == NULL) {
+		ret = i915_gem_object_bind_to_gtt(obj, alignment, 1);
+		if (ret != 0)
+			return (ret);
+	}
+
+	/*
+	 * due to lazy fence destruction we may have an invalid fence now.
+	 * So if so, nuke it before we do anything with the gpu.
+	 * XXX 965+ can put this off.. and be faster
+	 */
+	if (obj->do_flags & I915_FENCE_INVALID) {
+		ret= i915_gem_object_put_fence_reg(obj, 1);
+		if (ret)
+			return (ret);
+	}
+	/*
+	 * Pre-965 chips may need a fence register set up in order to
+	 * handle tiling properly. GTT mapping may have blown it away so
+	 * restore.
+	 * With execbuf2 support we don't always need it, but if we do grab
+	 * it.
+	 */
+	if (needs_fence && obj_priv->tiling_mode != I915_TILING_NONE &&
+	    (ret = i915_gem_get_fence_reg(obj, 1)) != 0)
+		return (ret);
+
+	/* If the object is not active and not pending a flush,
+	 * remove it from the inactive list
+	 */
+	if (++obj_priv->pin_count == 1) {
+		atomic_inc(&dev->pin_count);
+		atomic_add(obj->size, &dev->pin_memory);
+		if (!inteldrm_is_active(obj_priv))
+			i915_list_remove(obj_priv);
+	}
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+
+	return (0);
+}
+
+void
+i915_gem_object_unpin(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+	KASSERT(obj_priv->pin_count >= 1);
+	KASSERT(obj_priv->dmamap != NULL);
+	DRM_ASSERT_HELD(obj);
+
+	/* If the object is no longer pinned, and is
+	 * neither active nor being flushed, then stick it on
+	 * the inactive list
+	 */
+	if (--obj_priv->pin_count == 0) {
+		if (!inteldrm_is_active(obj_priv))
+			i915_gem_object_move_to_inactive(obj);
+		atomic_dec(&dev->pin_count);
+		atomic_sub(obj->size, &dev->pin_memory);
+	}
+	inteldrm_verify_inactive(dev_priv, __FILE__, __LINE__);
+}
+
+int
+i915_gem_pin_ioctl(struct drm_device *dev, void *data,
+		   struct drm_file *file_priv)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct drm_i915_gem_pin	*args = data;
+	struct drm_obj		*obj;
+	struct inteldrm_obj	*obj_priv;
+	int			 ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	DRM_LOCK();
+	drm_hold_object(obj);
+
+	obj_priv = (struct inteldrm_obj *)obj;
+	if (i915_obj_purgeable(obj_priv)) {
+		printf("%s: pinning purgeable object\n", __func__);
+		ret = EINVAL;
+		goto out;
+	}
+
+	if (++obj_priv->user_pin_count == 1) {
+		ret = i915_gem_object_pin(obj, args->alignment, 1);
+		if (ret != 0)
+			goto out;
+		inteldrm_set_max_obj_size(dev_priv);
+	}
+
+	/* XXX - flush the CPU caches for pinned objects
+	 * as the X server doesn't manage domains yet
+	 */
+	i915_gem_object_set_to_gtt_domain(obj, 1, 1);
+	args->offset = obj_priv->gtt_offset;
+
+out:
+	drm_unhold_and_unref(obj);
+	DRM_UNLOCK();
+
+	return (ret);
+}
+
+int
+i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
+		     struct drm_file *file_priv)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct drm_i915_gem_pin	*args = data;
+	struct inteldrm_obj	*obj_priv;
+	struct drm_obj		*obj;
+	int			 ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+
+	DRM_LOCK();
+	drm_hold_object(obj);
+
+	obj_priv = (struct inteldrm_obj *)obj;
+	if (obj_priv->user_pin_count == 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	if (--obj_priv->user_pin_count == 0) {
+		i915_gem_object_unpin(obj);
+		inteldrm_set_max_obj_size(dev_priv);
+	}
+
+out:
+	drm_unhold_and_unref(obj);
+	DRM_UNLOCK();
+	return (ret);
+}
+
+int
+i915_gem_busy_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_i915_gem_busy	*args = data;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	int				 ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL) {
+		DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
+			  args->handle);
+		return (EBADF);
+	}
+	
+	obj_priv = (struct inteldrm_obj *)obj;
+	args->busy = inteldrm_is_active(obj_priv);
+	if (args->busy) {
+		/*
+		 * Unconditionally flush objects write domain if they are
+		 * busy. The fact userland is calling this ioctl means that
+		 * it wants to use this buffer sooner rather than later, so
+		 * flushing now shoul reduce latency.
+		 */
+		if (obj->write_domain)
+			(void)i915_gem_flush(dev_priv, obj->write_domain,
+			    obj->write_domain);
+		/*
+		 * Update the active list after the flush otherwise this is
+		 * only updated on a delayed timer. Updating now reduces 
+		 * working set size.
+		 */
+		i915_gem_retire_requests(dev_priv);
+		args->busy = inteldrm_is_active(obj_priv);
+	}
+
+	drm_unref(&obj->uobj);
+	return (ret);
+}
+
+int
+i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
+    struct drm_file *file_priv)
+{
+	struct drm_i915_gem_madvise	*args = data;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	int				 need, ret = 0;
+
+	switch (args->madv) {
+	case I915_MADV_DONTNEED:
+		need = 0;
+		break;
+	case I915_MADV_WILLNEED:
+		need = 1;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+
+	drm_hold_object(obj);
+	obj_priv = (struct inteldrm_obj *)obj;
+
+	/* invalid to madvise on a pinned BO */
+	if (obj_priv->pin_count) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	if (!i915_obj_purged(obj_priv)) {
+		if (need) {
+			atomic_clearbits_int(&obj->do_flags,
+			    I915_DONTNEED);
+		} else {
+			atomic_setbits_int(&obj->do_flags, I915_DONTNEED);
+		}
+	}
+
+
+	/* if the object is no longer bound, discard its backing storage */
+	if (i915_obj_purgeable(obj_priv) && obj_priv->dmamap == NULL)
+		inteldrm_purge_obj(obj);
+
+	args->retained = !i915_obj_purged(obj_priv);
+
+out:
+	drm_unhold_and_unref(obj);
+
+	return (ret);
+}
+
+int
+i915_gem_init_object(struct drm_obj *obj)
+{
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+
+	/*
+	 * We've just allocated pages from the kernel,
+	 * so they've just been written by the CPU with
+	 * zeros. They'll need to be flushed before we
+	 * use them with the GPU.
+	 */
+	obj->write_domain = I915_GEM_DOMAIN_CPU;
+	obj->read_domains = I915_GEM_DOMAIN_CPU;
+
+	/* normal objects don't need special treatment */
+	obj_priv->dma_flags = 0;
+	obj_priv->fence_reg = I915_FENCE_REG_NONE;
+
+	return 0;
+}
+
+/*
+ * NOTE all object unreferences in this driver need to hold the DRM_LOCK(),
+ * because if they free they poke around in driver structures.
+ */
+void
+i915_gem_free_object(struct drm_obj *obj)
+{
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+
+	DRM_ASSERT_HELD(obj);
+	while (obj_priv->pin_count > 0)
+		i915_gem_object_unpin(obj);
+
+	i915_gem_object_unbind(obj, 0);
+	drm_free(obj_priv->bit_17);
+	obj_priv->bit_17 = NULL;
+	/* XXX dmatag went away? */
+}
+
+/* Clear out the inactive list and unbind everything in it. */
+int
+i915_gem_evict_inactive(struct inteldrm_softc *dev_priv, int interruptible)
+{
+	struct inteldrm_obj	*obj_priv;
+	int			 ret = 0;
+
+	mtx_enter(&dev_priv->list_lock);
+	while ((obj_priv = TAILQ_FIRST(&dev_priv->mm.inactive_list)) != NULL) {
+		if (obj_priv->pin_count != 0) {
+			ret = EINVAL;
+			DRM_ERROR("Pinned object in unbind list\n");
+			break;
+		}
+		/* reference it so that we can frob it outside the lock */
+		drm_ref(&obj_priv->obj.uobj);
+		mtx_leave(&dev_priv->list_lock);
+
+		drm_hold_object(&obj_priv->obj);
+		ret = i915_gem_object_unbind(&obj_priv->obj, interruptible);
+		drm_unhold_and_unref(&obj_priv->obj);
+
+		mtx_enter(&dev_priv->list_lock);
+		if (ret)
+			break;
+	}
+	mtx_leave(&dev_priv->list_lock);
+
+	return (ret);
+}
+
+void
+inteldrm_quiesce(struct inteldrm_softc *dev_priv)
+{
+	/*
+	 * Right now we depend on X vt switching, so we should be
+	 * already suspended, but fallbacks may fault, etc.
+	 * Since we can't readback the gtt to reset what we have, make
+	 * sure that everything is unbound.
+	 */
+	KASSERT(dev_priv->mm.suspended);
+	KASSERT(dev_priv->ring.ring_obj == NULL);
+	atomic_setbits_int(&dev_priv->sc_flags, INTELDRM_QUIET);
+	while (dev_priv->entries)
+		tsleep(&dev_priv->entries, 0, "intelquiet", 0);
+	/*
+	 * nothing should be dirty WRT the chip, only stuff that's bound
+	 * for gtt mapping. Nothing should be pinned over vt switch, if it
+	 * is then rendering corruption will occur due to api misuse, shame.
+	 */
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.flushing_list));
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.active_list));
+	/* Disabled because root could panic the kernel if this was enabled */
+	/* KASSERT(dev->pin_count == 0); */
+
+	/* can't fail since uninterruptible */
+	(void)i915_gem_evict_inactive(dev_priv, 0);
+}
+
+int
+i915_gem_idle(struct inteldrm_softc *dev_priv)
+{
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	int			 ret;
+
+	DRM_LOCK();
+	if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
+		DRM_UNLOCK();
+		return (0);
+	}
+
+	/*
+	 * To idle the gpu, flush anything pending then unbind the whole
+	 * shebang. If we're wedged, assume that the reset workq will clear
+	 * everything out and continue as normal.
+	 */
+	if ((ret = i915_gem_evict_everything(dev_priv, 1)) != 0 &&
+	    ret != ENOSPC && ret != EIO) {
+		DRM_UNLOCK();
+		return (ret);
+	}
+
+	/* Hack!  Don't let anybody do execbuf while we don't control the chip.
+	 * We need to replace this with a semaphore, or something.
+	 */
+	dev_priv->mm.suspended = 1;
+	/* if we hung then the timer alredy fired. */
+	timeout_del(&dev_priv->mm.hang_timer);
+
+	inteldrm_update_ring(dev_priv);
+	i915_gem_cleanup_ringbuffer(dev_priv);
+	DRM_UNLOCK();
+
+	/* this should be idle now */
+	timeout_del(&dev_priv->mm.retire_timer);
+
+	return 0;
+}
+
+int
+i915_gem_init_hws(struct inteldrm_softc *dev_priv)
+{
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	struct drm_obj		*obj;
+	struct inteldrm_obj	*obj_priv;
+	int			 ret;
+
+	/* If we need a physical address for the status page, it's already
+	 * initialized at driver load time.
+	 */
+	if (!I915_NEED_GFX_HWS(dev_priv))
+		return 0;
+
+	obj = drm_gem_object_alloc(dev, 4096);
+	if (obj == NULL) {
+		DRM_ERROR("Failed to allocate status page\n");
+		return (ENOMEM);
+	}
+	obj_priv = (struct inteldrm_obj *)obj;
+	drm_hold_object(obj);
+	/*
+	 * snooped gtt mapping please .
+	 * Normally this flag is only to dmamem_map, but it's been overloaded
+	 * for the agp mapping
+	 */
+	obj_priv->dma_flags = BUS_DMA_COHERENT | BUS_DMA_READ;
+
+	ret = i915_gem_object_pin(obj, 4096, 0);
+	if (ret != 0) {
+		drm_unhold_and_unref(obj);
+		return ret;
+	}
+
+	dev_priv->hw_status_page = (void *)vm_map_min(kernel_map);
+	obj->uao->pgops->pgo_reference(obj->uao);
+	ret = uvm_map(kernel_map, (vaddr_t *)&dev_priv->hw_status_page,
+	    PAGE_SIZE, obj->uao, 0, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
+	    UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
+	if (ret != 0) {
+		DRM_ERROR("Failed to map status page.\n");
+		obj->uao->pgops->pgo_detach(obj->uao);
+		i915_gem_object_unpin(obj);
+		drm_unhold_and_unref(obj);
+		return (EINVAL);
+	}
+	drm_unhold_object(obj);
+	dev_priv->hws_obj = obj;
+	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+	I915_WRITE(HWS_PGA, obj_priv->gtt_offset);
+	I915_READ(HWS_PGA); /* posting read */
+	DRM_DEBUG("hws offset: 0x%08jx\n", (uintmax_t)obj_priv->gtt_offset);
+
+	return 0;
+}
+
+void
+i915_gem_cleanup_hws(struct inteldrm_softc *dev_priv)
+{
+	struct drm_obj		*obj;
+
+	if (!I915_NEED_GFX_HWS(dev_priv) || dev_priv->hws_obj == NULL)
+		return;
+
+	obj = dev_priv->hws_obj;
+
+	uvm_unmap(kernel_map, (vaddr_t)dev_priv->hw_status_page,
+	    (vaddr_t)dev_priv->hw_status_page + PAGE_SIZE);
+	dev_priv->hw_status_page = NULL;
+	drm_hold_object(obj);
+	i915_gem_object_unpin(obj);
+	drm_unhold_and_unref(obj);
+	dev_priv->hws_obj = NULL;
+
+	/* Write high address into HWS_PGA when disabling. */
+	I915_WRITE(HWS_PGA, 0x1ffff000);
+}
+
+int
+i915_gem_init_ringbuffer(struct inteldrm_softc *dev_priv)
+{
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	struct drm_obj		*obj;
+	struct inteldrm_obj	*obj_priv;
+	int			 ret;
+
+	ret = i915_gem_init_hws(dev_priv);
+	if (ret != 0)
+		return ret;
+
+	obj = drm_gem_object_alloc(dev, 128 * 1024);
+	if (obj == NULL) {
+		DRM_ERROR("Failed to allocate ringbuffer\n");
+		ret = ENOMEM;
+		goto delhws;
+	}
+	drm_hold_object(obj);
+	obj_priv = (struct inteldrm_obj *)obj;
+
+	ret = i915_gem_object_pin(obj, 4096, 0);
+	if (ret != 0)
+		goto unref;
+
+	/* Set up the kernel mapping for the ring. */
+	dev_priv->ring.size = obj->size;
+
+	if ((ret = agp_map_subregion(dev_priv->agph, obj_priv->gtt_offset,
+	    obj->size, &dev_priv->ring.bsh)) != 0) {
+		DRM_INFO("can't map ringbuffer\n");
+		goto unpin;
+	}
+	dev_priv->ring.ring_obj = obj;
+
+	if ((ret = inteldrm_start_ring(dev_priv)) != 0)
+		goto unmap;
+
+	drm_unhold_object(obj);
+	return (0);
+
+unmap:
+	agp_unmap_subregion(dev_priv->agph, dev_priv->ring.bsh, obj->size);
+unpin:
+	memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+	i915_gem_object_unpin(obj);
+unref:
+	drm_unhold_and_unref(obj);
+delhws:
+	i915_gem_cleanup_hws(dev_priv);
+	return (ret);
+}
+
+int
+inteldrm_start_ring(struct inteldrm_softc *dev_priv)
+{
+	struct drm_obj		*obj = dev_priv->ring.ring_obj;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	u_int32_t		 head;
+
+	/* Stop the ring if it's running. */
+	I915_WRITE(PRB0_CTL, 0);
+	I915_WRITE(PRB0_TAIL, 0);
+	I915_WRITE(PRB0_HEAD, 0);
+
+	/* Initialize the ring. */
+	I915_WRITE(PRB0_START, obj_priv->gtt_offset);
+	head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+
+	/* G45 ring initialisation fails to reset head to zero */
+	if (head != 0) {
+		I915_WRITE(PRB0_HEAD, 0);
+		DRM_DEBUG("Forced ring head to zero ctl %08x head %08x"
+		    "tail %08x start %08x\n", I915_READ(PRB0_CTL),
+		    I915_READ(PRB0_HEAD), I915_READ(PRB0_TAIL),
+		    I915_READ(PRB0_START));
+	}
+
+	I915_WRITE(PRB0_CTL, ((obj->size - 4096) & RING_NR_PAGES) |
+	    RING_NO_REPORT | RING_VALID);
+
+	head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+	/* If ring head still != 0, the ring is dead */
+	if (head != 0) {
+		DRM_ERROR("Ring initialisation failed: ctl %08x head %08x"
+		    "tail %08x start %08x\n", I915_READ(PRB0_CTL),
+		    I915_READ(PRB0_HEAD), I915_READ(PRB0_TAIL),
+		    I915_READ(PRB0_START));
+		return (EIO);
+	}
+
+	/* Update our cache of the ring state */
+	inteldrm_update_ring(dev_priv);
+
+	if (IS_I9XX(dev_priv) && !IS_GEN3(dev_priv))
+		I915_WRITE(MI_MODE, (VS_TIMER_DISPATCH) << 15 |
+		    VS_TIMER_DISPATCH);
+
+	return (0);
+}
+
+void
+i915_gem_cleanup_ringbuffer(struct inteldrm_softc *dev_priv)
+{
+	if (dev_priv->ring.ring_obj == NULL)
+		return;
+	agp_unmap_subregion(dev_priv->agph, dev_priv->ring.bsh,
+	    dev_priv->ring.ring_obj->size);
+	drm_hold_object(dev_priv->ring.ring_obj);
+	i915_gem_object_unpin(dev_priv->ring.ring_obj);
+	drm_unhold_and_unref(dev_priv->ring.ring_obj);
+	dev_priv->ring.ring_obj = NULL;
+	memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+
+	i915_gem_cleanup_hws(dev_priv);
+}
+
+int
+i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
+		       struct drm_file *file_priv)
+{
+	struct inteldrm_softc *dev_priv = dev->dev_private;
+	int ret;
+
+	if (dev_priv->mm.wedged) {
+		DRM_ERROR("Reenabling wedged hardware, good luck\n");
+		dev_priv->mm.wedged = 0;
+	}
+
+
+	DRM_LOCK();
+	dev_priv->mm.suspended = 0;
+
+	ret = i915_gem_init_ringbuffer(dev_priv);
+	if (ret != 0) {
+		DRM_UNLOCK();
+		return (ret);
+	}
+
+	/* gtt mapping means that the inactive list may not be empty */
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.active_list));
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.flushing_list));
+	KASSERT(TAILQ_EMPTY(&dev_priv->mm.request_list));
+	DRM_UNLOCK();
+
+	drm_irq_install(dev);
+
+	return (0);
+}
+
+int
+i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
+		       struct drm_file *file_priv)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	int			 ret;
+
+	/* don't unistall if we fail, repeat calls on failure will screw us */
+	if ((ret = i915_gem_idle(dev_priv)) == 0)
+		drm_irq_uninstall(dev);
+	return (ret);
+}
+
+void
+inteldrm_timeout(void *arg)
+{
+	struct inteldrm_softc	*dev_priv = arg;
+
+	if (workq_add_task(dev_priv->workq, 0, i915_gem_retire_work_handler,
+	    dev_priv, NULL) == ENOMEM)
+		DRM_ERROR("failed to run retire handler\n");
+}
+
+/*
+ * handle hung hardware, or error interrupts. for now print debug info.
+ */
+void
+inteldrm_error(struct inteldrm_softc *dev_priv)
+{
+	u_int32_t	eir, ipeir;
+	u_int8_t	reset = GDRST_RENDER;
+	const char	*errbitstr;
+#if defined(__NetBSD__)
+	char		errbuf[128];
+#endif /* defined(__NetBSD__) */
+
+	eir = I915_READ(EIR);
+	if (eir == 0)
+		return;
+
+	if (IS_IRONLAKE(dev_priv)) {
+		errbitstr = "\20\x05PTEE\x04MPVE\x03CPVE";
+	} else if (IS_G4X(dev_priv)) {
+		errbitstr = "\20\x10 BCSINSTERR\x06PTEERR\x05MPVERR\x04CPVERR"
+		     "\x03 BCSPTEERR\x02REFRESHERR\x01INSTERR";
+	} else {
+		errbitstr = "\20\x5PTEERR\x2REFRESHERR\x1INSTERR";
+	}
+
+#if !defined(__NetBSD__)
+	printf("render error detected, EIR: %b\n", eir, errbitstr);
+#else /* !defined(__NetBSD__) */
+	snprintb(errbuf, sizeof(errbuf), errbitstr, eir);
+	printf("render error detected, EIR: %s\n", errbuf);
+#endif /* !defined(__NetBSD__) */
+	if (IS_IRONLAKE(dev_priv)) {
+		if (eir & GT_ERROR_PTE) {
+			dev_priv->mm.wedged = 1;
+			reset = GDRST_FULL;
+		}
+	} else {
+		if (IS_G4X(dev_priv)) {
+			if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
+				printf("  IPEIR: 0x%08x\n",
+				    I915_READ(IPEIR_I965));
+				printf("  IPEHR: 0x%08x\n",
+				    I915_READ(IPEHR_I965));
+				printf("  INSTDONE: 0x%08x\n",
+				    I915_READ(INSTDONE_I965));
+				printf("  INSTPS: 0x%08x\n",
+				    I915_READ(INSTPS));
+				printf("  INSTDONE1: 0x%08x\n",
+				    I915_READ(INSTDONE1));
+				printf("  ACTHD: 0x%08x\n",
+				    I915_READ(ACTHD_I965));
+			}
+			if (eir & GM45_ERROR_PAGE_TABLE) {
+				printf("  PGTBL_ER: 0x%08x\n",
+				    I915_READ(PGTBL_ER));
+				dev_priv->mm.wedged = 1;
+				reset = GDRST_FULL;
+
+			}
+		} else if (IS_I9XX(dev_priv) && eir & I915_ERROR_PAGE_TABLE) {
+			printf("  PGTBL_ER: 0x%08x\n", I915_READ(PGTBL_ER));
+			dev_priv->mm.wedged = 1;
+			reset = GDRST_FULL;
+		}
+		if (eir & I915_ERROR_MEMORY_REFRESH) {
+			printf("PIPEASTAT: 0x%08x\n",
+			    I915_READ(PIPEASTAT));
+			printf("PIPEBSTAT: 0x%08x\n",
+			    I915_READ(PIPEBSTAT));
+		}
+		if (eir & I915_ERROR_INSTRUCTION) {
+			printf("  INSTPM: 0x%08x\n",
+			       I915_READ(INSTPM));
+			if (!IS_I965G(dev_priv)) {
+				ipeir = I915_READ(IPEIR);
+
+				printf("  IPEIR: 0x%08x\n",
+				       I915_READ(IPEIR));
+				printf("  IPEHR: 0x%08x\n",
+					   I915_READ(IPEHR));
+				printf("  INSTDONE: 0x%08x\n",
+					   I915_READ(INSTDONE));
+				printf("  ACTHD: 0x%08x\n",
+					   I915_READ(ACTHD));
+				I915_WRITE(IPEIR, ipeir);
+				(void)I915_READ(IPEIR);
+			} else {
+				ipeir = I915_READ(IPEIR_I965);
+
+				printf("  IPEIR: 0x%08x\n",
+				       I915_READ(IPEIR_I965));
+				printf("  IPEHR: 0x%08x\n",
+				       I915_READ(IPEHR_I965));
+				printf("  INSTDONE: 0x%08x\n",
+				       I915_READ(INSTDONE_I965));
+				printf("  INSTPS: 0x%08x\n",
+				       I915_READ(INSTPS));
+				printf("  INSTDONE1: 0x%08x\n",
+				       I915_READ(INSTDONE1));
+				printf("  ACTHD: 0x%08x\n",
+				       I915_READ(ACTHD_I965));
+				I915_WRITE(IPEIR_I965, ipeir);
+				(void)I915_READ(IPEIR_I965);
+			}
+		}
+	}
+
+	I915_WRITE(EIR, eir);
+	eir = I915_READ(EIR);
+	/*
+	 * nasty errors don't clear and need a reset, mask them until we reset
+	 * else we'll get infinite interrupt storms.
+	 */
+	if (eir) {
+		if (dev_priv->mm.wedged == 0)
+			DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
+		I915_WRITE(EMR, I915_READ(EMR) | eir);
+		if (IS_IRONLAKE(dev_priv)) {
+			I915_WRITE(GTIIR, GT_MASTER_ERROR);
+		} else {
+			I915_WRITE(IIR,
+			    I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+		}
+	}
+	/*
+	 * if it was a pagetable error, or we were called from hangcheck, then
+	 * reset the gpu.
+	 */
+	if (dev_priv->mm.wedged && workq_add_task(dev_priv->workq, 0,
+	    inteldrm_hung, dev_priv, (void *)(uintptr_t)reset) == ENOMEM)
+		DRM_INFO("failed to schedule reset task\n");
+
+}
+
+void
+inteldrm_hung(void *arg, void *reset_type)
+{
+	struct inteldrm_softc	*dev_priv = arg;
+	struct drm_device	*dev = (struct drm_device *)dev_priv->drmdev;
+	struct inteldrm_obj	*obj_priv;
+	u_int8_t		 reset = (u_int8_t)(uintptr_t)reset_type;
+
+	DRM_LOCK();
+	if (HAS_RESET(dev_priv)) {
+		DRM_INFO("resetting gpu: ");
+		inteldrm_965_reset(dev_priv, reset);
+		printf("done!\n");
+	} else
+		printf("no reset function for chipset.\n");
+
+	/*
+	 * Clear out all of the requests and make everything inactive.
+	 */
+	i915_gem_retire_requests(dev_priv);
+
+	/*
+	 * Clear the active and flushing lists to inactive. Since
+	 * we've reset the hardware then they're not going to get
+	 * flushed or completed otherwise. nuke the domains since
+	 * they're now irrelavent.
+	 */
+	mtx_enter(&dev_priv->list_lock);
+	while ((obj_priv = TAILQ_FIRST(&dev_priv->mm.flushing_list)) != NULL) {
+		drm_lock_obj(&obj_priv->obj);
+		if (obj_priv->obj.write_domain & I915_GEM_GPU_DOMAINS) {
+			TAILQ_REMOVE(&dev_priv->mm.gpu_write_list,
+			    obj_priv, write_list);
+			atomic_clearbits_int(&obj_priv->obj.do_flags,
+			    I915_GPU_WRITE);
+			obj_priv->obj.write_domain &= ~I915_GEM_GPU_DOMAINS;
+		}
+		/* unlocks object and list */
+		i915_gem_object_move_to_inactive_locked(&obj_priv->obj);
+		mtx_enter(&dev_priv->list_lock);
+	}
+	mtx_leave(&dev_priv->list_lock);
+
+	/* unbind everything */
+	(void)i915_gem_evict_inactive(dev_priv, 0);
+
+	if (HAS_RESET(dev_priv))
+		dev_priv->mm.wedged = 0;
+	DRM_UNLOCK();
+}
+
+void
+inteldrm_hangcheck(void *arg)
+{
+	struct inteldrm_softc	*dev_priv = arg;
+	u_int32_t		 acthd, instdone, instdone1;
+
+	/* are we idle? no requests, or ring is empty */
+	if (TAILQ_EMPTY(&dev_priv->mm.request_list) ||
+	    (I915_READ(PRB0_HEAD) & HEAD_ADDR) ==
+	    (I915_READ(PRB0_TAIL) & TAIL_ADDR)) {
+		dev_priv->mm.hang_cnt = 0;
+		return;
+	}
+
+	if (IS_I965G(dev_priv)) {
+		acthd = I915_READ(ACTHD_I965);
+		instdone = I915_READ(INSTDONE_I965);
+		instdone1 = I915_READ(INSTDONE1);
+	} else {
+		acthd = I915_READ(ACTHD);
+		instdone = I915_READ(INSTDONE);
+		instdone1 = 0;
+	}
+
+	/* if we've hit ourselves before and the hardware hasn't moved, hung. */
+	if (dev_priv->mm.last_acthd == acthd &&
+	    dev_priv->mm.last_instdone == instdone &&
+	    dev_priv->mm.last_instdone1 == instdone1) {
+		/* if that's twice we didn't hit it, then we're hung */
+		if (++dev_priv->mm.hang_cnt >= 2) {
+			if (!IS_GEN2(dev_priv)) {
+				u_int32_t tmp = I915_READ(PRB0_CTL);
+				if (tmp & RING_WAIT) {
+					I915_WRITE(PRB0_CTL, tmp);
+					(void)I915_READ(PRB0_CTL);
+					goto out;
+				}
+			}
+			dev_priv->mm.hang_cnt = 0;
+			/* XXX atomic */
+			dev_priv->mm.wedged = 1; 
+			DRM_INFO("gpu hung!\n");
+			/* XXX locking */
+			mtx_enter(&dev_priv->user_irq_lock);
+#if !defined(__NetBSD__)
+			wakeup(dev_priv);
+#else /* !defined(__NetBSD__) */
+			cv_broadcast(&dev_priv->condvar);
+#endif /* !defined(__NetBSD__) */
+			mtx_leave(&dev_priv->user_irq_lock);
+			inteldrm_error(dev_priv);
+			return;
+		}
+	} else {
+		dev_priv->mm.hang_cnt = 0;
+
+		dev_priv->mm.last_acthd = acthd;
+		dev_priv->mm.last_instdone = instdone;
+		dev_priv->mm.last_instdone1 = instdone1;
+	}
+out:
+	/* Set ourselves up again, in case we haven't added another batch */
+	timeout_add_msec(&dev_priv->mm.hang_timer, 750);
+}
+
+void
+i915_move_to_tail(struct inteldrm_obj *obj_priv, struct i915_gem_list *head)
+{
+	i915_list_remove(obj_priv);
+	TAILQ_INSERT_TAIL(head, obj_priv, list);
+	obj_priv->current_list = head;
+}
+
+void
+i915_list_remove(struct inteldrm_obj *obj_priv)
+{
+	if (obj_priv->current_list != NULL)
+		TAILQ_REMOVE(obj_priv->current_list, obj_priv, list);
+	obj_priv->current_list = NULL;
+}
+
+/*
+ *
+ * Support for managing tiling state of buffer objects.
+ *
+ * The idea behind tiling is to increase cache hit rates by rearranging
+ * pixel data so that a group of pixel accesses are in the same cacheline.
+ * Performance improvement from doing this on the back/depth buffer are on
+ * the order of 30%.
+ *
+ * Intel architectures make this somewhat more complicated, though, by
+ * adjustments made to addressing of data when the memory is in interleaved
+ * mode (matched pairs of DIMMS) to improve memory bandwidth.
+ * For interleaved memory, the CPU sends every sequential 64 bytes
+ * to an alternate memory channel so it can get the bandwidth from both.
+ *
+ * The GPU also rearranges its accesses for increased bandwidth to interleaved
+ * memory, and it matches what the CPU does for non-tiled.  However, when tiled
+ * it does it a little differently, since one walks addresses not just in the
+ * X direction but also Y.  So, along with alternating channels when bit
+ * 6 of the address flips, it also alternates when other bits flip --  Bits 9
+ * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
+ * are common to both the 915 and 965-class hardware.
+ *
+ * The CPU also sometimes XORs in higher bits as well, to improve
+ * bandwidth doing strided access like we do so frequently in graphics.  This
+ * is called "Channel XOR Randomization" in the MCH documentation.  The result
+ * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
+ * decode.
+ *
+ * All of this bit 6 XORing has an effect on our memory management,
+ * as we need to make sure that the 3d driver can correctly address object
+ * contents.
+ *
+ * If we don't have interleaved memory, all tiling is safe and no swizzling is
+ * required.
+ *
+ * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
+ * 17 is not just a page offset, so as we page an object out and back in,
+ * individual pages in it will have different bit 17 addresses, resulting in
+ * each 64 bytes being swapped with its neighbor!
+ *
+ * Otherwise, if interleaved, we have to tell the 3d driver what the address
+ * swizzling it needs to do is, since it's writing with the CPU to the pages
+ * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
+ * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
+ * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
+ * to match what the GPU expects.
+ */
+
+#define MCHBAR_I915	0x44
+#define MCHBAR_I965	0x48
+#define	MCHBAR_SIZE	(4*4096)
+
+#define	DEVEN_REG	0x54
+#define	DEVEN_MCHBAR_EN	(1 << 28)
+
+
+/*
+ * Check the MCHBAR on the host bridge is enabled, and if not allocate it.
+ * we do not need to actually map it because we access the bar through it's
+ * mirror on the IGD, however, if it is disabled or not allocated then
+ * the mirror does not work. *sigh*.
+ *
+ * we return a trinary state:
+ * 0 = already enabled, or can not enable
+ * 1 = enabled, needs disable
+ * 2 = enabled, needs disable and free.
+ */
+int
+inteldrm_setup_mchbar(struct inteldrm_softc *dev_priv,
+#if !defined(__NetBSD__)
+    struct pci_attach_args *bpa)
+#else /* !defined(__NetBSD__) */
+    struct pci_attach_args *bpa, bus_space_handle_t *mchbsh)
+#endif /* !defined(__NetBSD__) */
+{
+	u_int64_t	mchbar_addr;
+	pcireg_t	tmp, low, high = 0;
+	u_long		addr;
+	int		reg = IS_I965G(dev_priv) ? MCHBAR_I965 : MCHBAR_I915;
+	int		ret = 1, enabled = 0;
+
+	if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
+		tmp = pci_conf_read(bpa->pa_pc, bpa->pa_tag, DEVEN_REG);
+		enabled = !!(tmp & DEVEN_MCHBAR_EN);
+	} else {
+		tmp = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg);
+		enabled = tmp & 1;
+	}
+
+	if (enabled) {
+		return (0);
+	}
+
+	if (IS_I965G(dev_priv))
+		high = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg + 4);
+	low = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg);
+	mchbar_addr = ((u_int64_t)high << 32) | low;
+
+	/*
+	 * XXX need to check to see if it's allocated in the pci resources,
+	 * right now we just check to see if there's any address there
+	 *
+	 * if there's no address, then we allocate one.
+	 * note that we can't just use pci_mapreg_map here since some intel
+	 * BARs are special in that they set bit 0 to show they're enabled,
+	 * this is not handled by generic pci code.
+	 */
+	if (mchbar_addr == 0) {
+		addr = (u_long)mchbar_addr;
+#if !defined(__NetBSD__)
+		if (bpa->pa_memex == NULL || extent_alloc(bpa->pa_memex,
+	            MCHBAR_SIZE, MCHBAR_SIZE, 0, 0, 0, &addr)) {
+#else /* !defined(__NetBSD__) */
+		if (bus_space_alloc(bpa->pa_memt, 0, 0xffffffff,
+		    MCHBAR_SIZE, MCHBAR_SIZE, 0, 0, &addr, mchbsh)) {
+#endif /* !defined(__NetBSD__) */
+			return (0); /* just say we don't need to disable */
+		} else {
+			mchbar_addr = addr;
+			ret = 2;
+			/* We've allocated it, now fill in the BAR again */
+			if (IS_I965G(dev_priv))
+				pci_conf_write(bpa->pa_pc, bpa->pa_tag,
+				    reg + 4, upper_32_bits(mchbar_addr));
+			pci_conf_write(bpa->pa_pc, bpa->pa_tag,
+			    reg, mchbar_addr & 0xffffffff);
+		}
+	}
+	/* set the enable bit */
+	if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
+		pci_conf_write(bpa->pa_pc, bpa->pa_tag, DEVEN_REG,
+		    tmp | DEVEN_MCHBAR_EN);
+	} else {
+		tmp = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg);
+		pci_conf_write(bpa->pa_pc, bpa->pa_tag, reg, tmp | 1);
+	}
+
+	return (ret);
+}
+
+/*
+ * we take the trinary returned from inteldrm_setup_mchbar and clean up after
+ * it.
+ */
+void
+inteldrm_teardown_mchbar(struct inteldrm_softc *dev_priv,
+#if !defined(__NetBSD__)
+    struct pci_attach_args *bpa, int disable)
+#else /* !defined(__NetBSD__) */
+    struct pci_attach_args *bpa, int disable, bus_space_handle_t mchbsh)
+#endif /* !defined(__NetBSD__) */
+{
+	u_int64_t	mchbar_addr;
+	pcireg_t	tmp, low, high = 0;
+	int		reg = IS_I965G(dev_priv) ? MCHBAR_I965 : MCHBAR_I915;
+
+	switch(disable) {
+	case 2:
+		if (IS_I965G(dev_priv))
+			high = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg + 4);
+		low = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg);
+		mchbar_addr = ((u_int64_t)high << 32) | low;
+#if !defined(__NetBSD__)
+		if (bpa->pa_memex)
+			extent_free(bpa->pa_memex, mchbar_addr, MCHBAR_SIZE, 0);
+#else /* !defined(__NetBSD__) */
+		bus_space_free(bpa->pa_memt, mchbsh, MCHBAR_SIZE);
+#endif /* !defined(__NetBSD__) */
+		/* FALLTHROUGH */
+	case 1:
+		if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
+			tmp = pci_conf_read(bpa->pa_pc, bpa->pa_tag, DEVEN_REG);
+			tmp &= ~DEVEN_MCHBAR_EN;
+			pci_conf_write(bpa->pa_pc, bpa->pa_tag, DEVEN_REG, tmp);
+		} else {
+			tmp = pci_conf_read(bpa->pa_pc, bpa->pa_tag, reg);
+			tmp &= ~1;
+			pci_conf_write(bpa->pa_pc, bpa->pa_tag, reg, tmp);
+		}
+		break;
+	case 0:
+	default:
+		break;
+	};
+}
+
+/**
+ * Detects bit 6 swizzling of address lookup between IGD access and CPU
+ * access through main memory.
+ */
+void
+inteldrm_detect_bit_6_swizzle(struct inteldrm_softc *dev_priv,
+    struct pci_attach_args *bpa)
+{
+	uint32_t	swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+	uint32_t	swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+	int		need_disable;
+
+	if (!IS_I9XX(dev_priv)) {
+		/* As far as we know, the 865 doesn't have these bit 6
+		 * swizzling issues.
+		 */
+		swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+		swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+	} else if (HAS_PCH_SPLIT(dev_priv)) {
+		/*
+		 * On ironlake and sandybridge the swizzling is the same
+		 * no matter what the DRAM config
+		 */
+		swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+		swizzle_y = I915_BIT_6_SWIZZLE_9;
+	} else if (IS_MOBILE(dev_priv)) {
+		uint32_t dcc;
+#if defined(__NetBSD__)
+		bus_space_handle_t mchbsh;
+#endif /* defined(__NetBSD__) */
+
+		/* try to enable MCHBAR, a lot of biosen disable it */
+#if !defined(__NetBSD__)
+		need_disable = inteldrm_setup_mchbar(dev_priv, bpa);
+#else /* !defined(__NetBSD__) */
+		need_disable = inteldrm_setup_mchbar(dev_priv, bpa, &mchbsh);
+#endif /* !defined(__NetBSD__) */
+
+		/* On 915-945 and GM965, channel interleave by the CPU is
+		 * determined by DCC.  The CPU will alternate based on bit 6
+		 * in interleaved mode, and the GPU will then also alternate
+		 * on bit 6, 9, and 10 for X, but the CPU may also optionally
+		 * alternate based on bit 17 (XOR not disabled and XOR
+		 * bit == 17).
+		 */
+		dcc = I915_READ(DCC);
+		switch (dcc & DCC_ADDRESSING_MODE_MASK) {
+		case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
+		case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
+			swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+			swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+			break;
+		case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
+			if (dcc & DCC_CHANNEL_XOR_DISABLE) {
+				/* This is the base swizzling by the GPU for
+				 * tiled buffers.
+				 */
+				swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+				swizzle_y = I915_BIT_6_SWIZZLE_9;
+			} else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
+				/* Bit 11 swizzling by the CPU in addition. */
+				swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
+				swizzle_y = I915_BIT_6_SWIZZLE_9_11;
+			} else {
+				/* Bit 17 swizzling by the CPU in addition. */
+				swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
+				swizzle_y = I915_BIT_6_SWIZZLE_9_17;
+			}
+			break;
+		}
+		if (dcc == 0xffffffff) {
+			DRM_ERROR("Couldn't read from MCHBAR.  "
+				  "Disabling tiling.\n");
+			swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+			swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
+		}
+
+#if !defined(__NetBSD__)
+		inteldrm_teardown_mchbar(dev_priv, bpa, need_disable);
+#else /* !defined(__NetBSD__) */
+		inteldrm_teardown_mchbar(dev_priv, bpa, need_disable, mchbsh);
+#endif /* !defined(__NetBSD__) */
+	} else {
+		/* The 965, G33, and newer, have a very flexible memory
+		 * configuration. It will enable dual-channel mode
+		 * (interleaving) on as much memory as it can, and the GPU
+		 * will additionally sometimes enable different bit 6
+		 * swizzling for tiled objects from the CPU.
+		 *
+		 * Here's what I found on G965:
+		 *
+		 *    slot fill			memory size	swizzling
+		 * 0A   0B	1A	1B	1-ch	2-ch
+		 * 512	0	0	0	512	0	O
+		 * 512	0	512	0	16	1008	X
+		 * 512	0	0	512	16	1008	X
+		 * 0	512	0	512	16	1008	X
+		 * 1024	1024	1024	0	2048	1024	O
+		 *
+		 * We could probably detect this based on either the DRB
+		 * matching, which was the case for the swizzling required in
+		 * the table above, or from the 1-ch value being less than
+		 * the minimum size of a rank.
+		 */
+		if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
+			swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+			swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+		} else {
+			swizzle_x = I915_BIT_6_SWIZZLE_9_10;
+			swizzle_y = I915_BIT_6_SWIZZLE_9;
+		}
+	}
+
+	dev_priv->mm.bit_6_swizzle_x = swizzle_x;
+	dev_priv->mm.bit_6_swizzle_y = swizzle_y;
+}
+
+int
+inteldrm_swizzle_page(struct vm_page *pg)
+{
+	vaddr_t	 va;
+	int	 i;
+	u_int8_t temp[64], *vaddr;
+
+#if defined (__HAVE_PMAP_DIRECT)
+	va = pmap_map_direct(pg);
+#else
+#if !defined(__NetBSD__)
+	va = uvm_km_valloc(kernel_map, PAGE_SIZE);
+#else /* !defined(__NetBSD__) */
+	va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY);
+#endif /* !defined(__NetBSD__) */
+	if (va == 0)
+		return (ENOMEM);
+#if !defined(__NetBSD__)
+	pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), UVM_PROT_RW);
+#else /* !defined(__NetBSD__) */
+	pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
+	    VM_PROT_READ | VM_PROT_WRITE, PMAP_WRITE_COMBINE);
+#endif /* !defined(__NetBSD__) */
+	pmap_update(pmap_kernel());
+#endif
+	vaddr = (u_int8_t *)va;
+
+	for (i = 0; i < PAGE_SIZE; i += 128) {
+		memcpy(temp, &vaddr[i], 64);
+		memcpy(&vaddr[i], &vaddr[i + 64], 64);
+		memcpy(&vaddr[i + 64], temp, 64);
+	}
+
+#if defined (__HAVE_PMAP_DIRECT)
+	pmap_unmap_direct(va);
+#else
+	pmap_kremove(va, PAGE_SIZE);
+	pmap_update(pmap_kernel());
+#if !defined(__NetBSD__)
+	uvm_km_free(kernel_map, va, PAGE_SIZE);
+#else /* !defined(__NetBSD__) */
+	uvm_km_free(kernel_map, va, PAGE_SIZE, UVM_KMF_VAONLY);
+#endif /* !defined(__NetBSD__) */
+#endif
+	return (0);
+}
+
+void
+i915_gem_bit_17_swizzle(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	struct vm_page		*pg;
+	bus_dma_segment_t	*segp;
+	int			 page_count = obj->size >> PAGE_SHIFT;
+	int                      i, n, ret;
+
+	if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17 ||
+	    obj_priv->bit_17 == NULL)
+		return;
+
+	segp = &obj_priv->dma_segs[0];
+	n = 0;
+	for (i = 0; i < page_count; i++) {
+		/* compare bit 17 with previous one (in case we swapped).
+		 * if they don't match we'll have to swizzle the page
+		 */
+		if ((((segp->ds_addr + n) >> 17) & 0x1) !=
+		    test_bit(i, obj_priv->bit_17)) {
+			/* XXX move this to somewhere where we already have pg */
+			pg = PHYS_TO_VM_PAGE(segp->ds_addr + n);
+			KASSERT(pg != NULL);
+			ret = inteldrm_swizzle_page(pg);
+			if (ret)
+				return;
+#if !defined(__NetBSD__)
+			atomic_clearbits_int(&pg->pg_flags, PG_CLEAN);
+#else /* !defined(__NetBSD__) */
+			/* XXX This assignment should be atomic. */
+			pg->flags &= ~(PG_CLEAN);
+#endif /* !defined(__NetBSD__) */
+		}
+
+		n += PAGE_SIZE;
+		if (n >= segp->ds_len) {
+			n = 0;
+			segp++;
+		}
+	}
+
+}
+
+void
+i915_gem_save_bit_17_swizzle(struct drm_obj *obj)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+	bus_dma_segment_t	*segp;
+	int			 page_count = obj->size >> PAGE_SHIFT, i, n;
+
+	if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
+		return;
+
+	if (obj_priv->bit_17 == NULL) {
+		/* round up number of pages to a multiple of 32 so we know what
+		 * size to make the bitmask. XXX this is wasteful with malloc
+		 * and a better way should be done
+		 */
+		size_t nb17 = ((page_count + 31) & ~31)/32;
+		obj_priv->bit_17 = drm_alloc(nb17 * sizeof(u_int32_t));
+		if (obj_priv->bit_17 == NULL) {
+			return;
+		}
+
+	}
+
+	segp = &obj_priv->dma_segs[0];
+	n = 0;
+	for (i = 0; i < page_count; i++) {
+		if ((segp->ds_addr + n) & (1 << 17))
+			set_bit(i, obj_priv->bit_17);
+		else
+			clear_bit(i, obj_priv->bit_17);
+
+		n += PAGE_SIZE;
+		if (n >= segp->ds_len) {
+			n = 0;
+			segp++;
+		}
+	}
+}
+
+bus_size_t
+i915_get_fence_size(struct inteldrm_softc *dev_priv, bus_size_t size)
+{
+	bus_size_t	i, start;
+
+	if (IS_I965G(dev_priv)) {
+		/* 965 can have fences anywhere, so align to gpu-page size */
+		return ((size + (4096 - 1)) & ~(4096 - 1));
+	} else {
+		/*
+		 * Align the size to a power of two greater than the smallest
+		 * fence size.
+		 */
+		if (IS_I9XX(dev_priv))
+			start = 1024 * 1024;
+		else
+			start = 512 * 1024;
+
+		for (i = start; i < size; i <<= 1)
+			;
+
+		return (i);
+	}
+}
+
+int
+i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	int			 tile_width;
+
+	/* Linear is always ok */
+	if (tiling_mode == I915_TILING_NONE)
+		return (1);
+
+	if (!IS_I9XX(dev_priv) || (tiling_mode == I915_TILING_Y &&
+	    HAS_128_BYTE_Y_TILING(dev_priv)))
+		tile_width = 128;
+	else
+		tile_width = 512;
+
+	/* Check stride and size constraints */
+	if (IS_I965G(dev_priv)) {
+		/* fence reg has end address, so size is ok */
+		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
+			return (0);
+	} else if (IS_GEN3(dev_priv) || IS_GEN2(dev_priv)) {
+		if (stride > 8192)
+			return (0);
+		if (IS_GEN3(dev_priv)) {
+			if (size > I830_FENCE_MAX_SIZE_VAL << 20)
+				return (0);
+		} else if (size > I830_FENCE_MAX_SIZE_VAL << 19)
+			return (0);
+	}
+
+	/* 965+ just needs multiples of the tile width */
+	if (IS_I965G(dev_priv))
+		return ((stride & (tile_width - 1)) == 0);
+
+	/* Pre-965 needs power-of-two */
+	if (stride < tile_width || stride & (stride - 1) ||
+	    i915_get_fence_size(dev_priv, size) != size)
+		return (0);
+	return (1);
+}
+
+int
+i915_gem_object_fence_offset_ok(struct drm_obj *obj, int tiling_mode)
+{
+	struct drm_device	*dev = obj->dev;
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct inteldrm_obj	*obj_priv = (struct inteldrm_obj *)obj;
+
+	if (obj_priv->dmamap == NULL || tiling_mode == I915_TILING_NONE)
+		return (1);
+
+	if (!IS_I965G(dev_priv)) {
+		if (obj_priv->gtt_offset & (obj->size -1))
+			return (0);
+		if (IS_I9XX(dev_priv)) {
+			if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+				return (0);
+		} else {
+			if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
+				return (0);
+		}
+	}
+	return (1);
+}
+/**
+ * Sets the tiling mode of an object, returning the required swizzling of
+ * bit 6 of addresses in the object.
+ */
+int
+i915_gem_set_tiling(struct drm_device *dev, void *data,
+		   struct drm_file *file_priv)
+{
+	struct drm_i915_gem_set_tiling	*args = data;
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+	int				 ret = 0;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	obj_priv = (struct inteldrm_obj *)obj;
+	drm_hold_object(obj);
+
+	if (obj_priv->pin_count != 0) {
+		ret = EBUSY;
+		goto out;
+	}
+	if (i915_tiling_ok(dev, args->stride, obj->size,
+	    args->tiling_mode) == 0) {
+		ret = EINVAL;
+		goto out;
+	}
+
+	if (args->tiling_mode == I915_TILING_NONE) {
+		args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+		args->stride = 0;
+	} else {
+		if (args->tiling_mode == I915_TILING_X)
+			args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+		else
+			args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+		/* If we can't handle the swizzling, make it untiled. */
+		if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
+			args->tiling_mode = I915_TILING_NONE;
+			args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+			args->stride = 0;
+		}
+	}
+
+	if (args->tiling_mode != obj_priv->tiling_mode ||
+	    args->stride != obj_priv->stride) {
+		/*
+		 * We need to rebind the object if its current allocation no
+		 * longer meets the alignment restrictions for its new tiling
+		 * mode. Otherwise we can leave it alone, but must clear any
+		 * fence register.
+		 */
+		/* fence may no longer be correct, wipe it */
+		inteldrm_wipe_mappings(obj);
+		if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
+			atomic_setbits_int(&obj->do_flags,
+			    I915_FENCE_INVALID);
+		obj_priv->tiling_mode = args->tiling_mode;
+		obj_priv->stride = args->stride;
+	}
+
+out:
+	drm_unhold_and_unref(obj);
+
+	return (ret);
+}
+
+/**
+ * Returns the current tiling mode and required bit 6 swizzling for the object.
+ */
+int
+i915_gem_get_tiling(struct drm_device *dev, void *data,
+		   struct drm_file *file_priv)
+{
+	struct drm_i915_gem_get_tiling	*args = data;
+	struct inteldrm_softc		*dev_priv = dev->dev_private;
+	struct drm_obj			*obj;
+	struct inteldrm_obj		*obj_priv;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL)
+		return (EBADF);
+	drm_hold_object(obj);
+	obj_priv = (struct inteldrm_obj *)obj;
+
+	args->tiling_mode = obj_priv->tiling_mode;
+	switch (obj_priv->tiling_mode) {
+	case I915_TILING_X:
+		args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
+		break;
+	case I915_TILING_Y:
+		args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
+		break;
+	case I915_TILING_NONE:
+		args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+		break;
+	default:
+		DRM_ERROR("unknown tiling mode\n");
+	}
+
+	drm_unhold_and_unref(obj);
+
+	return 0;
+}
+
+
+/**
+ * inteldrm_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+int
+inteldrm_pipe_enabled(struct inteldrm_softc *dev_priv, int pipe)
+{
+	bus_size_t	pipeconf;
+
+#if 0
+	if (IS_IRONLAKE(dev_priv)) {
+		pipeconf = (pipe ? PCH_DPLL_A : PCH_DPLL_B);
+	} else {
+#endif
+		pipeconf = (pipe ? PIPEBCONF : PIPEACONF);
+#if 0
+	}
+#endif
+	return ((I915_READ(pipeconf) & PIPEACONF_ENABLE) == PIPEACONF_ENABLE);
+}
+
+/*
+ * Register save/restore for various instances
+ */
+void
+i915_save_palette(struct inteldrm_softc *dev_priv, enum pipe pipe)
+{
+	u_int32_t	*array;
+	bus_size_t	 reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+	int		 i;
+
+	if (!inteldrm_pipe_enabled(dev_priv, pipe))
+		return;
+
+	if (IS_IRONLAKE(dev_priv))
+		reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
+
+	if (pipe == PIPE_A)
+		array = dev_priv->save_palette_a;
+	else
+		array = dev_priv->save_palette_b;
+
+	for (i = 0; i < 256; i++)
+		array[i] = I915_READ(reg + (i << 2));
+}
+
+void
+i915_restore_palette(struct inteldrm_softc *dev_priv, enum pipe pipe)
+{
+	u_int32_t	*array;
+	bus_size_t	 reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
+	int		 i;
+
+	if (!inteldrm_pipe_enabled(dev_priv, pipe))
+		return;
+
+	if (IS_IRONLAKE(dev_priv))
+		reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
+
+	if (pipe == PIPE_A)
+		array = dev_priv->save_palette_a;
+	else
+		array = dev_priv->save_palette_b;
+
+	for(i = 0; i < 256; i++)
+		I915_WRITE(reg + (i << 2), array[i]);
+}
+
+u_int8_t
+i915_read_ar(struct inteldrm_softc *dev_priv, u_int16_t st01,
+    u_int8_t reg, u_int16_t palette_enable)
+{
+	I915_READ8(st01);
+	I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+	return I915_READ8(VGA_AR_DATA_READ);
+}
+
+void
+i915_write_ar(struct inteldrm_softc *dev_priv, u_int16_t st01, u_int8_t reg,
+    u_int8_t val, u_int16_t palette_enable)
+{
+	I915_READ8(st01);
+	I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
+	I915_WRITE8(VGA_AR_DATA_WRITE, val);
+}
+
+u_int8_t
+i915_read_indexed(struct inteldrm_softc *dev_priv, u_int16_t index_port,
+    u_int16_t data_port, u_int8_t reg)
+{
+	I915_WRITE8(index_port, reg);
+	return I915_READ8(data_port);
+}
+
+void
+i915_write_indexed(struct inteldrm_softc *dev_priv, u_int16_t index_port,
+    u_int16_t data_port, u_int8_t reg, u_int8_t val)
+{
+	I915_WRITE8(index_port, reg);
+	I915_WRITE8(data_port, val);
+}
+
+void
+i915_save_vga(struct inteldrm_softc *dev_priv)
+{
+	int i;
+	u16 cr_index, cr_data, st01;
+
+	/* VGA color palette registers */
+	dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
+
+	/* MSR bits */
+	dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
+	if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+		cr_index = VGA_CR_INDEX_CGA;
+		cr_data = VGA_CR_DATA_CGA;
+		st01 = VGA_ST01_CGA;
+	} else {
+		cr_index = VGA_CR_INDEX_MDA;
+		cr_data = VGA_CR_DATA_MDA;
+		st01 = VGA_ST01_MDA;
+	}
+
+	/* CRT controller regs */
+	i915_write_indexed(dev_priv, cr_index, cr_data, 0x11,
+	    i915_read_indexed(dev_priv, cr_index, cr_data, 0x11) & (~0x80));
+	for (i = 0; i <= 0x24; i++)
+		dev_priv->saveCR[i] = i915_read_indexed(dev_priv,
+		    cr_index, cr_data, i);
+	/* Make sure we don't turn off CR group 0 writes */
+	dev_priv->saveCR[0x11] &= ~0x80;
+
+	/* Attribute controller registers */
+	I915_READ8(st01);
+	dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
+	for (i = 0; i <= 0x14; i++)
+		dev_priv->saveAR[i] = i915_read_ar(dev_priv, st01, i, 0);
+	I915_READ8(st01);
+	I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX);
+	I915_READ8(st01);
+
+	/* Graphics controller registers */
+	for (i = 0; i < 9; i++)
+		dev_priv->saveGR[i] = i915_read_indexed(dev_priv,
+		    VGA_GR_INDEX, VGA_GR_DATA, i);
+
+	dev_priv->saveGR[0x10] = i915_read_indexed(dev_priv,
+	    VGA_GR_INDEX, VGA_GR_DATA, 0x10);
+	dev_priv->saveGR[0x11] = i915_read_indexed(dev_priv,
+	    VGA_GR_INDEX, VGA_GR_DATA, 0x11);
+	dev_priv->saveGR[0x18] = i915_read_indexed(dev_priv,
+	    VGA_GR_INDEX, VGA_GR_DATA, 0x18);
+
+	/* Sequencer registers */
+	for (i = 0; i < 8; i++)
+		dev_priv->saveSR[i] = i915_read_indexed(dev_priv,
+		    VGA_SR_INDEX, VGA_SR_DATA, i);
+}
+
+void
+i915_restore_vga(struct inteldrm_softc *dev_priv)
+{
+	u_int16_t	cr_index, cr_data, st01;
+	int		i;
+
+	/* MSR bits */
+	I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR);
+	if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
+		cr_index = VGA_CR_INDEX_CGA;
+		cr_data = VGA_CR_DATA_CGA;
+		st01 = VGA_ST01_CGA;
+	} else {
+		cr_index = VGA_CR_INDEX_MDA;
+		cr_data = VGA_CR_DATA_MDA;
+		st01 = VGA_ST01_MDA;
+	}
+
+	/* Sequencer registers, don't write SR07 */
+	for (i = 0; i < 7; i++)
+		i915_write_indexed(dev_priv, VGA_SR_INDEX, VGA_SR_DATA, i,
+		    dev_priv->saveSR[i]);
+
+	/* CRT controller regs */
+	/* Enable CR group 0 writes */
+	i915_write_indexed(dev_priv, cr_index, cr_data, 0x11,
+	    dev_priv->saveCR[0x11]);
+	for (i = 0; i <= 0x24; i++)
+		i915_write_indexed(dev_priv, cr_index, cr_data,
+		    i, dev_priv->saveCR[i]);
+
+	/* Graphics controller regs */
+	for (i = 0; i < 9; i++)
+		i915_write_indexed(dev_priv, VGA_GR_INDEX, VGA_GR_DATA, i,
+				   dev_priv->saveGR[i]);
+
+	i915_write_indexed(dev_priv, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
+			   dev_priv->saveGR[0x10]);
+	i915_write_indexed(dev_priv, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
+			   dev_priv->saveGR[0x11]);
+	i915_write_indexed(dev_priv, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
+			   dev_priv->saveGR[0x18]);
+
+	/* Attribute controller registers */
+	I915_READ8(st01); /* switch back to index mode */
+	for (i = 0; i <= 0x14; i++)
+		i915_write_ar(dev_priv, st01, i, dev_priv->saveAR[i], 0);
+	I915_READ8(st01); /* switch back to index mode */
+	I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20);
+	I915_READ8(st01);
+
+	/* VGA color palette registers */
+	I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
+}
+
+void
+i915_save_modeset_reg(struct inteldrm_softc *dev_priv)
+{
+
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
+		dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
+	}
+
+	/* Pipe & plane A info */
+	dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
+	dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->saveFPA0 = I915_READ(PCH_FPA0);
+		dev_priv->saveFPA1 = I915_READ(PCH_FPA1);
+		dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A);
+	} else {
+		dev_priv->saveFPA0 = I915_READ(FPA0);
+		dev_priv->saveFPA1 = I915_READ(FPA1);
+		dev_priv->saveDPLL_A = I915_READ(DPLL_A);
+	}
+	if (IS_I965G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
+	dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
+	dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
+	dev_priv->saveHSYNC_A = I915_READ(HSYNC_A);
+	dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
+	dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
+	dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1);
+		dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1);
+		dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1);
+		dev_priv->savePIPEA_LINK_N1 = I915_READ(PIPEA_LINK_N1);
+
+		dev_priv->saveFDI_TXA_CTL = I915_READ(FDI_TXA_CTL);
+		dev_priv->saveFDI_RXA_CTL = I915_READ(FDI_RXA_CTL);
+
+		dev_priv->savePFA_CTL_1 = I915_READ(PFA_CTL_1);
+		dev_priv->savePFA_WIN_SZ = I915_READ(PFA_WIN_SZ);
+		dev_priv->savePFA_WIN_POS = I915_READ(PFA_WIN_POS);
+
+		dev_priv->saveTRANSACONF = I915_READ(TRANSACONF);
+		dev_priv->saveTRANS_HTOTAL_A = I915_READ(TRANS_HTOTAL_A);
+		dev_priv->saveTRANS_HBLANK_A = I915_READ(TRANS_HBLANK_A);
+		dev_priv->saveTRANS_HSYNC_A = I915_READ(TRANS_HSYNC_A);
+		dev_priv->saveTRANS_VTOTAL_A = I915_READ(TRANS_VTOTAL_A);
+		dev_priv->saveTRANS_VBLANK_A = I915_READ(TRANS_VBLANK_A);
+		dev_priv->saveTRANS_VSYNC_A = I915_READ(TRANS_VSYNC_A);
+	} else {
+		dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+	}
+
+	dev_priv->saveDSPACNTR = I915_READ(DSPACNTR);
+	dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE);
+	dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
+	dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
+	dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
+	if (IS_I965G(dev_priv)) {
+		dev_priv->saveDSPASURF = I915_READ(DSPASURF);
+		dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
+	}
+	i915_save_palette(dev_priv, PIPE_A);
+	dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT);
+
+	/* Pipe & plane B info */
+	dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
+	dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->saveFPA0 = I915_READ(PCH_FPB0);
+		dev_priv->saveFPA1 = I915_READ(PCH_FPB1);
+		dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_B);
+	} else {
+		dev_priv->saveFPB0 = I915_READ(FPB0);
+		dev_priv->saveFPB1 = I915_READ(FPB1);
+		dev_priv->saveDPLL_B = I915_READ(DPLL_B);
+	}
+	if (IS_I965G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
+	dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
+	dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
+	dev_priv->saveHSYNC_B = I915_READ(HSYNC_B);
+	dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
+	dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
+	dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1);
+		dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1);
+		dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1);
+		dev_priv->savePIPEB_LINK_N1 = I915_READ(PIPEB_LINK_N1);
+
+		dev_priv->saveFDI_TXB_CTL = I915_READ(FDI_TXB_CTL);
+		dev_priv->saveFDI_RXB_CTL = I915_READ(FDI_RXB_CTL);
+
+		dev_priv->savePFB_CTL_1 = I915_READ(PFB_CTL_1);
+		dev_priv->savePFB_WIN_SZ = I915_READ(PFB_WIN_SZ);
+		dev_priv->savePFB_WIN_POS = I915_READ(PFB_WIN_POS);
+
+		dev_priv->saveTRANSBCONF = I915_READ(TRANSBCONF);
+		dev_priv->saveTRANS_HTOTAL_B = I915_READ(TRANS_HTOTAL_B);
+		dev_priv->saveTRANS_HBLANK_B = I915_READ(TRANS_HBLANK_B);
+		dev_priv->saveTRANS_HSYNC_B = I915_READ(TRANS_HSYNC_B);
+		dev_priv->saveTRANS_VTOTAL_B = I915_READ(TRANS_VTOTAL_B);
+		dev_priv->saveTRANS_VBLANK_B = I915_READ(TRANS_VBLANK_B);
+		dev_priv->saveTRANS_VSYNC_B = I915_READ(TRANS_VSYNC_B);
+	} else {
+		dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
+	}
+
+	dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR);
+	dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE);
+	dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
+	dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
+	dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
+	if (IS_I965GM(dev_priv) || IS_GM45(dev_priv)) {
+		dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
+		dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
+	}
+	i915_save_palette(dev_priv, PIPE_B);
+	dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
+}
+
+void
+i915_restore_modeset_reg(struct inteldrm_softc *dev_priv)
+{
+	bus_size_t	dpll_a_reg, fpa0_reg, fpa1_reg;
+	bus_size_t	dpll_b_reg, fpb0_reg, fpb1_reg;
+
+	if (IS_IRONLAKE(dev_priv)) {
+		dpll_a_reg = PCH_DPLL_A;
+		dpll_b_reg = PCH_DPLL_B;
+		fpa0_reg = PCH_FPA0;
+		fpb0_reg = PCH_FPB0;
+		fpa1_reg = PCH_FPA1;
+		fpb1_reg = PCH_FPB1;
+	} else {
+		dpll_a_reg = DPLL_A;
+		dpll_b_reg = DPLL_B;
+		fpa0_reg = FPA0;
+		fpb0_reg = FPB0;
+		fpa1_reg = FPA1;
+		fpb1_reg = FPB1;
+	}
+
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL);
+		I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL);
+	}
+
+	/* Pipe & plane A info */
+	/* Prime the clock */
+	if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
+		I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
+			   ~DPLL_VCO_ENABLE);
+		DRM_UDELAY(150);
+	}
+	I915_WRITE(fpa0_reg, dev_priv->saveFPA0);
+	I915_WRITE(fpa1_reg, dev_priv->saveFPA1);
+	/* Actually enable it */
+	I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
+	DRM_UDELAY(150);
+	if (IS_I965G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
+	DRM_UDELAY(150);
+
+	/* Restore mode */
+	I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
+	I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
+	I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
+	I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
+	I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
+	I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1);
+		I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1);
+		I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1);
+		I915_WRITE(PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1);
+
+		I915_WRITE(FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL);
+		I915_WRITE(FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL);
+
+		I915_WRITE(PFA_CTL_1, dev_priv->savePFA_CTL_1);
+		I915_WRITE(PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ);
+		I915_WRITE(PFA_WIN_POS, dev_priv->savePFA_WIN_POS);
+
+		I915_WRITE(TRANSACONF, dev_priv->saveTRANSACONF);
+		I915_WRITE(TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A);
+		I915_WRITE(TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A);
+		I915_WRITE(TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A);
+		I915_WRITE(TRANS_VTOTAL_A, dev_priv->saveTRANS_VTOTAL_A);
+		I915_WRITE(TRANS_VBLANK_A, dev_priv->saveTRANS_VBLANK_A);
+		I915_WRITE(TRANS_VSYNC_A, dev_priv->saveTRANS_VSYNC_A);
+	} else {
+		I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
+	}
+
+	/* Restore plane info */
+	I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
+	I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
+	I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
+	I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
+	I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
+	if (IS_I965G(dev_priv)) {
+		I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
+		I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
+	}
+
+	I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+
+	i915_restore_palette(dev_priv, PIPE_A);
+	/* Enable the plane */
+	I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
+	I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
+
+	/* Pipe & plane B info */
+	if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
+		I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
+			   ~DPLL_VCO_ENABLE);
+		DRM_UDELAY(150);
+	}
+	I915_WRITE(fpb0_reg, dev_priv->saveFPB0);
+	I915_WRITE(fpb1_reg, dev_priv->saveFPB1);
+	/* Actually enable it */
+	I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
+	DRM_UDELAY(150);
+	if (IS_I965G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
+	DRM_UDELAY(150);
+
+	/* Restore mode */
+	I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
+	I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
+	I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
+	I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
+	I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
+	I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1);
+		I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1);
+		I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1);
+		I915_WRITE(PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1);
+
+		I915_WRITE(FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL);
+		I915_WRITE(FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL);
+
+		I915_WRITE(PFB_CTL_1, dev_priv->savePFB_CTL_1);
+		I915_WRITE(PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ);
+		I915_WRITE(PFB_WIN_POS, dev_priv->savePFB_WIN_POS);
+
+		I915_WRITE(TRANSBCONF, dev_priv->saveTRANSBCONF);
+		I915_WRITE(TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B);
+		I915_WRITE(TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B);
+		I915_WRITE(TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B);
+		I915_WRITE(TRANS_VTOTAL_B, dev_priv->saveTRANS_VTOTAL_B);
+		I915_WRITE(TRANS_VBLANK_B, dev_priv->saveTRANS_VBLANK_B);
+		I915_WRITE(TRANS_VSYNC_B, dev_priv->saveTRANS_VSYNC_B);
+	} else {
+		I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
+	}
+
+	/* Restore plane info */
+	I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
+	I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
+	I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
+	I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
+	I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
+	if (IS_I965G(dev_priv)) {
+		I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
+		I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
+	}
+
+	I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+	i915_restore_palette(dev_priv, PIPE_B);
+	/* Enable the plane */
+	I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
+	I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
+}
+
+int
+inteldrm_save_display(struct inteldrm_softc *dev_priv)
+{
+	/* Display arbitration control */
+	dev_priv->saveDSPARB = I915_READ(DSPARB);
+
+	/* This is only meaningful in non-KMS mode */
+	/* Don't save them in KMS mode */
+	i915_save_modeset_reg(dev_priv);
+	/* Cursor state */
+	dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+	dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+	dev_priv->saveCURABASE = I915_READ(CURABASE);
+	dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+	dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+	dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+	if (!IS_I9XX(dev_priv))
+		dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
+	/* CRT state */
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->saveADPA = I915_READ(PCH_ADPA);
+	} else {
+		dev_priv->saveADPA = I915_READ(ADPA);
+	}
+
+	/* LVDS state */
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
+		dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
+		dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
+		dev_priv->saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
+		dev_priv->saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
+		dev_priv->saveLVDS = I915_READ(PCH_LVDS);
+	} else {
+		dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+		dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
+		dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+		dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
+		if (IS_I965G(dev_priv))
+			dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+		if (IS_MOBILE(dev_priv) && !IS_I830(dev_priv))
+			dev_priv->saveLVDS = I915_READ(LVDS);
+	}
+	if (!IS_I830(dev_priv) && !IS_845G(dev_priv))
+		dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
+		dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
+		dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
+	} else {
+		dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
+		dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
+		dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
+	}
+
+	/* FIXME: save TV & SDVO state */
+
+	/* FBC state XXX only if supported */
+	if (IS_GM45(dev_priv)) {
+		dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
+	} else {
+		dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
+		dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
+		dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
+		dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+	}
+
+	/* VGA state */
+	dev_priv->saveVGA0 = I915_READ(VGA0);
+	dev_priv->saveVGA1 = I915_READ(VGA1);
+	dev_priv->saveVGA_PD = I915_READ(VGA_PD);
+	if (IS_IRONLAKE(dev_priv))
+		dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL);
+	else
+		dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
+
+	i915_save_vga(dev_priv);
+
+	return 0;
+}
+
+int
+inteldrm_restore_display(struct inteldrm_softc *dev_priv)
+{
+	/* Display arbitration */
+	I915_WRITE(DSPARB, dev_priv->saveDSPARB);
+
+	/* This is only meaningful in non-KMS mode */
+	/* Don't restore them in KMS mode */
+	i915_restore_modeset_reg(dev_priv);
+	/* Cursor state */
+	I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+	I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+	I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+	I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+	I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+	I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+	if (!IS_I9XX(dev_priv))
+		I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
+	/* CRT state */
+	if (IS_IRONLAKE(dev_priv))
+		I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
+	else
+		I915_WRITE(ADPA, dev_priv->saveADPA);
+
+	/* LVDS state */
+	if (IS_I965G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
+
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(PCH_LVDS, dev_priv->saveLVDS);
+	} else if (IS_MOBILE(dev_priv) && !IS_I830(dev_priv))
+		I915_WRITE(LVDS, dev_priv->saveLVDS);
+
+	if (!IS_I830(dev_priv) && !IS_845G(dev_priv) && !IS_IRONLAKE(dev_priv))
+		I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
+
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL);
+		I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2);
+		I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL);
+		I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->saveBLC_CPU_PWM_CTL2);
+		I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
+		I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
+		I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
+		I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
+		I915_WRITE(MCHBAR_RENDER_STANDBY,
+			   dev_priv->saveMCHBAR_RENDER_STANDBY);
+	} else {
+		I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
+		I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+		I915_WRITE(BLC_HIST_CTL, dev_priv->saveBLC_HIST_CTL);
+		I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
+		I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
+		I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
+		I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+	}
+
+	/* FIXME: restore TV & SDVO state */
+
+	/* FBC info */
+	if (IS_GM45(dev_priv)) {
+		I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
+	} else {
+		I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
+		I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
+		I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
+		I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
+	}
+
+	/* VGA state */
+	if (IS_IRONLAKE(dev_priv))
+		I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL);
+	else
+		I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
+	I915_WRITE(VGA0, dev_priv->saveVGA0);
+	I915_WRITE(VGA1, dev_priv->saveVGA1);
+	I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
+	DRM_UDELAY(150);
+
+	i915_restore_vga(dev_priv);
+
+	return 0;
+}
+
+int
+inteldrm_save_state(struct inteldrm_softc *dev_priv)
+{
+	int i;
+
+	dev_priv->saveLBB = pci_conf_read(dev_priv->pc, dev_priv->tag, LBB);
+
+	/* Hardware status page */
+	dev_priv->saveHWS = I915_READ(HWS_PGA);
+
+	inteldrm_save_display(dev_priv);
+
+	/* Interrupt state */
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->saveDEIER = I915_READ(DEIER);
+		dev_priv->saveDEIMR = I915_READ(DEIMR);
+		dev_priv->saveGTIER = I915_READ(GTIER);
+		dev_priv->saveGTIMR = I915_READ(GTIMR);
+		dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
+		dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
+		dev_priv->saveMCHBAR_RENDER_STANDBY =
+			I915_READ(MCHBAR_RENDER_STANDBY);
+	} else {
+		dev_priv->saveIER = I915_READ(IER);
+		dev_priv->saveIMR = I915_READ(IMR);
+	}
+
+	/* Clock gating state */
+	if (IS_IRONLAKE(dev_priv)) {
+		dev_priv->saveDSPCLK_GATE_D = I915_READ(PCH_DSPCLK_GATE_D);
+		dev_priv->saveDSPCLK_GATE = I915_READ(ILK_DSPCLK_GATE);
+	} else if (IS_G4X(dev_priv)) {
+		dev_priv->saveRENCLK_GATE_D1 = I915_READ(RENCLK_GATE_D1);
+		dev_priv->saveRENCLK_GATE_D2 = I915_READ(RENCLK_GATE_D2);
+		dev_priv->saveRAMCLK_GATE_D = I915_READ(RAMCLK_GATE_D);
+		dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
+	} else if (IS_I965GM(dev_priv)) {
+		dev_priv->saveRENCLK_GATE_D1 = I915_READ(RENCLK_GATE_D1);
+		dev_priv->saveRENCLK_GATE_D2 = I915_READ(RENCLK_GATE_D2);
+		dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
+		dev_priv->saveRAMCLK_GATE_D = I915_READ(RAMCLK_GATE_D);
+		dev_priv->saveDEUC = I915_READ16(DEUC);
+	} else if (IS_I965G(dev_priv)) {
+		dev_priv->saveRENCLK_GATE_D1 = I915_READ(RENCLK_GATE_D1);
+		dev_priv->saveRENCLK_GATE_D2 = I915_READ(RENCLK_GATE_D2);
+	} else if (IS_I9XX(dev_priv)) {
+		dev_priv->saveD_STATE = I915_READ(D_STATE);
+	} else if (IS_I85X(dev_priv) || IS_I865G(dev_priv)) {
+		dev_priv->saveRENCLK_GATE_D1 = I915_READ(RENCLK_GATE_D1);
+	} else if (IS_I830(dev_priv)) {
+		dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
+	}
+
+	/* Cache mode state */
+	dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
+
+	/* Memory Arbitration state */
+	dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
+
+	/* Scratch space */
+	for (i = 0; i < 16; i++) {
+		dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
+		dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
+	}
+	for (i = 0; i < 3; i++)
+		dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
+
+	/* Fences */
+	if (IS_I965G(dev_priv)) {
+		for (i = 0; i < 16; i++)
+			dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 +
+			    (i * 8));
+	} else {
+		for (i = 0; i < 8; i++)
+			dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+
+		if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+		    IS_G33(dev_priv))
+			for (i = 0; i < 8; i++)
+				dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+	}
+
+	return 0;
+}
+
+int
+inteldrm_restore_state(struct inteldrm_softc *dev_priv)
+{
+	int	i;
+
+	pci_conf_write(dev_priv->pc, dev_priv->tag, LBB, dev_priv->saveLBB);
+
+	/* Hardware status page */
+	I915_WRITE(HWS_PGA, dev_priv->saveHWS);
+
+	/* Fences */
+	if (IS_I965G(dev_priv)) {
+		for (i = 0; i < 16; i++)
+			I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]);
+	} else {
+		for (i = 0; i < 8; i++)
+			I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
+		if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+		    IS_G33(dev_priv))
+			for (i = 0; i < 8; i++)
+				I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
+	}
+
+	inteldrm_restore_display(dev_priv);
+
+	/* Interrupt state */
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(DEIER, dev_priv->saveDEIER);
+		I915_WRITE(DEIMR, dev_priv->saveDEIMR);
+		I915_WRITE(GTIER, dev_priv->saveGTIER);
+		I915_WRITE(GTIMR, dev_priv->saveGTIMR);
+		I915_WRITE(FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR);
+		I915_WRITE(FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR);
+	} else {
+		I915_WRITE (IER, dev_priv->saveIER);
+		I915_WRITE (IMR,  dev_priv->saveIMR);
+	}
+
+	/* Clock gating state */
+	if (IS_IRONLAKE(dev_priv)) {
+		I915_WRITE(PCH_DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
+		I915_WRITE(ILK_DSPCLK_GATE, dev_priv->saveDSPCLK_GATE);
+	} if (IS_G4X(dev_priv)) {
+		I915_WRITE(RENCLK_GATE_D1, dev_priv->saveRENCLK_GATE_D1);
+		I915_WRITE(RENCLK_GATE_D2, dev_priv->saveRENCLK_GATE_D2);
+		I915_WRITE(RAMCLK_GATE_D, dev_priv->saveRAMCLK_GATE_D);
+		I915_WRITE(DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
+	} else if (IS_I965GM(dev_priv)) {
+		I915_WRITE(RENCLK_GATE_D1, dev_priv->saveRENCLK_GATE_D1);
+		I915_WRITE(RENCLK_GATE_D2, dev_priv->saveRENCLK_GATE_D2);
+		I915_WRITE(DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
+		I915_WRITE(RAMCLK_GATE_D, dev_priv->saveRAMCLK_GATE_D);
+		I915_WRITE16(DEUC, dev_priv->saveDEUC);
+	} else if (IS_I965G(dev_priv)) {
+		I915_WRITE(RENCLK_GATE_D1, dev_priv->saveRENCLK_GATE_D1);
+		I915_WRITE(RENCLK_GATE_D2, dev_priv->saveRENCLK_GATE_D2);
+	} else if (IS_I9XX(dev_priv)) {
+		I915_WRITE(D_STATE, dev_priv->saveD_STATE);
+	} else if (IS_I85X(dev_priv) || IS_I865G(dev_priv)) {
+		I915_WRITE(RENCLK_GATE_D1, dev_priv->saveRENCLK_GATE_D1);
+	} else if (IS_I830(dev_priv)) {
+		I915_WRITE(DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
+	}
+
+	/* Cache mode state */
+	I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
+
+	/* Memory arbitration state */
+	I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
+
+	for (i = 0; i < 16; i++) {
+		I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
+		I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]);
+	}
+	for (i = 0; i < 3; i++)
+		I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
+
+	return 0;
+}
+
+/*
+ * Reset the chip after a hang (965 only)
+ *
+ * The procedure that should be followed is relatively simple:
+ *	- reset the chip using the reset reg
+ *	- re-init context state
+ *	- re-init Hardware status page
+ *	- re-init ringbuffer
+ *	- re-init interrupt state
+ *	- re-init display
+ */
+void
+inteldrm_965_reset(struct inteldrm_softc *dev_priv, u_int8_t flags)
+{
+	pcireg_t	reg;
+	int		i = 0;
+
+	if (flags == GDRST_FULL)
+		inteldrm_save_display(dev_priv);
+
+	reg = pci_conf_read(dev_priv->pc, dev_priv->tag, GDRST);
+	/*
+	 * Set the domains we want to reset, then bit 0 (reset itself).
+	 * then we wait for the hardware to clear it.
+	 */
+	pci_conf_write(dev_priv->pc, dev_priv->tag, GDRST,
+	    reg | (u_int32_t)flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
+	delay(50);
+	/* don't clobber the rest of the register */
+	pci_conf_write(dev_priv->pc, dev_priv->tag, GDRST, reg & 0xfe);
+
+	/* if this fails we're pretty much fucked, but don't loop forever */
+	do {
+		delay(100);
+		reg = pci_conf_read(dev_priv->pc, dev_priv->tag, GDRST);
+	} while ((reg & 0x1) && ++i < 10);
+
+	if (reg & 0x1)
+		printf("bit 0 not cleared .. ");
+
+	/* put everything back together again */
+
+	/*
+	 * GTT is already up (we didn't do a pci-level reset, thank god.
+	 *
+	 * We don't have to restore the contexts (we don't use them yet).
+	 * So, if X is running we need to put the ringbuffer back first.
+	 */
+	 if (dev_priv->mm.suspended == 0) {
+		struct drm_device *dev = (struct drm_device *)dev_priv->drmdev;
+		if (inteldrm_start_ring(dev_priv) != 0)
+			panic("can't restart ring, we're fucked");
+
+		/* put the hardware status page back */
+		if (I915_NEED_GFX_HWS(dev_priv))
+			I915_WRITE(HWS_PGA, ((struct inteldrm_obj *)
+			    dev_priv->hws_obj)->gtt_offset);
+		else
+			I915_WRITE(HWS_PGA,
+			    dev_priv->hws_dmamem->map->dm_segs[0].ds_addr);
+		I915_READ(HWS_PGA); /* posting read */
+
+		/* so we remove the handler and can put it back in */
+		DRM_UNLOCK();
+		drm_irq_uninstall(dev);
+		drm_irq_install(dev);
+		DRM_LOCK();
+	 } else
+		printf("not restarting ring...\n");
+
+
+	 if (flags == GDRST_FULL)
+		inteldrm_restore_display(dev_priv);
+}
+
+/*
+ * Debug code from here.
+ */
+#ifdef WATCH_INACTIVE
+void
+inteldrm_verify_inactive(struct inteldrm_softc *dev_priv, char *file,
+    int line)
+{
+	struct drm_obj		*obj;
+	struct inteldrm_obj	*obj_priv;
+
+	TAILQ_FOREACH(obj_priv, &dev_priv->mm.inactive_list, list) {
+		obj = (struct drm_obj *)obj_priv;
+		if (obj_priv->pin_count || inteldrm_is_active(obj_priv) ||
+		    obj->write_domain & I915_GEM_GPU_DOMAINS)
+			DRM_ERROR("inactive %p (p $d a $d w $x) %s:%d\n",
+			    obj, obj_priv->pin_count,
+			    inteldrm_is_active(obj_priv),
+			    obj->write_domain, file, line);
+	}
+}
+#endif /* WATCH_INACTIVE */
+
+#if (INTELDRM_DEBUG > 1)
+
+static const char *get_pin_flag(struct inteldrm_obj *obj_priv)
+{
+	if (obj_priv->pin_count > 0)
+		return "p";
+	else
+		return " ";
+}
+
+static const char *get_tiling_flag(struct inteldrm_obj *obj_priv)
+{
+    switch (obj_priv->tiling_mode) {
+    default:
+    case I915_TILING_NONE: return " ";
+    case I915_TILING_X: return "X";
+    case I915_TILING_Y: return "Y";
+    }
+}
+
+void
+i915_gem_seqno_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	if (dev_priv->hw_status_page != NULL) {
+		printf("Current sequence: %d\n", i915_get_gem_seqno(dev_priv));
+	} else {
+		printf("Current sequence: hws uninitialized\n");
+	}
+}
+
+void
+i915_interrupt_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	printf("Interrupt enable:    %08x\n",
+		   I915_READ(IER));
+	printf("Interrupt identity:  %08x\n",
+		   I915_READ(IIR));
+	printf("Interrupt mask:      %08x\n",
+		   I915_READ(IMR));
+	printf("Pipe A stat:         %08x\n",
+		   I915_READ(PIPEASTAT));
+	printf("Pipe B stat:         %08x\n",
+		   I915_READ(PIPEBSTAT));
+	printf("Interrupts received: 0\n");
+	if (dev_priv->hw_status_page != NULL) {
+		printf("Current sequence:    %d\n",
+			   i915_get_gem_seqno(dev_priv));
+	} else {
+		printf("Current sequence:    hws uninitialized\n");
+	}
+}
+
+void
+i915_gem_fence_regs_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	int i;
+
+	printf("Reserved fences = %d\n", dev_priv->fence_reg_start);
+	printf("Total fences = %d\n", dev_priv->num_fence_regs);
+	for (i = 0; i < dev_priv->num_fence_regs; i++) {
+		struct drm_obj *obj = dev_priv->fence_regs[i].obj;
+
+		if (obj == NULL) {
+			printf("Fenced object[%2d] = unused\n", i);
+		} else {
+			struct inteldrm_obj *obj_priv;
+
+			obj_priv = (struct inteldrm_obj *)obj;
+			printf("Fenced object[%2d] = %p: %s "
+				   "%08jx %08zx %08x %s %08x %08x %d",
+				   i, obj, get_pin_flag(obj_priv),
+				   (uintmax_t)obj_priv->gtt_offset,
+				   obj->size, obj_priv->stride,
+				   get_tiling_flag(obj_priv),
+				   obj->read_domains, obj->write_domain,
+				   obj_priv->last_rendering_seqno);
+			if (obj->name)
+				printf(" (name: %d)", obj->name);
+			printf("\n");
+		}
+	}
+}
+
+void
+i915_hws_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	int i;
+	volatile u32 *hws;
+
+	hws = (volatile u32 *)dev_priv->hw_status_page;
+	if (hws == NULL)
+		return;
+
+	for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
+		printf("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			   i * 4,
+			   hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
+	}
+}
+
+static void
+i915_dump_pages(bus_space_tag_t bst, bus_space_handle_t bsh,
+    bus_size_t size)
+{
+	bus_addr_t	offset = 0;
+	int		i = 0;
+
+	/*
+	 * this is a bit odd so i don't have to play with the intel
+	 * tools too much.
+	 */
+	for (offset = 0; offset < size; offset += 4, i += 4) {
+		if (i == PAGE_SIZE)
+			i = 0;
+		printf("%08x :  %08x\n", i, bus_space_read_4(bst, bsh,
+		    offset));
+	}
+}
+
+void
+i915_batchbuffer_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	struct drm_obj		*obj;
+	struct inteldrm_obj	*obj_priv;
+	bus_space_handle_t	 bsh;
+	int			 ret;
+
+	TAILQ_FOREACH(obj_priv, &dev_priv->mm.active_list, list) {
+		obj = &obj_priv->obj;
+		if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
+			if ((ret = agp_map_subregion(dev_priv->agph,
+			    obj_priv->gtt_offset, obj->size, &bsh)) != 0) {
+				DRM_ERROR("Failed to map pages: %d\n", ret);
+				return;
+			}
+			printf("--- gtt_offset = 0x%08jx\n",
+			    (uintmax_t)obj_priv->gtt_offset);
+			i915_dump_pages(dev_priv->bst, bsh, obj->size);
+			agp_unmap_subregion(dev_priv->agph, dev_priv->ring.bsh,
+			    obj->size);
+		}
+	}
+}
+
+void
+i915_ringbuffer_data(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	bus_size_t		 off;
+
+	if (!dev_priv->ring.ring_obj) {
+		printf("No ringbuffer setup\n");
+		return;
+	}
+
+	for (off = 0; off < dev_priv->ring.size; off += 4)
+		printf("%08zx :  %08x\n", off, bus_space_read_4(dev_priv->bst,
+		    dev_priv->ring.bsh, off));
+}
+
+void
+i915_ringbuffer_info(int kdev)
+{
+	struct drm_device	*dev = drm_get_device_from_kdev(kdev);
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	u_int32_t		 head, tail;
+
+	head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+	tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+
+	printf("RingHead :  %08x\n", head);
+	printf("RingTail :  %08x\n", tail);
+	printf("RingMask :  %08zx\n", dev_priv->ring.size - 1);
+	printf("RingSize :  %08zx\n", dev_priv->ring.size);
+	printf("Acthd :  %08x\n", I915_READ(IS_I965G(dev_priv) ?
+	    ACTHD_I965 : ACTHD));
+}
+
+#endif
diff -Naurp old/src/sys/dev/pci/drm/i915_drv.h new/src/sys/dev/pci/drm/i915_drv.h
--- old/src/sys/dev/pci/drm/i915_drv.h	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/i915_drv.h	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,3261 @@
+/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
+ */
+/*
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS 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.
+ *
+ */
+
+#ifndef _I915_DRV_H_
+#define _I915_DRV_H_
+
+/* General customization:
+ */
+
+#define DRIVER_AUTHOR		"Tungsten Graphics, Inc."
+
+#define DRIVER_NAME		"i915"
+#define DRIVER_DESC		"Intel Graphics"
+#define DRIVER_DATE		"20080730"
+
+enum pipe {
+	PIPE_A = 0,
+	PIPE_B,
+};
+
+/* Interface history:
+ *
+ * 1.1: Original.
+ * 1.2: Add Power Management
+ * 1.3: Add vblank support
+ * 1.4: Fix cmdbuffer path, add heap destroy
+ * 1.5: Add vblank pipe configuration
+ * 1.6: - New ioctl for scheduling buffer swaps on vertical blank
+ *      - Support vertical blank on secondary display pipe
+ */
+#define DRIVER_MAJOR		1
+#define DRIVER_MINOR		6
+#define DRIVER_PATCHLEVEL	0
+
+struct inteldrm_ring {
+	struct drm_obj		*ring_obj;
+	bus_space_handle_t	 bsh;
+	bus_size_t		 size;
+	u_int32_t		 head;
+	int32_t			 space;
+	u_int32_t		 tail;
+	u_int32_t		 woffset;
+};
+
+#define I915_FENCE_REG_NONE -1
+
+struct inteldrm_fence {
+	TAILQ_ENTRY(inteldrm_fence)	 list;
+	struct drm_obj			*obj;
+	u_int32_t			 last_rendering_seqno;
+};
+
+#if defined(__NetBSD__)
+struct workq;
+#endif /* defined(__NetBSD__) */
+
+/*
+ * lock ordering:
+ * exec lock,
+ * request lock
+ * list lock.
+ *
+ * XXX fence lock ,object lock
+ */
+struct inteldrm_softc {
+	struct device		 dev;
+	struct device		*drmdev;
+	bus_dma_tag_t		 agpdmat; /* tag from intagp for GEM */
+	bus_dma_tag_t		 dmat;
+	bus_space_tag_t		 bst;
+	struct agp_map		*agph;
+
+	u_long			 flags;
+	u_int16_t		 pci_device;
+
+	pci_chipset_tag_t	 pc;
+	pcitag_t		 tag;
+	pci_intr_handle_t	 ih;
+	void			*irqh;
+
+#if !defined(__NetBSD__)
+	struct vga_pci_bar	*regs;
+#else /* !defined(__NetBSD__) */
+	struct {
+		bus_space_tag_t		bst;
+		bus_space_handle_t	bsh;
+	}			 regs[1];
+#endif /* !defined(__NetBSD__) */
+
+	union flush {
+		struct {
+			bus_space_tag_t		bst;
+			bus_space_handle_t	bsh;
+			bool			valid;
+		} i9xx;
+		struct {
+			bus_dma_segment_t	seg;
+			caddr_t			kva;
+		} i8xx;
+	}			 ifp;
+	struct inteldrm_ring	 ring;
+	struct workq		*workq;
+#if !defined(__NetBSD__) /* XXX [GS] Cf. comment in inteldrm_attach(). */
+	struct vm_page		*pgs;
+#endif /* !defined(__NetBSD__) */
+	union hws {
+		struct drm_obj		*obj;
+		struct drm_dmamem	*dmamem;
+	}	hws;
+#define				 hws_obj	hws.obj
+#define				 hws_dmamem	hws.dmamem
+	void			*hw_status_page;
+	size_t			 max_gem_obj_size; /* XXX */
+
+	/* Protects user_irq_refcount and irq_mask reg */
+#if !defined(__NetBSD__)
+	struct mutex		 user_irq_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 user_irq_lock;
+	kcondvar_t		 condvar;
+#endif /* !defined(__NetBSD__) */
+	/* Refcount for user irq, only enabled when needed */
+	int			 user_irq_refcount;
+	/* Cached value of IMR to avoid reads in updating the bitfield */
+	u_int32_t		 irq_mask_reg;
+	u_int32_t		 pipestat[2];
+	/* these two  ironlake only, we should union this with pipestat XXX */
+	u_int32_t		 gt_irq_mask_reg;
+	u_int32_t		 pch_irq_mask_reg;
+
+#if !defined(__NetBSD__)
+	struct mutex		 fence_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 fence_lock;
+#endif /* !defined(__NetBSD__) */
+	struct inteldrm_fence	 fence_regs[16]; /* 965 */
+	int			 fence_reg_start; /* 4 by default */
+	int			 num_fence_regs; /* 8 pre-965, 16 post */
+
+#define	INTELDRM_QUIET		0x01 /* suspend close, get off the hardware */
+#define	INTELDRM_WEDGED		0x02 /* chipset hung pending reset */
+#define	INTELDRM_SUSPENDED	0x04 /* in vt switch, no commands */
+	int			 sc_flags; /* quiet, suspended, hung */
+	/* number of ioctls + faults in flight */
+	int			 entries;
+
+	/* protects inactive, flushing, active and exec locks */
+#if !defined(__NetBSD__)
+	struct mutex		 list_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 list_lock;
+#endif /* !defined(__NetBSD__) */
+
+	/* protects access to request_list */
+#if !defined(__NetBSD__)
+	struct mutex		 request_lock;
+#else /* !defined(__NetBSD__) */
+	kmutex_t		 request_lock;
+#endif /* !defined(__NetBSD__) */
+
+	/* Register state */
+	u8 saveLBB;
+	u32 saveDSPACNTR;
+	u32 saveDSPBCNTR;
+	u32 saveDSPARB;
+	u32 saveHWS;
+	u32 savePIPEACONF;
+	u32 savePIPEBCONF;
+	u32 savePIPEASRC;
+	u32 savePIPEBSRC;
+	u32 saveFPA0;
+	u32 saveFPA1;
+	u32 saveDPLL_A;
+	u32 saveDPLL_A_MD;
+	u32 saveHTOTAL_A;
+	u32 saveHBLANK_A;
+	u32 saveHSYNC_A;
+	u32 saveVTOTAL_A;
+	u32 saveVBLANK_A;
+	u32 saveVSYNC_A;
+	u32 saveBCLRPAT_A;
+	u32 saveTRANSACONF;
+	u32 saveTRANS_HTOTAL_A;
+	u32 saveTRANS_HBLANK_A;
+	u32 saveTRANS_HSYNC_A;
+	u32 saveTRANS_VTOTAL_A;
+	u32 saveTRANS_VBLANK_A;
+	u32 saveTRANS_VSYNC_A;
+	u32 savePIPEASTAT;
+	u32 saveDSPASTRIDE;
+	u32 saveDSPASIZE;
+	u32 saveDSPAPOS;
+	u32 saveDSPAADDR;
+	u32 saveDSPASURF;
+	u32 saveDSPATILEOFF;
+	u32 savePFIT_PGM_RATIOS;
+	u32 saveBLC_HIST_CTL;
+	u32 saveBLC_PWM_CTL;
+	u32 saveBLC_PWM_CTL2;
+	u32 saveBLC_CPU_PWM_CTL;
+	u32 saveBLC_CPU_PWM_CTL2;
+	u32 saveFPB0;
+	u32 saveFPB1;
+	u32 saveDPLL_B;
+	u32 saveDPLL_B_MD;
+	u32 saveHTOTAL_B;
+	u32 saveHBLANK_B;
+	u32 saveHSYNC_B;
+	u32 saveVTOTAL_B;
+	u32 saveVBLANK_B;
+	u32 saveVSYNC_B;
+	u32 saveBCLRPAT_B;
+	u32 saveTRANSBCONF;
+	u32 saveTRANS_HTOTAL_B;
+	u32 saveTRANS_HBLANK_B;
+	u32 saveTRANS_HSYNC_B;
+	u32 saveTRANS_VTOTAL_B;
+	u32 saveTRANS_VBLANK_B;
+	u32 saveTRANS_VSYNC_B;
+	u32 savePIPEBSTAT;
+	u32 saveDSPBSTRIDE;
+	u32 saveDSPBSIZE;
+	u32 saveDSPBPOS;
+	u32 saveDSPBADDR;
+	u32 saveDSPBSURF;
+	u32 saveDSPBTILEOFF;
+	u32 saveVGA0;
+	u32 saveVGA1;
+	u32 saveVGA_PD;
+	u32 saveVGACNTRL;
+	u32 saveADPA;
+	u32 saveLVDS;
+	u32 savePP_ON_DELAYS;
+	u32 savePP_OFF_DELAYS;
+	u32 saveDVOA;
+	u32 saveDVOB;
+	u32 saveDVOC;
+	u32 savePP_ON;
+	u32 savePP_OFF;
+	u32 savePP_CONTROL;
+	u32 savePP_DIVISOR;
+	u32 savePFIT_CONTROL;
+	u32 save_palette_a[256];
+	u32 save_palette_b[256];
+	u32 saveDPFC_CB_BASE;
+	u32 saveFBC_CFB_BASE;
+	u32 saveFBC_LL_BASE;
+	u32 saveFBC_CONTROL;
+	u32 saveFBC_CONTROL2;
+	u32 saveIER;
+	u32 saveIIR;
+	u32 saveIMR;
+	u32 saveDEIER;
+	u32 saveDEIMR;
+	u32 saveGTIER;
+	u32 saveGTIMR;
+	u32 saveFDI_RXA_IMR;
+	u32 saveFDI_RXB_IMR;
+	u32 saveCACHE_MODE_0;
+	u32 saveD_STATE;
+	u32 saveDSPCLK_GATE_D;
+	u32 saveDSPCLK_GATE;
+	u32 saveRENCLK_GATE_D1;
+	u32 saveRENCLK_GATE_D2;
+	u32 saveRAMCLK_GATE_D;
+	u32 saveDEUC;
+	u32 saveMI_ARB_STATE;
+	u32 saveSWF0[16];
+	u32 saveSWF1[16];
+	u32 saveSWF2[3];
+	u8 saveMSR;
+	u8 saveSR[8];
+	u8 saveGR[25];
+	u8 saveAR_INDEX;
+	u8 saveAR[21];
+	u8 saveDACMASK;
+	u8 saveCR[37];
+	uint64_t saveFENCE[16];
+	u32 saveCURACNTR;
+	u32 saveCURAPOS;
+	u32 saveCURABASE;
+	u32 saveCURBCNTR;
+	u32 saveCURBPOS;
+	u32 saveCURBBASE;
+	u32 saveCURSIZE;
+	u32 saveDP_B;
+	u32 saveDP_C;
+	u32 saveDP_D;
+	u32 savePIPEA_GMCH_DATA_M;
+	u32 savePIPEB_GMCH_DATA_M;
+	u32 savePIPEA_GMCH_DATA_N;
+	u32 savePIPEB_GMCH_DATA_N;
+	u32 savePIPEA_DP_LINK_M;
+	u32 savePIPEB_DP_LINK_M;
+	u32 savePIPEA_DP_LINK_N;
+	u32 savePIPEB_DP_LINK_N;
+	u32 saveFDI_RXA_CTL;
+	u32 saveFDI_TXA_CTL;
+	u32 saveFDI_RXB_CTL;
+	u32 saveFDI_TXB_CTL;
+	u32 savePFA_CTL_1;
+	u32 savePFB_CTL_1;
+	u32 savePFA_WIN_SZ;
+	u32 savePFB_WIN_SZ;
+	u32 savePFA_WIN_POS;
+	u32 savePFB_WIN_POS;
+	u32 savePCH_DREF_CONTROL;
+	u32 saveDISP_ARB_CTL;
+	u32 savePIPEA_DATA_M1;
+	u32 savePIPEA_DATA_N1;
+	u32 savePIPEA_LINK_M1;
+	u32 savePIPEA_LINK_N1;
+	u32 savePIPEB_DATA_M1;
+	u32 savePIPEB_DATA_N1;
+	u32 savePIPEB_LINK_M1;
+	u32 savePIPEB_LINK_N1;
+	u32 saveMCHBAR_RENDER_STANDBY;
+
+	struct {
+		/**
+		 * List of objects currently involved in rendering from the
+		 * ringbuffer.
+		 *
+		 * Includes buffers having the contents of their GPU caches
+		 * flushed, not necessarily primitives. last_rendering_seqno
+		 * represents when the rendering involved will be completed.
+		 *
+		 * A reference is held on the buffer while on this list.
+		 */
+		TAILQ_HEAD(i915_gem_list, inteldrm_obj) active_list;
+
+		/**
+		 * List of objects which are not in the ringbuffer but which
+		 * still have a write_domain which needs to be flushed before
+		 * unbinding.
+		 *
+		 * last_rendering_seqno is 0 while an object is in this list
+		 *
+		 * A reference is held on the buffer while on this list.
+		 */
+		struct i915_gem_list flushing_list;
+
+		/*
+		 * list of objects currently pending a GPU write flush.
+		 *
+		 * All elements on this list will either be on the active
+		 * or flushing list, last rendiering_seqno differentiates the
+		 * two.
+		 */
+		struct i915_gem_list gpu_write_list;
+		/**
+		 * LRU list of objects which are not in the ringbuffer and
+		 * are ready to unbind, but are still in the GTT.
+		 *
+		 * last_rendering_seqno is 0 while an object is in this list
+		 *
+		 * A reference is not held on the buffer while on this list,
+		 * as merely being GTT-bound shouldn't prevent its being
+		 * freed, and we'll pull it off the list in the free path.
+		 */
+		struct i915_gem_list inactive_list;
+
+		/* Fence LRU */
+		TAILQ_HEAD(i915_fence, inteldrm_fence)	fence_list;
+
+		/**
+		 * List of breadcrumbs associated with GPU requests currently
+		 * outstanding.
+		 */
+		TAILQ_HEAD(i915_request , inteldrm_request) request_list;
+
+		/**
+		 * We leave the user IRQ off as much as possible,
+		 * but this means that requests will finish and never
+		 * be retired once the system goes idle. Set a timer to
+		 * fire periodically while the ring is running. When it
+		 * fires, go retire requests in a workq.
+		 */
+#if !defined(__NetBSD__)
+		struct timeout retire_timer;
+		struct timeout hang_timer;
+#else /* !defined(__NetBSD__) */
+		callout_t retire_timer;
+		callout_t hang_timer;
+#endif /* !defined(__NetBSD__) */
+		/* for hangcheck */
+		int		hang_cnt;
+		u_int32_t	last_acthd;
+		u_int32_t	last_instdone;
+		u_int32_t	last_instdone1;
+
+		uint32_t next_gem_seqno;
+
+		/**
+		 * Flag if the X Server, and thus DRM, is not currently in
+		 * control of the device.
+		 *
+		 * This is set between LeaveVT and EnterVT.  It needs to be
+		 * replaced with a semaphore.  It also needs to be
+		 * transitioned away from for kernel modesetting.
+		 */
+		int suspended;
+
+		/**
+		 * Flag if the hardware appears to be wedged.
+		 *
+		 * This is set when attempts to idle the device timeout.
+		 * It prevents command submission from occuring and makes
+		 * every pending request fail
+		 */
+		int wedged;
+
+		/** Bit 6 swizzling required for X tiling */
+		uint32_t bit_6_swizzle_x;
+		/** Bit 6 swizzling required for Y tiling */
+		uint32_t bit_6_swizzle_y;
+	} mm;
+};
+
+struct inteldrm_file {
+	struct drm_file	file_priv;
+	struct {
+	} mm;
+};
+
+/* chip type flags */
+#define CHIP_I830	0x00001
+#define CHIP_I845G	0x00002
+#define CHIP_I85X	0x00004
+#define CHIP_I865G	0x00008
+#define CHIP_I9XX	0x00010
+#define CHIP_I915G	0x00020
+#define CHIP_I915GM	0x00040
+#define CHIP_I945G	0x00080
+#define CHIP_I945GM	0x00100
+#define CHIP_I965	0x00200
+#define CHIP_I965GM	0x00400
+#define CHIP_G33	0x00800
+#define CHIP_GM45	0x01000
+#define CHIP_G4X	0x02000
+#define CHIP_M		0x04000
+#define CHIP_HWS	0x08000
+#define CHIP_GEN2	0x10000
+#define CHIP_GEN3	0x20000
+#define CHIP_GEN4	0x40000
+#define CHIP_GEN6	0x80000
+#define	CHIP_PINEVIEW	0x100000
+#define	CHIP_IRONLAKE	0x200000
+#define CHIP_IRONLAKE_D	0x400000
+#define CHIP_IRONLAKE_M	0x800000
+
+/* flags we use in drm_obj's do_flags */
+#define I915_ACTIVE		0x0010	/* being used by the gpu. */
+#define I915_IN_EXEC		0x0020	/* being processed in execbuffer */
+#define I915_USER_PINNED	0x0040	/* BO has been pinned from userland */
+#define I915_GPU_WRITE		0x0080	/* BO has been not flushed */
+#define I915_DONTNEED		0x0100	/* BO backing pages purgable */
+#define I915_PURGED		0x0200	/* BO backing pages purged */
+#define I915_DIRTY		0x0400	/* BO written to since last bound */
+#define I915_EXEC_NEEDS_FENCE	0x0800	/* being processed but will need fence*/
+#define I915_FENCED_EXEC	0x1000	/* Most recent exec needs fence */
+#define I915_FENCE_INVALID	0x2000	/* fence has been lazily invalidated */
+
+/** driver private structure attached to each drm_gem_object */
+struct inteldrm_obj {
+	struct drm_obj				 obj;
+
+	/** This object's place on the active/flushing/inactive lists */
+	TAILQ_ENTRY(inteldrm_obj)		 list;
+	TAILQ_ENTRY(inteldrm_obj)		 write_list;
+	struct i915_gem_list			*current_list;
+	/* GTT binding. */
+	bus_dmamap_t				 dmamap;
+	bus_dma_segment_t			*dma_segs;
+	/* Current offset of the object in GTT space. */
+	bus_addr_t				 gtt_offset;
+	u_int32_t				*bit_17;
+	/* extra flags to bus_dma */
+	int					 dma_flags;
+	/* Fence register for this object. needed for tiling. */
+	int					 fence_reg;
+	/** refcount for times pinned this object in GTT space */
+	int					 pin_count;
+	/* number of times pinned by pin ioctl. */
+	u_int					 user_pin_count;
+
+	/** Breadcrumb of last rendering to the buffer. */
+	u_int32_t				 last_rendering_seqno;
+	u_int32_t				 last_write_seqno;
+	/** Current tiling mode for the object. */
+	u_int32_t				 tiling_mode;
+	u_int32_t				 stride;
+};
+
+/**
+ * Request queue structure.
+ *
+ * The request queue allows us to note sequence numbers that have been emitted
+ * and may be associated with active buffers to be retired.
+ *
+ * By keeping this list, we can avoid having to do questionable
+ * sequence-number comparisons on buffer last_rendering_seqnos, and associate
+ * an emission time with seqnos for tracking how far ahead of the GPU we are.
+ */
+struct inteldrm_request {
+	TAILQ_ENTRY(inteldrm_request)	list;
+	/** GEM sequence number associated with this request. */
+	uint32_t			seqno;
+};
+
+u_int32_t	inteldrm_read_hws(struct inteldrm_softc *, int);
+int		inteldrm_wait_ring(struct inteldrm_softc *dev, int n);
+void		inteldrm_begin_ring(struct inteldrm_softc *, int);
+void		inteldrm_out_ring(struct inteldrm_softc *, u_int32_t);
+void		inteldrm_advance_ring(struct inteldrm_softc *);
+void		inteldrm_update_ring(struct inteldrm_softc *);
+int		inteldrm_pipe_enabled(struct inteldrm_softc *, int);
+int		i915_init_phys_hws(struct inteldrm_softc *, bus_dma_tag_t);
+
+/* i915_irq.c */
+
+extern int i915_driver_irq_install(struct drm_device * dev);
+extern void i915_driver_irq_uninstall(struct drm_device * dev);
+extern int i915_enable_vblank(struct drm_device *dev, int crtc);
+extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
+extern void i915_user_irq_get(struct inteldrm_softc *);
+extern void i915_user_irq_put(struct inteldrm_softc *);
+
+/* XXX need bus_space_write_8, this evaluated arguments twice */
+static __inline void
+write64(struct inteldrm_softc *dev_priv, bus_size_t off, u_int64_t reg)
+{
+	bus_space_write_4(dev_priv->regs->bst, dev_priv->regs->bsh,
+	    off, (u_int32_t)reg);
+	bus_space_write_4(dev_priv->regs->bst, dev_priv->regs->bsh,
+	    off + 4, upper_32_bits(reg));
+}
+
+static __inline u_int64_t
+read64(struct inteldrm_softc *dev_priv, bus_size_t off)
+{
+	u_int32_t low, high;
+
+	low = bus_space_read_4(dev_priv->regs->bst,
+	    dev_priv->regs->bsh, off);
+	high = bus_space_read_4(dev_priv->regs->bst,
+	    dev_priv->regs->bsh, off + 4);
+
+	return ((u_int64_t)low | ((u_int64_t)high << 32));
+}
+
+#define I915_READ64(off)	read64(dev_priv, off)
+
+#define I915_WRITE64(off, reg)	write64(dev_priv, off, reg)
+
+#define I915_READ(reg)		bus_space_read_4(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg))
+#define I915_WRITE(reg,val)	bus_space_write_4(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg), (val))
+#define I915_READ16(reg)	bus_space_read_2(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg))
+#define I915_WRITE16(reg,val)	bus_space_write_2(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg), (val))
+#define I915_READ8(reg)		bus_space_read_1(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg))
+#define I915_WRITE8(reg,val)	bus_space_write_1(dev_priv->regs->bst,	\
+				    dev_priv->regs->bsh, (reg), (val))
+#define INTELDRM_VERBOSE 0
+#if INTELDRM_VERBOSE > 0
+#define	INTELDRM_VPRINTF(fmt, args...) DRM_INFO(fmt, ##args)
+#else
+#define	INTELDRM_VPRINTF(fmt, args...)
+#endif
+
+#define BEGIN_LP_RING(n) inteldrm_begin_ring(dev_priv, n)
+#define OUT_RING(n) inteldrm_out_ring(dev_priv, n)
+#define ADVANCE_LP_RING() inteldrm_advance_ring(dev_priv)
+
+/* MCH IFP BARs */
+#define	I915_IFPADDR	0x60
+#define I965_IFPADDR	0x70
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL		0x52
+#define INTEL_GMCH_ENABLED	0x4
+#define INTEL_GMCH_MEM_MASK	0x1
+#define INTEL_GMCH_MEM_64M	0x1
+#define INTEL_GMCH_MEM_128M	0
+
+#define INTEL_855_GMCH_GMS_MASK		(0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
+
+#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4)
+
+/* PCI config space */
+
+#define HPLLCC	0xc0 /* 855 only */
+#define   GC_CLOCK_CONTROL_MASK		(3 << 0)
+#define   GC_CLOCK_133_200		(0 << 0)
+#define   GC_CLOCK_100_200		(1 << 0)
+#define   GC_CLOCK_100_133		(2 << 0)
+#define   GC_CLOCK_166_250		(3 << 0)
+#define GCFGC	0xf0 /* 915+ only */
+#define   GC_LOW_FREQUENCY_ENABLE	(1 << 7)
+#define   GC_DISPLAY_CLOCK_190_200_MHZ	(0 << 4)
+#define   GC_DISPLAY_CLOCK_333_MHZ	(4 << 4)
+#define   GC_DISPLAY_CLOCK_MASK		(7 << 4)
+#define LBB	0xf4
+/* reset register, 965+. this is byte-sized */
+#define GDRST	0xc0
+#define GDRST_FULL	(0<<2)
+#define GDRST_RENDER	(1<<2)
+#define GDRST_MEDIA	(3<<2)
+
+/* VGA stuff */
+
+#define VGA_ST01_MDA 0x3ba
+#define VGA_ST01_CGA 0x3da
+
+#define VGA_MSR_WRITE 0x3c2
+#define VGA_MSR_READ 0x3cc
+#define   VGA_MSR_MEM_EN (1<<1)
+#define   VGA_MSR_CGA_MODE (1<<0)
+
+#define VGA_SR_INDEX 0x3c4
+#define VGA_SR_DATA 0x3c5
+
+#define VGA_AR_INDEX 0x3c0
+#define   VGA_AR_VID_EN (1<<5)
+#define VGA_AR_DATA_WRITE 0x3c0
+#define VGA_AR_DATA_READ 0x3c1
+
+#define VGA_GR_INDEX 0x3ce
+#define VGA_GR_DATA 0x3cf
+/* GR05 */
+#define   VGA_GR_MEM_READ_MODE_SHIFT 3
+#define     VGA_GR_MEM_READ_MODE_PLANE 1
+/* GR06 */
+#define   VGA_GR_MEM_MODE_MASK 0xc
+#define   VGA_GR_MEM_MODE_SHIFT 2
+#define   VGA_GR_MEM_A0000_AFFFF 0
+#define   VGA_GR_MEM_A0000_BFFFF 1
+#define   VGA_GR_MEM_B0000_B7FFF 2
+#define   VGA_GR_MEM_B0000_BFFFF 3
+
+#define VGA_DACMASK 0x3c6
+#define VGA_DACRX 0x3c7
+#define VGA_DACWX 0x3c8
+#define VGA_DACDATA 0x3c9
+
+#define VGA_CR_INDEX_MDA 0x3b4
+#define VGA_CR_DATA_MDA 0x3b5
+#define VGA_CR_INDEX_CGA 0x3d4
+#define VGA_CR_DATA_CGA 0x3d5
+
+/*
+ * Memory interface instructions used by the kernel
+ */
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+
+#define MI_NOOP			MI_INSTR(0, 0)
+#define MI_USER_INTERRUPT	MI_INSTR(0x02, 0)
+#define MI_WAIT_FOR_EVENT       MI_INSTR(0x03, 0)
+#define   MI_WAIT_FOR_PLANE_B_FLIP      (1<<6)
+#define   MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
+#define   MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
+#define MI_FLUSH		MI_INSTR(0x04, 0)
+#define   MI_READ_FLUSH		(1 << 0)
+#define   MI_EXE_FLUSH		(1 << 1)
+#define   MI_NO_WRITE_FLUSH	(1 << 2)
+#define   MI_SCENE_COUNT	(1 << 3) /* just increment scene count */
+#define   MI_END_SCENE		(1 << 4) /* flush binner and incr scene count */
+#define MI_BATCH_BUFFER_END	MI_INSTR(0x0a, 0)
+#define MI_REPORT_HEAD		MI_INSTR(0x07, 0)
+#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0)
+#define MI_STORE_DWORD_IMM	MI_INSTR(0x20, 1)
+#define   MI_MEM_VIRTUAL	(1 << 22) /* 965+ only */
+#define MI_STORE_DWORD_INDEX	MI_INSTR(0x21, 1)
+#define MI_STORE_DWORD_INDEX_SHIFT 2
+#define MI_LOAD_REGISTER_IMM	MI_INSTR(0x22, 1)
+#define MI_BATCH_BUFFER		MI_INSTR(0x30, 1)
+#define   MI_BATCH_NON_SECURE	(1)
+#define   MI_BATCH_NON_SECURE_I965 (1<<8)
+#define MI_BATCH_BUFFER_START	MI_INSTR(0x31, 0)
+
+/**
+ * Reads a dword out of the status page, which is written to from the command
+ * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
+ * MI_STORE_DATA_IMM.
+ *
+ * The following dwords have a reserved meaning:
+ * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
+ * 0x04: ring 0 head pointer
+ * 0x05: ring 1 head pointer (915-class)
+ * 0x06: ring 2 head pointer (915-class)
+ * 0x10-0x1b: Context status DWords (GM45)
+ * 0x1f: Last written status offset. (GM45)
+ *
+ * The area from dword 0x20 to 0x3ff is available for driver usage.
+ */
+#define READ_HWSP(dev_priv, reg)  inteldrm_read_hws(dev_priv, reg)
+#define I915_GEM_HWS_INDEX		0x20
+
+/*
+ * 3D instructions used by the kernel
+ */
+#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags))
+
+#define GFX_OP_RASTER_RULES    ((0x3<<29)|(0x7<<24))
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define   SC_UPDATE_SCISSOR       (0x1<<1)
+#define   SC_ENABLE_MASK          (0x1<<0)
+#define   SC_ENABLE               (0x1<<0)
+#define GFX_OP_LOAD_INDIRECT   ((0x3<<29)|(0x1d<<24)|(0x7<<16))
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define   SCI_YMIN_MASK      (0xffff<<16)
+#define   SCI_XMIN_MASK      (0xffff<<0)
+#define   SCI_YMAX_MASK      (0xffff<<16)
+#define   SCI_XMAX_MASK      (0xffff<<0)
+#define GFX_OP_SCISSOR_ENABLE	 ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT	 ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DESTBUFFER_INFO	 ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_DRAWRECT_INFO_I965  ((0x7900<<16)|0x2)
+#define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)
+#define XY_SRC_COPY_BLT_CMD		((2<<29)|(0x53<<22)|6)
+#define XY_MONO_SRC_COPY_IMM_BLT	((2<<29)|(0x71<<22)|5)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA	(1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB	(1<<20)
+#define   BLT_DEPTH_8			(0<<24)
+#define   BLT_DEPTH_16_565		(1<<24)
+#define   BLT_DEPTH_16_1555		(2<<24)
+#define   BLT_DEPTH_32			(3<<24)
+#define   BLT_ROP_GXCOPY		(0xcc<<16)
+#define XY_SRC_COPY_BLT_SRC_TILED	(1<<15) /* 965+ only */
+#define XY_SRC_COPY_BLT_DST_TILED	(1<<11) /* 965+ only */
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define   ASYNC_FLIP                (1<<22)
+#define   DISPLAY_PLANE_A           (0<<20)
+#define   DISPLAY_PLANE_B           (1<<20)
+
+/*
+ * Fence registers
+ */
+#define FENCE_REG_830_0			0x2000
+#define FENCE_REG_945_8			0x3000
+#define   I830_FENCE_START_MASK		0x07f80000
+#define   I830_FENCE_TILING_Y_SHIFT	12
+#define   I830_FENCE_SIZE_BITS(size)	((ffs((size) >> 19) - 1) << 8)
+#define   I830_FENCE_PITCH_SHIFT	4
+#define   I830_FENCE_REG_VALID		(1<<0)
+#define   I915_FENCE_MAX_PITCH_VAL	4
+#define   I830_FENCE_MAX_PITCH_VAL	6
+#define   I830_FENCE_MAX_SIZE_VAL	(1<<8)
+
+#define   I915_FENCE_START_MASK		0x0ff00000
+#define   I915_FENCE_SIZE_BITS(size)	((ffs((size) >> 20) - 1) << 8)
+
+#define FENCE_REG_965_0			0x03000
+#define   I965_FENCE_PITCH_SHIFT	2
+#define   I965_FENCE_TILING_Y_SHIFT	1
+#define   I965_FENCE_REG_VALID		(1<<0)
+#define   I965_FENCE_MAX_PITCH_VAL	0x0400
+
+/*
+ * Instruction and interrupt control regs
+ */
+
+#define PGTBL_ER	0x02024
+#define PRB0_TAIL	0x02030
+#define PRB0_HEAD	0x02034
+#define PRB0_START	0x02038
+#define PRB0_CTL	0x0203c
+#define   TAIL_ADDR		0x001FFFF8
+#define   HEAD_WRAP_COUNT	0xFFE00000
+#define   HEAD_WRAP_ONE		0x00200000
+#define   HEAD_ADDR		0x001FFFFC
+#define   RING_NR_PAGES		0x001FF000
+#define   RING_REPORT_MASK	0x00000006
+#define   RING_REPORT_64K	0x00000002
+#define   RING_REPORT_128K	0x00000004
+#define   RING_NO_REPORT	0x00000000
+#define   RING_VALID_MASK	0x00000001
+#define   RING_VALID		0x00000001
+#define   RING_INVALID		0x00000000
+#define   RING_WAIT_I8XX	(1<<0) /* gen2, PRBx_HEAD */
+#define   RING_WAIT		(1<<11) /* gen3+, PRBx_CTL */
+#define PRB1_TAIL	0x02040 /* 915+ only */
+#define PRB1_HEAD	0x02044 /* 915+ only */
+#define PRB1_START	0x02048 /* 915+ only */
+#define PRB1_CTL	0x0204c /* 915+ only */
+#define IPEIR_I965	0x02064
+#define IPEHR_I965	0x02068
+#define INSTDONE_I965	0x0206c
+#define INSTPS		0x02070 /* 965+ only */
+#define INSTDONE1	0x0207c /* 965+ only */
+#define ACTHD_I965	0x02074
+#define HWS_PGA		0x02080
+#define HWS_ADDRESS_MASK	0xfffff000
+#define HWS_START_ADDRESS_SHIFT	4
+#define IPEIR		0x02088
+#define IPEHR		0x0208c
+#define INSTDONE	0x02090
+#define NOPID		0x02094
+#define HWSTAM		0x02098
+
+#define MI_MODE		0x0209c
+#define VS_TIMER_DISPATCH	(1 << 6)
+
+#define SCPD0		0x0209c /* 915+ only */
+#define IER		0x020a0
+#define IIR		0x020a4
+#define IMR		0x020a8
+#define ISR		0x020ac
+#define   I915_PIPE_CONTROL_NOTIFY_INTERRUPT		(1<<18)
+#define   I915_DISPLAY_PORT_INTERRUPT			(1<<17)
+#define   I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT	(1<<15)
+#define   I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT	(1<<14)
+#define   I915_HWB_OOM_INTERRUPT			(1<<13)
+#define   I915_SYNC_STATUS_INTERRUPT			(1<<12)
+#define   I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT	(1<<11)
+#define   I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT	(1<<10)
+#define   I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT	(1<<9)
+#define   I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT	(1<<8)
+#define   I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT		(1<<7)
+#define   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT		(1<<6)
+#define   I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT		(1<<5)
+#define   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT		(1<<4)
+#define   I915_DEBUG_INTERRUPT				(1<<2)
+#define   I915_USER_INTERRUPT				(1<<1)
+#define   I915_ASLE_INTERRUPT				(1<<0)
+#define EIR		0x020b0
+#define EMR		0x020b4
+#define ESR		0x020b8
+#define   GM45_ERROR_PAGE_TABLE				(1<<5)
+#define   GM45_ERROR_MEM_PRIV				(1<<4)
+#define   I915_ERROR_PAGE_TABLE				(1<<4)
+#define   GM45_ERROR_CP_PRIV				(1<<3)
+#define   I915_ERROR_MEMORY_REFRESH			(1<<1)
+#define   I915_ERROR_INSTRUCTION			(1<<0)
+/* ironlake error bits */
+#define   GT_ERROR_PTE					(1<<4)
+	/* memory privilege violation error */
+#define   GT_ERROR_MPE					(1<<3)
+	/* command privilege violation error */
+#define   GT_ERROR_CPE					(1<<2)
+#define INSTPM	        0x020c0
+#define ACTHD	        0x020c8
+#define FW_BLC		0x020d8
+#define FW_BLC_SELF	0x020e0 /* 915+ only */
+#define MI_ARB_STATE	0x020e4 /* 915+ only */
+#define   MI_ARB_MASK_SHIFT	  16	/* shift for enable bits */
+
+/* Make render/texture TLB fetches lower priorty than associated data
+ *   fetches. This is not turned on by default
+ */
+#define   MI_ARB_RENDER_TLB_LOW_PRIORITY	(1 << 15)
+
+/* Isoch request wait on GTT enable (Display A/B/C streams).
+ * Make isoch requests stall on the TLB update. May cause
+ * display underruns (test mode only)
+ */
+#define   MI_ARB_ISOCH_WAIT_GTT			(1 << 14)
+
+/* Block grant count for isoch requests when block count is
+ * set to a finite value.
+ */
+#define   MI_ARB_BLOCK_GRANT_MASK		(3 << 12)
+#define   MI_ARB_BLOCK_GRANT_8			(0 << 12)	/* for 3 display planes */
+#define   MI_ARB_BLOCK_GRANT_4			(1 << 12)	/* for 2 display planes */
+#define   MI_ARB_BLOCK_GRANT_2			(2 << 12)	/* for 1 display plane */
+#define   MI_ARB_BLOCK_GRANT_0			(3 << 12)	/* don't use */
+
+/* Enable render writes to complete in C2/C3/C4 power states.
+ * If this isn't enabled, render writes are prevented in low
+ * power states. That seems bad to me.
+ */
+#define   MI_ARB_C3_LP_WRITE_ENABLE		(1 << 11)
+
+/* This acknowledges an async flip immediately instead
+ * of waiting for 2TLB fetches.
+ */
+#define   MI_ARB_ASYNC_FLIP_ACK_IMMEDIATE	(1 << 10)
+
+/* Enables non-sequential data reads through arbiter
+ */
+#define   MI_ARB_DUAL_DATA_PHASE_DISABLE       	(1 << 9)
+
+/* Disable FSB snooping of cacheable write cycles from binner/render
+ * command stream
+ */
+#define   MI_ARB_CACHE_SNOOP_DISABLE		(1 << 8)
+
+/* Arbiter time slice for non-isoch streams */
+#define   MI_ARB_TIME_SLICE_MASK		(7 << 5)
+#define   MI_ARB_TIME_SLICE_1			(0 << 5)
+#define   MI_ARB_TIME_SLICE_2			(1 << 5)
+#define   MI_ARB_TIME_SLICE_4			(2 << 5)
+#define   MI_ARB_TIME_SLICE_6			(3 << 5)
+#define   MI_ARB_TIME_SLICE_8			(4 << 5)
+#define   MI_ARB_TIME_SLICE_10			(5 << 5)
+#define   MI_ARB_TIME_SLICE_14			(6 << 5)
+#define   MI_ARB_TIME_SLICE_16			(7 << 5)
+
+/* Low priority grace period page size */
+#define   MI_ARB_LOW_PRIORITY_GRACE_4KB		(0 << 4)	/* default */
+#define   MI_ARB_LOW_PRIORITY_GRACE_8KB		(1 << 4)
+
+/* Disable display A/B trickle feed */
+#define   MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE	(1 << 2)
+
+/* Set display plane priority */
+#define   MI_ARB_DISPLAY_PRIORITY_A_B		(0 << 0)	/* display A > display B */
+#define   MI_ARB_DISPLAY_PRIORITY_B_A		(1 << 0)	/* display B > display A */
+
+#define CACHE_MODE_0	0x02120 /* 915+ only */
+#define   CM0_MASK_SHIFT          16
+#define   CM0_IZ_OPT_DISABLE      (1<<6)
+#define   CM0_ZR_OPT_DISABLE      (1<<5)
+#define   CM0_DEPTH_EVICT_DISABLE (1<<4)
+#define   CM0_COLOR_EVICT_DISABLE (1<<3)
+#define   CM0_DEPTH_WRITE_DISABLE (1<<1)
+#define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
+#define GFX_FLSH_CNTL	0x02170 /* 915+ only */
+
+/*
+ * Framebuffer compression (915+ only)
+ */
+
+#define FBC_CFB_BASE		0x03200 /* 4k page aligned */
+#define FBC_LL_BASE		0x03204 /* 4k page aligned */
+#define FBC_CONTROL		0x03208
+#define   FBC_CTL_EN		(1<<31)
+#define   FBC_CTL_PERIODIC	(1<<30)
+#define   FBC_CTL_INTERVAL_SHIFT (16)
+#define   FBC_CTL_UNCOMPRESSIBLE (1<<14)
+#define   FBC_CTL_STRIDE_SHIFT	(5)
+#define   FBC_CTL_FENCENO	(1<<0)
+#define FBC_COMMAND		0x0320c
+#define   FBC_CMD_COMPRESS	(1<<0)
+#define FBC_STATUS		0x03210
+#define   FBC_STAT_COMPRESSING	(1<<31)
+#define   FBC_STAT_COMPRESSED	(1<<30)
+#define   FBC_STAT_MODIFIED	(1<<29)
+#define   FBC_STAT_CURRENT_LINE	(1<<0)
+#define FBC_CONTROL2		0x03214
+#define   FBC_CTL_FENCE_DBL	(0<<4)
+#define   FBC_CTL_IDLE_IMM	(0<<2)
+#define   FBC_CTL_IDLE_FULL	(1<<2)
+#define   FBC_CTL_IDLE_LINE	(2<<2)
+#define   FBC_CTL_IDLE_DEBUG	(3<<2)
+#define   FBC_CTL_CPU_FENCE	(1<<1)
+#define   FBC_CTL_PLANEA	(0<<0)
+#define   FBC_CTL_PLANEB	(1<<0)
+#define FBC_FENCE_OFF		0x0321b
+
+#define FBC_LL_SIZE		(1536)
+
+/* Framebuffer compression for GM45+ */
+#define DPFC_CB_BASE		0x3200
+#define DPFC_CONTROL		0x3208
+#define   DPFC_CTL_EN		(1<<31)
+#define   DPFC_CTL_PLANEA	(0<<30)
+#define   DPFC_CTL_PLANEB	(1<<30)
+#define   DPFC_CTL_FENCE_EN	(1<<29)
+#define   DPFC_SR_EN		(1<<10)
+#define   DPFC_CTL_LIMIT_1X	(0<<6)
+#define   DPFC_CTL_LIMIT_2X	(1<<6)
+#define   DPFC_CTL_LIMIT_4X	(2<<6)
+#define DPFC_RECOMP_CTL		0x320c
+#define   DPFC_RECOMP_STALL_EN	(1<<27)
+#define   DPFC_RECOMP_STALL_WM_SHIFT (16)
+#define   DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
+#define   DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
+#define   DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
+#define DPFC_STATUS		0x3210
+#define   DPFC_INVAL_SEG_SHIFT  (16)
+#define   DPFC_INVAL_SEG_MASK	(0x07ff0000)
+#define   DPFC_COMP_SEG_SHIFT	(0)
+#define   DPFC_COMP_SEG_MASK	(0x000003ff)
+#define DPFC_STATUS2		0x3214
+#define DPFC_FENCE_YOFF		0x3218
+#define DPFC_CHICKEN		0x3224
+#define   DPFC_HT_MODIFY	(1<<31)
+
+/*
+ * GPIO regs
+ */
+#define GPIOA			0x5010
+#define GPIOB			0x5014
+#define GPIOC			0x5018
+#define GPIOD			0x501c
+#define GPIOE			0x5020
+#define GPIOF			0x5024
+#define GPIOG			0x5028
+#define GPIOH			0x502c
+# define GPIO_CLOCK_DIR_MASK		(1 << 0)
+# define GPIO_CLOCK_DIR_IN		(0 << 1)
+# define GPIO_CLOCK_DIR_OUT		(1 << 1)
+# define GPIO_CLOCK_VAL_MASK		(1 << 2)
+# define GPIO_CLOCK_VAL_OUT		(1 << 3)
+# define GPIO_CLOCK_VAL_IN		(1 << 4)
+# define GPIO_CLOCK_PULLUP_DISABLE	(1 << 5)
+# define GPIO_DATA_DIR_MASK		(1 << 8)
+# define GPIO_DATA_DIR_IN		(0 << 9)
+# define GPIO_DATA_DIR_OUT		(1 << 9)
+# define GPIO_DATA_VAL_MASK		(1 << 10)
+# define GPIO_DATA_VAL_OUT		(1 << 11)
+# define GPIO_DATA_VAL_IN		(1 << 12)
+# define GPIO_DATA_PULLUP_DISABLE	(1 << 13)
+
+/*
+ * Clock control & power management
+ */
+
+#define VGA0	0x6000
+#define VGA1	0x6004
+#define VGA_PD	0x6010
+#define   VGA0_PD_P2_DIV_4	(1 << 7)
+#define   VGA0_PD_P1_DIV_2	(1 << 5)
+#define   VGA0_PD_P1_SHIFT	0
+#define   VGA0_PD_P1_MASK	(0x1f << 0)
+#define   VGA1_PD_P2_DIV_4	(1 << 15)
+#define   VGA1_PD_P1_DIV_2	(1 << 13)
+#define   VGA1_PD_P1_SHIFT	8
+#define   VGA1_PD_P1_MASK	(0x1f << 8)
+#define DPLL_A	0x06014
+#define DPLL_B	0x06018
+#define   DPLL_VCO_ENABLE		(1 << 31)
+#define   DPLL_DVO_HIGH_SPEED		(1 << 30)
+#define   DPLL_SYNCLOCK_ENABLE		(1 << 29)
+#define   DPLL_VGA_MODE_DIS		(1 << 28)
+#define   DPLLB_MODE_DAC_SERIAL		(1 << 26) /* i915 */
+#define   DPLLB_MODE_LVDS		(2 << 26) /* i915 */
+#define   DPLL_MODE_MASK		(3 << 26)
+#define   DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */
+#define   DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */
+#define   DPLLB_LVDS_P2_CLOCK_DIV_14	(0 << 24) /* i915 */
+#define   DPLLB_LVDS_P2_CLOCK_DIV_7	(1 << 24) /* i915 */
+#define   DPLL_P2_CLOCK_DIV_MASK	0x03000000 /* i915 */
+#define   DPLL_FPA01_P1_POST_DIV_MASK	0x00ff0000 /* i915 */
+
+#define I915_FIFO_UNDERRUN_STATUS		(1UL<<31)
+#define I915_CRC_ERROR_ENABLE			(1UL<<29)
+#define I915_CRC_DONE_ENABLE			(1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE			(1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE		(1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE	(1UL<<24)
+#define I915_DPST_EVENT_ENABLE			(1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE		(1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE		(1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE	(1UL<<20)
+#define I915_START_VBLANK_INTERRUPT_ENABLE	(1UL<<18)	/* 965 or later */
+#define I915_VBLANK_INTERRUPT_ENABLE		(1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE		(1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS		(1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS		(1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS		(1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS		(1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS	(1UL<<8)
+#define I915_DPST_EVENT_STATUS			(1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS		(1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS		(1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS	(1UL<<4)
+#define I915_START_VBLANK_INTERRUPT_STATUS	(1UL<<2)	/* 965 or later */
+#define I915_VBLANK_INTERRUPT_STATUS		(1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS		(1UL<<0)
+
+#define SRX_INDEX		0x3c4
+#define SRX_DATA		0x3c5
+#define SR01			1
+#define SR01_SCREEN_OFF		(1<<5)
+
+#define PPCR			0x61204
+#define PPCR_ON			(1<<0)
+
+#define DVOB			0x61140
+#define DVOB_ON			(1<<31)
+#define DVOC			0x61160
+#define DVOC_ON			(1<<31)
+#define LVDS			0x61180
+#define LVDS_ON			(1<<31)
+
+#define ADPA			0x61100
+#define ADPA_DPMS_MASK		(~(3<<10))
+#define ADPA_DPMS_ON		(0<<10)
+#define ADPA_DPMS_SUSPEND	(1<<10)
+#define ADPA_DPMS_STANDBY	(2<<10)
+#define ADPA_DPMS_OFF		(3<<10)
+
+#define RING_TAIL		0x00
+#define TAIL_ADDR		0x001FFFF8
+#define RING_HEAD		0x04
+#define HEAD_WRAP_COUNT		0xFFE00000
+#define HEAD_WRAP_ONE		0x00200000
+#define HEAD_ADDR		0x001FFFFC
+#define RING_START		0x08
+#define START_ADDR		0xFFFFF000
+#define RING_LEN		0x0C
+#define RING_NR_PAGES		0x001FF000
+#define RING_REPORT_MASK	0x00000006
+#define RING_REPORT_64K		0x00000002
+#define RING_REPORT_128K	0x00000004
+#define RING_NO_REPORT		0x00000000
+#define RING_VALID_MASK		0x00000001
+#define RING_VALID		0x00000001
+#define RING_INVALID		0x00000000
+
+/* Scratch pad debug 0 reg:
+ */
+#define   DPLL_FPA01_P1_POST_DIV_MASK_I830	0x001f0000
+/*
+ * The i830 generation, in LVDS mode, defines P1 as the bit number set within
+ * this field (only one bit may be set).
+ */
+#define   DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS	0x003f0000
+#define   DPLL_FPA01_P1_POST_DIV_SHIFT	16
+#define   DPLL_FPA01_P1_POST_DIV_SHIFT_IGD 15
+/* i830, required in DVO non-gang */
+#define   PLL_P2_DIVIDE_BY_4		(1 << 23)
+#define   PLL_P1_DIVIDE_BY_TWO		(1 << 21) /* i830 */
+#define   PLL_REF_INPUT_DREFCLK		(0 << 13)
+#define   PLL_REF_INPUT_TVCLKINA	(1 << 13) /* i830 */
+#define   PLL_REF_INPUT_TVCLKINBC	(2 << 13) /* SDVO TVCLKIN */
+#define   PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
+#define   PLL_REF_INPUT_MASK		(3 << 13)
+#define   PLL_LOAD_PULSE_PHASE_SHIFT		9
+/* IGDNG */
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT     9
+# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK      (7 << 9)
+# define PLL_REF_SDVO_HDMI_MULTIPLIER(x)	(((x)-1) << 9)
+# define DPLL_FPA1_P1_POST_DIV_SHIFT            0
+# define DPLL_FPA1_P1_POST_DIV_MASK             0xff
+
+/*
+ * Parallel to Serial Load Pulse phase selection.
+ * Selects the phase for the 10X DPLL clock for the PCIe
+ * digital display port. The range is 4 to 13; 10 or more
+ * is just a flip delay. The default is 6
+ */
+#define   PLL_LOAD_PULSE_PHASE_MASK		(0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
+#define   DISPLAY_RATE_SELECT_FPA1		(1 << 8)
+/*
+ * SDVO multiplier for 945G/GM. Not used on 965.
+ */
+#define   SDVO_MULTIPLIER_MASK			0x000000ff
+#define   SDVO_MULTIPLIER_SHIFT_HIRES		4
+#define   SDVO_MULTIPLIER_SHIFT_VGA		0
+#define DPLL_A_MD 0x0601c /* 965+ only */
+/*
+ * UDI pixel divider, controlling how many pixels are stuffed into a packet.
+ *
+ * Value is pixels minus 1.  Must be set to 1 pixel for SDVO.
+ */
+#define   DPLL_MD_UDI_DIVIDER_MASK		0x3f000000
+#define   DPLL_MD_UDI_DIVIDER_SHIFT		24
+/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */
+#define   DPLL_MD_VGA_UDI_DIVIDER_MASK		0x003f0000
+#define   DPLL_MD_VGA_UDI_DIVIDER_SHIFT		16
+/*
+ * SDVO/UDI pixel multiplier.
+ *
+ * SDVO requires that the bus clock rate be between 1 and 2 GHz, and the bus
+ * clock rate is 10 times the DPLL clock.  At low resolution/refresh rate
+ * modes, the bus rate would be below the limits, so SDVO allows for stuffing
+ * dummy bytes in the datastream at an increased clock rate, with both sides of
+ * the link knowing how many bytes are fill.
+ *
+ * So, for a mode with a dotclock of 65MHz, we would want to double the clock
+ * rate to 130MHz to get a bus rate of 1.30GHz.  The DPLL clock rate would be
+ * set to 130MHz, and the SDVO multiplier set to 2x in this register and
+ * through an SDVO command.
+ *
+ * This register field has values of multiplication factor minus 1, with
+ * a maximum multiplier of 5 for SDVO.
+ */
+#define   DPLL_MD_UDI_MULTIPLIER_MASK		0x00003f00
+#define   DPLL_MD_UDI_MULTIPLIER_SHIFT		8
+/*
+ * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK.
+ * This best be set to the default value (3) or the CRT won't work. No,
+ * I don't entirely understand what this does...
+ */
+#define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK	0x0000003f
+#define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT	0
+#define DPLL_B_MD 0x06020 /* 965+ only */
+#define FPA0	0x06040
+#define FPA1	0x06044
+#define FPB0	0x06048
+#define FPB1	0x0604c
+#define   FP_N_DIV_MASK		0x003f0000
+#define   FP_N_IGD_DIV_MASK	0x00ff0000
+#define   FP_N_DIV_SHIFT		16
+#define   FP_M1_DIV_MASK	0x00003f00
+#define   FP_M1_DIV_SHIFT		 8
+#define   FP_M2_DIV_MASK	0x0000003f
+#define   FP_M2_IGD_DIV_MASK	0x000000ff
+#define   FP_M2_DIV_SHIFT		 0
+#define DPLL_TEST	0x606c
+#define   DPLLB_TEST_SDVO_DIV_1		(0 << 22)
+#define   DPLLB_TEST_SDVO_DIV_2		(1 << 22)
+#define   DPLLB_TEST_SDVO_DIV_4		(2 << 22)
+#define   DPLLB_TEST_SDVO_DIV_MASK	(3 << 22)
+#define   DPLLB_TEST_N_BYPASS		(1 << 19)
+#define   DPLLB_TEST_M_BYPASS		(1 << 18)
+#define   DPLLB_INPUT_BUFFER_ENABLE	(1 << 16)
+#define   DPLLA_TEST_N_BYPASS		(1 << 3)
+#define   DPLLA_TEST_M_BYPASS		(1 << 2)
+#define   DPLLA_INPUT_BUFFER_ENABLE	(1 << 0)
+#define D_STATE		0x6104
+#define  DSTATE_PLL_D3_OFF			(1<<3)
+#define  DSTATE_GFX_CLOCK_GATING		(1<<1)
+#define  DSTATE_DOT_CLOCK_GATING		(1<<0)
+#define DSPCLK_GATE_D		0x6200
+# define DPUNIT_B_CLOCK_GATE_DISABLE		(1 << 30) /* 965 */
+# define VSUNIT_CLOCK_GATE_DISABLE		(1 << 29) /* 965 */
+# define VRHUNIT_CLOCK_GATE_DISABLE		(1 << 28) /* 965 */
+# define VRDUNIT_CLOCK_GATE_DISABLE		(1 << 27) /* 965 */
+# define AUDUNIT_CLOCK_GATE_DISABLE		(1 << 26) /* 965 */
+# define DPUNIT_A_CLOCK_GATE_DISABLE		(1 << 25) /* 965 */
+# define DPCUNIT_CLOCK_GATE_DISABLE		(1 << 24) /* 965 */
+# define TVRUNIT_CLOCK_GATE_DISABLE		(1 << 23) /* 915-945 */
+# define TVCUNIT_CLOCK_GATE_DISABLE		(1 << 22) /* 915-945 */
+# define TVFUNIT_CLOCK_GATE_DISABLE		(1 << 21) /* 915-945 */
+# define TVEUNIT_CLOCK_GATE_DISABLE		(1 << 20) /* 915-945 */
+# define DVSUNIT_CLOCK_GATE_DISABLE		(1 << 19) /* 915-945 */
+# define DSSUNIT_CLOCK_GATE_DISABLE		(1 << 18) /* 915-945 */
+# define DDBUNIT_CLOCK_GATE_DISABLE		(1 << 17) /* 915-945 */
+# define DPRUNIT_CLOCK_GATE_DISABLE		(1 << 16) /* 915-945 */
+# define DPFUNIT_CLOCK_GATE_DISABLE		(1 << 15) /* 915-945 */
+# define DPBMUNIT_CLOCK_GATE_DISABLE		(1 << 14) /* 915-945 */
+# define DPLSUNIT_CLOCK_GATE_DISABLE		(1 << 13) /* 915-945 */
+# define DPLUNIT_CLOCK_GATE_DISABLE		(1 << 12) /* 915-945 */
+# define DPOUNIT_CLOCK_GATE_DISABLE		(1 << 11)
+# define DPBUNIT_CLOCK_GATE_DISABLE		(1 << 10)
+# define DCUNIT_CLOCK_GATE_DISABLE		(1 << 9)
+# define DPUNIT_CLOCK_GATE_DISABLE		(1 << 8)
+# define VRUNIT_CLOCK_GATE_DISABLE		(1 << 7) /* 915+: reserved */
+# define OVHUNIT_CLOCK_GATE_DISABLE		(1 << 6) /* 830-865 */
+# define DPIOUNIT_CLOCK_GATE_DISABLE		(1 << 6) /* 915-945 */
+# define OVFUNIT_CLOCK_GATE_DISABLE		(1 << 5)
+# define OVBUNIT_CLOCK_GATE_DISABLE		(1 << 4)
+/**
+ * This bit must be set on the 830 to prevent hangs when turning off the
+ * overlay scaler.
+ */
+# define OVRUNIT_CLOCK_GATE_DISABLE		(1 << 3)
+# define OVCUNIT_CLOCK_GATE_DISABLE		(1 << 2)
+# define OVUUNIT_CLOCK_GATE_DISABLE		(1 << 1)
+# define ZVUNIT_CLOCK_GATE_DISABLE		(1 << 0) /* 830 */
+# define OVLUNIT_CLOCK_GATE_DISABLE		(1 << 0) /* 845,865 */
+
+#define RENCLK_GATE_D1		0x6204
+# define BLITTER_CLOCK_GATE_DISABLE		(1 << 13) /* 945GM only */
+# define MPEG_CLOCK_GATE_DISABLE		(1 << 12) /* 945GM only */
+# define PC_FE_CLOCK_GATE_DISABLE		(1 << 11)
+# define PC_BE_CLOCK_GATE_DISABLE		(1 << 10)
+# define WINDOWER_CLOCK_GATE_DISABLE		(1 << 9)
+# define INTERPOLATOR_CLOCK_GATE_DISABLE	(1 << 8)
+# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE	(1 << 7)
+# define MOTION_COMP_CLOCK_GATE_DISABLE		(1 << 6)
+# define MAG_CLOCK_GATE_DISABLE			(1 << 5)
+/** This bit must be unset on 855,865 */
+# define MECI_CLOCK_GATE_DISABLE		(1 << 4)
+# define DCMP_CLOCK_GATE_DISABLE		(1 << 3)
+# define MEC_CLOCK_GATE_DISABLE			(1 << 2)
+# define MECO_CLOCK_GATE_DISABLE		(1 << 1)
+/** This bit must be set on 855,865. */
+# define SV_CLOCK_GATE_DISABLE			(1 << 0)
+# define I915_MPEG_CLOCK_GATE_DISABLE		(1 << 16)
+# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE	(1 << 15)
+# define I915_MOTION_COMP_CLOCK_GATE_DISABLE	(1 << 14)
+# define I915_BD_BF_CLOCK_GATE_DISABLE		(1 << 13)
+# define I915_SF_SE_CLOCK_GATE_DISABLE		(1 << 12)
+# define I915_WM_CLOCK_GATE_DISABLE		(1 << 11)
+# define I915_IZ_CLOCK_GATE_DISABLE		(1 << 10)
+# define I915_PI_CLOCK_GATE_DISABLE		(1 << 9)
+# define I915_DI_CLOCK_GATE_DISABLE		(1 << 8)
+# define I915_SH_SV_CLOCK_GATE_DISABLE		(1 << 7)
+# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE	(1 << 6)
+# define I915_SC_CLOCK_GATE_DISABLE		(1 << 5)
+# define I915_FL_CLOCK_GATE_DISABLE		(1 << 4)
+# define I915_DM_CLOCK_GATE_DISABLE		(1 << 3)
+# define I915_PS_CLOCK_GATE_DISABLE		(1 << 2)
+# define I915_CC_CLOCK_GATE_DISABLE		(1 << 1)
+# define I915_BY_CLOCK_GATE_DISABLE		(1 << 0)
+
+# define I965_RCZ_CLOCK_GATE_DISABLE		(1 << 30)
+/** This bit must always be set on 965G/965GM */
+# define I965_RCC_CLOCK_GATE_DISABLE		(1 << 29)
+# define I965_RCPB_CLOCK_GATE_DISABLE		(1 << 28)
+# define I965_DAP_CLOCK_GATE_DISABLE		(1 << 27)
+# define I965_ROC_CLOCK_GATE_DISABLE		(1 << 26)
+# define I965_GW_CLOCK_GATE_DISABLE		(1 << 25)
+# define I965_TD_CLOCK_GATE_DISABLE		(1 << 24)
+/** This bit must always be set on 965G */
+# define I965_ISC_CLOCK_GATE_DISABLE		(1 << 23)
+# define I965_IC_CLOCK_GATE_DISABLE		(1 << 22)
+# define I965_EU_CLOCK_GATE_DISABLE		(1 << 21)
+# define I965_IF_CLOCK_GATE_DISABLE		(1 << 20)
+# define I965_TC_CLOCK_GATE_DISABLE		(1 << 19)
+# define I965_SO_CLOCK_GATE_DISABLE		(1 << 17)
+# define I965_FBC_CLOCK_GATE_DISABLE		(1 << 16)
+# define I965_MARI_CLOCK_GATE_DISABLE		(1 << 15)
+# define I965_MASF_CLOCK_GATE_DISABLE		(1 << 14)
+# define I965_MAWB_CLOCK_GATE_DISABLE		(1 << 13)
+# define I965_EM_CLOCK_GATE_DISABLE		(1 << 12)
+# define I965_UC_CLOCK_GATE_DISABLE		(1 << 11)
+# define I965_SI_CLOCK_GATE_DISABLE		(1 << 6)
+# define I965_MT_CLOCK_GATE_DISABLE		(1 << 5)
+# define I965_PL_CLOCK_GATE_DISABLE		(1 << 4)
+# define I965_DG_CLOCK_GATE_DISABLE		(1 << 3)
+# define I965_QC_CLOCK_GATE_DISABLE		(1 << 2)
+# define I965_FT_CLOCK_GATE_DISABLE		(1 << 1)
+# define I965_DM_CLOCK_GATE_DISABLE		(1 << 0)
+
+#define RENCLK_GATE_D2		0x6208
+#define VF_UNIT_CLOCK_GATE_DISABLE		(1 << 9)
+#define GS_UNIT_CLOCK_GATE_DISABLE		(1 << 7)
+#define CL_UNIT_CLOCK_GATE_DISABLE		(1 << 6)
+#define RAMCLK_GATE_D		0x6210		/* CRL only */
+#define DEUC			0x6214          /* CRL only */
+
+/*
+ * Palette regs
+ */
+
+#define PALETTE_A		0x0a000
+#define PALETTE_B		0x0a800
+
+/* MCH MMIO space */
+
+/*
+ * MCHBAR mirror.
+ *
+ * This mirrors the MCHBAR MMIO space whose location is determined by
+ * device 0 function 0's pci config register 0x44 or 0x48 and matches it in
+ * every way.  It is not accessible from the CP register read instructions.
+ *
+ */
+#define MCHBAR_MIRROR_BASE	0x10000
+
+/** 915-945 and GM965 MCH register controlling DRAM channel access */
+#define DCC			0x10200
+#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL		(0 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC	(1 << 0)
+#define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED	(2 << 0)
+#define DCC_ADDRESSING_MODE_MASK			(3 << 0)
+#define DCC_CHANNEL_XOR_DISABLE				(1 << 10)
+#define DCC_CHANNEL_XOR_BIT_17				(1 << 9)
+
+/** 965 MCH register controlling DRAM channel configuration */
+#define C0DRB3			0x10206
+#define C1DRB3			0x10606
+
+/* Clocking configuration register */
+#define CLKCFG			0x10c00
+#define CLKCFG_FSB_400					(5 << 0)	/* hrawclk 100 */
+#define CLKCFG_FSB_533					(1 << 0)	/* hrawclk 133 */
+#define CLKCFG_FSB_667					(3 << 0)	/* hrawclk 166 */
+#define CLKCFG_FSB_800					(2 << 0)	/* hrawclk 200 */
+#define CLKCFG_FSB_1067					(6 << 0)	/* hrawclk 266 */
+#define CLKCFG_FSB_1333					(7 << 0)	/* hrawclk 333 */
+/* Note, below two are guess */
+#define CLKCFG_FSB_1600					(4 << 0)	/* hrawclk 400 */
+#define CLKCFG_FSB_1600_ALT				(0 << 0)	/* hrawclk 400 */
+#define CLKCFG_FSB_MASK					(7 << 0)
+#define CLKCFG_MEM_533					(1 << 4)
+#define CLKCFG_MEM_667					(2 << 4)
+#define CLKCFG_MEM_800					(3 << 4)
+#define CLKCFG_MEM_MASK					(7 << 4)
+
+/** GM965 GM45 render standby register */
+#define MCHBAR_RENDER_STANDBY	0x111B8
+
+#define PEG_BAND_GAP_DATA	0x14d68
+
+/*
+ * Overlay regs
+ */
+
+#define OVADD			0x30000
+#define DOVSTA			0x30008
+#define OC_BUF			(0x3<<20)
+#define OGAMC5			0x30010
+#define OGAMC4			0x30014
+#define OGAMC3			0x30018
+#define OGAMC2			0x3001c
+#define OGAMC1			0x30020
+#define OGAMC0			0x30024
+
+/*
+ * Display engine regs
+ */
+
+/* Pipe A timing regs */
+#define HTOTAL_A	0x60000
+#define HBLANK_A	0x60004
+#define HSYNC_A		0x60008
+#define VTOTAL_A	0x6000c
+#define VBLANK_A	0x60010
+#define VSYNC_A		0x60014
+#define PIPEASRC	0x6001c
+#define BCLRPAT_A	0x60020
+
+/* Pipe B timing regs */
+#define HTOTAL_B	0x61000
+#define HBLANK_B	0x61004
+#define HSYNC_B		0x61008
+#define VTOTAL_B	0x6100c
+#define VBLANK_B	0x61010
+#define VSYNC_B		0x61014
+#define PIPEBSRC	0x6101c
+#define BCLRPAT_B	0x61020
+
+/* VGA port control */
+#define ADPA			0x61100
+#define   ADPA_DAC_ENABLE	(1<<31)
+#define   ADPA_DAC_DISABLE	0
+#define   ADPA_PIPE_SELECT_MASK	(1<<30)
+#define   ADPA_PIPE_A_SELECT	0
+#define   ADPA_PIPE_B_SELECT	(1<<30)
+#define   ADPA_USE_VGA_HVPOLARITY (1<<15)
+#define   ADPA_SETS_HVPOLARITY	0
+#define   ADPA_VSYNC_CNTL_DISABLE (1<<11)
+#define   ADPA_VSYNC_CNTL_ENABLE 0
+#define   ADPA_HSYNC_CNTL_DISABLE (1<<10)
+#define   ADPA_HSYNC_CNTL_ENABLE 0
+#define   ADPA_VSYNC_ACTIVE_HIGH (1<<4)
+#define   ADPA_VSYNC_ACTIVE_LOW	0
+#define   ADPA_HSYNC_ACTIVE_HIGH (1<<3)
+#define   ADPA_HSYNC_ACTIVE_LOW	0
+#define   ADPA_DPMS_MASK	(~(3<<10))
+#define   ADPA_DPMS_ON		(0<<10)
+#define   ADPA_DPMS_SUSPEND	(1<<10)
+#define   ADPA_DPMS_STANDBY	(2<<10)
+#define   ADPA_DPMS_OFF		(3<<10)
+
+/* Hotplug control (945+ only) */
+#define PORT_HOTPLUG_EN		0x61110
+#define   SDVOB_HOTPLUG_INT_EN			(1 << 26)
+#define   SDVOC_HOTPLUG_INT_EN			(1 << 25)
+#define   TV_HOTPLUG_INT_EN			(1 << 18)
+#define   CRT_HOTPLUG_INT_EN			(1 << 9)
+#define   CRT_HOTPLUG_FORCE_DETECT		(1 << 3)
+
+#define PORT_HOTPLUG_STAT	0x61114
+#define   CRT_HOTPLUG_INT_STATUS		(1 << 11)
+#define   TV_HOTPLUG_INT_STATUS			(1 << 10)
+#define   CRT_HOTPLUG_MONITOR_MASK		(3 << 8)
+#define   CRT_HOTPLUG_MONITOR_COLOR		(3 << 8)
+#define   CRT_HOTPLUG_MONITOR_MONO		(2 << 8)
+#define   CRT_HOTPLUG_MONITOR_NONE		(0 << 8)
+#define   SDVOC_HOTPLUG_INT_STATUS		(1 << 7)
+#define   SDVOB_HOTPLUG_INT_STATUS		(1 << 6)
+
+/* SDVO port control */
+#define SDVOB			0x61140
+#define SDVOC			0x61160
+#define   SDVO_ENABLE		(1 << 31)
+#define   SDVO_PIPE_B_SELECT	(1 << 30)
+#define   SDVO_STALL_SELECT	(1 << 29)
+#define   SDVO_INTERRUPT_ENABLE	(1 << 26)
+/**
+ * 915G/GM SDVO pixel multiplier.
+ *
+ * Programmed value is multiplier - 1, up to 5x.
+ *
+ * \sa DPLL_MD_UDI_MULTIPLIER_MASK
+ */
+#define   SDVO_PORT_MULTIPLY_MASK	(7 << 23)
+#define   SDVO_PORT_MULTIPLY_SHIFT		23
+#define   SDVO_PHASE_SELECT_MASK	(15 << 19)
+#define   SDVO_PHASE_SELECT_DEFAULT	(6 << 19)
+#define   SDVO_CLOCK_OUTPUT_INVERT	(1 << 18)
+#define   SDVOC_GANG_MODE		(1 << 16)
+#define   SDVO_BORDER_ENABLE		(1 << 7)
+#define   SDVOB_PCIE_CONCURRENCY	(1 << 3)
+#define   SDVO_DETECTED			(1 << 2)
+/* Bits to be preserved when writing */
+#define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
+#define   SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
+
+/* DVO port control */
+#define DVOA			0x61120
+#define DVOB			0x61140
+#define DVOC			0x61160
+#define   DVO_ENABLE			(1 << 31)
+#define   DVO_PIPE_B_SELECT		(1 << 30)
+#define   DVO_PIPE_STALL_UNUSED		(0 << 28)
+#define   DVO_PIPE_STALL		(1 << 28)
+#define   DVO_PIPE_STALL_TV		(2 << 28)
+#define   DVO_PIPE_STALL_MASK		(3 << 28)
+#define   DVO_USE_VGA_SYNC		(1 << 15)
+#define   DVO_DATA_ORDER_I740		(0 << 14)
+#define   DVO_DATA_ORDER_FP		(1 << 14)
+#define   DVO_VSYNC_DISABLE		(1 << 11)
+#define   DVO_HSYNC_DISABLE		(1 << 10)
+#define   DVO_VSYNC_TRISTATE		(1 << 9)
+#define   DVO_HSYNC_TRISTATE		(1 << 8)
+#define   DVO_BORDER_ENABLE		(1 << 7)
+#define   DVO_DATA_ORDER_GBRG		(1 << 6)
+#define   DVO_DATA_ORDER_RGGB		(0 << 6)
+#define   DVO_DATA_ORDER_GBRG_ERRATA	(0 << 6)
+#define   DVO_DATA_ORDER_RGGB_ERRATA	(1 << 6)
+#define   DVO_VSYNC_ACTIVE_HIGH		(1 << 4)
+#define   DVO_HSYNC_ACTIVE_HIGH		(1 << 3)
+#define   DVO_BLANK_ACTIVE_HIGH		(1 << 2)
+#define   DVO_OUTPUT_CSTATE_PIXELS	(1 << 1)	/* SDG only */
+#define   DVO_OUTPUT_SOURCE_SIZE_PIXELS	(1 << 0)	/* SDG only */
+#define   DVO_PRESERVE_MASK		(0x7<<24)
+#define DVOA_SRCDIM		0x61124
+#define DVOB_SRCDIM		0x61144
+#define DVOC_SRCDIM		0x61164
+#define   DVO_SRCDIM_HORIZONTAL_SHIFT	12
+#define   DVO_SRCDIM_VERTICAL_SHIFT	0
+
+/* LVDS port control */
+#define LVDS			0x61180
+/*
+ * Enables the LVDS port.  This bit must be set before DPLLs are enabled, as
+ * the DPLL semantics change when the LVDS is assigned to that pipe.
+ */
+#define   LVDS_PORT_EN			(1 << 31)
+/* Selects pipe B for LVDS data.  Must be set on pre-965. */
+#define   LVDS_PIPEB_SELECT		(1 << 30)
+/*
+ * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per
+ * pixel.
+ */
+#define   LVDS_A0A2_CLKA_POWER_MASK	(3 << 8)
+#define   LVDS_A0A2_CLKA_POWER_DOWN	(0 << 8)
+#define   LVDS_A0A2_CLKA_POWER_UP	(3 << 8)
+/*
+ * Controls the A3 data pair, which contains the additional LSBs for 24 bit
+ * mode.  Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be
+ * on.
+ */
+#define   LVDS_A3_POWER_MASK		(3 << 6)
+#define   LVDS_A3_POWER_DOWN		(0 << 6)
+#define   LVDS_A3_POWER_UP		(3 << 6)
+/*
+ * Controls the CLKB pair.  This should only be set when LVDS_B0B3_POWER_UP
+ * is set.
+ */
+#define   LVDS_CLKB_POWER_MASK		(3 << 4)
+#define   LVDS_CLKB_POWER_DOWN		(0 << 4)
+#define   LVDS_CLKB_POWER_UP		(3 << 4)
+/*
+ * Controls the B0-B3 data pairs.  This must be set to match the DPLL p2
+ * setting for whether we are in dual-channel mode.  The B3 pair will
+ * additionally only be powered up when LVDS_A3_POWER_UP is set.
+ */
+#define   LVDS_B0B3_POWER_MASK		(3 << 2)
+#define   LVDS_B0B3_POWER_DOWN		(0 << 2)
+#define   LVDS_B0B3_POWER_UP		(3 << 2)
+
+/* Panel power sequencing */
+#define PP_STATUS	0x61200
+#define   PP_ON		(1 << 31)
+/*
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+#define   PP_READY		(1 << 30)
+#define   PP_SEQUENCE_NONE	(0 << 28)
+#define   PP_SEQUENCE_ON	(1 << 28)
+#define   PP_SEQUENCE_OFF	(2 << 28)
+#define   PP_SEQUENCE_MASK	0x30000000
+#define PP_CONTROL	0x61204
+#define   POWER_TARGET_ON	(1 << 0)
+#define PP_ON_DELAYS	0x61208
+#define PP_OFF_DELAYS	0x6120c
+#define PP_DIVISOR	0x61210
+
+/* Panel fitting */
+#define PFIT_CONTROL	0x61230
+#define   PFIT_ENABLE		(1 << 31)
+#define   PFIT_PIPE_MASK	(3 << 29)
+#define   PFIT_PIPE_SHIFT	29
+#define   VERT_INTERP_DISABLE	(0 << 10)
+#define   VERT_INTERP_BILINEAR	(1 << 10)
+#define   VERT_INTERP_MASK	(3 << 10)
+#define   VERT_AUTO_SCALE	(1 << 9)
+#define   HORIZ_INTERP_DISABLE	(0 << 6)
+#define   HORIZ_INTERP_BILINEAR	(1 << 6)
+#define   HORIZ_INTERP_MASK	(3 << 6)
+#define   HORIZ_AUTO_SCALE	(1 << 5)
+#define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define PFIT_PGM_RATIOS	0x61234
+#define   PFIT_VERT_SCALE_MASK			0xfff00000
+#define   PFIT_HORIZ_SCALE_MASK			0x0000fff0
+#define PFIT_AUTO_RATIOS 0x61238
+
+/* Backlight control */
+#define BLC_PWM_CTL		0x61254
+#define   BACKLIGHT_MODULATION_FREQ_SHIFT		(17)
+#define BLC_PWM_CTL2		0x61250 /* 965+ only */
+/*
+ * This is the most significant 15 bits of the number of backlight cycles in a
+ * complete cycle of the modulated backlight control.
+ *
+ * The actual value is this field multiplied by two.
+ */
+#define   BACKLIGHT_MODULATION_FREQ_MASK		(0x7fff << 17)
+#define   BLM_LEGACY_MODE				(1 << 16)
+/*
+ * This is the number of cycles out of the backlight modulation cycle for which
+ * the backlight is on.
+ *
+ * This field must be no greater than the number of cycles in the complete
+ * backlight modulation cycle.
+ */
+#define   BACKLIGHT_DUTY_CYCLE_SHIFT		(0)
+#define   BACKLIGHT_DUTY_CYCLE_MASK		(0xffff)
+
+#define BLC_HIST_CTL		0x61260
+
+/* TV port control */
+#define TV_CTL			0x68000
+/** Enables the TV encoder */
+# define TV_ENC_ENABLE			(1 << 31)
+/** Sources the TV encoder input from pipe B instead of A. */
+# define TV_ENC_PIPEB_SELECT		(1 << 30)
+/** Outputs composite video (DAC A only) */
+# define TV_ENC_OUTPUT_COMPOSITE	(0 << 28)
+/** Outputs SVideo video (DAC B/C) */
+# define TV_ENC_OUTPUT_SVIDEO		(1 << 28)
+/** Outputs Component video (DAC A/B/C) */
+# define TV_ENC_OUTPUT_COMPONENT	(2 << 28)
+/** Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE	(3 << 28)
+# define TV_TRILEVEL_SYNC		(1 << 21)
+/** Enables slow sync generation (945GM only) */
+# define TV_SLOW_SYNC			(1 << 20)
+/** Selects 4x oversampling for 480i and 576p */
+# define TV_OVERSAMPLE_4X		(0 << 18)
+/** Selects 2x oversampling for 720p and 1080i */
+# define TV_OVERSAMPLE_2X		(1 << 18)
+/** Selects no oversampling for 1080p */
+# define TV_OVERSAMPLE_NONE		(2 << 18)
+/** Selects 8x oversampling */
+# define TV_OVERSAMPLE_8X		(3 << 18)
+/** Selects progressive mode rather than interlaced */
+# define TV_PROGRESSIVE			(1 << 17)
+/** Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
+# define TV_PAL_BURST			(1 << 16)
+/** Field for setting delay of Y compared to C */
+# define TV_YC_SKEW_MASK		(7 << 12)
+/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
+# define TV_ENC_SDP_FIX			(1 << 11)
+/**
+ * Enables a fix for the 915GM only.
+ *
+ * Not sure what it does.
+ */
+# define TV_ENC_C0_FIX			(1 << 10)
+/** Bits that must be preserved by software */
+# define TV_CTL_SAVE			((3 << 8) | (3 << 6))
+# define TV_FUSE_STATE_MASK		(3 << 4)
+/** Read-only state that reports all features enabled */
+# define TV_FUSE_STATE_ENABLED		(0 << 4)
+/** Read-only state that reports that Macrovision is disabled in hardware*/
+# define TV_FUSE_STATE_NO_MACROVISION	(1 << 4)
+/** Read-only state that reports that TV-out is disabled in hardware. */
+# define TV_FUSE_STATE_DISABLED		(2 << 4)
+/** Normal operation */
+# define TV_TEST_MODE_NORMAL		(0 << 0)
+/** Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1		(1 << 0)
+/** Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2		(2 << 0)
+/** Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3		(3 << 0)
+/** Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4		(4 << 0)
+/** Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5		(5 << 0)
+/**
+ * This test mode forces the DACs to 50% of full output.
+ *
+ * This is used for load detection in combination with TVDAC_SENSE_MASK
+ */
+# define TV_TEST_MODE_MONITOR_DETECT	(7 << 0)
+# define TV_TEST_MODE_MASK		(7 << 0)
+
+#define TV_DAC			0x68004
+/**
+ * Reports that DAC state change logic has reported change (RO).
+ *
+ * This gets cleared when TV_DAC_STATE_EN is cleared
+*/
+# define TVDAC_STATE_CHG		(1 << 31)
+# define TVDAC_SENSE_MASK		(7 << 28)
+/** Reports that DAC A voltage is above the detect threshold */
+# define TVDAC_A_SENSE			(1 << 30)
+/** Reports that DAC B voltage is above the detect threshold */
+# define TVDAC_B_SENSE			(1 << 29)
+/** Reports that DAC C voltage is above the detect threshold */
+# define TVDAC_C_SENSE			(1 << 28)
+/**
+ * Enables DAC state detection logic, for load-based TV detection.
+ *
+ * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
+ * to off, for load detection to work.
+ */
+# define TVDAC_STATE_CHG_EN		(1 << 27)
+/** Sets the DAC A sense value to high */
+# define TVDAC_A_SENSE_CTL		(1 << 26)
+/** Sets the DAC B sense value to high */
+# define TVDAC_B_SENSE_CTL		(1 << 25)
+/** Sets the DAC C sense value to high */
+# define TVDAC_C_SENSE_CTL		(1 << 24)
+/** Overrides the ENC_ENABLE and DAC voltage levels */
+# define DAC_CTL_OVERRIDE		(1 << 7)
+/** Sets the slew rate.  Must be preserved in software */
+# define ENC_TVDAC_SLEW_FAST		(1 << 6)
+# define DAC_A_1_3_V			(0 << 4)
+# define DAC_A_1_1_V			(1 << 4)
+# define DAC_A_0_7_V			(2 << 4)
+# define DAC_A_OFF			(3 << 4)
+# define DAC_B_1_3_V			(0 << 2)
+# define DAC_B_1_1_V			(1 << 2)
+# define DAC_B_0_7_V			(2 << 2)
+# define DAC_B_OFF			(3 << 2)
+# define DAC_C_1_3_V			(0 << 0)
+# define DAC_C_1_1_V			(1 << 0)
+# define DAC_C_0_7_V			(2 << 0)
+# define DAC_C_OFF			(3 << 0)
+
+/**
+ * CSC coefficients are stored in a floating point format with 9 bits of
+ * mantissa and 2 or 3 bits of exponent.  The exponent is represented as 2**-n,
+ * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
+ * -1 (0x3) being the only legal negative value.
+ */
+#define TV_CSC_Y		0x68010
+# define TV_RY_MASK			0x07ff0000
+# define TV_RY_SHIFT			16
+# define TV_GY_MASK			0x00000fff
+# define TV_GY_SHIFT			0
+
+#define TV_CSC_Y2		0x68014
+# define TV_BY_MASK			0x07ff0000
+# define TV_BY_SHIFT			16
+/**
+ * Y attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AY_MASK			0x000003ff
+# define TV_AY_SHIFT			0
+
+#define TV_CSC_U		0x68018
+# define TV_RU_MASK			0x07ff0000
+# define TV_RU_SHIFT			16
+# define TV_GU_MASK			0x000007ff
+# define TV_GU_SHIFT			0
+
+#define TV_CSC_U2		0x6801c
+# define TV_BU_MASK			0x07ff0000
+# define TV_BU_SHIFT			16
+/**
+ * U attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AU_MASK			0x000003ff
+# define TV_AU_SHIFT			0
+
+#define TV_CSC_V		0x68020
+# define TV_RV_MASK			0x0fff0000
+# define TV_RV_SHIFT			16
+# define TV_GV_MASK			0x000007ff
+# define TV_GV_SHIFT			0
+
+#define TV_CSC_V2		0x68024
+# define TV_BV_MASK			0x07ff0000
+# define TV_BV_SHIFT			16
+/**
+ * V attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AV_MASK			0x000007ff
+# define TV_AV_SHIFT			0
+
+#define TV_CLR_KNOBS		0x68028
+/** 2s-complement brightness adjustment */
+# define TV_BRIGHTNESS_MASK		0xff000000
+# define TV_BRIGHTNESS_SHIFT		24
+/** Contrast adjustment, as a 2.6 unsigned floating point number */
+# define TV_CONTRAST_MASK		0x00ff0000
+# define TV_CONTRAST_SHIFT		16
+/** Saturation adjustment, as a 2.6 unsigned floating point number */
+# define TV_SATURATION_MASK		0x0000ff00
+# define TV_SATURATION_SHIFT		8
+/** Hue adjustment, as an integer phase angle in degrees */
+# define TV_HUE_MASK			0x000000ff
+# define TV_HUE_SHIFT			0
+
+#define TV_CLR_LEVEL		0x6802c
+/** Controls the DAC level for black */
+# define TV_BLACK_LEVEL_MASK		0x01ff0000
+# define TV_BLACK_LEVEL_SHIFT		16
+/** Controls the DAC level for blanking */
+# define TV_BLANK_LEVEL_MASK		0x000001ff
+# define TV_BLANK_LEVEL_SHIFT		0
+
+#define TV_H_CTL_1		0x68030
+/** Number of pixels in the hsync. */
+# define TV_HSYNC_END_MASK		0x1fff0000
+# define TV_HSYNC_END_SHIFT		16
+/** Total number of pixels minus one in the line (display and blanking). */
+# define TV_HTOTAL_MASK			0x00001fff
+# define TV_HTOTAL_SHIFT		0
+
+#define TV_H_CTL_2		0x68034
+/** Enables the colorburst (needed for non-component color) */
+# define TV_BURST_ENA			(1 << 31)
+/** Offset of the colorburst from the start of hsync, in pixels minus one. */
+# define TV_HBURST_START_SHIFT		16
+# define TV_HBURST_START_MASK		0x1fff0000
+/** Length of the colorburst */
+# define TV_HBURST_LEN_SHIFT		0
+# define TV_HBURST_LEN_MASK		0x0001fff
+
+#define TV_H_CTL_3		0x68038
+/** End of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_END_SHIFT		16
+# define TV_HBLANK_END_MASK		0x1fff0000
+/** Start of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_START_SHIFT		0
+# define TV_HBLANK_START_MASK		0x0001fff
+
+#define TV_V_CTL_1		0x6803c
+/** XXX */
+# define TV_NBR_END_SHIFT		16
+# define TV_NBR_END_MASK		0x07ff0000
+/** XXX */
+# define TV_VI_END_F1_SHIFT		8
+# define TV_VI_END_F1_MASK		0x00003f00
+/** XXX */
+# define TV_VI_END_F2_SHIFT		0
+# define TV_VI_END_F2_MASK		0x0000003f
+
+#define TV_V_CTL_2		0x68040
+/** Length of vsync, in half lines */
+# define TV_VSYNC_LEN_MASK		0x07ff0000
+# define TV_VSYNC_LEN_SHIFT		16
+/** Offset of the start of vsync in field 1, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F1_MASK		0x00007f00
+# define TV_VSYNC_START_F1_SHIFT	8
+/**
+ * Offset of the start of vsync in field 2, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F2_MASK		0x0000007f
+# define TV_VSYNC_START_F2_SHIFT	0
+
+#define TV_V_CTL_3		0x68044
+/** Enables generation of the equalization signal */
+# define TV_EQUAL_ENA			(1 << 31)
+/** Length of vsync, in half lines */
+# define TV_VEQ_LEN_MASK		0x007f0000
+# define TV_VEQ_LEN_SHIFT		16
+/** Offset of the start of equalization in field 1, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F1_MASK		0x0007f00
+# define TV_VEQ_START_F1_SHIFT		8
+/**
+ * Offset of the start of equalization in field 2, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F2_MASK		0x000007f
+# define TV_VEQ_START_F2_SHIFT		0
+
+#define TV_V_CTL_4		0x68048
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F1_MASK	0x003f0000
+# define TV_VBURST_START_F1_SHIFT	16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F1_MASK		0x000000ff
+# define TV_VBURST_END_F1_SHIFT		0
+
+#define TV_V_CTL_5		0x6804c
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F2_MASK	0x003f0000
+# define TV_VBURST_START_F2_SHIFT	16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F2_MASK		0x000000ff
+# define TV_VBURST_END_F2_SHIFT		0
+
+#define TV_V_CTL_6		0x68050
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F3_MASK	0x003f0000
+# define TV_VBURST_START_F3_SHIFT	16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F3_MASK		0x000000ff
+# define TV_VBURST_END_F3_SHIFT		0
+
+#define TV_V_CTL_7		0x68054
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F4_MASK	0x003f0000
+# define TV_VBURST_START_F4_SHIFT	16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F4_MASK		0x000000ff
+# define TV_VBURST_END_F4_SHIFT		0
+
+#define TV_SC_CTL_1		0x68060
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA1_EN			(1 << 31)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA2_EN			(1 << 30)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA3_EN			(1 << 29)
+/** Sets the subcarrier DDA to reset frequency every other field */
+# define TV_SC_RESET_EVERY_2		(0 << 24)
+/** Sets the subcarrier DDA to reset frequency every fourth field */
+# define TV_SC_RESET_EVERY_4		(1 << 24)
+/** Sets the subcarrier DDA to reset frequency every eighth field */
+# define TV_SC_RESET_EVERY_8		(2 << 24)
+/** Sets the subcarrier DDA to never reset the frequency */
+# define TV_SC_RESET_NEVER		(3 << 24)
+/** Sets the peak amplitude of the colorburst.*/
+# define TV_BURST_LEVEL_MASK		0x00ff0000
+# define TV_BURST_LEVEL_SHIFT		16
+/** Sets the increment of the first subcarrier phase generation DDA */
+# define TV_SCDDA1_INC_MASK		0x00000fff
+# define TV_SCDDA1_INC_SHIFT		0
+
+#define TV_SC_CTL_2		0x68064
+/** Sets the rollover for the second subcarrier phase generation DDA */
+# define TV_SCDDA2_SIZE_MASK		0x7fff0000
+# define TV_SCDDA2_SIZE_SHIFT		16
+/** Sets the increent of the second subcarrier phase generation DDA */
+# define TV_SCDDA2_INC_MASK		0x00007fff
+# define TV_SCDDA2_INC_SHIFT		0
+
+#define TV_SC_CTL_3		0x68068
+/** Sets the rollover for the third subcarrier phase generation DDA */
+# define TV_SCDDA3_SIZE_MASK		0x7fff0000
+# define TV_SCDDA3_SIZE_SHIFT		16
+/** Sets the increent of the third subcarrier phase generation DDA */
+# define TV_SCDDA3_INC_MASK		0x00007fff
+# define TV_SCDDA3_INC_SHIFT		0
+
+#define TV_WIN_POS		0x68070
+/** X coordinate of the display from the start of horizontal active */
+# define TV_XPOS_MASK			0x1fff0000
+# define TV_XPOS_SHIFT			16
+/** Y coordinate of the display from the start of vertical active (NBR) */
+# define TV_YPOS_MASK			0x00000fff
+# define TV_YPOS_SHIFT			0
+
+#define TV_WIN_SIZE		0x68074
+/** Horizontal size of the display window, measured in pixels*/
+# define TV_XSIZE_MASK			0x1fff0000
+# define TV_XSIZE_SHIFT			16
+/**
+ * Vertical size of the display window, measured in pixels.
+ *
+ * Must be even for interlaced modes.
+ */
+# define TV_YSIZE_MASK			0x00000fff
+# define TV_YSIZE_SHIFT			0
+
+#define TV_FILTER_CTL_1		0x68080
+/**
+ * Enables automatic scaling calculation.
+ *
+ * If set, the rest of the registers are ignored, and the calculated values can
+ * be read back from the register.
+ */
+# define TV_AUTO_SCALE			(1 << 31)
+/**
+ * Disables the vertical filter.
+ *
+ * This is required on modes more than 1024 pixels wide */
+# define TV_V_FILTER_BYPASS		(1 << 29)
+/** Enables adaptive vertical filtering */
+# define TV_VADAPT			(1 << 28)
+# define TV_VADAPT_MODE_MASK		(3 << 26)
+/** Selects the least adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_LEAST		(0 << 26)
+/** Selects the moderately adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MODERATE	(1 << 26)
+/** Selects the most adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MOST		(3 << 26)
+/**
+ * Sets the horizontal scaling factor.
+ *
+ * This should be the fractional part of the horizontal scaling factor divided
+ * by the oversampling rate.  TV_HSCALE should be less than 1, and set to:
+ *
+ * (src width - 1) / ((oversample * dest width) - 1)
+ */
+# define TV_HSCALE_FRAC_MASK		0x00003fff
+# define TV_HSCALE_FRAC_SHIFT		0
+
+#define TV_FILTER_CTL_2		0x68084
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
+ */
+# define TV_VSCALE_INT_MASK		0x00038000
+# define TV_VSCALE_INT_SHIFT		15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * \sa TV_VSCALE_INT_MASK
+ */
+# define TV_VSCALE_FRAC_MASK		0x00007fff
+# define TV_VSCALE_FRAC_SHIFT		0
+
+#define TV_FILTER_CTL_3		0x68088
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ */
+# define TV_VSCALE_IP_INT_MASK		0x00038000
+# define TV_VSCALE_IP_INT_SHIFT		15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ *
+ * \sa TV_VSCALE_IP_INT_MASK
+ */
+# define TV_VSCALE_IP_FRAC_MASK		0x00007fff
+# define TV_VSCALE_IP_FRAC_SHIFT		0
+
+#define TV_CC_CONTROL		0x68090
+# define TV_CC_ENABLE			(1 << 31)
+/**
+ * Specifies which field to send the CC data in.
+ *
+ * CC data is usually sent in field 0.
+ */
+# define TV_CC_FID_MASK			(1 << 27)
+# define TV_CC_FID_SHIFT		27
+/** Sets the horizontal position of the CC data.  Usually 135. */
+# define TV_CC_HOFF_MASK		0x03ff0000
+# define TV_CC_HOFF_SHIFT		16
+/** Sets the vertical position of the CC data.  Usually 21 */
+# define TV_CC_LINE_MASK		0x0000003f
+# define TV_CC_LINE_SHIFT		0
+
+#define TV_CC_DATA		0x68094
+# define TV_CC_RDY			(1 << 31)
+/** Second word of CC data to be transmitted. */
+# define TV_CC_DATA_2_MASK		0x007f0000
+# define TV_CC_DATA_2_SHIFT		16
+/** First word of CC data to be transmitted. */
+# define TV_CC_DATA_1_MASK		0x0000007f
+# define TV_CC_DATA_1_SHIFT		0
+
+#define TV_H_LUMA_0		0x68100
+#define TV_H_LUMA_59		0x681ec
+#define TV_H_CHROMA_0		0x68200
+#define TV_H_CHROMA_59		0x682ec
+#define TV_V_LUMA_0		0x68300
+#define TV_V_LUMA_42		0x683a8
+#define TV_V_CHROMA_0		0x68400
+#define TV_V_CHROMA_42		0x684a8
+
+/* Display Port */
+#define DP_A				0x64000 /* eDP */
+#define DP_B				0x64100
+#define DP_C				0x64200
+#define DP_D				0x64300
+
+#define   DP_PORT_EN			(1 << 31)
+#define   DP_PIPEB_SELECT		(1 << 30)
+
+/* Link training mode - select a suitable mode for each stage */
+#define   DP_LINK_TRAIN_PAT_1		(0 << 28)
+#define   DP_LINK_TRAIN_PAT_2		(1 << 28)
+#define   DP_LINK_TRAIN_PAT_IDLE	(2 << 28)
+#define   DP_LINK_TRAIN_OFF		(3 << 28)
+#define   DP_LINK_TRAIN_MASK		(3 << 28)
+#define   DP_LINK_TRAIN_SHIFT		28
+
+/* Signal voltages. These are mostly controlled by the other end */
+#define   DP_VOLTAGE_0_4		(0 << 25)
+#define   DP_VOLTAGE_0_6		(1 << 25)
+#define   DP_VOLTAGE_0_8		(2 << 25)
+#define   DP_VOLTAGE_1_2		(3 << 25)
+#define   DP_VOLTAGE_MASK		(7 << 25)
+#define   DP_VOLTAGE_SHIFT		25
+
+/* Signal pre-emphasis levels, like voltages, the other end tells us what
+ * they want
+ */
+#define   DP_PRE_EMPHASIS_0		(0 << 22)
+#define   DP_PRE_EMPHASIS_3_5		(1 << 22)
+#define   DP_PRE_EMPHASIS_6		(2 << 22)
+#define   DP_PRE_EMPHASIS_9_5		(3 << 22)
+#define   DP_PRE_EMPHASIS_MASK		(7 << 22)
+#define   DP_PRE_EMPHASIS_SHIFT		22
+
+/* How many wires to use. I guess 3 was too hard */
+#define   DP_PORT_WIDTH_1		(0 << 19)
+#define   DP_PORT_WIDTH_2		(1 << 19)
+#define   DP_PORT_WIDTH_4		(3 << 19)
+#define   DP_PORT_WIDTH_MASK		(7 << 19)
+
+/* Mystic DPCD version 1.1 special mode */
+#define   DP_ENHANCED_FRAMING		(1 << 18)
+
+/* eDP */
+#define   DP_PLL_FREQ_270MHZ		(0 << 16)
+#define   DP_PLL_FREQ_160MHZ		(1 << 16)
+#define   DP_PLL_FREQ_MASK		(3 << 16)
+
+/** locked once port is enabled */
+#define   DP_PORT_REVERSAL		(1 << 15)
+
+/* eDP */
+#define   DP_PLL_ENABLE			(1 << 14)
+
+/** sends the clock on lane 15 of the PEG for debug */
+#define   DP_CLOCK_OUTPUT_ENABLE	(1 << 13)
+
+#define   DP_SCRAMBLING_DISABLE		(1 << 12)
+#define   DP_SCRAMBLING_DISABLE_IGDNG	(1 << 7)
+
+/** limit RGB values to avoid confusing TVs */
+#define   DP_COLOR_RANGE_16_235		(1 << 8)
+
+/** Turn on the audio link */
+#define   DP_AUDIO_OUTPUT_ENABLE	(1 << 6)
+
+/** vs and hs sync polarity */
+#define   DP_SYNC_VS_HIGH		(1 << 4)
+#define   DP_SYNC_HS_HIGH		(1 << 3)
+
+/** A fantasy */
+#define   DP_DETECTED			(1 << 2)
+
+/** The aux channel provides a way to talk to the
+ * signal sink for DDC etc. Max packet size supported
+ * is 20 bytes in each direction, hence the 5 fixed
+ * data registers
+ */
+#define DPA_AUX_CH_CTL			0x64010
+#define DPA_AUX_CH_DATA1		0x64014
+#define DPA_AUX_CH_DATA2		0x64018
+#define DPA_AUX_CH_DATA3		0x6401c
+#define DPA_AUX_CH_DATA4		0x64020
+#define DPA_AUX_CH_DATA5		0x64024
+
+#define DPB_AUX_CH_CTL			0x64110
+#define DPB_AUX_CH_DATA1		0x64114
+#define DPB_AUX_CH_DATA2		0x64118
+#define DPB_AUX_CH_DATA3		0x6411c
+#define DPB_AUX_CH_DATA4		0x64120
+#define DPB_AUX_CH_DATA5		0x64124
+
+#define DPC_AUX_CH_CTL			0x64210
+#define DPC_AUX_CH_DATA1		0x64214
+#define DPC_AUX_CH_DATA2		0x64218
+#define DPC_AUX_CH_DATA3		0x6421c
+#define DPC_AUX_CH_DATA4		0x64220
+#define DPC_AUX_CH_DATA5		0x64224
+
+#define DPD_AUX_CH_CTL			0x64310
+#define DPD_AUX_CH_DATA1		0x64314
+#define DPD_AUX_CH_DATA2		0x64318
+#define DPD_AUX_CH_DATA3		0x6431c
+#define DPD_AUX_CH_DATA4		0x64320
+#define DPD_AUX_CH_DATA5		0x64324
+
+#define   DP_AUX_CH_CTL_SEND_BUSY	    (1 << 31)
+#define   DP_AUX_CH_CTL_DONE		    (1 << 30)
+#define   DP_AUX_CH_CTL_INTERRUPT	    (1 << 29)
+#define   DP_AUX_CH_CTL_TIME_OUT_ERROR	    (1 << 28)
+#define   DP_AUX_CH_CTL_TIME_OUT_400us	    (0 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_600us	    (1 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_800us	    (2 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_1600us	    (3 << 26)
+#define   DP_AUX_CH_CTL_TIME_OUT_MASK	    (3 << 26)
+#define   DP_AUX_CH_CTL_RECEIVE_ERROR	    (1 << 25)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_MASK    (0x1f << 20)
+#define   DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT   20
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_MASK   (0xf << 16)
+#define   DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT  16
+#define   DP_AUX_CH_CTL_AUX_AKSV_SELECT	    (1 << 15)
+#define   DP_AUX_CH_CTL_MANCHESTER_TEST	    (1 << 14)
+#define   DP_AUX_CH_CTL_SYNC_TEST	    (1 << 13)
+#define   DP_AUX_CH_CTL_DEGLITCH_TEST	    (1 << 12)
+#define   DP_AUX_CH_CTL_PRECHARGE_TEST	    (1 << 11)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK    (0x7ff)
+#define   DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT   0
+
+/*
+ * Computing GMCH M and N values for the Display Port link
+ *
+ * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
+ *
+ * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
+ *
+ * The GMCH value is used internally
+ *
+ * bytes_per_pixel is the number of bytes coming out of the plane,
+ * which is after the LUTs, so we want the bytes for our color format.
+ * For our current usage, this is always 3, one byte for R, G and B.
+ */
+#define PIPEA_GMCH_DATA_M			0x70050
+#define PIPEB_GMCH_DATA_M			0x71050
+
+/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
+#define   PIPE_GMCH_DATA_M_TU_SIZE_MASK		(0x3f << 25)
+#define   PIPE_GMCH_DATA_M_TU_SIZE_SHIFT	25
+
+#define   PIPE_GMCH_DATA_M_MASK			(0xffffff)
+
+#define PIPEA_GMCH_DATA_N			0x70054
+#define PIPEB_GMCH_DATA_N			0x71054
+#define   PIPE_GMCH_DATA_N_MASK			(0xffffff)
+
+/*
+ * Computing Link M and N values for the Display Port link
+ *
+ * Link M / N = pixel_clock / ls_clk
+ *
+ * (the DP spec calls pixel_clock the 'strm_clk')
+ *
+ * The Link value is transmitted in the Main Stream
+ * Attributes and VB-ID.
+ */
+
+#define PIPEA_DP_LINK_M				0x70060
+#define PIPEB_DP_LINK_M				0x71060
+#define   PIPEA_DP_LINK_M_MASK			(0xffffff)
+
+#define PIPEA_DP_LINK_N				0x70064
+#define PIPEB_DP_LINK_N				0x71064
+#define   PIPEA_DP_LINK_N_MASK			(0xffffff)
+
+/* Display & cursor control */
+
+/* Pipe A */
+#define PIPEADSL		0x70000
+#define PIPEACONF		 0x70008
+#define   PIPEACONF_ENABLE	(1<<31)
+#define   PIPEACONF_DISABLE	0
+#define   PIPEACONF_DOUBLE_WIDE	(1<<30)
+#define   I965_PIPECONF_ACTIVE	(1<<30)
+#define   PIPEACONF_SINGLE_WIDE	0
+#define   PIPEACONF_PIPE_UNLOCKED 0
+#define   PIPEACONF_PIPE_LOCKED	(1<<25)
+#define   PIPEACONF_PALETTE	0
+#define   PIPEACONF_GAMMA		(1<<24)
+#define   PIPECONF_FORCE_BORDER	(1<<25)
+#define   PIPECONF_PROGRESSIVE	(0 << 21)
+#define   PIPECONF_INTERLACE_W_FIELD_INDICATION	(6 << 21)
+#define   PIPECONF_INTERLACE_FIELD_0_ONLY		(7 << 21)
+#define PIPEASTAT		0x70024
+#define   PIPE_FIFO_UNDERRUN_STATUS		(1UL<<31)
+#define   PIPE_CRC_ERROR_ENABLE			(1UL<<29)
+#define   PIPE_CRC_DONE_ENABLE			(1UL<<28)
+#define   PIPE_GMBUS_EVENT_ENABLE		(1UL<<27)
+#define   PIPE_HOTPLUG_INTERRUPT_ENABLE		(1UL<<26)
+#define   PIPE_VSYNC_INTERRUPT_ENABLE		(1UL<<25)
+#define   PIPE_DISPLAY_LINE_COMPARE_ENABLE	(1UL<<24)
+#define   PIPE_DPST_EVENT_ENABLE		(1UL<<23)
+#define   PIPE_LEGACY_BLC_EVENT_ENABLE		(1UL<<22)
+#define   PIPE_ODD_FIELD_INTERRUPT_ENABLE	(1UL<<21)
+#define   PIPE_EVEN_FIELD_INTERRUPT_ENABLE	(1UL<<20)
+#define   PIPE_HOTPLUG_TV_INTERRUPT_ENABLE	(1UL<<18) /* pre-965 */
+#define   PIPE_START_VBLANK_INTERRUPT_ENABLE	(1UL<<18) /* 965 or later */
+#define   PIPE_VBLANK_INTERRUPT_ENABLE		(1UL<<17)
+#define   PIPE_OVERLAY_UPDATED_ENABLE		(1UL<<16)
+#define   PIPE_CRC_ERROR_INTERRUPT_STATUS	(1UL<<13)
+#define   PIPE_CRC_DONE_INTERRUPT_STATUS	(1UL<<12)
+#define   PIPE_GMBUS_INTERRUPT_STATUS		(1UL<<11)
+#define   PIPE_HOTPLUG_INTERRUPT_STATUS		(1UL<<10)
+#define   PIPE_VSYNC_INTERRUPT_STATUS		(1UL<<9)
+#define   PIPE_DISPLAY_LINE_COMPARE_STATUS	(1UL<<8)
+#define   PIPE_DPST_EVENT_STATUS		(1UL<<7)
+#define   PIPE_LEGACY_BLC_EVENT_STATUS		(1UL<<6)
+#define   PIPE_ODD_FIELD_INTERRUPT_STATUS	(1UL<<5)
+#define   PIPE_EVEN_FIELD_INTERRUPT_STATUS	(1UL<<4)
+#define   PIPE_HOTPLUG_TV_INTERRUPT_STATUS	(1UL<<2) /* pre-965 */
+#define   PIPE_START_VBLANK_INTERRUPT_STATUS	(1UL<<2) /* 965 or later */
+#define   PIPE_VBLANK_INTERRUPT_STATUS		(1UL<<1)
+#define   PIPE_OVERLAY_UPDATED_STATUS		(1UL<<0)
+
+#define DSPARB			0x70030
+#define   DSPARB_CSTART_MASK	(0x7f << 7)
+#define   DSPARB_CSTART_SHIFT	7
+#define   DSPARB_BSTART_MASK	(0x7f)
+#define   DSPARB_BSTART_SHIFT	0
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code
+ * should work:
+ *
+ *  do {
+ *    high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT;
+ *    low1 =  ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
+ *             PIPE_FRAME_LOW_SHIFT);
+ *    high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT);
+ *  } while (high1 != high2);
+ *  frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH          0x70040
+#define   PIPE_FRAME_HIGH_MASK    0x0000ffff
+#define   PIPE_FRAME_HIGH_SHIFT   0
+#define PIPEAFRAMEPIXEL         0x70044
+#define   PIPE_FRAME_LOW_MASK     0xff000000
+#define   PIPE_FRAME_LOW_SHIFT    24
+#define   PIPE_PIXEL_MASK         0x00ffffff
+#define   PIPE_PIXEL_SHIFT        0
+/* GM45+ just has to be different */
+#define	PIPEA_FRMCOUNT_GM45       0x70040
+#define	PIPEA_FLIPCOUNT_GM45      0x70044
+
+/* Cursor A & B regs */
+#define CURACNTR		0x70080
+#define   CURSOR_MODE_DISABLE   0x00
+#define   CURSOR_MODE_64_32B_AX 0x07
+#define   CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define   MCURSOR_GAMMA_ENABLE  (1 << 26)
+#define CURABASE		0x70084
+#define CURAPOS			0x70088
+#define   CURSOR_POS_MASK       0x007FF
+#define   CURSOR_POS_SIGN       0x8000
+#define   CURSOR_X_SHIFT        0
+#define   CURSOR_Y_SHIFT        16
+#define CURSIZE			0x700a0
+#define CURBCNTR		0x700c0
+#define CURBBASE		0x700c4
+#define CURBPOS			0x700c8
+
+/* Display A control */
+#define DSPACNTR                0x70180
+#define   DISPLAY_PLANE_ENABLE			(1<<31)
+#define   DISPLAY_PLANE_DISABLE			0
+#define   DISPPLANE_GAMMA_ENABLE		(1<<30)
+#define   DISPPLANE_GAMMA_DISABLE		0
+#define   DISPPLANE_PIXFORMAT_MASK		(0xf<<26)
+#define   DISPPLANE_8BPP			(0x2<<26)
+#define   DISPPLANE_15_16BPP			(0x4<<26)
+#define   DISPPLANE_16BPP			(0x5<<26)
+#define   DISPPLANE_32BPP_NO_ALPHA		(0x6<<26)
+#define   DISPPLANE_32BPP			(0x7<<26)
+#define   DISPPLANE_STEREO_ENABLE		(1<<25)
+#define   DISPPLANE_STEREO_DISABLE		0
+#define   DISPPLANE_SEL_PIPE_MASK		(1<<24)
+#define   DISPPLANE_SEL_PIPE_A			0
+#define   DISPPLANE_SEL_PIPE_B			(1<<24)
+#define   DISPPLANE_SRC_KEY_ENABLE		(1<<22)
+#define   DISPPLANE_SRC_KEY_DISABLE		0
+#define   DISPPLANE_LINE_DOUBLE			(1<<20)
+#define   DISPPLANE_NO_LINE_DOUBLE		0
+#define   DISPPLANE_STEREO_POLARITY_FIRST	0
+#define   DISPPLANE_STEREO_POLARITY_SECOND	(1<<18)
+#define DSPAADDR		0x70184
+#define DSPASTRIDE		0x70188
+#define DSPAPOS			0x7018C /* reserved */
+#define DSPASIZE		0x70190
+#define DSPASURF		0x7019C /* 965+ only */
+#define DSPATILEOFF		0x701A4 /* 965+ only */
+
+/* VBIOS flags */
+#define SWF00			0x71410
+#define SWF01			0x71414
+#define SWF02			0x71418
+#define SWF03			0x7141c
+#define SWF04			0x71420
+#define SWF05			0x71424
+#define SWF06			0x71428
+#define SWF10			0x70410
+#define SWF11			0x70414
+#define SWF14			0x71420
+#define SWF30			0x72414
+#define SWF31			0x72418
+#define SWF32			0x7241c
+
+/* Pipe B */
+#define PIPEBDSL		0x71000
+#define PIPEBCONF		0x71008
+#define PIPEBSTAT		0x71024
+#define PIPEBFRAMEHIGH		0x71040
+#define PIPEBFRAMEPIXEL		0x71044
+#define PIPEB_FRMCOUNT_GM45	0x71040
+#define PIPEB_FLIPCOUNT_GM45	0x71044
+
+/* Display B control */
+#define DSPBCNTR		0x71180
+#define   DISPPLANE_ALPHA_TRANS_ENABLE		(1<<15)
+#define   DISPPLANE_ALPHA_TRANS_DISABLE		0
+#define   DISPPLANE_SPRITE_ABOVE_DISPLAY	0
+#define   DISPPLANE_SPRITE_ABOVE_OVERLAY	(1)
+#define DSPBADDR		0x71184
+#define DSPBSTRIDE		0x71188
+#define DSPBPOS			0x7118C
+#define DSPBSIZE		0x71190
+#define DSPBSURF		0x7119C
+#define DSPBTILEOFF		0x711A4
+
+/* VBIOS regs */
+#define VGACNTRL		0x71400
+# define VGA_DISP_DISABLE			(1 << 31)
+# define VGA_2X_MODE				(1 << 30)
+# define VGA_PIPE_B_SELECT			(1 << 29)
+
+/* Ironlake */
+
+#define CPU_VGACNTRL	0x41000
+
+#define DIGITAL_PORT_HOTPLUG_CNTRL      0x44030
+#define  DIGITAL_PORTA_HOTPLUG_ENABLE           (1 << 4)
+#define  DIGITAL_PORTA_SHORT_PULSE_2MS          (0 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_4_5MS        (1 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_6MS          (2 << 2)
+#define  DIGITAL_PORTA_SHORT_PULSE_100MS        (3 << 2)
+#define  DIGITAL_PORTA_NO_DETECT                (0 << 0)
+#define  DIGITAL_PORTA_LONG_PULSE_DETECT_MASK   (1 << 1)
+#define  DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK  (1 << 0)
+
+/* refresh rate hardware control */
+#define RR_HW_CTL       0x45300
+#define  RR_HW_LOW_POWER_FRAMES_MASK    0xff
+#define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
+
+#define FDI_PLL_BIOS_0  0x46000
+#define FDI_PLL_BIOS_1  0x46004
+#define FDI_PLL_BIOS_2  0x46008
+#define DISPLAY_PORT_PLL_BIOS_0         0x4600c
+#define DISPLAY_PORT_PLL_BIOS_1         0x46010
+#define DISPLAY_PORT_PLL_BIOS_2         0x46014
+
+#define PCH_DSPCLK_GATE_D	0x42020
+# define DPFDUNIT_CLOCK_GATE_DISABLE		(1 << 7)
+# define DPARBUNIT_CLOCK_GATE_DISABLE		(1 << 5)
+
+#define PCH_3DCGDIS0		0x46020
+# define MARIUNIT_CLOCK_GATE_DISABLE		(1 << 18)
+# define SVSMUNIT_CLOCK_GATE_DISABLE		(1 << 1)
+
+#define FDI_PLL_FREQ_CTL        0x46030
+#define  FDI_PLL_FREQ_CHANGE_REQUEST    (1<<24)
+#define  FDI_PLL_FREQ_LOCK_LIMIT_MASK   0xfff00
+#define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
+
+
+#define PIPEA_DATA_M1           0x60030
+#define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
+#define  TU_SIZE_MASK           0x7e000000
+#define  PIPEA_DATA_M1_OFFSET   0
+#define PIPEA_DATA_N1           0x60034
+#define  PIPEA_DATA_N1_OFFSET   0
+
+#define PIPEA_DATA_M2           0x60038
+#define  PIPEA_DATA_M2_OFFSET   0
+#define PIPEA_DATA_N2           0x6003c
+#define  PIPEA_DATA_N2_OFFSET   0
+
+#define PIPEA_LINK_M1           0x60040
+#define  PIPEA_LINK_M1_OFFSET   0
+#define PIPEA_LINK_N1           0x60044
+#define  PIPEA_LINK_N1_OFFSET   0
+
+#define PIPEA_LINK_M2           0x60048
+#define  PIPEA_LINK_M2_OFFSET   0
+#define PIPEA_LINK_N2           0x6004c
+#define  PIPEA_LINK_N2_OFFSET   0
+
+/* PIPEB timing regs are same start from 0x61000 */
+
+#define PIPEB_DATA_M1           0x61030
+#define  PIPEB_DATA_M1_OFFSET   0
+#define PIPEB_DATA_N1           0x61034
+#define  PIPEB_DATA_N1_OFFSET   0
+
+#define PIPEB_DATA_M2           0x61038
+#define  PIPEB_DATA_M2_OFFSET   0
+#define PIPEB_DATA_N2           0x6103c
+#define  PIPEB_DATA_N2_OFFSET   0
+
+#define PIPEB_LINK_M1           0x61040
+#define  PIPEB_LINK_M1_OFFSET   0
+#define PIPEB_LINK_N1           0x61044
+#define  PIPEB_LINK_N1_OFFSET   0
+
+#define PIPEB_LINK_M2           0x61048
+#define  PIPEB_LINK_M2_OFFSET   0
+#define PIPEB_LINK_N2           0x6104c
+#define  PIPEB_LINK_N2_OFFSET   0
+
+/* CPU panel fitter */
+#define PFA_CTL_1               0x68080
+#define PFB_CTL_1               0x68880
+#define  PF_ENABLE              (1<<31)
+#define  PF_FILTER_MASK		(3<<23)
+#define  PF_FILTER_PROGRAMMED	(0<<23)
+#define  PF_FILTER_MED_3x3	(1<<23)
+#define  PF_FILTER_EDGE_ENHANCE	(2<<23)
+#define  PF_FILTER_EDGE_SOFTEN	(3<<23)
+#define PFA_WIN_SZ		0x68074
+#define PFB_WIN_SZ		0x68874
+#define PFA_WIN_POS		0x68070
+#define PFB_WIN_POS		0x68870
+
+/* legacy palette */
+#define LGC_PALETTE_A           0x4a000
+#define LGC_PALETTE_B           0x4a800
+
+/* interrupts */
+#define DE_MASTER_IRQ_CONTROL   (1 << 31)
+#define DE_SPRITEB_FLIP_DONE    (1 << 29)
+#define DE_SPRITEA_FLIP_DONE    (1 << 28)
+#define DE_PLANEB_FLIP_DONE     (1 << 27)
+#define DE_PLANEA_FLIP_DONE     (1 << 26)
+#define DE_PCU_EVENT            (1 << 25)
+#define DE_GTT_FAULT            (1 << 24)
+#define DE_POISON               (1 << 23)
+#define DE_PERFORM_COUNTER      (1 << 22)
+#define DE_PCH_EVENT            (1 << 21)
+#define DE_AUX_CHANNEL_A        (1 << 20)
+#define DE_DP_A_HOTPLUG         (1 << 19)
+#define DE_GSE                  (1 << 18)
+#define DE_PIPEB_VBLANK         (1 << 15)
+#define DE_PIPEB_EVEN_FIELD     (1 << 14)
+#define DE_PIPEB_ODD_FIELD      (1 << 13)
+#define DE_PIPEB_LINE_COMPARE   (1 << 12)
+#define DE_PIPEB_VSYNC          (1 << 11)
+#define DE_PIPEB_FIFO_UNDERRUN  (1 << 8)
+#define DE_PIPEA_VBLANK         (1 << 7)
+#define DE_PIPEA_EVEN_FIELD     (1 << 6)
+#define DE_PIPEA_ODD_FIELD      (1 << 5)
+#define DE_PIPEA_LINE_COMPARE   (1 << 4)
+#define DE_PIPEA_VSYNC          (1 << 3)
+#define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
+
+#define DEISR   0x44000
+#define DEIMR   0x44004
+#define DEIIR   0x44008
+#define DEIER   0x4400c
+
+/* GT interrupt */
+#define GT_MASTER_ERROR         (1 << 3)
+#define GT_SYNC_STATUS          (1 << 2)
+#define GT_USER_INTERRUPT       (1 << 0)
+
+#define GTISR   0x44010
+#define GTIMR   0x44014
+#define GTIIR   0x44018
+#define GTIER   0x4401c
+
+#define ILK_DISPLAY_CHICKEN2	0x42004
+#define  ILK_DPARB_GATE	(1<<22)
+#define  ILK_VSDPFD_FULL	(1<<21)
+#define ILK_DSPCLK_GATE		0x42020
+#define  ILK_DPARB_CLK_GATE	(1<<5)
+
+#define DISP_ARB_CTL	0x45000
+#define  DISP_TILE_SURFACE_SWIZZLING	(1<<13)
+#define  DISP_FBC_WM_DIS		(1<<15)
+
+/* PCH */
+
+/* south display engine interrupt */
+#define SDE_CRT_HOTPLUG         (1 << 11)
+#define SDE_PORTD_HOTPLUG       (1 << 10)
+#define SDE_PORTC_HOTPLUG       (1 << 9)
+#define SDE_PORTB_HOTPLUG       (1 << 8)
+#define SDE_SDVOB_HOTPLUG       (1 << 6)
+#define SDE_HOTPLUG_MASK	(0xf << 8)
+/* CPT */
+#define SDE_CRT_HOTPLUG_CPT	(1 << 19)
+#define SDE_PORTD_HOTPLUG_CPT	(1 << 23)
+#define SDE_PORTC_HOTPLUG_CPT	(1 << 22)
+#define SDE_PORTB_HOTPLUG_CPT	(1 << 21)
+
+#define SDEISR  0xc4000
+#define SDEIMR  0xc4004
+#define SDEIIR  0xc4008
+#define SDEIER  0xc400c
+
+/* digital port hotplug */
+#define PCH_PORT_HOTPLUG        0xc4030
+#define PORTD_HOTPLUG_ENABLE            (1 << 20)
+#define PORTD_PULSE_DURATION_2ms        (0)
+#define PORTD_PULSE_DURATION_4_5ms      (1 << 18)
+#define PORTD_PULSE_DURATION_6ms        (2 << 18)
+#define PORTD_PULSE_DURATION_100ms      (3 << 18)
+#define PORTD_HOTPLUG_NO_DETECT         (0)
+#define PORTD_HOTPLUG_SHORT_DETECT      (1 << 16)
+#define PORTD_HOTPLUG_LONG_DETECT       (1 << 17)
+#define PORTC_HOTPLUG_ENABLE            (1 << 12)
+#define PORTC_PULSE_DURATION_2ms        (0)
+#define PORTC_PULSE_DURATION_4_5ms      (1 << 10)
+#define PORTC_PULSE_DURATION_6ms        (2 << 10)
+#define PORTC_PULSE_DURATION_100ms      (3 << 10)
+#define PORTC_HOTPLUG_NO_DETECT         (0)
+#define PORTC_HOTPLUG_SHORT_DETECT      (1 << 8)
+#define PORTC_HOTPLUG_LONG_DETECT       (1 << 9)
+#define PORTB_HOTPLUG_ENABLE            (1 << 4)
+#define PORTB_PULSE_DURATION_2ms        (0)
+#define PORTB_PULSE_DURATION_4_5ms      (1 << 2)
+#define PORTB_PULSE_DURATION_6ms        (2 << 2)
+#define PORTB_PULSE_DURATION_100ms      (3 << 2)
+#define PORTB_HOTPLUG_NO_DETECT         (0)
+#define PORTB_HOTPLUG_SHORT_DETECT      (1 << 0)
+#define PORTB_HOTPLUG_LONG_DETECT       (1 << 1)
+
+#define PCH_GPIOA               0xc5010
+#define PCH_GPIOB               0xc5014
+#define PCH_GPIOC               0xc5018
+#define PCH_GPIOD               0xc501c
+#define PCH_GPIOE               0xc5020
+#define PCH_GPIOF               0xc5024
+
+#define PCH_GMBUS0		0xc5100
+#define PCH_GMBUS1		0xc5104
+#define PCH_GMBUS2		0xc5108
+#define PCH_GMBUS3		0xc510c
+#define PCH_GMBUS4		0xc5110
+#define PCH_GMBUS5		0xc5120
+
+#define PCH_DPLL_A              0xc6014
+#define PCH_DPLL_B              0xc6018
+
+#define PCH_FPA0                0xc6040
+#define PCH_FPA1                0xc6044
+#define PCH_FPB0                0xc6048
+#define PCH_FPB1                0xc604c
+
+#define PCH_DPLL_TEST           0xc606c
+
+#define PCH_DREF_CONTROL        0xC6200
+#define  DREF_CONTROL_MASK      0x7fc3
+#define  DREF_CPU_SOURCE_OUTPUT_DISABLE         (0<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD      (2<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_NONSPREAD       (3<<13)
+#define  DREF_CPU_SOURCE_OUTPUT_MASK		(3<<13)
+#define  DREF_SSC_SOURCE_DISABLE                (0<<11)
+#define  DREF_SSC_SOURCE_ENABLE                 (2<<11)
+#define  DREF_SSC_SOURCE_MASK			(3<<11)
+#define  DREF_NONSPREAD_SOURCE_DISABLE          (0<<9)
+#define  DREF_NONSPREAD_CK505_ENABLE		(1<<9)
+#define  DREF_NONSPREAD_SOURCE_ENABLE           (2<<9)
+#define  DREF_NONSPREAD_SOURCE_MASK		(3<<9)
+#define  DREF_SUPERSPREAD_SOURCE_DISABLE        (0<<7)
+#define  DREF_SUPERSPREAD_SOURCE_ENABLE         (2<<7)
+#define  DREF_SSC4_DOWNSPREAD                   (0<<6)
+#define  DREF_SSC4_CENTERSPREAD                 (1<<6)
+#define  DREF_SSC1_DISABLE                      (0<<1)
+#define  DREF_SSC1_ENABLE                       (1<<1)
+#define  DREF_SSC4_DISABLE                      (0)
+#define  DREF_SSC4_ENABLE                       (1)
+
+#define PCH_RAWCLK_FREQ         0xc6204
+#define  FDL_TP1_TIMER_SHIFT    12
+#define  FDL_TP1_TIMER_MASK     (3<<12)
+#define  FDL_TP2_TIMER_SHIFT    10
+#define  FDL_TP2_TIMER_MASK     (3<<10)
+#define  RAWCLK_FREQ_MASK       0x3ff
+
+#define PCH_DPLL_TMR_CFG        0xc6208
+
+#define PCH_SSC4_PARMS          0xc6210
+#define PCH_SSC4_AUX_PARMS      0xc6214
+
+#define PCH_DPLL_SEL		0xc7000
+#define  TRANSA_DPLL_ENABLE	(1<<3)
+#define	 TRANSA_DPLLB_SEL	(1<<0)
+#define	 TRANSA_DPLLA_SEL	0
+#define  TRANSB_DPLL_ENABLE	(1<<7)
+#define	 TRANSB_DPLLB_SEL	(1<<4)
+#define	 TRANSB_DPLLA_SEL	(0)
+#define  TRANSC_DPLL_ENABLE	(1<<11)
+#define	 TRANSC_DPLLB_SEL	(1<<8)
+#define	 TRANSC_DPLLA_SEL	(0)
+
+/* transcoder */
+
+#define TRANS_HTOTAL_A          0xe0000
+#define  TRANS_HTOTAL_SHIFT     16
+#define  TRANS_HACTIVE_SHIFT    0
+#define TRANS_HBLANK_A          0xe0004
+#define  TRANS_HBLANK_END_SHIFT 16
+#define  TRANS_HBLANK_START_SHIFT 0
+#define TRANS_HSYNC_A           0xe0008
+#define  TRANS_HSYNC_END_SHIFT  16
+#define  TRANS_HSYNC_START_SHIFT 0
+#define TRANS_VTOTAL_A          0xe000c
+#define  TRANS_VTOTAL_SHIFT     16
+#define  TRANS_VACTIVE_SHIFT    0
+#define TRANS_VBLANK_A          0xe0010
+#define  TRANS_VBLANK_END_SHIFT 16
+#define  TRANS_VBLANK_START_SHIFT 0
+#define TRANS_VSYNC_A           0xe0014
+#define  TRANS_VSYNC_END_SHIFT  16
+#define  TRANS_VSYNC_START_SHIFT 0
+
+#define TRANSA_DATA_M1          0xe0030
+#define TRANSA_DATA_N1          0xe0034
+#define TRANSA_DATA_M2          0xe0038
+#define TRANSA_DATA_N2          0xe003c
+#define TRANSA_DP_LINK_M1       0xe0040
+#define TRANSA_DP_LINK_N1       0xe0044
+#define TRANSA_DP_LINK_M2       0xe0048
+#define TRANSA_DP_LINK_N2       0xe004c
+
+#define TRANS_HTOTAL_B          0xe1000
+#define TRANS_HBLANK_B          0xe1004
+#define TRANS_HSYNC_B           0xe1008
+#define TRANS_VTOTAL_B          0xe100c
+#define TRANS_VBLANK_B          0xe1010
+#define TRANS_VSYNC_B           0xe1014
+
+#define TRANSB_DATA_M1          0xe1030
+#define TRANSB_DATA_N1          0xe1034
+#define TRANSB_DATA_M2          0xe1038
+#define TRANSB_DATA_N2          0xe103c
+#define TRANSB_DP_LINK_M1       0xe1040
+#define TRANSB_DP_LINK_N1       0xe1044
+#define TRANSB_DP_LINK_M2       0xe1048
+#define TRANSB_DP_LINK_N2       0xe104c
+
+#define TRANSACONF              0xf0008
+#define TRANSBCONF              0xf1008
+#define  TRANS_DISABLE          (0<<31)
+#define  TRANS_ENABLE           (1<<31)
+#define  TRANS_STATE_MASK       (1<<30)
+#define  TRANS_STATE_DISABLE    (0<<30)
+#define  TRANS_STATE_ENABLE     (1<<30)
+#define  TRANS_FSYNC_DELAY_HB1  (0<<27)
+#define  TRANS_FSYNC_DELAY_HB2  (1<<27)
+#define  TRANS_FSYNC_DELAY_HB3  (2<<27)
+#define  TRANS_FSYNC_DELAY_HB4  (3<<27)
+#define  TRANS_DP_AUDIO_ONLY    (1<<26)
+#define  TRANS_DP_VIDEO_AUDIO   (0<<26)
+#define  TRANS_PROGRESSIVE      (0<<21)
+#define  TRANS_8BPC             (0<<5)
+#define  TRANS_10BPC            (1<<5)
+#define  TRANS_6BPC             (2<<5)
+#define  TRANS_12BPC            (3<<5)
+
+#define FDI_RXA_CHICKEN         0xc200c
+#define FDI_RXB_CHICKEN         0xc2010
+#define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+
+/* CPU: FDI_TX */
+#define FDI_TXA_CTL             0x60100
+#define FDI_TXB_CTL             0x61100
+#define  FDI_TX_DISABLE         (0<<31)
+#define  FDI_TX_ENABLE          (1<<31)
+#define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
+#define  FDI_LINK_TRAIN_PATTERN_2       (1<<28)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE    (2<<28)
+#define  FDI_LINK_TRAIN_NONE            (3<<28)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_4V    (0<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_6V    (1<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_0_8V    (2<<25)
+#define  FDI_LINK_TRAIN_VOLTAGE_1_2V    (3<<25)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_2X   (2<<22)
+#define  FDI_LINK_TRAIN_PRE_EMPHASIS_3X   (3<<22)
+/* ILK always use 400mV 0dB for voltage swing and pre-emphasis level.
+   SNB has different settings. */
+/* SNB A-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_A		(0x38<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_A		(0x02<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_A	(0x01<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_A		(0x0<<22)
+/* SNB B-stepping */
+#define  FDI_LINK_TRAIN_400MV_0DB_SNB_B		(0x0<<22)
+#define  FDI_LINK_TRAIN_400MV_6DB_SNB_B		(0x3a<<22)
+#define  FDI_LINK_TRAIN_600MV_3_5DB_SNB_B	(0x39<<22)
+#define  FDI_LINK_TRAIN_800MV_0DB_SNB_B		(0x38<<22)
+#define  FDI_LINK_TRAIN_VOL_EMP_MASK		(0x3f<<22)
+#define  FDI_DP_PORT_WIDTH_X1           (0<<19)
+#define  FDI_DP_PORT_WIDTH_X2           (1<<19)
+#define  FDI_DP_PORT_WIDTH_X3           (2<<19)
+#define  FDI_DP_PORT_WIDTH_X4           (3<<19)
+#define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
+/* Ironlake: hardwired to 1 */
+#define  FDI_TX_PLL_ENABLE              (1<<14)
+/* both Tx and Rx */
+#define  FDI_SCRAMBLING_ENABLE          (0<<7)
+#define  FDI_SCRAMBLING_DISABLE         (1<<7)
+
+/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
+#define FDI_RXA_CTL             0xf000c
+#define FDI_RXB_CTL             0xf100c
+#define  FDI_RX_ENABLE          (1<<31)
+#define  FDI_RX_DISABLE         (0<<31)
+/* train, dp width same as FDI_TX */
+#define  FDI_DP_PORT_WIDTH_X8           (7<<19)
+#define  FDI_8BPC                       (0<<16)
+#define  FDI_10BPC                      (1<<16)
+#define  FDI_6BPC                       (2<<16)
+#define  FDI_12BPC                      (3<<16)
+#define  FDI_LINK_REVERSE_OVERWRITE     (1<<15)
+#define  FDI_DMI_LINK_REVERSE_MASK      (1<<14)
+#define  FDI_RX_PLL_ENABLE              (1<<13)
+#define  FDI_FS_ERR_CORRECT_ENABLE      (1<<11)
+#define  FDI_FE_ERR_CORRECT_ENABLE      (1<<10)
+#define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
+#define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
+#define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
+#define  FDI_SEL_RAWCLK                 (0<<4)
+#define  FDI_SEL_PCDCLK                 (1<<4)
+/* CPT */
+#define  FDI_AUTO_TRAINING			(1<<10)
+#define  FDI_LINK_TRAIN_PATTERN_1_CPT		(0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_CPT		(1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_CPT	(2<<8)
+#define  FDI_LINK_TRAIN_NORMAL_CPT		(3<<8)
+#define  FDI_LINK_TRAIN_PATTERN_MASK_CPT	(3<<8)
+
+#define FDI_RXA_MISC            0xf0010
+#define FDI_RXB_MISC            0xf1010
+#define FDI_RXA_TUSIZE1         0xf0030
+#define FDI_RXA_TUSIZE2         0xf0038
+#define FDI_RXB_TUSIZE1         0xf1030
+#define FDI_RXB_TUSIZE2         0xf1038
+
+/* FDI_RX interrupt register format */
+#define FDI_RX_INTER_LANE_ALIGN         (1<<10)
+#define FDI_RX_SYMBOL_LOCK              (1<<9) /* train 2 */
+#define FDI_RX_BIT_LOCK                 (1<<8) /* train 1 */
+#define FDI_RX_TRAIN_PATTERN_2_FAIL     (1<<7)
+#define FDI_RX_FS_CODE_ERR              (1<<6)
+#define FDI_RX_FE_CODE_ERR              (1<<5)
+#define FDI_RX_SYMBOL_ERR_RATE_ABOVE    (1<<4)
+#define FDI_RX_HDCP_LINK_FAIL           (1<<3)
+#define FDI_RX_PIXEL_FIFO_OVERFLOW      (1<<2)
+#define FDI_RX_CROSS_CLOCK_OVERFLOW     (1<<1)
+#define FDI_RX_SYMBOL_QUEUE_OVERFLOW    (1<<0)
+
+#define FDI_RXA_IIR             0xf0014
+#define FDI_RXA_IMR             0xf0018
+#define FDI_RXB_IIR             0xf1014
+#define FDI_RXB_IMR             0xf1018
+
+#define FDI_PLL_CTL_1           0xfe000
+#define FDI_PLL_CTL_2           0xfe004
+
+/* CRT */
+#define PCH_ADPA                0xe1100
+#define  ADPA_TRANS_SELECT_MASK (1<<30)
+#define  ADPA_TRANS_A_SELECT    0
+#define  ADPA_TRANS_B_SELECT    (1<<30)
+#define  ADPA_CRT_HOTPLUG_MASK  0x03ff0000 /* bit 25-16 */
+#define  ADPA_CRT_HOTPLUG_MONITOR_NONE  (0<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MASK  (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
+#define  ADPA_CRT_HOTPLUG_MONITOR_MONO  (2<<24)
+#define  ADPA_CRT_HOTPLUG_ENABLE        (1<<23)
+#define  ADPA_CRT_HOTPLUG_PERIOD_64     (0<<22)
+#define  ADPA_CRT_HOTPLUG_PERIOD_128    (1<<22)
+#define  ADPA_CRT_HOTPLUG_WARMUP_5MS    (0<<21)
+#define  ADPA_CRT_HOTPLUG_WARMUP_10MS   (1<<21)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_2S     (0<<20)
+#define  ADPA_CRT_HOTPLUG_SAMPLE_4S     (1<<20)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_40    (0<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_50    (1<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_60    (2<<18)
+#define  ADPA_CRT_HOTPLUG_VOLTAGE_70    (3<<18)
+#define  ADPA_CRT_HOTPLUG_VOLREF_325MV  (0<<17)
+#define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
+#define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
+
+/* or SDVOB */
+#define HDMIB   0xe1140
+#define  PORT_ENABLE    (1 << 31)
+#define  TRANSCODER_A   (0)
+#define  TRANSCODER_B   (1 << 30)
+#define  COLOR_FORMAT_8bpc      (0)
+#define  COLOR_FORMAT_12bpc     (3 << 26)
+#define  SDVOB_HOTPLUG_ENABLE   (1 << 23)
+#define  SDVO_ENCODING          (0)
+#define  TMDS_ENCODING          (2 << 10)
+#define  NULL_PACKET_VSYNC_ENABLE       (1 << 9)
+#define  SDVOB_BORDER_ENABLE    (1 << 7)
+#define  AUDIO_ENABLE           (1 << 6)
+#define  VSYNC_ACTIVE_HIGH      (1 << 4)
+#define  HSYNC_ACTIVE_HIGH      (1 << 3)
+#define  PORT_DETECTED          (1 << 2)
+
+/* PCH SDVOB multiplex with HDMIB */
+#define PCH_SDVOB	HDMIB
+
+#define HDMIC   0xe1150
+#define HDMID   0xe1160
+
+#define PCH_LVDS	0xe1180
+#define  LVDS_DETECTED	(1 << 1)
+
+#define BLC_PWM_CPU_CTL2	0x48250
+#define  PWM_ENABLE		(1 << 31)
+#define  PWM_PIPE_A		(0 << 29)
+#define  PWM_PIPE_B		(1 << 29)
+#define BLC_PWM_CPU_CTL		0x48254
+
+#define BLC_PWM_PCH_CTL1	0xc8250
+#define  PWM_PCH_ENABLE		(1 << 31)
+#define  PWM_POLARITY_ACTIVE_LOW	(1 << 29)
+#define  PWM_POLARITY_ACTIVE_HIGH	(0 << 29)
+#define  PWM_POLARITY_ACTIVE_LOW2	(1 << 28)
+#define  PWM_POLARITY_ACTIVE_HIGH2	(0 << 28)
+
+#define BLC_PWM_PCH_CTL2	0xc8254
+
+#define PCH_PP_STATUS		0xc7200
+#define PCH_PP_CONTROL		0xc7204
+#define  EDP_FORCE_VDD		(1 << 3)
+#define  EDP_BLC_ENABLE		(1 << 2)
+#define  PANEL_POWER_RESET	(1 << 1)
+#define  PANEL_POWER_OFF	(0 << 0)
+#define  PANEL_POWER_ON		(1 << 0)
+#define PCH_PP_ON_DELAYS	0xc7208
+#define  EDP_PANEL		(1 << 30)
+#define PCH_PP_OFF_DELAYS	0xc720c
+#define PCH_PP_DIVISOR		0xc7210
+
+#define PCH_DP_B		0xe4100
+#define PCH_DPB_AUX_CH_CTL	0xe4110
+#define PCH_DPB_AUX_CH_DATA1	0xe4114
+#define PCH_DPB_AUX_CH_DATA2	0xe4118
+#define PCH_DPB_AUX_CH_DATA3	0xe411c
+#define PCH_DPB_AUX_CH_DATA4	0xe4120
+#define PCH_DPB_AUX_CH_DATA5	0xe4124
+
+#define PCH_DP_C		0xe4200
+#define PCH_DPC_AUX_CH_CTL	0xe4210
+#define PCH_DPC_AUX_CH_DATA1	0xe4214
+#define PCH_DPC_AUX_CH_DATA2	0xe4218
+#define PCH_DPC_AUX_CH_DATA3	0xe421c
+#define PCH_DPC_AUX_CH_DATA4	0xe4220
+#define PCH_DPC_AUX_CH_DATA5	0xe4224
+
+#define PCH_DP_D		0xe4300
+#define PCH_DPD_AUX_CH_CTL	0xe4310
+#define PCH_DPD_AUX_CH_DATA1	0xe4314
+#define PCH_DPD_AUX_CH_DATA2	0xe4318
+#define PCH_DPD_AUX_CH_DATA3	0xe431c
+#define PCH_DPD_AUX_CH_DATA4	0xe4320
+#define PCH_DPD_AUX_CH_DATA5	0xe4324
+
+/* CPT */
+#define  PORT_TRANS_A_SEL_CPT	0
+#define  PORT_TRANS_B_SEL_CPT	(1<<29)
+#define  PORT_TRANS_C_SEL_CPT	(2<<29)
+#define  PORT_TRANS_SEL_MASK	(3<<29)
+
+#define TRANS_DP_CTL_A		0xe0300
+#define TRANS_DP_CTL_B		0xe1300
+#define TRANS_DP_CTL_C		0xe2300
+#define  TRANS_DP_OUTPUT_ENABLE	(1<<31)
+#define  TRANS_DP_PORT_SEL_B	(0<<29)
+#define  TRANS_DP_PORT_SEL_C	(1<<29)
+#define  TRANS_DP_PORT_SEL_D	(2<<29)
+#define  TRANS_DP_PORT_SEL_MASK	(3<<29)
+#define  TRANS_DP_AUDIO_ONLY	(1<<26)
+#define  TRANS_DP_ENH_FRAMING	(1<<18)
+#define  TRANS_DP_8BPC		(0<<9)
+#define  TRANS_DP_10BPC		(1<<9)
+#define  TRANS_DP_6BPC		(2<<9)
+#define  TRANS_DP_12BPC		(3<<9)
+#define  TRANS_DP_VSYNC_ACTIVE_HIGH	(1<<4)
+#define  TRANS_DP_VSYNC_ACTIVE_LOW	0
+#define  TRANS_DP_HSYNC_ACTIVE_HIGH	(1<<3)
+#define  TRANS_DP_HSYNC_ACTIVE_LOW	0
+
+/* SNB eDP training params */
+/* SNB A-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_A		(0x38<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_A		(0x02<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_A	(0x01<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_A		(0x0<<22)
+/* SNB B-stepping */
+#define  EDP_LINK_TRAIN_400MV_0DB_SNB_B		(0x0<<22)
+#define  EDP_LINK_TRAIN_400MV_6DB_SNB_B		(0x3a<<22)
+#define  EDP_LINK_TRAIN_600MV_3_5DB_SNB_B	(0x39<<22)
+#define  EDP_LINK_TRAIN_800MV_0DB_SNB_B		(0x38<<22)
+#define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB	(0x3f<<22)
+
+
+/* Chipset type macros */
+
+#define IS_I830(dev_priv) ((dev_priv)->flags & CHIP_I830)
+#define IS_845G(dev_priv) ((dev_priv)->flags & CHIP_I845G)
+#define IS_I85X(dev_priv) ((dev_priv)->flags & CHIP_I85X)
+#define IS_I865G(dev_priv) ((dev_priv)->flags & CHIP_I865G)
+
+#define IS_I915G(dev_priv) ((dev_priv)->flags & CHIP_I915G)
+#define IS_I915GM(dev_priv) ((dev_priv)->flags & CHIP_I915GM)
+#define IS_I945G(dev_priv) ((dev_priv)->flags & CHIP_I945G)
+#define IS_I945GM(dev_priv) ((dev_priv)->flags & CHIP_I945GM)
+#define IS_I965G(dev_priv) ((dev_priv)->flags & CHIP_I965)
+#define IS_I965GM(dev_priv) ((dev_priv)->flags & CHIP_I965GM)
+
+#define IS_GM45(dev_priv) ((dev_priv)->flags & CHIP_GM45)
+#define IS_G4X(dev_priv) ((dev_priv)->flags & CHIP_G4X)
+
+#define IS_G33(dev_priv)    ((dev_priv)->flags & CHIP_G33)
+
+#define IS_I9XX(dev_priv) ((dev_priv)->flags & CHIP_I9XX)
+
+#define IS_IRONLAKE(dev_priv) ((dev_priv)->flags & CHIP_IRONLAKE)
+#define IS_IRONLAKE_D(dev_priv) ((dev_priv)->flags & CHIP_IRONLAKE_D)
+#define IS_IRONLAKE_M(dev_priv) ((dev_priv)->flags & CHIP_IRONLAKE_M)
+
+#define IS_MOBILE(dev_priv) (dev_priv->flags & CHIP_M)
+
+#define I915_NEED_GFX_HWS(dev_priv) (dev_priv->flags & CHIP_HWS)
+
+#define HAS_RESET(dev_priv)	IS_I965G(dev_priv)
+
+#define IS_GEN2(dev_priv)	(dev_priv->flags & CHIP_GEN2)
+#define IS_GEN3(dev_priv)	(dev_priv->flags & CHIP_GEN3)
+#define IS_GEN4(dev_priv)	(dev_priv->flags & CHIP_GEN4)
+#define IS_GEN6(dev_priv)	(dev_priv->flags & CHIP_GEN6)
+
+#define HAS_PCH_SPLIT(dev_priv) (IS_IRONLAKE(dev_priv) ||	\
+				 IS_GEN6(dev_priv))
+
+/*
+ * Interrupts that are always left unmasked.
+ *
+ * Since pipe events are edge-triggered from the PIPESTAT register to IIRC,
+ * we leave them always unmasked in IMR and then control enabling them through
+ * PIPESTAT alone.
+ */
+#define I915_INTERRUPT_ENABLE_FIX		\
+	(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |	\
+	I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |	\
+	I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+
+/* Interrupts that we mask and unmask at runtime */
+#define I915_INTERRUPT_ENABLE_VAR	(I915_USER_INTERRUPT)
+
+/* These are all of the interrupts used by the driver */
+#define I915_INTERRUPT_ENABLE_MASK	\
+	(I915_INTERRUPT_ENABLE_FIX |	\
+	I915_INTERRUPT_ENABLE_VAR)
+
+/*
+ * if kms we want pch event, gse, and plane flip masks too
+ */
+#define PCH_SPLIT_DISPLAY_INTR_FIX	(DE_MASTER_IRQ_CONTROL)
+#define PCH_SPLIT_DISPLAY_INTR_VAR	(DE_PIPEA_VBLANK | DE_PIPEB_VBLANK)
+#define PCH_SPLIT_DISPLAY_ENABLE_MASK	\
+	(PCH_SPLIT_DISPLAY_INTR_FIX | PCH_SPLIT_DISPLAY_INTR_VAR)
+#define PCH_SPLIT_RENDER_INTR_FIX	(0)
+#define PCH_SPLIT_RENDER_INTR_VAR	(GT_USER_INTERRUPT | GT_MASTER_ERROR)
+#define PCH_SPLIT_RENDER_ENABLE_MASK	\
+	(PCH_SPLIT_RENDER_INTR_FIX | PCH_SPLIT_RENDER_INTR_VAR)
+/* not yet */
+#define PCH_SPLIT_HOTPLUG_INTR_FIX	(0)
+#define PCH_SPLIT_HOTPLUG_INTR_VAR	(0)
+#define PCH_SPLIT_HOTPLUG_ENABLE_MASK	\
+	(PCH_SPLIT_HOTPLUG_INTR_FIX | PCH_SPLIT_HOTPLUG_INTR_VAR)
+
+#define	printeir(val)	printf("%s: error reg: %b\n", __func__, val,	\
+	"\20\x10PTEERR\x2REFRESHERR\x1INSTERR")
+
+/*
+ * With the i45 and later, Y tiling got adjusted so that it was 32 128-byte
+ * rows, which changes the alignment requirements and fence programming.
+ */
+#define HAS_128_BYTE_Y_TILING(dev_priv) (IS_I9XX(dev_priv) &&	\
+	!(IS_I915G(dev_priv) || IS_I915GM(dev_priv)))
+
+#define PRIMARY_RINGBUFFER_SIZE         (128*1024)
+
+/* Inlines */
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static __inline int
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+	return ((int32_t)(seq1 - seq2) >= 0);
+}
+
+/*
+ * Read seqence number from the Hardware status page.
+ */
+static __inline u_int32_t
+i915_get_gem_seqno(struct inteldrm_softc *dev_priv)
+{
+	return (READ_HWSP(dev_priv, I915_GEM_HWS_INDEX));
+}
+
+static __inline int
+i915_obj_purgeable(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_DONTNEED);
+}
+
+static __inline int
+i915_obj_purged(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_PURGED);
+}
+
+static __inline int
+inteldrm_is_active(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_ACTIVE);
+}
+
+static __inline int
+inteldrm_is_dirty(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_DIRTY);
+}
+
+static __inline int
+inteldrm_exec_needs_fence(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_EXEC_NEEDS_FENCE);
+}
+
+static __inline int
+inteldrm_needs_fence(struct inteldrm_obj *obj_priv)
+{
+	return (obj_priv->obj.do_flags & I915_FENCED_EXEC);
+}
+
+#if defined(__NetBSD__)
+/* OpenBSD PCI IDs compatibility definitions. */
+#undef PCI_PRODUCT_INTEL_82830M_IGD
+#undef PCI_PRODUCT_INTEL_82865G_IGD
+#undef PCI_PRODUCT_INTEL_82915G_IGD_1
+#undef PCI_PRODUCT_INTEL_82915GM_IGD_1
+#undef PCI_PRODUCT_INTEL_82945G_IGD_1
+#undef PCI_PRODUCT_INTEL_82945GM_IGD_1
+#undef PCI_PRODUCT_INTEL_82945GME_IGD_1
+#undef PCI_PRODUCT_INTEL_82946GZ_IGD_1
+#undef PCI_PRODUCT_INTEL_82G35_IGD_1
+#undef PCI_PRODUCT_INTEL_82Q965_IGD_1
+#undef PCI_PRODUCT_INTEL_82G965_IGD_1
+#undef PCI_PRODUCT_INTEL_82GM965_IGD_1
+#undef PCI_PRODUCT_INTEL_82GME965_IGD_1
+#undef PCI_PRODUCT_INTEL_82G33_IGD_1
+#undef PCI_PRODUCT_INTEL_82Q35_IGD_1
+#undef PCI_PRODUCT_INTEL_82Q33_IGD_1
+#undef PCI_PRODUCT_INTEL_82GM45_IGD_1
+#undef PCI_PRODUCT_INTEL_82Q45_IGD_1
+#undef PCI_PRODUCT_INTEL_82G45_IGD_1
+#undef PCI_PRODUCT_INTEL_82G41_IGD_1
+#undef PCI_PRODUCT_INTEL_PINEVIEW_IGC_1
+#undef PCI_PRODUCT_INTEL_PINEVIEW_M_IGC_1
+#undef PCI_PRODUCT_INTEL_CLARKDALE_IGD
+#undef PCI_PRODUCT_INTEL_ARRANDALE_IGD
+#define PCI_PRODUCT_INTEL_82830M_IGD		PCI_PRODUCT_INTEL_82830MP_IV
+#define PCI_PRODUCT_INTEL_82865G_IGD		PCI_PRODUCT_INTEL_82865_IGD
+#define PCI_PRODUCT_INTEL_82915G_IGD_1		PCI_PRODUCT_INTEL_82915G_IGD
+#define PCI_PRODUCT_INTEL_82915GM_IGD_1		PCI_PRODUCT_INTEL_82915GM_IGD
+#define PCI_PRODUCT_INTEL_82945G_IGD_1		PCI_PRODUCT_INTEL_82945P_IGD
+#define PCI_PRODUCT_INTEL_82945GM_IGD_1		PCI_PRODUCT_INTEL_82945GM_IGD
+#define PCI_PRODUCT_INTEL_82945GME_IGD_1	PCI_PRODUCT_INTEL_82945GME_IGD
+#define PCI_PRODUCT_INTEL_82946GZ_IGD_1		PCI_PRODUCT_INTEL_82946GZ_IGD
+#define PCI_PRODUCT_INTEL_82G35_IGD_1		PCI_PRODUCT_INTEL_82G35_IGD
+#define PCI_PRODUCT_INTEL_82Q965_IGD_1		PCI_PRODUCT_INTEL_82965Q_IGD
+#define PCI_PRODUCT_INTEL_82Q965_IGD_1		PCI_PRODUCT_INTEL_82965Q_IGD
+#define PCI_PRODUCT_INTEL_82G965_IGD_1		PCI_PRODUCT_INTEL_82965G_IGD
+#define PCI_PRODUCT_INTEL_82GM965_IGD_1		PCI_PRODUCT_INTEL_82965PM_IGD
+#define PCI_PRODUCT_INTEL_82GME965_IGD_1	PCI_PRODUCT_INTEL_82965GME_IGD
+#define PCI_PRODUCT_INTEL_82G33_IGD_1		PCI_PRODUCT_INTEL_82G33_IGD
+#define PCI_PRODUCT_INTEL_82Q35_IGD_1		PCI_PRODUCT_INTEL_82Q35_IGD
+#define PCI_PRODUCT_INTEL_82Q33_IGD_1		PCI_PRODUCT_INTEL_82Q33_IGD
+#define PCI_PRODUCT_INTEL_82GM45_IGD_1		PCI_PRODUCT_INTEL_82GM45_IGD
+#define PCI_PRODUCT_INTEL_82Q45_IGD_1		PCI_PRODUCT_INTEL_82Q45_IGD
+#define PCI_PRODUCT_INTEL_82G45_IGD_1		PCI_PRODUCT_INTEL_82G45_IGD
+#define PCI_PRODUCT_INTEL_82G41_IGD_1		PCI_PRODUCT_INTEL_82G41_IGD
+#define PCI_PRODUCT_INTEL_PINEVIEW_IGC_1	PCI_PRODUCT_INTEL_PINEVIEW_IGD
+#define PCI_PRODUCT_INTEL_PINEVIEW_M_IGC_1	PCI_PRODUCT_INTEL_PINEVIEW_M_IGD
+#define PCI_PRODUCT_INTEL_CLARKDALE_IGD		PCI_PRODUCT_INTEL_IRONLAKE_D_IGD
+#define PCI_PRODUCT_INTEL_ARRANDALE_IGD		PCI_PRODUCT_INTEL_IRONLAKE_M_IGD
+#endif /* defined(__NetBSD__) */
+
+#endif
diff -Naurp old/src/sys/dev/pci/drm/i915_irq.c new/src/sys/dev/pci/drm/i915_irq.c
--- old/src/sys/dev/pci/drm/i915_irq.c	1970-01-01 01:00:00.000000000 +0100
+++ new/src/sys/dev/pci/drm/i915_irq.c	2011-02-08 11:14:00.000000000 +0100
@@ -0,0 +1,347 @@
+/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
+ */
+/*
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS 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.
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+int	inteldrm_intr(void *);
+void	i915_enable_irq(struct inteldrm_softc *, u_int32_t);
+void	i915_disable_irq(struct inteldrm_softc *, u_int32_t);
+void	ironlake_enable_graphics_irq(struct inteldrm_softc *, u_int32_t);
+void	ironlake_disable_graphics_irq(struct inteldrm_softc *, u_int32_t);
+void	ironlake_enable_display_irq(struct inteldrm_softc *, u_int32_t);
+void	ironlake_disable_display_irq(struct inteldrm_softc *, u_int32_t);
+void	i915_enable_pipestat(struct inteldrm_softc *, int, u_int32_t);
+void	i915_disable_pipestat(struct inteldrm_softc *, int, u_int32_t);
+int	ironlake_irq_install(struct inteldrm_softc *);
+
+void
+i915_enable_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != 0) {
+		dev_priv->irq_mask_reg &= ~mask;
+		I915_WRITE(IMR, dev_priv->irq_mask_reg);
+		(void)I915_READ(IMR);
+	}
+}
+
+void
+i915_disable_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != mask) {
+		dev_priv->irq_mask_reg |= mask;
+		I915_WRITE(IMR, dev_priv->irq_mask_reg);
+		(void)I915_READ(IMR);
+	}
+}
+
+inline void
+ironlake_enable_graphics_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->gt_irq_mask_reg & mask) != 0) {
+		dev_priv->gt_irq_mask_reg &= ~mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void)I915_READ(GTIMR);
+	}
+}
+
+inline void
+ironlake_disable_graphics_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
+		dev_priv->gt_irq_mask_reg |= mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void)I915_READ(GTIMR);
+	}
+}
+
+/* display hotplug and vblank irqs */
+inline void
+ironlake_enable_display_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != 0) {
+		dev_priv->irq_mask_reg &= ~mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void)I915_READ(DEIMR);
+	}
+}
+
+inline void
+ironlake_disable_display_irq(struct inteldrm_softc *dev_priv, u_int32_t mask)
+{
+	if ((dev_priv->irq_mask_reg & mask) != mask) {
+		dev_priv->irq_mask_reg |= mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void)I915_READ(DEIMR);
+	}
+}
+
+void
+i915_enable_pipestat(struct inteldrm_softc *dev_priv, int pipe, u_int32_t mask)
+{
+	if ((dev_priv->pipestat[pipe] & mask) != mask) {
+		bus_size_t reg = pipe == 0 ? PIPEASTAT : PIPEBSTAT;
+
+		dev_priv->pipestat[pipe] |= mask;
+		/* Enable the interrupt, clear and pending status */
+		I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
+		(void)I915_READ(reg);
+	}
+}
+
+void
+i915_disable_pipestat(struct inteldrm_softc *dev_priv, int pipe, u_int32_t mask)
+{
+	if ((dev_priv->pipestat[pipe] & mask) != 0) {
+		bus_size_t reg = pipe == 0 ? PIPEASTAT : PIPEBSTAT;
+
+		dev_priv->pipestat[pipe] &= ~mask;
+		I915_WRITE(reg, dev_priv->pipestat[pipe]);
+		(void)I915_READ(reg);
+	}
+}
+
+u_int32_t
+i915_get_vblank_counter(struct drm_device *dev, int pipe)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+	bus_size_t		 high_frame, low_frame;
+	u_int32_t		 high1, high2, low;
+
+	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+	if (inteldrm_pipe_enabled(dev_priv, pipe) == 0) {
+		DRM_DEBUG("trying to get vblank count for disabled pipe %d\n",
+		    pipe);
+		return (0);
+	}
+
+	/* GM45 just had to be different... */
+	if (IS_GM45(dev_priv) || IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv)) {
+		return (I915_READ(pipe ? PIPEB_FRMCOUNT_GM45 :
+		    PIPEA_FRMCOUNT_GM45));
+	}
+
+	/*
+	 * High & low register fields aren't synchronized, so make sure
+	 * we get a low value that's stable across two reads of the high
+	 * register.
+	 */
+	do {
+		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+			PIPE_FRAME_LOW_SHIFT);
+		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+	} while (high1 != high2);
+
+	return ((high1 << 8) | low);
+}
+
+void
+i915_user_irq_get(struct inteldrm_softc *dev_priv)
+{
+	if (++dev_priv->user_irq_refcount == 1) {
+		if (HAS_PCH_SPLIT(dev_priv))
+			ironlake_enable_graphics_irq(dev_priv,
+			    GT_USER_INTERRUPT);
+		else
+			i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
+}
+
+void
+i915_user_irq_put(struct inteldrm_softc *dev_priv)
+{
+	if (--dev_priv->user_irq_refcount == 0) {
+		if (HAS_PCH_SPLIT(dev_priv))
+			ironlake_disable_graphics_irq(dev_priv,
+			    GT_USER_INTERRUPT);
+		else
+			i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
+}
+
+int
+i915_enable_vblank(struct drm_device *dev, int pipe)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	if (inteldrm_pipe_enabled(dev_priv, pipe) == 0)
+		return (EINVAL);
+
+	mtx_enter(&dev_priv->user_irq_lock);
+	if (HAS_PCH_SPLIT(dev_priv))
+		ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+		    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
+	else
+		i915_enable_pipestat(dev_priv, pipe, (IS_I965G(dev_priv) ?
+		    PIPE_START_VBLANK_INTERRUPT_ENABLE :
+		    PIPE_VBLANK_INTERRUPT_ENABLE));
+	mtx_leave(&dev_priv->user_irq_lock);
+
+	return (0);
+}
+
+void
+i915_disable_vblank(struct drm_device *dev, int pipe)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	mtx_enter(&dev_priv->user_irq_lock);
+	if (HAS_PCH_SPLIT(dev_priv))
+		ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+		    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
+	else
+		i915_disable_pipestat(dev_priv, pipe,
+		    PIPE_START_VBLANK_INTERRUPT_ENABLE |
+		    PIPE_VBLANK_INTERRUPT_ENABLE);
+	mtx_leave(&dev_priv->user_irq_lock);
+}
+
+/* drm_dma.h hooks
+*/
+int
+i915_driver_irq_install(struct drm_device *dev)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	dev->vblank->vb_max = 0xffffff; /* only 24 bits of frame count */
+	if (IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv))
+		dev->vblank->vb_max = 0xffffffff;
+
+	I915_WRITE(HWSTAM, 0xeffe);
+
+	if (HAS_PCH_SPLIT(dev_priv))
+		return (ironlake_irq_install(dev_priv));
+
+	I915_WRITE(PIPEASTAT, 0);
+	I915_WRITE(PIPEBSTAT, 0);
+	I915_WRITE(IMR, 0xffffffff);
+	I915_WRITE(IER, 0x0);
+	(void)I915_READ(IER);
+
+
+	/*
+	 * Enable some error detection, note the instruction error mask
+	 * bit is reserved, so we leave it masked.
+	 */
+	I915_WRITE(EMR, IS_G4X(dev_priv) ?
+	    ~(GM45_ERROR_PAGE_TABLE | GM45_ERROR_MEM_PRIV |
+	    GM45_ERROR_CP_PRIV | I915_ERROR_MEMORY_REFRESH) :
+	    ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
+
+	/*
+	 * Disable pipe interrupt enables, clear pending pipe status
+	 * add back in the enabled interrupts from previous iterations
+	 * (say in the reset case where we want vblank interrupts etc to be
+	 * switched back on if they were running
+	 */
+	I915_WRITE(PIPEASTAT, (I915_READ(PIPEASTAT) & 0x8000ffff) |
+	    dev_priv->pipestat[0]);
+	I915_WRITE(PIPEBSTAT, (I915_READ(PIPEBSTAT) & 0x8000ffff) |
+	    dev_priv->pipestat[1]);
+	/* Clear pending interrupt status */
+	I915_WRITE(IIR, I915_READ(IIR));
+
+	I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+	I915_WRITE(IMR, dev_priv->irq_mask_reg);
+	(void)I915_READ(IER);
+
+	return (0);
+}
+
+int
+ironlake_irq_install(struct inteldrm_softc *dev_priv)
+{
+	/* mask and ack everything before we turn anything on. */
+	/*
+	 * XXX this is a legacy of the only preinstall/postinstall split.
+	 * I wonder if we could avoid this now...
+	 */
+	I915_WRITE(DEIMR, 0xffffffff);
+	I915_WRITE(DEIER, 0x0);
+	(void)I915_READ(DEIER);
+
+	/* GT */
+	I915_WRITE(GTIMR, 0xfffffff);
+	I915_WRITE(GTIER, 0x0);
+	(void)I915_READ(GTIER);
+
+	/*
+	 * Everything is turned off now and everything acked.
+	 * now we can set everything up
+	 */
+
+	I915_WRITE(DEIIR, I915_READ(DEIIR));
+	I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+	I915_WRITE(DEIER, PCH_SPLIT_DISPLAY_ENABLE_MASK);
+
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+	I915_WRITE(GTIER, PCH_SPLIT_RENDER_ENABLE_MASK);
+
+	/* south display irq -- hotplug off for now */
+	I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+	I915_WRITE(SDEIMR, dev_priv->pch_irq_mask_reg);
+	I915_WRITE(SDEIER, PCH_SPLIT_HOTPLUG_ENABLE_MASK);
+	(void)I915_READ(SDEIER);
+
+	return (0);
+}
+
+void
+i915_driver_irq_uninstall(struct drm_device *dev)
+{
+	struct inteldrm_softc	*dev_priv = dev->dev_private;
+
+	I915_WRITE(HWSTAM, 0xffffffff);
+
+	if (HAS_PCH_SPLIT(dev_priv)) {
+		I915_WRITE(DEIMR, 0xffffffff);
+		I915_WRITE(DEIER, 0x0);
+		I915_WRITE(DEIIR, I915_READ(DEIIR));
+
+		I915_WRITE(GTIMR, 0xfffffff);
+		I915_WRITE(GTIER, 0x0);
+		I915_WRITE(GTIIR, I915_READ(GTIIR));
+	} else {
+		I915_WRITE(PIPEASTAT, 0);
+		I915_WRITE(PIPEBSTAT, 0);
+		I915_WRITE(IMR, 0xffffffff);
+		I915_WRITE(IER, 0x0);
+
+		I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
+		I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
+		I915_WRITE(IIR, I915_READ(IIR));
+	}
+}
diff -Naurp old/src/sys/dev/pci/vga_pci.c new/src/sys/dev/pci/vga_pci.c
--- old/src/sys/dev/pci/vga_pci.c	2011-01-22 16:14:28.000000000 +0100
+++ new/src/sys/dev/pci/vga_pci.c	2011-02-08 11:14:00.000000000 +0100
@@ -300,6 +300,15 @@ vga_drm_print(void *aux, const char *pnp
 	return (UNCONF);
 }
 
+bus_addr_t
+vga_bar_base(device_t dv, int bar)
+{
+	struct vga_pci_softc *sc;
+
+	KASSERT(dv != NULL && device_is_a(dv, "vga"));
+	sc = device_private(dv);
+	return sc->sc_bars[bar].vb_base;
+}
 
 static int
 vga_pci_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
diff -Naurp old/src/sys/dev/pci/vga_pcivar.h new/src/sys/dev/pci/vga_pcivar.h
--- old/src/sys/dev/pci/vga_pcivar.h	2007-03-20 19:05:31.000000000 +0100
+++ new/src/sys/dev/pci/vga_pcivar.h	2011-02-08 11:14:00.000000000 +0100
@@ -37,3 +37,5 @@ int vga_pci_cnattach(bus_space_tag_t, bu
 			  pci_chipset_tag_t, int, int, int);
 
 int vga_drm_print(void *aux, const char *pnp);
+
+bus_addr_t vga_bar_base(device_t, int);
diff -Naurp old/src/sys/kern/sysv_shm.c new/src/sys/kern/sysv_shm.c
--- old/src/sys/kern/sysv_shm.c	2010-07-27 16:25:23.000000000 +0200
+++ new/src/sys/kern/sysv_shm.c	2011-02-08 11:14:00.000000000 +0100
@@ -268,7 +268,7 @@ shm_memlock(struct lwp *l, struct shmid_
 		if (cmd == SHM_LOCK &&
 		    (shmseg->shm_perm.mode & SHMSEG_WIRED) == 0) {
 			/* Wire the object and map, then tag it */
-			error = uobj_wirepages(shmseg->_shm_internal, 0, size);
+			error = uobj_wirepages(shmseg->_shm_internal, 0, size, NULL);
 			if (error)
 				return EIO;
 			error = uvm_map_pageable(&p->p_vmspace->vm_map,
@@ -730,7 +730,7 @@ sys_shmget(struct lwp *l, const struct s
 	shmseg->_shm_internal = uao_create(size, 0);
 	if (lockmem) {
 		/* Wire the pages and tag it */
-		error = uobj_wirepages(shmseg->_shm_internal, 0, size);
+		error = uobj_wirepages(shmseg->_shm_internal, 0, size, NULL);
 		if (error) {
 			uao_detach(shmseg->_shm_internal);
 			mutex_enter(&shm_lock);
diff -Naurp old/src/sys/modules/Makefile new/src/sys/modules/Makefile
--- old/src/sys/modules/Makefile	2011-01-16 02:13:10.000000000 +0100
+++ new/src/sys/modules/Makefile	2011-02-08 11:14:00.000000000 +0100
@@ -122,8 +122,8 @@ SUBDIR+=	azalia
 SUBDIR+=	compat_linux
 SUBDIR+=	compat_linux32
 SUBDIR+=	compat_netbsd32
-SUBDIR+=	drm
-SUBDIR+=	i915drm
+#SUBDIR+=	drm
+#SUBDIR+=	i915drm
 SUBDIR+=	pad
 .endif
 
@@ -133,10 +133,10 @@ SUBDIR+=	compat_freebsd
 SUBDIR+=	compat_ibcs2
 SUBDIR+=	compat_linux
 SUBDIR+=	compat_svr4
-SUBDIR+=	drm
-SUBDIR+=	i915drm
-SUBDIR+=	radeondrm
-SUBDIR+=	viadrm
+#SUBDIR+=	drm
+#SUBDIR+=	i915drm
+#SUBDIR+=	radeondrm
+#SUBDIR+=	viadrm
 SUBDIR+=	pad
 .endif
 
diff -Naurp old/src/sys/uvm/uvm_extern.h new/src/sys/uvm/uvm_extern.h
--- old/src/sys/uvm/uvm_extern.h	2011-01-04 09:26:33.000000000 +0100
+++ new/src/sys/uvm/uvm_extern.h	2011-02-08 11:14:00.000000000 +0100
@@ -705,10 +705,9 @@ int			uvm_mremap(struct vm_map *, vaddr_
 			    struct proc *, int);
 
 /* uvm_object.c */
-int			uobj_wirepages(struct uvm_object *uobj, off_t start,
-			    off_t end);
-void			uobj_unwirepages(struct uvm_object *uobj, off_t start,
-			    off_t end);
+int			uobj_wirepages(struct uvm_object *, off_t, off_t,
+			    struct pglist *);
+void			uobj_unwirepages(struct uvm_object *, off_t, off_t);
 
 /* uvm_page.c */
 struct vm_page		*uvm_pagealloc_strat(struct uvm_object *,
diff -Naurp old/src/sys/uvm/uvm_object.c new/src/sys/uvm/uvm_object.c
--- old/src/sys/uvm/uvm_object.c	2009-08-18 21:16:09.000000000 +0200
+++ new/src/sys/uvm/uvm_object.c	2011-02-08 11:14:00.000000000 +0100
@@ -60,7 +60,8 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_object.c
  */
 
 int
-uobj_wirepages(struct uvm_object *uobj, off_t start, off_t end)
+uobj_wirepages(struct uvm_object *uobj, off_t start, off_t end,
+    struct pglist *list)
 {
 	int i, npages, error;
 	struct vm_page *pgs[FETCH_PAGECOUNT], *pg = NULL;
@@ -114,6 +115,8 @@ uobj_wirepages(struct uvm_object *uobj,
 		mutex_enter(&uvm_pageqlock);
 		for (i = 0; i < npages; i++) {
 			uvm_pagewire(pgs[i]);
+			if (list != NULL)
+				TAILQ_INSERT_TAIL(list, pgs[i], pageq.queue);
 		}
 		mutex_exit(&uvm_pageqlock);
 
