[prev in list] [next in list] [prev in thread] [next in thread] 

List:       dri-patches
Subject:    drm: Branch 'nouveau-1' - 43 commits
From:       marcheu () kemper ! freedesktop ! org (Stephane Marchesin)
Date:       2006-10-14 22:07:32
Message-ID: 20061014220732.91FB810078 () kemper ! freedesktop ! org
[Download RAW message or body]

bsd-core/drmP.h            |    6 
 bsd-core/drm_drawable.c    |   52 -------
 bsd-core/drm_drv.c         |    3 
 libdrm/xf86drm.c           |   16 ++
 libdrm/xf86drm.h           |    8 -
 linux-core/Makefile        |    4 
 linux-core/drmP.h          |   39 +++++
 linux-core/drm_bufs.c      |   10 -
 linux-core/drm_core.h      |    8 -
 linux-core/drm_drawable.c  |   57 -------
 linux-core/drm_drv.c       |   14 +
 linux-core/drm_irq.c       |  155 +++++++++++++++++----
 linux-core/drm_lock.c      |   11 +
 linux-core/drm_stub.c      |    4 
 linux-core/drm_vm.c        |   16 ++
 linux-core/i915_drv.c      |    4 
 linux-core/radeon_drv.c    |    2 
 shared-core/drm.h          |   33 ++++
 shared-core/drm_drawable.c |  330 +++++++++++++++++++++++++++++++++++++++++++++
 shared-core/drm_pciids.txt |  177 ++++++++++++------------
 shared-core/i915_dma.c     |   10 -
 shared-core/i915_drm.h     |   19 ++
 shared-core/i915_drv.h     |   22 ++-
 shared-core/i915_irq.c     |  265 ++++++++++++++++++++++++++++++++++--
 shared-core/mach64_dma.c   |  232 ++++++++++++++++---------------
 shared-core/mach64_drm.h   |    2 
 shared-core/mach64_drv.h   |    7 
 shared-core/mach64_state.c |  209 +++++++++++++---------------
 shared-core/r300_cmdbuf.c  |   33 ++++
 shared-core/radeon_cp.c    |   46 +++---
 shared-core/radeon_drv.h   |   23 +--
 shared-core/radeon_state.c |  134 ++++++++++++++++--
 32 files changed, 1428 insertions(+), 523 deletions(-)

New commits:
diff-tree 93fee5cf222ad6d97e0dcb85e13a8d8b84dba81f (from parents)
Merge: 2c5b91aecf3d21684ffca758c034cd9a8ed2155d \
                a9f57a2b9c5897cbf568bf75342204b780566de0
Author: Stephane Marchesin <marchesin@icps.u-strasbg.fr>
Date:   Sun Oct 15 00:12:13 2006 +0200

    Merge branch 'master' of git://anongit.freedesktop.org/git/mesa/drm into \
nouveau-1

diff-tree a9f57a2b9c5897cbf568bf75342204b780566de0 (from \
                c9e3aa961eb90265ec024ff57013786e4d47d0e7)
Author: Roland Scheidegger <rscheidegger_lists@hispeed.ch>
Date:   Tue Oct 10 02:24:19 2006 +0200

    only allow specific type-3 packets to pass the verifier instead of all for \
r100/r200 as others might be unsafe (r300 already does this), and add checking for \
these we need but aren't safe. Check the RADEON_CP_INDX_BUFFER packet on both r200 \
and r300 as it isn't safe neither.

diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c
index dc86682..c65ffd5 100644
--- a/shared-core/r300_cmdbuf.c
+++ b/shared-core/r300_cmdbuf.c
@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_m
 	return 0;
 }
 
+static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
+					     drm_radeon_kcmd_buffer_t *cmdbuf)
+{
+	u32 *cmd = (u32 *) cmdbuf->buf;
+	int count, ret;
+	RING_LOCALS;
+
+	count=(cmd[0]>>16) & 0x3fff;
+
+	if ((cmd[1] & 0x8000ffff) != 0x80000810) {
+		DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
+		return DRM_ERR(EINVAL);
+	}
+	ret = r300_check_offset(dev_priv, cmd[2]);
+	if (ret) {
+		DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+		return DRM_ERR(EINVAL);
+	}
+
+	BEGIN_RING(count+2);
+	OUT_RING(cmd[0]);
+	OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
+	ADVANCE_RING();
+
+	cmdbuf->buf += (count+2)*4;
+	cmdbuf->bufsz -= (count+2)*4;
+
+	return 0;
+}
+
 static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
 					    drm_radeon_kcmd_buffer_t *cmdbuf)
 {
@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_pack
 	case RADEON_CNTL_BITBLT_MULTI:
 		return r300_emit_bitblt_multi(dev_priv, cmdbuf);
 
+	case RADEON_CP_INDX_BUFFER:	/* DRAW_INDX_2 without INDX_BUFFER seems to lock up the \
gpu */ +		return r300_emit_indx_buffer(dev_priv, cmdbuf);
 	case RADEON_CP_3D_DRAW_IMMD_2:	/* triggers drawing using in-packet vertex data */
 	case RADEON_CP_3D_DRAW_VBUF_2:	/* triggers drawing of vertex buffers setup \
elsewhere */  case RADEON_CP_3D_DRAW_INDX_2:	/* triggers drawing using indices to \
                vertex buffer */
-	case RADEON_CP_INDX_BUFFER:	/* DRAW_INDX_2 without INDX_BUFFER seems to lock up the \
gpu */  case RADEON_WAIT_FOR_IDLE:
 	case RADEON_CP_NOP:
 		/* these packets are safe */
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index b447801..bf5e3d2 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_f
 						     unsigned int *cmdsz)
 {
 	u32 *cmd = (u32 *) cmdbuf->buf;
+	u32 offset, narrays;
+	int count, i, k;
 
 	*cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
 
@@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_f
 		return DRM_ERR(EINVAL);
 	}
 
-	/* Check client state and fix it up if necessary */
-	if (cmd[0] & 0x8000) {	/* MSB of opcode: next DWORD GUI_CNTL */
-		u32 offset;
+	switch(cmd[0] & 0xff00) {
+	/* XXX Are there old drivers needing other packets? */
 
+	case RADEON_3D_DRAW_IMMD:
+	case RADEON_3D_DRAW_VBUF:
+	case RADEON_3D_DRAW_INDX:
+	case RADEON_WAIT_FOR_IDLE:
+	case RADEON_CP_NOP:
+	case RADEON_3D_CLEAR_ZMASK:
+/*	case RADEON_CP_NEXT_CHAR:
+	case RADEON_CP_PLY_NEXTSCAN:
+	case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
+		/* these packets are safe */
+		break;
+
+	case RADEON_CP_3D_DRAW_IMMD_2:
+	case RADEON_CP_3D_DRAW_VBUF_2:
+	case RADEON_CP_3D_DRAW_INDX_2:
+	case RADEON_3D_CLEAR_HIZ:
+		/* safe but r200 only */
+		if (dev_priv->microcode_version != UCODE_R200) {
+			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
+			return DRM_ERR(EINVAL);
+		}
+		break;
+
+	case RADEON_3D_LOAD_VBPNTR:
+		count = (cmd[0] >> 16) & 0x3fff;
+
+		if (count > 18) { /* 12 arrays max */
+			DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
+				  count);
+			return DRM_ERR(EINVAL);
+		}
+
+		/* carefully check packet contents */
+		narrays = cmd[1] & ~0xc000;
+		k = 0;
+		i = 2;
+		while ((k < narrays) && (i < (count + 2))) {
+			i++;		/* skip attribute field */
+			if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+				DRM_ERROR
+				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
+				     k, i);
+				return DRM_ERR(EINVAL);
+			}
+			k++;
+			i++;
+			if (k == narrays)
+				break;
+			/* have one more to process, they come in pairs */
+			if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+				DRM_ERROR
+				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
+				     k, i);
+				return DRM_ERR(EINVAL);
+			}
+			k++;
+			i++;
+		}
+		/* do the counts match what we expect ? */
+		if ((k != narrays) || (i != (count + 2))) {
+			DRM_ERROR
+			    ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
+			      k, i, narrays, count + 1);
+			return DRM_ERR(EINVAL);
+		}
+		break;
+
+	case RADEON_3D_RNDR_GEN_INDX_PRIM:
+		if (dev_priv->microcode_version != UCODE_R100) {
+			DRM_ERROR("Invalid 3d packet for r200-class chip\n");
+			return DRM_ERR(EINVAL);
+		}
+		if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
+				DRM_ERROR("Invalid rndr_gen_indx offset\n");
+				return DRM_ERR(EINVAL);
+		}
+		break;
+
+	case RADEON_CP_INDX_BUFFER:
+		if (dev_priv->microcode_version != UCODE_R200) {
+			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
+			return DRM_ERR(EINVAL);
+		}
+		if ((cmd[1] & 0x8000ffff) != 0x80000810) {
+			DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
+			return DRM_ERR(EINVAL);
+		}
+		if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
+			DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
+			return DRM_ERR(EINVAL);
+		}
+		break;
+
+	case RADEON_CNTL_HOSTDATA_BLT:
+	case RADEON_CNTL_PAINT_MULTI:
+	case RADEON_CNTL_BITBLT_MULTI:
+		/* MSB of opcode: next DWORD GUI_CNTL */
 		if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
 			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
 			offset = cmd[2] << 10;
@@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_f
 			}
 			cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
 		}
+		break;
+
+	default:
+		DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
+		return DRM_ERR(EINVAL);
 	}
 
 	return 0;
diff-tree c9e3aa961eb90265ec024ff57013786e4d47d0e7 (from \
                f3deef730d52c94ce21ada7e4ceb63aa28a8601b)
Author: George Sapountzis <gsap7@yahoo.gr>
Date:   Mon Oct 2 06:13:38 2006 +0300

    Bug 6242: [mach64] Use private DMA buffers, part #4.
    
    mach64_state.c: convert the DRM_MACH64_BLIT ioctl to submit a pointer to
    user-space memory rather than a DMA buffer index, similar to DRM_MACH64_VERTEX.
    
    This change allows the DDX to map the DMA buffers read-only and eliminate a
    security problem where a client can alter the contents of the DMA buffer after
    submission to the DRM.
    
    This change also affects the DRI/DRM interface. Performace-wise, it basically
    affects PCI mode where I get a ~12% speedup for some Mesa demos I tested.
    This is mainly due to eliminating an ioctl for allocating the DMA buffer.
    
    mach64_dma.c: move the responsibility for allocating memory for the DMA ring
    in PCI mode to the DDX.
    
    This change affects the DDX/DRM interface and unifies a couple of PCI/AGP code
    paths for ring memory in the DRM.
    
    Bump the mach64 DRM version major and date.

diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c
index 7cba8ad..3a5fdee 100644
--- a/shared-core/mach64_dma.c
+++ b/shared-core/mach64_dma.c
@@ -815,17 +815,18 @@ static int mach64_do_dma_init(drm_device
 		return DRM_ERR(EINVAL);
 	}
 
+	dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset);
+	if (!dev_priv->ring_map) {
+		DRM_ERROR("can not find ring map!\n");
+		dev->dev_private = (void *)dev_priv;
+		mach64_do_cleanup_dma(dev);
+		return DRM_ERR(EINVAL);
+	}
+
 	dev_priv->sarea_priv = (drm_mach64_sarea_t *)
 	    ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
 
 	if (!dev_priv->is_pci) {
-		dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset);
-		if (!dev_priv->ring_map) {
-			DRM_ERROR("can not find ring map!\n");
-			dev->dev_private = (void *)dev_priv;
-			mach64_do_cleanup_dma(dev);
-			return DRM_ERR(EINVAL);
-		}
 		drm_core_ioremap(dev_priv->ring_map, dev);
 		if (!dev_priv->ring_map->handle) {
 			DRM_ERROR("can not ioremap virtual address for"
@@ -891,27 +892,9 @@ static int mach64_do_dma_init(drm_device
 		}
 	}
 
-	/* allocate descriptor memory from pci pool */
-	DRM_DEBUG("Allocating dma descriptor ring\n");
 	dev_priv->ring.size = 0x4000;	/* 16KB */
-
-	if (dev_priv->is_pci) {
-		dev_priv->ring.dmah = drm_pci_alloc(dev, dev_priv->ring.size,
-						     dev_priv->ring.size,
-						     0xfffffffful);
-
-		if (!dev_priv->ring.dmah) {
-			DRM_ERROR("Allocating dma descriptor ring failed\n");
-			return DRM_ERR(ENOMEM);
-		} else {
-			dev_priv->ring.start = dev_priv->ring.dmah->vaddr;
-			dev_priv->ring.start_addr =
-			    (u32) dev_priv->ring.dmah->busaddr;
-		}
-	} else {
-		dev_priv->ring.start = dev_priv->ring_map->handle;
-		dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset;
-	}
+	dev_priv->ring.start = dev_priv->ring_map->handle;
+	dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset;
 
 	memset(dev_priv->ring.start, 0, dev_priv->ring.size);
 	DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n",
@@ -1149,18 +1132,14 @@ int mach64_do_cleanup_dma(drm_device_t *
 	if (dev->dev_private) {
 		drm_mach64_private_t *dev_priv = dev->dev_private;
 
-		if (dev_priv->is_pci) {
-			if (dev_priv->ring.dmah) {
-				drm_pci_free(dev, dev_priv->ring.dmah);
-			}
-		} else {
+		if (!dev_priv->is_pci) {
 			if (dev_priv->ring_map)
 				drm_core_ioremapfree(dev_priv->ring_map, dev);
-		}
 
-		if (dev->agp_buffer_map) {
-			drm_core_ioremapfree(dev->agp_buffer_map, dev);
-			dev->agp_buffer_map = NULL;
+			if (dev->agp_buffer_map) {
+				drm_core_ioremapfree(dev->agp_buffer_map, dev);
+				dev->agp_buffer_map = NULL;
+			}
 		}
 
 		mach64_destroy_freelist(dev);
diff --git a/shared-core/mach64_drm.h b/shared-core/mach64_drm.h
index 1fd8c00..083f959 100644
--- a/shared-core/mach64_drm.h
+++ b/shared-core/mach64_drm.h
@@ -237,7 +237,7 @@ typedef struct drm_mach64_vertex {
 } drm_mach64_vertex_t;
 
 typedef struct drm_mach64_blit {
-	int idx;
+	void *buf;
 	int pitch;
 	int offset;
 	int format;
diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h
index e8dc71e..bb8b309 100644
--- a/shared-core/mach64_drv.h
+++ b/shared-core/mach64_drv.h
@@ -42,9 +42,9 @@
 
 #define DRIVER_NAME		"mach64"
 #define DRIVER_DESC		"DRM module for the ATI Rage Pro"
-#define DRIVER_DATE		"20020904"
+#define DRIVER_DATE		"20060718"
 
-#define DRIVER_MAJOR		1
+#define DRIVER_MAJOR		2
 #define DRIVER_MINOR		0
 #define DRIVER_PATCHLEVEL	0
 
@@ -61,7 +61,6 @@ typedef struct drm_mach64_freelist {
 } drm_mach64_freelist_t;
 
 typedef struct drm_mach64_descriptor_ring {
-	drm_dma_handle_t *dmah;	/* Handle to pci dma memory */
 	void *start;		/* write pointer (cpu address) to start of descriptor ring */
 	u32 start_addr;		/* bus address of beginning of descriptor ring */
 	int size;		/* size of ring in bytes */
diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c
index 31e3b56..38cefca 100644
--- a/shared-core/mach64_state.c
+++ b/shared-core/mach64_state.c
@@ -480,16 +480,16 @@ static int mach64_do_get_frames_queued(d
 /* Copy and verify a client submited buffer.
  * FIXME: Make an assembly optimized version
  */
-static __inline__ int copy_and_verify_from_user(u32 *to,
-						const u32 __user *ufrom,
-						unsigned long bytes)
+static __inline__ int copy_from_user_vertex(u32 *to,
+					    const u32 __user *ufrom,
+					    unsigned long bytes)
 {
 	unsigned long n = bytes;	/* dwords remaining in buffer */
 	u32 *from, *orig_from;
 
 	from = drm_alloc(bytes, DRM_MEM_DRIVER);
 	if (from == NULL)
-		return ENOMEM;
+		return DRM_ERR(ENOMEM);
 
 	if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
 		drm_free(from, bytes, DRM_MEM_DRIVER);
@@ -571,7 +571,7 @@ static int mach64_dma_dispatch_vertex(DR
 		return DRM_ERR(EAGAIN);
 	}
 
-	verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used);
+	verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used);
 
 	if (verify_ret != 0) {
 		mach64_freelist_put(dev_priv, copy_buf);
@@ -627,13 +627,27 @@ _vertex_done:
 	return verify_ret;
 }
 
+static __inline__ int copy_from_user_blit(u32 *to,
+					  const u32 __user *ufrom,
+					  unsigned long bytes)
+{
+	to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET);
+
+	if (DRM_COPY_FROM_USER(to, ufrom, bytes)) {
+		return DRM_ERR(EFAULT);
+	}
+
+	return 0;
+}
+
 static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev,
 				    drm_mach64_blit_t * blit)
 {
 	drm_mach64_private_t *dev_priv = dev->dev_private;
-	drm_device_dma_t *dma = dev->dma;
 	int dword_shift, dwords;
-	drm_buf_t *buf;
+	unsigned long used;
+	drm_buf_t *copy_buf;
+	int verify_ret = 0;
 	DMALOCALS;
 
 	/* The compiler won't optimize away a division by a variable,
@@ -660,34 +674,34 @@ static int mach64_dma_dispatch_blit(DRMF
 		return DRM_ERR(EINVAL);
 	}
 
-	/* Dispatch the blit buffer.
-	 */
-	buf = dma->buflist[blit->idx];
-
-	if (buf->filp != filp) {
-		DRM_ERROR("process %d (filp %p) using buffer with filp %p\n",
-			  DRM_CURRENTPID, filp, buf->filp);
-		return DRM_ERR(EINVAL);
-	}
-
-	if (buf->pending) {
-		DRM_ERROR("sending pending buffer %d\n", blit->idx);
-		return DRM_ERR(EINVAL);
-	}
-
 	/* Set buf->used to the bytes of blit data based on the blit dimensions
 	 * and verify the size.  When the setup is emitted to the buffer with
 	 * the DMA* macros below, buf->used is incremented to include the bytes
 	 * used for setup as well as the blit data.
 	 */
 	dwords = (blit->width * blit->height) >> dword_shift;
-	buf->used = dwords << 2;
-	if (buf->used <= 0 ||
-	    buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
-		DRM_ERROR("Invalid blit size: %d bytes\n", buf->used);
+	used = dwords << 2;
+	if (used <= 0 ||
+	    used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
+		DRM_ERROR("Invalid blit size: %lu bytes\n", used);
 		return DRM_ERR(EINVAL);
 	}
 
+	copy_buf = mach64_freelist_get(dev_priv);
+	if (copy_buf == NULL) {
+		DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__);
+		return DRM_ERR(EAGAIN);
+	}
+
+	verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used);
+
+	if (verify_ret != 0) {
+		mach64_freelist_put(dev_priv, copy_buf);
+		goto _blit_done;
+	}
+
+	copy_buf->used = used;
+
 	/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
 	 * continuation buffers?
 	 */
@@ -696,7 +710,7 @@ static int mach64_dma_dispatch_blit(DRMF
 	 * a register command every 16 dwords.  State setup is added at the start of the
 	 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
 	 */
-	DMASETPTR(buf);
+	DMASETPTR(copy_buf);
 
 	DMAOUTREG(MACH64_Z_CNTL, 0);
 	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
@@ -726,12 +740,13 @@ static int mach64_dma_dispatch_blit(DRMF
 	DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
 	DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
 
-	DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used);
+	DRM_DEBUG("%s: %lu bytes\n", __FUNCTION__, used);
 
 	/* Add the buffer to the queue */
 	DMAADVANCEHOSTDATA(dev_priv);
 
-	return 0;
+_blit_done:
+	return verify_ret;
 }
 
 /* ================================================================
@@ -829,7 +844,6 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS)
 int mach64_dma_blit(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
-	drm_device_dma_t *dma = dev->dma;
 	drm_mach64_private_t *dev_priv = dev->dev_private;
 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_mach64_blit_t blit;
@@ -840,15 +854,6 @@ int mach64_dma_blit(DRM_IOCTL_ARGS)
 	DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data,
 				 sizeof(blit));
 
-	DRM_DEBUG("%s: pid=%d index=%d\n",
-		  __FUNCTION__, DRM_CURRENTPID, blit.idx);
-
-	if (blit.idx < 0 || blit.idx >= dma->buf_count) {
-		DRM_ERROR("buffer index %d (of %d max)\n",
-			  blit.idx, dma->buf_count - 1);
-		return DRM_ERR(EINVAL);
-	}
-
 	ret = mach64_dma_dispatch_blit(filp, dev, &blit);
 
 	/* Make sure we restore the 3D state next time.
diff-tree f3deef730d52c94ce21ada7e4ceb63aa28a8601b (from \
                25760c30d4aedb370423d0bb03c014cab47b5d4f)
Author: George Sapountzis <gsap7@yahoo.gr>
Date:   Mon Oct 2 05:46:42 2006 +0300

    Bug 6242: [mach64] Use private DMA buffers, part #3.
    
    Add DRM_PCI_BUFFER_RO flag for mapping PCI DMA buffer read-only. An additional
    flag is needed, since PCI DMA buffers do not have an associated map.

diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index 2ad7080..d58baa7 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -149,7 +149,8 @@ typedef enum {
     DRM_PAGE_ALIGN       = 0x01,
     DRM_AGP_BUFFER       = 0x02,
     DRM_SG_BUFFER        = 0x04,
-    DRM_FB_BUFFER        = 0x08
+    DRM_FB_BUFFER        = 0x08,
+    DRM_PCI_BUFFER_RO    = 0x10
 } drmBufDescFlags;
 
 typedef enum {
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 5c9644e..2bbec70 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -449,7 +449,8 @@ typedef struct drm_device_dma {
 	enum {
 		_DRM_DMA_USE_AGP = 0x01,
 		_DRM_DMA_USE_SG = 0x02,
-		_DRM_DMA_USE_FB = 0x04
+		_DRM_DMA_USE_FB = 0x04,
+		_DRM_DMA_USE_PCI_RO = 0x08
 	} flags;
 
 } drm_device_dma_t;
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
index abd7c82..a2a3dbf 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -942,6 +942,9 @@ int drm_addbufs_pci(drm_device_t * dev, 
 	request->count = entry->buf_count;
 	request->size = size;
 
+	if (request->flags & _DRM_PCI_BUFFER_RO)
+		dma->flags = _DRM_DMA_USE_PCI_RO;
+
 	atomic_dec(&dev->buf_alloc);
 	return 0;
 
@@ -1528,9 +1531,10 @@ int drm_freebufs(struct inode *inode, st
  * \param arg pointer to a drm_buf_map structure.
  * \return zero on success or a negative number on failure.
  *
- * Maps the AGP or SG buffer region with do_mmap(), and copies information
- * about each buffer into user space. The PCI buffers are already mapped on the
- * addbufs_pci() call.
+ * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information
+ * about each buffer into user space. For PCI buffers, it calls do_mmap() with
+ * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
+ * drm_mmap_dma().
  */
 int drm_mapbufs(struct inode *inode, struct file *filp,
 		unsigned int cmd, unsigned long arg)
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index 9672269..adff7d1 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -506,6 +506,22 @@ static int drm_mmap_dma(struct file *fil
 	}
 	unlock_kernel();
 
+	if (!capable(CAP_SYS_ADMIN) &&
+	    (dma->flags & _DRM_DMA_USE_PCI_RO)) {
+		vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+#if defined(__i386__) || defined(__x86_64__)
+		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+		/* Ye gads this is ugly.  With more thought
+		   we could move this up higher and use
+		   `protection_map' instead.  */
+		vma->vm_page_prot =
+		    __pgprot(pte_val
+			     (pte_wrprotect
+			      (__pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+	}
+
 	vma->vm_ops = &drm_vm_dma_ops;
 
 #if LINUX_VERSION_CODE <= 0x02040e	/* KERNEL_VERSION(2,4,14) */
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 7f90a96..8c0c5d2 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -416,7 +416,8 @@ typedef struct drm_buf_desc {
 		_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_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
diff-tree 25760c30d4aedb370423d0bb03c014cab47b5d4f (from \
                eea150e776657faca7d5b76aca75a33dc74fbc9d)
Author: George Sapountzis <gsap7@yahoo.gr>
Date:   Mon Aug 28 05:44:37 2006 +0300

    Bug 6242: [mach64] Use private DMA buffers, part #2.
    
    Factor out from mach64_dma_dispatch_vertex() the code to reclaim an unsed
    buffer, in preperation for using it in mach64_dma_dispatch_blit() also.

diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c
index 3f4394c..7cba8ad 100644
--- a/shared-core/mach64_dma.c
+++ b/shared-core/mach64_dma.c
@@ -1449,6 +1449,33 @@ drm_buf_t *mach64_freelist_get(drm_mach6
 	return entry->buf;
 }
 
+int mach64_freelist_put(drm_mach64_private_t * dev_priv, drm_buf_t * copy_buf)
+{
+	struct list_head *ptr;
+	drm_mach64_freelist_t *entry;
+
+#if MACH64_EXTRA_CHECKING
+	list_for_each(ptr, &dev_priv->pending) {
+		entry = list_entry(ptr, drm_mach64_freelist_t, list);
+		if (copy_buf == entry->buf) {
+			DRM_ERROR("%s: Trying to release a pending buf\n",
+			     __FUNCTION__);
+			return DRM_ERR(EFAULT);
+		}
+	}
+#endif
+	ptr = dev_priv->placeholders.next;
+	entry = list_entry(ptr, drm_mach64_freelist_t, list);
+	copy_buf->pending = 0;
+	copy_buf->used = 0;
+	entry->buf = copy_buf;
+	entry->discard = 1;
+	list_del(ptr);
+	list_add_tail(ptr, &dev_priv->free_list);
+
+	return 0;
+}
+
 /*@}*/
 
 
diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h
index 2a5f2ff..e8dc71e 100644
--- a/shared-core/mach64_drv.h
+++ b/shared-core/mach64_drv.h
@@ -123,6 +123,8 @@ extern void mach64_driver_lastclose(drm_
 extern int mach64_init_freelist(drm_device_t * dev);
 extern void mach64_destroy_freelist(drm_device_t * dev);
 extern drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv);
+extern int mach64_freelist_put(drm_mach64_private_t * dev_priv,
+			       drm_buf_t * copy_buf);
 
 extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv,
 				   int entries);
diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c
index ce44f0d..31e3b56 100644
--- a/shared-core/mach64_state.c
+++ b/shared-core/mach64_state.c
@@ -546,12 +546,15 @@ static __inline__ int copy_and_verify_fr
 }
 
 static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev,
-				      int prim, void *buf, unsigned long used,
-				      int discard)
+				      drm_mach64_vertex_t * vertex)
 {
 	drm_mach64_private_t *dev_priv = dev->dev_private;
 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_buf_t *copy_buf;
+	void *buf = vertex->buf;
+	unsigned long used = vertex->used;
+	int ret = 0;
+	int i = 0;
 	int done = 0;
 	int verify_ret = 0;
 	DMALOCALS;
@@ -559,87 +562,65 @@ static int mach64_dma_dispatch_vertex(DR
 	DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n",
 		  __FUNCTION__, buf, used, sarea_priv->nbox);
 
-	if (used) {
-		int ret = 0;
-		int i = 0;
-
-		copy_buf = mach64_freelist_get(dev_priv);
-		if (copy_buf == NULL) {
-			DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n",
-				  __FUNCTION__);
-			return DRM_ERR(EAGAIN);
-		}
+	if (!used)
+		goto _vertex_done;
 
-		if ((verify_ret =
-		     copy_and_verify_from_user(GETBUFPTR(copy_buf), buf,
-					       used)) == 0) {
-
-			copy_buf->used = used;
-
-			DMASETPTR(copy_buf);
-
-			if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
-				ret = mach64_emit_state(filp, dev_priv);
-				if (ret < 0)
-					return ret;
-			}
+	copy_buf = mach64_freelist_get(dev_priv);
+	if (copy_buf == NULL) {
+		DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__);
+		return DRM_ERR(EAGAIN);
+	}
+
+	verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used);
+
+	if (verify_ret != 0) {
+		mach64_freelist_put(dev_priv, copy_buf);
+		goto _vertex_done;
+	}
 
-			do {
-				/* Emit the next cliprect */
-				if (i < sarea_priv->nbox) {
-					ret =
-					    mach64_emit_cliprect(filp, dev_priv,
-								 &sarea_priv->
-								 boxes[i]);
-					if (ret < 0) {
-						/* failed to get buffer */
-						return ret;
-					} else if (ret != 0) {
-						/* null intersection with scissor */
-						continue;
-					}
-				}
-				if ((i >= sarea_priv->nbox - 1))
-					done = 1;
+	copy_buf->used = used;
 
-				/* Add the buffer to the DMA queue */
-				DMAADVANCE(dev_priv, done);
+	DMASETPTR(copy_buf);
 
-			} while (++i < sarea_priv->nbox);
+	if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
+		ret = mach64_emit_state(filp, dev_priv);
+		if (ret < 0)
+			return ret;
+	}
+
+	do {
+		/* Emit the next cliprect */
+		if (i < sarea_priv->nbox) {
+			ret = mach64_emit_cliprect(filp, dev_priv,
+						   &sarea_priv->boxes[i]);
+			if (ret < 0) {
+				/* failed to get buffer */
+				return ret;
+			} else if (ret != 0) {
+				/* null intersection with scissor */
+				continue;
+			}
 		}
+		if ((i >= sarea_priv->nbox - 1))
+			done = 1;
 
-		if (copy_buf->pending && !done) {
+		/* Add the buffer to the DMA queue */
+		DMAADVANCE(dev_priv, done);
+
+	} while (++i < sarea_priv->nbox);
+
+	if (!done) {
+		if (copy_buf->pending) {
 			DMADISCARDBUF();
-		} else if (!done) {
-			/* This buffer wasn't used (no cliprects or verify failed), so place it back
-			 * on the free list
+		} else {
+			/* This buffer wasn't used (no cliprects), so place it
+			 * back on the free list
 			 */
-			struct list_head *ptr;
-			drm_mach64_freelist_t *entry;
-#if MACH64_EXTRA_CHECKING
-			list_for_each(ptr, &dev_priv->pending) {
-				entry =
-				    list_entry(ptr, drm_mach64_freelist_t,
-					       list);
-				if (copy_buf == entry->buf) {
-					DRM_ERROR
-					    ("%s: Trying to release a pending buf\n",
-					     __FUNCTION__);
-					return DRM_ERR(EFAULT);
-				}
-			}
-#endif
-			ptr = dev_priv->placeholders.next;
-			entry = list_entry(ptr, drm_mach64_freelist_t, list);
-			copy_buf->pending = 0;
-			copy_buf->used = 0;
-			entry->buf = copy_buf;
-			entry->discard = 1;
-			list_del(ptr);
-			list_add_tail(ptr, &dev_priv->free_list);
+			mach64_freelist_put(dev_priv, copy_buf);
 		}
 	}
 
+_vertex_done:
 	sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
 	sarea_priv->nbox = 0;
 
@@ -842,8 +823,7 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS)
 	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
 		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
 
-	return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf,
-					  vertex.used, vertex.discard);
+	return mach64_dma_dispatch_vertex(filp, dev, &vertex);
 }
 
 int mach64_dma_blit(DRM_IOCTL_ARGS)
diff-tree eea150e776657faca7d5b76aca75a33dc74fbc9d (from \
                d1b31a228b72b8dd8e588f0a0cc8eeabc3845f70)
Author: George Sapountzis <gsap7@yahoo.gr>
Date:   Sun Jul 16 02:15:02 2006 +0300

    Bug 6242: [mach64] Use private DMA buffers, part #1.
    
    Factor out from mach64_freelist_get() the code to reclaim a completed buffer,
    this is to improve readability for me.

diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c
index 36fddf0..3f4394c 100644
--- a/shared-core/mach64_dma.c
+++ b/shared-core/mach64_dma.c
@@ -1329,17 +1329,88 @@ int mach64_do_release_used_buffers(drm_m
 	return 0;
 }
 
+static int mach64_do_reclaim_completed(drm_mach64_private_t * dev_priv)
+{
+	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
+	struct list_head *ptr;
+	struct list_head *tmp;
+	drm_mach64_freelist_t *entry;
+	u32 head, tail, ofs;
+
+	mach64_ring_tick(dev_priv, ring);
+	head = ring->head;
+	tail = ring->tail;
+
+	if (head == tail) {
+#if MACH64_EXTRA_CHECKING
+		if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) {
+			DRM_ERROR("Empty ring with non-idle engine!\n");
+			mach64_dump_ring_info(dev_priv);
+			return -1;
+		}
+#endif
+		/* last pass is complete, so release everything */
+		mach64_do_release_used_buffers(dev_priv);
+		DRM_DEBUG("%s: idle engine, freed all buffers.\n",
+		     __FUNCTION__);
+		if (list_empty(&dev_priv->free_list)) {
+			DRM_ERROR("Freelist empty with idle engine\n");
+			return -1;
+		}
+		return 0;
+	}
+	/* Look for a completed buffer and bail out of the loop
+	 * as soon as we find one -- don't waste time trying
+	 * to free extra bufs here, leave that to do_release_used_buffers
+	 */
+	list_for_each_safe(ptr, tmp, &dev_priv->pending) {
+		entry = list_entry(ptr, drm_mach64_freelist_t, list);
+		ofs = entry->ring_ofs;
+		if (entry->discard &&
+		    ((head < tail && (ofs < head || ofs >= tail)) ||
+		     (head > tail && (ofs < head && ofs >= tail)))) {
+#if MACH64_EXTRA_CHECKING
+			int i;
+
+			for (i = head; i != tail; i = (i + 4) & ring->tail_mask)
+			{
+				u32 o1 = le32_to_cpu(((u32 *) ring->
+						 start)[i + 1]);
+				u32 o2 = GETBUFADDR(entry->buf);
+
+				if (o1 == o2) {
+					DRM_ERROR
+					    ("Attempting to free used buffer: "
+					     "i=%d  buf=0x%08x\n",
+					     i, o1);
+					mach64_dump_ring_info(dev_priv);
+					return -1;
+				}
+			}
+#endif
+			/* found a processed buffer */
+			entry->buf->pending = 0;
+			list_del(ptr);
+			list_add_tail(ptr, &dev_priv->free_list);
+			DRM_DEBUG
+			    ("%s: freed processed buffer (head=%d tail=%d "
+			     "buf ring ofs=%d).\n",
+			     __FUNCTION__, head, tail, ofs);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
 drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv)
 {
 	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
 	drm_mach64_freelist_t *entry;
 	struct list_head *ptr;
-	struct list_head *tmp;
 	int t;
 
 	if (list_empty(&dev_priv->free_list)) {
-		u32 head, tail, ofs;
-
 		if (list_empty(&dev_priv->pending)) {
 			DRM_ERROR
 			    ("Couldn't get buffer - pending and free lists empty\n");
@@ -1351,81 +1422,15 @@ drm_buf_t *mach64_freelist_get(drm_mach6
 			return NULL;
 		}
 
-		tail = ring->tail;
 		for (t = 0; t < dev_priv->usec_timeout; t++) {
-			mach64_ring_tick(dev_priv, ring);
-			head = ring->head;
+			int ret;
 
-			if (head == tail) {
-#if MACH64_EXTRA_CHECKING
-				if (MACH64_READ(MACH64_GUI_STAT) &
-				    MACH64_GUI_ACTIVE) {
-					DRM_ERROR
-					    ("Empty ring with non-idle engine!\n");
-					mach64_dump_ring_info(dev_priv);
-					return NULL;
-				}
-#endif
-				/* last pass is complete, so release everything */
-				mach64_do_release_used_buffers(dev_priv);
-				DRM_DEBUG
-				    ("%s: idle engine, freed all buffers.\n",
-				     __FUNCTION__);
-				if (list_empty(&dev_priv->free_list)) {
-					DRM_ERROR
-					    ("Freelist empty with idle engine\n");
-					return NULL;
-				}
+			ret = mach64_do_reclaim_completed(dev_priv);
+			if (ret == 0)
 				goto _freelist_entry_found;
-			}
-			/* Look for a completed buffer and bail out of the loop
-			 * as soon as we find one -- don't waste time trying
-			 * to free extra bufs here, leave that to do_release_used_buffers
-			 */
-			list_for_each_safe(ptr, tmp, &dev_priv->pending) {
-				entry =
-				    list_entry(ptr, drm_mach64_freelist_t,
-					       list);
-				ofs = entry->ring_ofs;
-				if (entry->discard &&
-				    ((head < tail
-				      && (ofs < head || ofs >= tail))
-				     || (head > tail
-					 && (ofs < head && ofs >= tail)))) {
-#if MACH64_EXTRA_CHECKING
-					int i;
+			if (ret < 0)
+				return NULL;
 
-					for (i = head; i != tail;
-					     i = (i + 4) & ring->tail_mask) {
-						u32 o1 =
-						    le32_to_cpu(((u32 *) ring->
-								 start)[i + 1]);
-						u32 o2 = GETBUFADDR(entry->buf);
-
-						if (o1 == o2) {
-							DRM_ERROR
-							    ("Attempting to free used buffer: "
-							     "i=%d  buf=0x%08x\n",
-							     i, o1);
-							mach64_dump_ring_info
-							    (dev_priv);
-							return NULL;
-						}
-					}
-#endif
-					/* found a processed buffer */
-					entry->buf->pending = 0;
-					list_del(ptr);
-					entry->buf->used = 0;
-					list_add_tail(ptr,
-						      &dev_priv->placeholders);
-					DRM_DEBUG
-					    ("%s: freed processed buffer (head=%d tail=%d "
-					     "buf ring ofs=%d).\n",
-					     __FUNCTION__, head, tail, ofs);
-					return entry->buf;
-				}
-			}
 			DRM_UDELAY(1);
 		}
 		mach64_dump_ring_info(dev_priv);
diff-tree d1b31a228b72b8dd8e588f0a0cc8eeabc3845f70 (from \
                f6238cf6244b32bd84e3d2819963d7f5473867c8)
Author: George Sapountzis <gsap7@yahoo.gr>
Date:   Sun Jul 16 01:02:06 2006 +0300

    Bug 6209: [mach64] AGP DMA buffers not mapped correctly.
    
    Map the DMA buffers from the same linear address as the vertex bufs. If
    dev->agp_buffer_token is not set, mach64 drm maps the DMA buffers from
    linear address 0x0.

diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c
index 4c8edea..36fddf0 100644
--- a/shared-core/mach64_dma.c
+++ b/shared-core/mach64_dma.c
@@ -834,6 +834,7 @@ static int mach64_do_dma_init(drm_device
 			mach64_do_cleanup_dma(dev);
 			return DRM_ERR(ENOMEM);
 		}
+		dev->agp_buffer_token = init->buffers_offset;
 		dev->agp_buffer_map =
 		    drm_core_findmap(dev, init->buffers_offset);
 		if (!dev->agp_buffer_map) {
diff-tree f6238cf6244b32bd84e3d2819963d7f5473867c8 (from \
                3a16e615cabfed18b1891a732e7243ef41dc0ad0)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Mon Oct 2 15:33:19 2006 +0200

    Fix type of second argument to spin_lock_irqsave().

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 41038fd..4d8e4a2 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -416,7 +416,7 @@ EXPORT_SYMBOL(drm_vbl_send_signals);
 static void drm_locked_tasklet_func(unsigned long data)
 {
 	drm_device_t *dev = (drm_device_t*)data;
-	unsigned int irqflags;
+	unsigned long irqflags;
 
 	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
 
@@ -454,7 +454,7 @@ static void drm_locked_tasklet_func(unsi
  */
 void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
 {
-	unsigned int irqflags;
+	unsigned long irqflags;
 	static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
 
 	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) ||
diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c
index fa677ba..d1b85a1 100644
--- a/linux-core/drm_lock.c
+++ b/linux-core/drm_lock.c
@@ -152,7 +152,7 @@ int drm_unlock(struct inode *inode, stru
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
 	drm_lock_t lock;
-	unsigned int irqflags;
+	unsigned long irqflags;
 
 	if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
 		return -EFAULT;
diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index d203b24..0817e32 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -43,7 +43,7 @@
 int drm_adddraw(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
-	unsigned int irqflags;
+	unsigned long irqflags;
 	int i, j;
 	u32 *bitfield = dev->drw_bitfield;
 	unsigned int bitfield_length = dev->drw_bitfield_length;
@@ -134,7 +134,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 	drm_draw_t draw;
 	int id, idx;
 	unsigned int shift;
-	unsigned int irqflags;
+	unsigned long irqflags;
 	u32 *bitfield = dev->drw_bitfield;
 	unsigned int bitfield_length = dev->drw_bitfield_length;
 	drm_drawable_info_t **info = dev->drw_info;
@@ -220,9 +220,9 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 int drm_update_drawable_info(DRM_IOCTL_ARGS) {
 	DRM_DEVICE;
 	drm_update_draw_t update;
-	unsigned int id, idx, shift;
+	unsigned int id, idx, shift, bitfield_length = dev->drw_bitfield_length;
 	u32 *bitfield = dev->drw_bitfield;
-	unsigned int irqflags, bitfield_length = dev->drw_bitfield_length;
+	unsigned long irqflags;
 	drm_drawable_info_t *info;
 	drm_clip_rect_t *rects;
 	int err;
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 76c3a81..feb7acc 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -45,7 +45,7 @@
 static void i915_vblank_tasklet(drm_device_t *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned int irqflags;
+	unsigned long irqflags;
 	struct list_head *list, *tmp;
 
 	DRM_DEBUG("\n");
@@ -388,7 +388,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	drm_i915_vblank_swap_t swap;
 	drm_i915_vbl_swap_t *vbl_swap;
-	unsigned int pipe, seqtype, irqflags, curseq;
+	unsigned int pipe, seqtype, curseq;
+	unsigned long irqflags;
 	struct list_head *list;
 
 	if (!dev_priv) {
diff-tree 3a16e615cabfed18b1891a732e7243ef41dc0ad0 (from \
                d58389968124191a546a14b42ef84edc224be23d)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Mon Oct 2 11:04:42 2006 +0200

    Make locked tasklet handling more robust.
    
    Initialize the spinlock unconditionally when struct drm_device is filled in,
    and return early in drm_locked_tasklet() if the driver doesn't support IRQs.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index d1a6a6b..41038fd 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -118,7 +118,6 @@ static int drm_irq_install(drm_device_t 
 		init_waitqueue_head(&dev->vbl_queue);
 
 		spin_lock_init(&dev->vbl_lock);
-		spin_lock_init(&dev->tasklet_lock);
 
 		INIT_LIST_HEAD(&dev->vbl_sigs.head);
 		INIT_LIST_HEAD(&dev->vbl_sigs2.head);
@@ -458,7 +457,8 @@ void drm_locked_tasklet(drm_device_t *de
 	unsigned int irqflags;
 	static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
 
-	if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
+	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) ||
+	    test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
 		return;
 
 	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index ad78dcf..839cf44 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t 
 
 	spin_lock_init(&dev->count_lock);
 	spin_lock_init(&dev->drw_lock);
+	spin_lock_init(&dev->tasklet_lock);
 	init_timer(&dev->timer);
 	mutex_init(&dev->struct_mutex);
 	mutex_init(&dev->ctxlist_mutex);
diff-tree d58389968124191a546a14b42ef84edc224be23d (from \
                7af93dd9849442270ec89cb4bbeef5bfd4f9e424)
Author: Felix Kühling <fxkuehl@gmx.de>
Date:   Mon Oct 2 10:50:40 2006 +0200

    drm_rmdraw: Declare id and idx as signed so testing for < 0 works as intended.

diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index 5e2fc86..d203b24 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -132,7 +132,8 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_draw_t draw;
-	unsigned int id, idx, shift;
+	int id, idx;
+	unsigned int shift;
 	unsigned int irqflags;
 	u32 *bitfield = dev->drw_bitfield;
 	unsigned int bitfield_length = dev->drw_bitfield_length;
diff-tree 7af93dd9849442270ec89cb4bbeef5bfd4f9e424 (from \
                881ba569929ceafd42e3c86228b0172099083d1d)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 29 10:27:29 2006 +0200

    i915: Only schedule vblank tasklet if there are scheduled swaps pending.
    
    This fixes issues on X server startup with versions of xf86-video-intel that
    enable the IRQ before they have a context ID.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index fbc6674..76c3a81 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -171,7 +171,8 @@ irqreturn_t i915_driver_irq_handler(DRM_
 		DRM_WAKEUP(&dev->vbl_queue);
 		drm_vbl_send_signals(dev);
 
-		drm_locked_tasklet(dev, i915_vblank_tasklet);
+		if (dev_priv->swaps_pending > 0)
+			drm_locked_tasklet(dev, i915_vblank_tasklet);
 	}
 
 	return IRQ_HANDLED;
diff-tree 881ba569929ceafd42e3c86228b0172099083d1d (from \
                2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Sep 27 18:22:10 2006 +0200

    i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A.
    
    It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has
    VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled.
    So we only increase dev->vbl_received if the corresponding bit is also set in
    dev->vblank_pipe.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 9db3870..fbc6674 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -153,14 +153,19 @@ irqreturn_t i915_driver_irq_handler(DRM_
 		DRM_WAKEUP(&dev_priv->irq_queue);
 
 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-		if ((dev_priv->vblank_pipe &
+		int vblank_pipe = dev_priv->vblank_pipe;
+
+		if ((vblank_pipe &
 		     (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
 		    == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
 			if (temp & VSYNC_PIPEA_FLAG)
 				atomic_inc(&dev->vbl_received);
 			if (temp & VSYNC_PIPEB_FLAG)
 				atomic_inc(&dev->vbl_received2);
-		} else
+		} else if (((temp & VSYNC_PIPEA_FLAG) &&
+			    (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
+			   ((temp & VSYNC_PIPEB_FLAG) &&
+			    (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
 			atomic_inc(&dev->vbl_received);
 
 		DRM_WAKEUP(&dev->vbl_queue);
diff-tree 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b (from \
                0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Mon Sep 18 12:15:38 2006 +0200

    i915: Bump minor for swap scheduling ioctl and secondary vblank support.

diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index dc9bbc5..de7f822 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -46,9 +46,11 @@
  * 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		5
+#define DRIVER_MINOR		6
 #define DRIVER_PATCHLEVEL	0
 
 typedef struct _drm_i915_ring_buffer {
diff-tree 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 (from \
                50a0284a61d4415c0ebdb02decee76ef3115007a)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Sep 13 08:59:35 2006 +0200

    i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index d32f592..9db3870 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -399,7 +399,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 				 sizeof(swap));
 
 	if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
-			     _DRM_VBLANK_SECONDARY)) {
+			     _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
 		DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
 		return DRM_ERR(EINVAL);
 	}
@@ -408,11 +408,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
 
-	if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) {
-		DRM_DEBUG("Not scheduling swap for current sequence\n");
-		return DRM_ERR(EINVAL);
-	}
-
 	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
 		DRM_ERROR("Invalid pipe %d\n", pipe);
 		return DRM_ERR(EINVAL);
@@ -430,21 +425,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
 
-	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
-
-	switch (seqtype) {
-	case _DRM_VBLANK_RELATIVE:
+	if (seqtype == _DRM_VBLANK_RELATIVE)
 		swap.sequence += curseq;
-		break;
-	case _DRM_VBLANK_ABSOLUTE:
-		if ((curseq - swap.sequence) <= (1<<23)) {
-			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+	if ((curseq - swap.sequence) <= (1<<23)) {
+		if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
+			swap.sequence = curseq + 1;
+		} else {
 			DRM_DEBUG("Missed target sequence\n");
 			return DRM_ERR(EINVAL);
 		}
-		break;
 	}
 
+	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
 	list_for_each(list, &dev_priv->vbl_swaps.head) {
 		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
 
diff-tree 50a0284a61d4415c0ebdb02decee76ef3115007a (from \
                cf6b2c5299e9be3542d4deddfd05d5811f11d2ef)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 1 11:48:07 2006 +0200

    Only return EBUSY after we've established we need to schedule a new swap.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 9cd8ece..d32f592 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -395,11 +395,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 		return DRM_ERR(EINVAL);
 	}
 
-	if (dev_priv->swaps_pending >= 100) {
-		DRM_DEBUG("Too many swaps queued\n");
-		return DRM_ERR(EBUSY);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
 				 sizeof(swap));
 
@@ -464,6 +459,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 
+	if (dev_priv->swaps_pending >= 100) {
+		DRM_DEBUG("Too many swaps queued\n");
+		return DRM_ERR(EBUSY);
+	}
+
 	vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
 
 	if (!vbl_swap) {
diff-tree cf6b2c5299e9be3542d4deddfd05d5811f11d2ef (from \
                89e323e4900af84cc33219ad24eb0b435a039d23)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 1 11:35:31 2006 +0200

    Core vsync: Don't clobber target sequence number when scheduling signal.
    
    It looks like this would have caused signals to always get sent on the next
    vertical blank, regardless of the sequence number.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index bd8a9c8..d1a6a6b 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -295,8 +295,6 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 				      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
 		drm_vbl_sig_t *vbl_sig;
 
-		vblwait.reply.sequence = seq;
-
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
 		/* Check if this task has already scheduled the same signal
@@ -309,6 +307,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 			    && vbl_sig->task == current) {
 				spin_unlock_irqrestore(&dev->vbl_lock,
 						       irqflags);
+				vblwait.reply.sequence = seq;
 				goto done;
 			}
 		}
@@ -339,6 +338,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
 
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+		vblwait.reply.sequence = seq;
 	} else {
 		if (flags & _DRM_VBLANK_SECONDARY) {
 			if (dev->driver->vblank_wait2)
diff-tree 89e323e4900af84cc33219ad24eb0b435a039d23 (from \
                7f09f957d9a61ac107f8fd29128d7899a3e8a228)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 1 11:27:14 2006 +0200

    Core vsync: Add flag DRM_VBLANK_NEXTONMISS.
    
    When this flag is set and the target sequence is missed, wait for the next
    vertical blank instead of returning immediately.

diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index cda570d..2ad7080 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -252,6 +252,7 @@ typedef struct _drmTextureRegion {
 typedef enum {
     DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
     DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+    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 */
 } drmVBlankSeqType;
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index fef0e8d..bd8a9c8 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	drm_wait_vblank_t vblwait;
 	struct timeval now;
 	int ret = 0;
-	unsigned int flags;
-	atomic_t *seq;
+	unsigned int flags, seq;
 
 	if ((!dev->irq) || (!dev->irq_enabled))
 		return -EINVAL;
@@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
 		return -EINVAL;
 
-	seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 :
-	      &dev->vbl_received;
+	seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
+			  : &dev->vbl_received);
 
 	switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
 	case _DRM_VBLANK_RELATIVE:
-		vblwait.request.sequence += atomic_read(seq);
+		vblwait.request.sequence += seq;
 		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
 	case _DRM_VBLANK_ABSOLUTE:
 		break;
@@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		return -EINVAL;
 	}
 
+	if ((flags & _DRM_VBLANK_NEXTONMISS) &&
+	    (seq - vblwait.request.sequence) <= (1<<23)) {
+		vblwait.request.sequence = seq + 1;
+	}
+
 	if (flags & _DRM_VBLANK_SIGNAL) {
 		unsigned long irqflags;
 		drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
 				      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
 		drm_vbl_sig_t *vbl_sig;
 
-		vblwait.reply.sequence = atomic_read(seq);
+		vblwait.reply.sequence = seq;
 
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 614422b..7f90a96 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -551,12 +551,14 @@ typedef struct drm_irq_busid {
 typedef enum {
 	_DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
 	_DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+	_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 */
 } drm_vblank_seq_type_t;
 
 #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
-#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
+				_DRM_VBLANK_NEXTONMISS)
 
 struct drm_wait_vblank_request {
 	drm_vblank_seq_type_t type;
diff-tree 7f09f957d9a61ac107f8fd29128d7899a3e8a228 (from \
                c2bdb76814755c9ac6e66a8815f23af0fe4f3a91)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 1 11:24:38 2006 +0200

    Fix 'sequence has passed' condition in i915_vblank_swap().

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 68e7c66..9cd8ece 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -442,7 +442,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 		swap.sequence += curseq;
 		break;
 	case _DRM_VBLANK_ABSOLUTE:
-		if ((curseq - swap.sequence) > (1<<23)) {
+		if ((curseq - swap.sequence) <= (1<<23)) {
 			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 			DRM_DEBUG("Missed target sequence\n");
 			return DRM_ERR(EINVAL);
diff-tree c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 (from \
                84b38b63f05e04ade8b1ddfb770047fd86de0d64)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Thu Aug 31 18:33:04 2006 +0200

    Add SAREA fileds for determining which pipe to sync window buffer swaps to.

diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index 3a39d53..358b11e 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea {
 	unsigned int depth_tiled;
 	unsigned int rotated_tiled;
 	unsigned int rotated2_tiled;
+
+	int pipeA_x;
+	int pipeA_y;
+	int pipeA_w;
+	int pipeA_h;
+	int pipeB_x;
+	int pipeB_y;
+	int pipeB_w;
+	int pipeB_h;
 } drm_i915_sarea_t;
 
 /* Flags for perf_boxes
diff-tree 84b38b63f05e04ade8b1ddfb770047fd86de0d64 (from \
                87c57cba1a70221fc570b253bf3b24682ef6b894)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Thu Aug 31 18:32:08 2006 +0200

    Add definition of DRM_VBLANK_SECONDARY.

diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index 9e71eb6..cda570d 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -252,6 +252,7 @@ typedef struct _drmTextureRegion {
 typedef enum {
     DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
     DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+    DRM_VBLANK_SECONDARY = 0x20000000,	/**< Secondary display controller */
     DRM_VBLANK_SIGNAL   = 0x40000000	/* Send signal instead of blocking */
 } drmVBlankSeqType;
 
diff-tree 87c57cba1a70221fc570b253bf3b24682ef6b894 (from \
                d5a0f107511e128658e2d5e15bd7e6215c507f29)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Thu Aug 31 18:30:55 2006 +0200

    Make handling of dev_priv->vblank_pipe more robust.
    
    Initialize it to default value if it hasn't been set by the X server yet.
    
    In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call
    i915_enable_interrupt() if the argument passed from userspace is valid to avoid
    corrupting dev_priv->vblank_pipe on invalid arguments.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 6f00feb..68e7c66 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -307,7 +307,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
 	return i915_wait_irq(dev, irqwait.irq_seq);
 }
 
-static int i915_enable_interrupt (drm_device_t *dev)
+static void i915_enable_interrupt (drm_device_t *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u16 flag;
@@ -317,13 +317,8 @@ static int i915_enable_interrupt (drm_de
 		flag |= VSYNC_PIPEA_FLAG;
 	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
 		flag |= VSYNC_PIPEB_FLAG;
-	if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
-		DRM_ERROR("%s called with invalid pipe 0x%x\n", 
-			  __FUNCTION__, dev_priv->vblank_pipe);
-		return DRM_ERR(EINVAL);
-	}
+
 	I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
-	return 0;
 }
 
 /* Set the vblank monitor pipe
@@ -342,8 +337,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
 	DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
 				 sizeof(pipe));
 
+	if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+		DRM_ERROR("%s called with invalid pipe 0x%x\n", 
+			  __FUNCTION__, pipe.pipe);
+		return DRM_ERR(EINVAL);
+	}
+
 	dev_priv->vblank_pipe = pipe.pipe;
-	return i915_enable_interrupt (dev);
+
+	i915_enable_interrupt (dev);
+
+	return 0;
 }
 
 int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
@@ -505,6 +509,8 @@ void i915_driver_irq_postinstall(drm_dev
 	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
 	dev_priv->swaps_pending = 0;
 
+	if (!dev_priv->vblank_pipe)
+		dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
 	i915_enable_interrupt(dev);
 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 }
diff-tree d5a0f107511e128658e2d5e15bd7e6215c507f29 (from \
                df7551ef7334d728ec0371423661bb403d3e270a)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 30 19:33:28 2006 +0200

    DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number.
    
    Handle relative as well as absolute target sequence numbers.
    
    Return error if target sequence has already passed, so userspace can deal with
    this situation as it sees fit.
    
    On success, return the sequence number of the vertical blank when the buffer
    swap is expected to take place.
    
    Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want
    to use ioctl() instead of drmCommandWriteRead().

diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index 7e4ba13..3a39d53 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -149,6 +149,7 @@ typedef struct _drm_i915_sarea {
 #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)  
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
@@ -249,7 +250,7 @@ typedef struct drm_i915_vblank_pipe {
  */
 typedef struct drm_i915_vblank_swap {
 	drm_drawable_t drawable;
-	unsigned int pipe;
+	drm_vblank_seq_type_t seqtype;
 	unsigned int sequence;
 } drm_i915_vblank_swap_t;
 
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 39d8c38..6f00feb 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -378,7 +378,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	drm_i915_vblank_swap_t swap;
 	drm_i915_vbl_swap_t *vbl_swap;
-	unsigned int irqflags;
+	unsigned int pipe, seqtype, irqflags, curseq;
 	struct list_head *list;
 
 	if (!dev_priv) {
@@ -399,8 +399,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
 				 sizeof(swap));
 
-	if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) {
-		DRM_ERROR("Invalid pipe %d\n", swap.pipe);
+	if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+			     _DRM_VBLANK_SECONDARY)) {
+		DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
+		return DRM_ERR(EINVAL);
+	}
+
+	pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+
+	seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+
+	if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) {
+		DRM_DEBUG("Not scheduling swap for current sequence\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
+		DRM_ERROR("Invalid pipe %d\n", pipe);
 		return DRM_ERR(EINVAL);
 	}
 
@@ -414,13 +429,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
+	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+
 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
 
+	switch (seqtype) {
+	case _DRM_VBLANK_RELATIVE:
+		swap.sequence += curseq;
+		break;
+	case _DRM_VBLANK_ABSOLUTE:
+		if ((curseq - swap.sequence) > (1<<23)) {
+			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+			DRM_DEBUG("Missed target sequence\n");
+			return DRM_ERR(EINVAL);
+		}
+		break;
+	}
+
 	list_for_each(list, &dev_priv->vbl_swaps.head) {
 		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
 
 		if (vbl_swap->drw_id == swap.drawable &&
-		    vbl_swap->pipe == swap.pipe &&
+		    vbl_swap->pipe == pipe &&
 		    vbl_swap->sequence == swap.sequence) {
 			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 			DRM_DEBUG("Already scheduled\n");
@@ -440,7 +470,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	DRM_DEBUG("\n");
 
 	vbl_swap->drw_id = swap.drawable;
-	vbl_swap->pipe = swap.pipe;
+	vbl_swap->pipe = pipe;
 	vbl_swap->sequence = swap.sequence;
 
 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -450,6 +480,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 
+	DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
+			       sizeof(swap));
+
 	return 0;
 }
 
diff-tree df7551ef7334d728ec0371423661bb403d3e270a (from \
                d04751facea36cb888c7510b126658fdbc4277d5)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 30 19:24:04 2006 +0200

    Change first valid DRM drawable ID to be 1 instead of 0.
    
    This makes it easier for userspace to know when it needs to allocate an ID.
    
    Also free drawable information memory when it's no longer needed.

diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 2c878b6..228c8b8 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -156,6 +156,18 @@ int drm_lastclose(drm_device_t * dev)
 	if (dev->irq_enabled)
 		drm_irq_uninstall(dev);
 
+	/* Free drawable information memory */
+	for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
+	     i++) {
+		drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
+
+		if (info) {
+			drm_free(info->rects, info->num_rects *
+				 sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+			drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+		}
+	}
+
 	mutex_lock(&dev->struct_mutex);
 	del_timer(&dev->timer);
 
diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index bbfaf13..5e2fc86 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -92,13 +92,13 @@ done:
 		bitfield[i] = 0;
 	}
 
-	draw.handle = i * 8 * sizeof(*bitfield) + j;
+	draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
 	DRM_DEBUG("%d\n", draw.handle);
 
 	spin_lock_irqsave(&dev->drw_lock, irqflags);
 
 	bitfield[i] |= 1 << j;
-	info[draw.handle] = NULL;
+	info[draw.handle - 1] = NULL;
 
 	if (bitfield != dev->drw_bitfield) {
 		memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
@@ -132,7 +132,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_draw_t draw;
-	unsigned int idx, shift;
+	unsigned int id, idx, shift;
 	unsigned int irqflags;
 	u32 *bitfield = dev->drw_bitfield;
 	unsigned int bitfield_length = dev->drw_bitfield_length;
@@ -142,10 +142,11 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 	DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
 				 sizeof(draw));
 
-	idx = draw.handle / (8 * sizeof(*bitfield));
-	shift = draw.handle % (8 * sizeof(*bitfield));
+	id = draw.handle - 1;
+	idx = id / (8 * sizeof(*bitfield));
+	shift = id % (8 * sizeof(*bitfield));
 
-	if (idx >= bitfield_length ||
+	if (idx < 0 || idx >= bitfield_length ||
 	    !(bitfield[idx] & (1 << shift))) {
 		DRM_DEBUG("No such drawable %d\n", draw.handle);
 		return 0;
@@ -157,6 +158,12 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
+	if (info[id]) {
+		drm_free(info[id]->rects, info[id]->num_rects *
+			 sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+		drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
+	}
+
 	/* Can we shrink the arrays? */
 	if (idx == bitfield_length - 1) {
 		while (idx >= 0 && !bitfield[idx])
@@ -164,7 +171,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 
 		bitfield_length = idx + 1;
 
-		if (idx != draw.handle / (8 * sizeof(*bitfield)))
+		if (idx != id / (8 * sizeof(*bitfield)))
 			bitfield = drm_alloc(bitfield_length *
 					     sizeof(*bitfield), DRM_MEM_BUFS);
 
@@ -222,11 +229,12 @@ int drm_update_drawable_info(DRM_IOCTL_A
 	DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
 				 sizeof(update));
 
-	id = update.handle;
+	id = update.handle - 1;
 	idx = id / (8 * sizeof(*bitfield));
 	shift = id % (8 * sizeof(*bitfield));
 
-	if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) {
+	if (idx < 0 || idx >= bitfield_length ||
+	    !(bitfield[idx] & (1 << shift))) {
 		DRM_ERROR("No such drawable %d\n", update.handle);
 		return DRM_ERR(EINVAL);
 	}
@@ -304,10 +312,13 @@ error:
  */
 drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
 	u32 *bitfield = dev->drw_bitfield;
-	unsigned int idx = id / (8 * sizeof(*bitfield));
-	unsigned int shift = id % (8 * sizeof(*bitfield));
+	unsigned int idx, shift;
+
+	id--;
+	idx = id / (8 * sizeof(*bitfield));
+	shift = id % (8 * sizeof(*bitfield));
 
-	if (idx >= dev->drw_bitfield_length ||
+	if (idx < 0 || idx >= dev->drw_bitfield_length ||
 	    !(bitfield[idx] & (1 << shift))) {
 		DRM_DEBUG("No such drawable %d\n", id);
 		return NULL;
diff-tree d04751facea36cb888c7510b126658fdbc4277d5 (from \
                257771fa290b62d4d2ad896843cf3a207978d0bb)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Mon Aug 28 18:19:58 2006 +0200

    Add copyright notice.

diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index 81eb9f0..bbfaf13 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -12,6 +12,7 @@
  *
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
diff-tree 257771fa290b62d4d2ad896843cf3a207978d0bb (from \
                23d2833aaa37a33b9ddcf06cc796f59befc0d360)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Aug 25 19:01:05 2006 +0200

    i915: Add ioctl for scheduling buffer swaps at vertical blanks.
    
    This uses the core facility to schedule a driver callback that will be called
    ASAP after the given vertical blank interrupt with the HW lock held.

diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 3863490..be235c1 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -163,6 +163,7 @@ static int i915_initialize(drm_device_t 
 
 	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
 
+	dev_priv->cpp = init->cpp;
 	dev_priv->back_offset = init->back_offset;
 	dev_priv->front_offset = init->front_offset;
 	dev_priv->current_page = 0;
@@ -797,6 +798,7 @@ drm_ioctl_desc_t i915_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },  [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { \
i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },  \
[DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, \
+	[DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},  };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index fcffb25..7e4ba13 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -132,6 +132,7 @@ typedef struct _drm_i915_sarea {
 #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_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) @@ -244,4 +245,12 @@ 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;
+	unsigned int pipe;
+	unsigned int sequence;
+} drm_i915_vblank_swap_t;
+
 #endif				/* _I915_DRM_H_ */
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 69cf811..dc9bbc5 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -71,6 +71,13 @@ struct mem_block {
 	DRMFILE filp;		/* 0: free, -1: heap, other: real files */
 };
 
+typedef struct _drm_i915_vbl_swap {
+	struct list_head head;
+	drm_drawable_t drw_id;
+	unsigned int pipe;
+	unsigned int sequence;
+} drm_i915_vbl_swap_t;
+
 typedef struct drm_i915_private {
 	drm_local_map_t *sarea;
 	drm_local_map_t *mmio_map;
@@ -83,6 +90,7 @@ typedef struct drm_i915_private {
 	dma_addr_t dma_status_page;
 	unsigned long counter;
 
+	unsigned int cpp;
 	int back_offset;
 	int front_offset;
 	int current_page;
@@ -98,6 +106,10 @@ typedef struct drm_i915_private {
 	struct mem_block *agp_heap;
 	unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
 	int vblank_pipe;
+
+	spinlock_t swaps_lock;
+	drm_i915_vbl_swap_t vbl_swaps;
+	unsigned int swaps_pending;
 } drm_i915_private_t;
 
 extern drm_ioctl_desc_t i915_ioctls[];
@@ -124,6 +136,7 @@ extern void i915_driver_irq_postinstall(
 extern void i915_driver_irq_uninstall(drm_device_t * dev);
 extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
 extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
+extern int i915_vblank_swap(DRM_IOCTL_ARGS);
 
 /* i915_mem.c */
 extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -257,6 +270,10 @@ extern int i915_wait_ring(drm_device_t *
 
 #define GFX_OP_DRAWRECT_INFO_I965  ((0x7900<<16)|0x2)
 
+#define XY_SRC_COPY_BLT_CMD		((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA	(1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB	(1<<20)
+
 #define MI_BATCH_BUFFER 	((0x30<<23)|1)
 #define MI_BATCH_BUFFER_START 	(0x31<<23)
 #define MI_BATCH_BUFFER_END 	(0xA<<23)
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 2eac29f..39d8c38 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -37,6 +37,99 @@
 
 #define MAX_NOPID ((u32)~0)
 
+/**
+ * Emit blits for scheduled buffer swaps.
+ *
+ * This function will be called with the HW lock held.
+ */
+static void i915_vblank_tasklet(drm_device_t *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned int irqflags;
+	struct list_head *list, *tmp;
+
+	DRM_DEBUG("\n");
+
+	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+	list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
+		drm_i915_vbl_swap_t *vbl_swap =
+			list_entry(list, drm_i915_vbl_swap_t, head);
+		atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 :
+			&dev->vbl_received;
+
+		if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) {
+			drm_drawable_info_t *drw;
+
+			spin_unlock(&dev_priv->swaps_lock);
+
+			spin_lock(&dev->drw_lock);
+
+			drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
+				
+			if (drw) {
+				int i, num_rects = drw->num_rects;
+				drm_clip_rect_t *rect = drw->rects;
+				drm_i915_sarea_t *sarea_priv =
+				    dev_priv->sarea_priv;
+				u32 cpp = dev_priv->cpp;
+				u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
+							XY_SRC_COPY_BLT_WRITE_ALPHA |
+							XY_SRC_COPY_BLT_WRITE_RGB)
+						     : XY_SRC_COPY_BLT_CMD;
+				u32 pitchropcpp = (sarea_priv->pitch * cpp) |
+						  (0xcc << 16) | (cpp << 23) |
+						  (1 << 24);
+				RING_LOCALS;
+
+				i915_kernel_lost_context(dev);
+
+				BEGIN_LP_RING(6);
+
+				OUT_RING(GFX_OP_DRAWRECT_INFO);
+				OUT_RING(0);
+				OUT_RING(0);
+				OUT_RING(sarea_priv->width |
+					 sarea_priv->height << 16);
+				OUT_RING(sarea_priv->width |
+					 sarea_priv->height << 16);
+				OUT_RING(0);
+
+				ADVANCE_LP_RING();
+
+				sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+				for (i = 0; i < num_rects; i++, rect++) {
+					BEGIN_LP_RING(8);
+
+					OUT_RING(cmd);
+					OUT_RING(pitchropcpp);
+					OUT_RING((rect->y1 << 16) | rect->x1);
+					OUT_RING((rect->y2 << 16) | rect->x2);
+					OUT_RING(sarea_priv->front_offset);
+					OUT_RING((rect->y1 << 16) | rect->x1);
+					OUT_RING(pitchropcpp & 0xffff);
+					OUT_RING(sarea_priv->back_offset);
+
+					ADVANCE_LP_RING();
+				}
+			}
+
+			spin_unlock(&dev->drw_lock);
+
+			spin_lock(&dev_priv->swaps_lock);
+
+			list_del(list);
+
+			drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
+
+			dev_priv->swaps_pending--;
+		}
+	}
+
+	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
 	drm_device_t *dev = (drm_device_t *) arg;
@@ -72,6 +165,8 @@ irqreturn_t i915_driver_irq_handler(DRM_
 
 		DRM_WAKEUP(&dev->vbl_queue);
 		drm_vbl_send_signals(dev);
+
+		drm_locked_tasklet(dev, i915_vblank_tasklet);
 	}
 
 	return IRQ_HANDLED;
@@ -274,6 +369,90 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
 	return 0;
 }
 
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+int i915_vblank_swap(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_vblank_swap_t swap;
+	drm_i915_vbl_swap_t *vbl_swap;
+	unsigned int irqflags;
+	struct list_head *list;
+
+	if (!dev_priv) {
+		DRM_ERROR("%s called with no initialization\n", __func__);
+		return DRM_ERR(EINVAL);
+	}
+
+	if (dev_priv->sarea_priv->rotation) {
+		DRM_DEBUG("Rotation not supported\n");
+		return DRM_ERR(EINVAL);
+	}
+
+	if (dev_priv->swaps_pending >= 100) {
+		DRM_DEBUG("Too many swaps queued\n");
+		return DRM_ERR(EBUSY);
+	}
+
+	DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
+				 sizeof(swap));
+
+	if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) {
+		DRM_ERROR("Invalid pipe %d\n", swap.pipe);
+		return DRM_ERR(EINVAL);
+	}
+
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	if (!drm_get_drawable_info(dev, swap.drawable)) {
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+		DRM_ERROR("Invalid drawable ID %d\n", swap.drawable);
+		return DRM_ERR(EINVAL);
+	}
+
+	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+	list_for_each(list, &dev_priv->vbl_swaps.head) {
+		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+
+		if (vbl_swap->drw_id == swap.drawable &&
+		    vbl_swap->pipe == swap.pipe &&
+		    vbl_swap->sequence == swap.sequence) {
+			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+			DRM_DEBUG("Already scheduled\n");
+			return 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+	vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+
+	if (!vbl_swap) {
+		DRM_ERROR("Failed to allocate memory to queue swap\n");
+		return DRM_ERR(ENOMEM);
+	}
+
+	DRM_DEBUG("\n");
+
+	vbl_swap->drw_id = swap.drawable;
+	vbl_swap->pipe = swap.pipe;
+	vbl_swap->sequence = swap.sequence;
+
+	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+
+	list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
+	dev_priv->swaps_pending++;
+
+	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
+
+	return 0;
+}
+
 /* drm_dma.h hooks
 */
 void i915_driver_irq_preinstall(drm_device_t * dev)
@@ -289,6 +468,10 @@ void i915_driver_irq_postinstall(drm_dev
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+	dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
+	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
+	dev_priv->swaps_pending = 0;
+
 	i915_enable_interrupt(dev);
 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 }
diff-tree 23d2833aaa37a33b9ddcf06cc796f59befc0d360 (from \
                b9f3009160d8bd1a26a77d6f1616f1679c7b969d)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Aug 25 18:55:55 2006 +0200

    Locking and memory management fixes.

diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index 0a35794..81eb9f0 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -36,70 +36,86 @@
 
 #include "drmP.h"
 
-/** No-op. */
+/**
+ * Allocate drawable ID and memory to store information about it.
+ */
 int drm_adddraw(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	unsigned int irqflags;
-	int i, j = 0;
+	int i, j;
+	u32 *bitfield = dev->drw_bitfield;
+	unsigned int bitfield_length = dev->drw_bitfield_length;
+	drm_drawable_info_t **info = dev->drw_info;
+	unsigned int info_length = dev->drw_info_length;
 	drm_draw_t draw;
 
-	spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-	for (i = 0; i < dev->drw_bitfield_length; i++) {
-		u32 bitfield = dev->drw_bitfield[i];
-
-		if (bitfield == ~0)
+	for (i = 0, j = 0; i < bitfield_length; i++) {
+		if (bitfield[i] == ~0)
 			continue;
 
-		for (; j < sizeof(bitfield); j++)
-			if (!(bitfield & (1 << j)))
+		for (; j < 8 * sizeof(*bitfield); j++)
+			if (!(bitfield[i] & (1 << j)))
 				goto done;
 	}
 done:
 
-	if (i == dev->drw_bitfield_length) {
-		u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4,
-						(i + 1) * 4, DRM_MEM_BUFS);
+	if (i == bitfield_length) {
+		bitfield_length++;
+
+		bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
+				     DRM_MEM_BUFS);
 
-		if (!new_bitfield) {
+		if (!bitfield) {
 			DRM_ERROR("Failed to allocate new drawable bitfield\n");
-			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 			return DRM_ERR(ENOMEM);
 		}
 
-		if (32 * (i + 1) > dev->drw_info_length) {
-			void *new_info = drm_realloc(dev->drw_info,
-						     dev->drw_info_length *
-						     sizeof(drm_drawable_info_t*),
-						     32 * (i + 1) *
-						     sizeof(drm_drawable_info_t*),
-						     DRM_MEM_BUFS);
+		if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
+			info_length += 8 * sizeof(*bitfield);
 
-			if (!new_info) {
+			info = drm_alloc(info_length * sizeof(*info),
+					 DRM_MEM_BUFS);
+
+			if (!info) {
 				DRM_ERROR("Failed to allocate new drawable info"
 					  " array\n");
 
-				drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS);
-				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+				drm_free(bitfield,
+					 bitfield_length * sizeof(*bitfield),
+					 DRM_MEM_BUFS);
 				return DRM_ERR(ENOMEM);
 			}
-
-			dev->drw_info = (drm_drawable_info_t**)new_info;
 		}
 
-		new_bitfield[i] = 0;
-
-		dev->drw_bitfield = new_bitfield;
-		dev->drw_bitfield_length++;
+		bitfield[i] = 0;
 	}
 
-	dev->drw_bitfield[i] |= 1 << j;
-
-	draw.handle = i * sizeof(u32) + j;
+	draw.handle = i * 8 * sizeof(*bitfield) + j;
 	DRM_DEBUG("%d\n", draw.handle);
 
-	dev->drw_info[draw.handle] = NULL;
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	bitfield[i] |= 1 << j;
+	info[draw.handle] = NULL;
+
+	if (bitfield != dev->drw_bitfield) {
+		memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
+		       sizeof(*bitfield));
+		drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+			 dev->drw_bitfield_length, DRM_MEM_BUFS);
+		dev->drw_bitfield = bitfield;
+		dev->drw_bitfield_length = bitfield_length;
+	}
+
+	if (info != dev->drw_info) {
+		memcpy(info, dev->drw_info, dev->drw_info_length *
+		       sizeof(*info));
+		drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
+			 DRM_MEM_BUFS);
+		dev->drw_info = info;
+		dev->drw_info_length = info_length;
+	}
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
@@ -108,63 +124,85 @@ done:
 	return 0;
 }
 
-/** No-op. */
+/**
+ * Free drawable ID and memory to store information about it.
+ */
 int drm_rmdraw(DRM_IOCTL_ARGS)
 {
 	DRM_DEVICE;
 	drm_draw_t draw;
-	unsigned int idx, mod;
+	unsigned int idx, shift;
 	unsigned int irqflags;
+	u32 *bitfield = dev->drw_bitfield;
+	unsigned int bitfield_length = dev->drw_bitfield_length;
+	drm_drawable_info_t **info = dev->drw_info;
+	unsigned int info_length = dev->drw_info_length;
 
 	DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
 				 sizeof(draw));
 
-	idx = draw.handle / 32;
-	mod = draw.handle % 32;
+	idx = draw.handle / (8 * sizeof(*bitfield));
+	shift = draw.handle % (8 * sizeof(*bitfield));
 
-	spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-	if (idx >= dev->drw_bitfield_length ||
-	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+	if (idx >= bitfield_length ||
+	    !(bitfield[idx] & (1 << shift))) {
 		DRM_DEBUG("No such drawable %d\n", draw.handle);
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 		return 0;
 	}
 
-	dev->drw_bitfield[idx] &= ~(1 << mod);
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	bitfield[idx] &= ~(1 << shift);
+
+	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-	if (idx == (dev->drw_bitfield_length - 1)) {
-		while (idx >= 0 && !dev->drw_bitfield[idx])
+	/* Can we shrink the arrays? */
+	if (idx == bitfield_length - 1) {
+		while (idx >= 0 && !bitfield[idx])
 			--idx;
 
-		if (idx != draw.handle / 32) {
-			u32 *new_bitfield = drm_realloc(dev->drw_bitfield,
-							dev->drw_bitfield_length * 4,
-							(idx + 1) * 4,
-							DRM_MEM_BUFS);
-
-			if (new_bitfield || idx == -1) {
-				dev->drw_bitfield = new_bitfield;
-				dev->drw_bitfield_length = idx + 1;
-			}
+		bitfield_length = idx + 1;
+
+		if (idx != draw.handle / (8 * sizeof(*bitfield)))
+			bitfield = drm_alloc(bitfield_length *
+					     sizeof(*bitfield), DRM_MEM_BUFS);
+
+		if (!bitfield && bitfield_length) {
+			bitfield = dev->drw_bitfield;
+			bitfield_length = dev->drw_bitfield_length;
 		}
 	}
 
-	if (32 * dev->drw_bitfield_length < dev->drw_info_length) {
-		void *new_info = drm_realloc(dev->drw_info,
-					     dev->drw_info_length *
-					     sizeof(drm_drawable_info_t*),
-					     32 * dev->drw_bitfield_length *
-					     sizeof(drm_drawable_info_t*),
-					     DRM_MEM_BUFS);
-
-		if (new_info || !dev->drw_bitfield_length) {
-			dev->drw_info = (drm_drawable_info_t**)new_info;
-			dev->drw_info_length = 32 * dev->drw_bitfield_length;
+	if (bitfield != dev->drw_bitfield) {
+		info_length = 8 * sizeof(*bitfield) * bitfield_length;
+
+		info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS);
+
+		if (!info && info_length) {
+			info = dev->drw_info;
+			info_length = dev->drw_info_length;
 		}
-	}
 
-	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+		spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+		memcpy(bitfield, dev->drw_bitfield, bitfield_length *
+		       sizeof(*bitfield));
+		drm_free(dev->drw_bitfield, sizeof(*bitfield) *
+			 dev->drw_bitfield_length, DRM_MEM_BUFS);
+		dev->drw_bitfield = bitfield;
+		dev->drw_bitfield_length = bitfield_length;
+
+		if (info != dev->drw_info) {
+			memcpy(info, dev->drw_info, info_length *
+			       sizeof(*info));
+			drm_free(dev->drw_info, sizeof(*info) *
+				 dev->drw_info_length, DRM_MEM_BUFS);
+			dev->drw_info = info;
+			dev->drw_info_length = info_length;
+		}
+
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+	}
 
 	DRM_DEBUG("%d\n", draw.handle);
 	return 0;
@@ -173,24 +211,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 int drm_update_drawable_info(DRM_IOCTL_ARGS) {
 	DRM_DEVICE;
 	drm_update_draw_t update;
-	unsigned int id, idx, mod;
-	unsigned int irqflags;
+	unsigned int id, idx, shift;
+	u32 *bitfield = dev->drw_bitfield;
+	unsigned int irqflags, bitfield_length = dev->drw_bitfield_length;
 	drm_drawable_info_t *info;
-	void *new_data;
+	drm_clip_rect_t *rects;
+	int err;
 
 	DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
 				 sizeof(update));
 
 	id = update.handle;
-	idx = id / 32;
-	mod = id % 32;
-
-	spin_lock_irqsave(&dev->drw_lock, irqflags);
+	idx = id / (8 * sizeof(*bitfield));
+	shift = id % (8 * sizeof(*bitfield));
 
-	if (idx >= dev->drw_bitfield_length ||
-	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+	if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) {
 		DRM_ERROR("No such drawable %d\n", update.handle);
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 		return DRM_ERR(EINVAL);
 	}
 
@@ -201,66 +237,77 @@ int drm_update_drawable_info(DRM_IOCTL_A
 
 		if (!info) {
 			DRM_ERROR("Failed to allocate drawable info memory\n");
-			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 			return DRM_ERR(ENOMEM);
 		}
-
-		dev->drw_info[id] = info;
 	}
 
 	switch (update.type) {
 	case DRM_DRAWABLE_CLIPRECTS:
 		if (update.num != info->num_rects) {
-			new_data = drm_alloc(update.num *
-					     sizeof(drm_clip_rect_t),
-					     DRM_MEM_BUFS);
-
-			if (!new_data) {
-				DRM_ERROR("Can't allocate cliprect memory\n");
-				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-				return DRM_ERR(ENOMEM);
-			}
-
-			info->rects = new_data;
+			rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
+					 DRM_MEM_BUFS);
+		} else
+			rects = info->rects;
+
+		if (update.num && !rects) {
+			DRM_ERROR("Failed to allocate cliprect memory\n");
+			err = DRM_ERR(ENOMEM);
+			goto error;
 		}
 
-		if (DRM_COPY_FROM_USER(info->rects,
-				       (drm_clip_rect_t __user *) 
-				       (unsigned long)update.data,
-				       update.num * sizeof(drm_clip_rect_t))) {
-			DRM_ERROR("Can't copy cliprects from userspace\n");
-			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-			return DRM_ERR(EFAULT);
+		if (update.num && DRM_COPY_FROM_USER(rects,
+						     (drm_clip_rect_t __user *)
+						     (unsigned long)update.data,
+						     update.num *
+						     sizeof(*rects))) {
+			DRM_ERROR("Failed to copy cliprects from userspace\n");
+			err = DRM_ERR(EFAULT);
+			goto error;
 		}
 
-		if (update.num != info->num_rects) {
+		spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+		if (rects != info->rects) {
 			drm_free(info->rects, info->num_rects *
 				 sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
-			info->num_rects = update.num;
 		}
 
+		info->rects = rects;
+		info->num_rects = update.num;
+		dev->drw_info[id] = info;
+
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
 		DRM_DEBUG("Updated %d cliprects for drawable %d\n",
 			  info->num_rects, id);
 		break;
 	default:
 		DRM_ERROR("Invalid update type %d\n", update.type);
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 		return DRM_ERR(EINVAL);
 	}
 
-	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
 	return 0;
+
+error:
+	if (!dev->drw_info[id])
+		drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+	else if (rects != dev->drw_info[id]->rects)
+		drm_free(rects, update.num *
+			 sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+
+	return err;
 }
 
 /**
  * Caller must hold the drawable spinlock!
  */
 drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
-	unsigned int idx = id / 32, mod = id % 32;
+	u32 *bitfield = dev->drw_bitfield;
+	unsigned int idx = id / (8 * sizeof(*bitfield));
+	unsigned int shift = id % (8 * sizeof(*bitfield));
 
 	if (idx >= dev->drw_bitfield_length ||
-	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+	    !(bitfield[idx] & (1 << shift))) {
 		DRM_DEBUG("No such drawable %d\n", id);
 		return NULL;
 	}
diff-tree b9f3009160d8bd1a26a77d6f1616f1679c7b969d (from \
                43f8675534c7e95efbc92eaf2c8cc43aef95f125)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Aug 25 18:55:06 2006 +0200

    Drop tasklet locked driver callback when uninstalling IRQ.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index b57fffb..fef0e8d 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -176,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev
 
 	free_irq(dev->irq, dev);
 
+	dev->locked_tasklet_func = NULL;
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_irq_uninstall);
diff-tree 43f8675534c7e95efbc92eaf2c8cc43aef95f125 (from \
                98a89504589427a76c3f5cfa2266962a1a212672)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 23 19:00:26 2006 +0200

    Export drm_get_drawable_info symbol from core.

diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index 511f3ea..0a35794 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -267,3 +267,4 @@ drm_drawable_info_t *drm_get_drawable_in
 
 	return dev->drw_info[id];
 }
+EXPORT_SYMBOL(drm_get_drawable_info);
diff-tree 98a89504589427a76c3f5cfa2266962a1a212672 (from \
                af48be1096221d551319c67a9e782b50ef58fefd)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 23 16:05:47 2006 +0200

    Hook up DRM_IOCTL_UPDATE_DRAW ioctl.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 8ccbed4..5c9644e 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -931,6 +931,8 @@ extern int drm_adddraw(struct inode *ino
 		       unsigned int cmd, unsigned long arg);
 extern int drm_rmdraw(struct inode *inode, struct file *filp,
 		      unsigned int cmd, unsigned long arg);
+extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
 extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
 						  drm_drawable_t id);
 
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 5ddcd4c..2c878b6 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -119,6 +119,8 @@ static drm_ioctl_desc_t drm_ioctls[] = {
 	[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},  
 	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+
+	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},  };
 
 #define DRIVER_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff-tree af48be1096221d551319c67a9e782b50ef58fefd (from \
                29598e5253ff5c085ccf63580fd24b84db848424)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 23 16:04:41 2006 +0200

    Only reallocate cliprect memory if the number of cliprects changes.
    
    Also improve diagnostic output.

diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
index ca6eb81..511f3ea 100644
--- a/shared-core/drm_drawable.c
+++ b/shared-core/drm_drawable.c
@@ -166,6 +166,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
+	DRM_DEBUG("%d\n", draw.handle);
 	return 0;
 }
 
@@ -209,30 +210,42 @@ int drm_update_drawable_info(DRM_IOCTL_A
 
 	switch (update.type) {
 	case DRM_DRAWABLE_CLIPRECTS:
-		new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t),
-				     DRM_MEM_BUFS);
+		if (update.num != info->num_rects) {
+			new_data = drm_alloc(update.num *
+					     sizeof(drm_clip_rect_t),
+					     DRM_MEM_BUFS);
+
+			if (!new_data) {
+				DRM_ERROR("Can't allocate cliprect memory\n");
+				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+				return DRM_ERR(ENOMEM);
+			}
 
-		if (!new_data) {
-			DRM_ERROR("Failed to allocate cliprect memory\n");
-			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-			return DRM_ERR(ENOMEM);
+			info->rects = new_data;
 		}
 
-		if (DRM_COPY_FROM_USER(new_data,
+		if (DRM_COPY_FROM_USER(info->rects,
 				       (drm_clip_rect_t __user *) 
 				       (unsigned long)update.data,
 				       update.num * sizeof(drm_clip_rect_t))) {
-			DRM_ERROR("Failed to copy cliprects from userspace\n");
+			DRM_ERROR("Can't copy cliprects from userspace\n");
 			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 			return DRM_ERR(EFAULT);
 		}
 
-		drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t),
-			 DRM_MEM_BUFS);
+		if (update.num != info->num_rects) {
+			drm_free(info->rects, info->num_rects *
+				 sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+			info->num_rects = update.num;
+		}
 
-		info->rects = new_data;
-		info->num_rects = update.num;
+		DRM_DEBUG("Updated %d cliprects for drawable %d\n",
+			  info->num_rects, id);
 		break;
+	default:
+		DRM_ERROR("Invalid update type %d\n", update.type);
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+		return DRM_ERR(EINVAL);
 	}
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
diff-tree 29598e5253ff5c085ccf63580fd24b84db848424 (from \
                d817cc1f30060fcc4a85a05b2de8a2a1687421b5)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Tue Aug 22 16:40:07 2006 +0200

    Add support for tracking drawable information to core
    
    Actually make the existing ioctls for adding and removing drawables do
    something useful, and add another ioctl for the X server to update drawable
    information. The only kind of drawable information tracked so far is cliprects.

diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c
deleted file mode 100644
index 379e0aa..d64bbe1
--- a/bsd-core/drm_drawable.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*-
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.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>
- *
- */
-
-#include "drmP.h"
-
-int drm_adddraw(DRM_IOCTL_ARGS)
-{
-	drm_draw_t draw;
-
-	draw.handle = 0;	/* NOOP */
-	DRM_DEBUG("%d\n", draw.handle);
-	
-	DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) );
-
-	return 0;
-}
-
-int drm_rmdraw(DRM_IOCTL_ARGS)
-{
-	return 0;		/* NOOP */
-}
diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c
new file mode 120000
index 379e0aa..d64bbe1
--- /dev/null
+++ b/bsd-core/drm_drawable.c
@@ -0,0 +1 @@
+../shared-core/drm_drawable.c
\ No newline at end of file
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c
index c9f1b2d..d4f80b4 100644
--- a/libdrm/xf86drm.c
+++ b/libdrm/xf86drm.c
@@ -1397,6 +1397,22 @@ int drmDestroyDrawable(int fd, drm_drawa
     return 0;
 }
 
+int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
+			   drm_drawable_info_type_t type, unsigned int num,
+			   void *data)
+{
+    drm_update_draw_t update;
+
+    update.handle = handle;
+    update.type = type;
+    update.num = num;
+    update.data = (unsigned long long)(unsigned long)data;
+
+    if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) return -errno;
+
+    return 0;
+}
+
 /**
  * Acquire the AGP device.
  *
diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h
index 48a18f2..9e71eb6 100644
--- a/libdrm/xf86drm.h
+++ b/libdrm/xf86drm.h
@@ -544,6 +544,9 @@ extern int           drmSwitchToContext(
 extern int           drmDestroyContext(int fd, drm_context_t handle);
 extern int           drmCreateDrawable(int fd, drm_drawable_t * handle);
 extern int           drmDestroyDrawable(int fd, drm_drawable_t handle);
+extern int           drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
+					   drm_drawable_info_type_t type,
+					   unsigned int num, void *data);
 extern int           drmCtlInstHandler(int fd, int irq);
 extern int           drmCtlUninstHandler(int fd);
 
diff --git a/linux-core/Makefile b/linux-core/Makefile
index 32828d2..3aecec4 100644
--- a/linux-core/Makefile
+++ b/linux-core/Makefile
@@ -75,8 +75,8 @@ DRM_MODULES ?= $(MODULE_LIST)
 
 # These definitions are for handling dependencies in the out of kernel build.
 
-DRMSHARED =     drm.h drm_sarea.h
-DRMHEADERS =    drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED)
+DRMSHARED =     drm.h drm_sarea.h drm_drawable.c
+DRMHEADERS =    drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h
 COREHEADERS =   drm_core.h drm_sman.h drm_hashtab.h 
 
 TDFXHEADERS =   tdfx_drv.h $(DRMHEADERS)
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index e61be1a..8ccbed4 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -772,6 +772,15 @@ typedef struct drm_device {
 	drm_local_map_t *agp_buffer_map;
 	unsigned int agp_buffer_token;
 	drm_head_t primary;		/**< primary screen head */
+
+	/** \name Drawable information */
+	/*@{ */
+	spinlock_t drw_lock;
+	unsigned int drw_bitfield_length;
+	u32 *drw_bitfield;
+	unsigned int drw_info_length;
+	drm_drawable_info_t **drw_info;
+	/*@} */
 } drm_device_t;
 
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
@@ -922,6 +931,8 @@ extern int drm_adddraw(struct inode *ino
 		       unsigned int cmd, unsigned long arg);
 extern int drm_rmdraw(struct inode *inode, struct file *filp,
 		      unsigned int cmd, unsigned long arg);
+extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
+						  drm_drawable_t id);
 
 				/* Authentication IOCTL support (drm_auth.h) */
 extern int drm_getmagic(struct inode *inode, struct file *filp,
diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c
deleted file mode 100644
index 7857453..d64bbe1
--- a/linux-core/drm_drawable.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * \file drm_drawable.c
- * IOCTLs for drawables
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
-/*
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.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.
- */
-
-#include "drmP.h"
-
-/** No-op. */
-int drm_adddraw(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
-{
-	drm_draw_t draw;
-
-	draw.handle = 0;	/* NOOP */
-	DRM_DEBUG("%d\n", draw.handle);
-	if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw)))
-		return -EFAULT;
-	return 0;
-}
-
-/** No-op. */
-int drm_rmdraw(struct inode *inode, struct file *filp,
-	       unsigned int cmd, unsigned long arg)
-{
-	return 0;		/* NOOP */
-}
diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c
new file mode 120000
index 7857453..d64bbe1
--- /dev/null
+++ b/linux-core/drm_drawable.c
@@ -0,0 +1 @@
+../shared-core/drm_drawable.c
\ No newline at end of file
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 4708222..ad78dcf 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -61,6 +61,7 @@ static int drm_fill_in_dev(drm_device_t 
 	int retcode;
 
 	spin_lock_init(&dev->count_lock);
+	spin_lock_init(&dev->drw_lock);
 	init_timer(&dev->timer);
 	mutex_init(&dev->struct_mutex);
 	mutex_init(&dev->ctxlist_mutex);
diff --git a/shared-core/drm.h b/shared-core/drm.h
index eaeb21e..614422b 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -159,6 +159,14 @@ typedef struct drm_clip_rect {
 } drm_clip_rect_t;
 
 /**
+ * Drawable information.
+ */
+typedef struct drm_drawable_info {
+	unsigned int num_rects;
+	drm_clip_rect_t *rects;
+} drm_drawable_info_t;
+
+/**
  * Texture region,
  */
 typedef struct drm_tex_region {
@@ -508,6 +516,20 @@ typedef struct drm_draw {
 } drm_draw_t;
 
 /**
+ * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
+ */
+typedef enum {
+	DRM_DRAWABLE_CLIPRECTS,
+} drm_drawable_info_type_t;
+
+typedef struct drm_update_draw {
+	drm_drawable_t handle;
+	unsigned int type;
+	unsigned int num;
+	unsigned long long data;
+} drm_update_draw_t;
+
+/**
  * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
  */
 typedef struct drm_auth {
@@ -696,6 +718,8 @@ typedef struct drm_set_version {
 
 #define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, drm_wait_vblank_t)
 
+#define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, drm_update_draw_t)
+
 /*@}*/
 
 /**
diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c
new file mode 100644
index 0000000..ca6eb81
--- /dev/null
+++ b/shared-core/drm_drawable.c
@@ -0,0 +1,256 @@
+/**
+ * \file drm_drawable.c
+ * IOCTLs for drawables
+ *
+ * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * \author Gareth Hughes <gareth@valinux.com>
+ * \author Michel Dänzer <michel@tungstengraphics.com>
+ */
+
+/*
+ * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.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.
+ */
+
+#include "drmP.h"
+
+/** No-op. */
+int drm_adddraw(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	unsigned int irqflags;
+	int i, j = 0;
+	drm_draw_t draw;
+
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	for (i = 0; i < dev->drw_bitfield_length; i++) {
+		u32 bitfield = dev->drw_bitfield[i];
+
+		if (bitfield == ~0)
+			continue;
+
+		for (; j < sizeof(bitfield); j++)
+			if (!(bitfield & (1 << j)))
+				goto done;
+	}
+done:
+
+	if (i == dev->drw_bitfield_length) {
+		u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4,
+						(i + 1) * 4, DRM_MEM_BUFS);
+
+		if (!new_bitfield) {
+			DRM_ERROR("Failed to allocate new drawable bitfield\n");
+			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+			return DRM_ERR(ENOMEM);
+		}
+
+		if (32 * (i + 1) > dev->drw_info_length) {
+			void *new_info = drm_realloc(dev->drw_info,
+						     dev->drw_info_length *
+						     sizeof(drm_drawable_info_t*),
+						     32 * (i + 1) *
+						     sizeof(drm_drawable_info_t*),
+						     DRM_MEM_BUFS);
+
+			if (!new_info) {
+				DRM_ERROR("Failed to allocate new drawable info"
+					  " array\n");
+
+				drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS);
+				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+				return DRM_ERR(ENOMEM);
+			}
+
+			dev->drw_info = (drm_drawable_info_t**)new_info;
+		}
+
+		new_bitfield[i] = 0;
+
+		dev->drw_bitfield = new_bitfield;
+		dev->drw_bitfield_length++;
+	}
+
+	dev->drw_bitfield[i] |= 1 << j;
+
+	draw.handle = i * sizeof(u32) + j;
+	DRM_DEBUG("%d\n", draw.handle);
+
+	dev->drw_info[draw.handle] = NULL;
+
+	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+	DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
+
+	return 0;
+}
+
+/** No-op. */
+int drm_rmdraw(DRM_IOCTL_ARGS)
+{
+	DRM_DEVICE;
+	drm_draw_t draw;
+	unsigned int idx, mod;
+	unsigned int irqflags;
+
+	DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
+				 sizeof(draw));
+
+	idx = draw.handle / 32;
+	mod = draw.handle % 32;
+
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	if (idx >= dev->drw_bitfield_length ||
+	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+		DRM_DEBUG("No such drawable %d\n", draw.handle);
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+		return 0;
+	}
+
+	dev->drw_bitfield[idx] &= ~(1 << mod);
+
+	if (idx == (dev->drw_bitfield_length - 1)) {
+		while (idx >= 0 && !dev->drw_bitfield[idx])
+			--idx;
+
+		if (idx != draw.handle / 32) {
+			u32 *new_bitfield = drm_realloc(dev->drw_bitfield,
+							dev->drw_bitfield_length * 4,
+							(idx + 1) * 4,
+							DRM_MEM_BUFS);
+
+			if (new_bitfield || idx == -1) {
+				dev->drw_bitfield = new_bitfield;
+				dev->drw_bitfield_length = idx + 1;
+			}
+		}
+	}
+
+	if (32 * dev->drw_bitfield_length < dev->drw_info_length) {
+		void *new_info = drm_realloc(dev->drw_info,
+					     dev->drw_info_length *
+					     sizeof(drm_drawable_info_t*),
+					     32 * dev->drw_bitfield_length *
+					     sizeof(drm_drawable_info_t*),
+					     DRM_MEM_BUFS);
+
+		if (new_info || !dev->drw_bitfield_length) {
+			dev->drw_info = (drm_drawable_info_t**)new_info;
+			dev->drw_info_length = 32 * dev->drw_bitfield_length;
+		}
+	}
+
+	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+	return 0;
+}
+
+int drm_update_drawable_info(DRM_IOCTL_ARGS) {
+	DRM_DEVICE;
+	drm_update_draw_t update;
+	unsigned int id, idx, mod;
+	unsigned int irqflags;
+	drm_drawable_info_t *info;
+	void *new_data;
+
+	DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
+				 sizeof(update));
+
+	id = update.handle;
+	idx = id / 32;
+	mod = id % 32;
+
+	spin_lock_irqsave(&dev->drw_lock, irqflags);
+
+	if (idx >= dev->drw_bitfield_length ||
+	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+		DRM_ERROR("No such drawable %d\n", update.handle);
+		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+		return DRM_ERR(EINVAL);
+	}
+
+	info = dev->drw_info[id];
+
+	if (!info) {
+		info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
+
+		if (!info) {
+			DRM_ERROR("Failed to allocate drawable info memory\n");
+			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+			return DRM_ERR(ENOMEM);
+		}
+
+		dev->drw_info[id] = info;
+	}
+
+	switch (update.type) {
+	case DRM_DRAWABLE_CLIPRECTS:
+		new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t),
+				     DRM_MEM_BUFS);
+
+		if (!new_data) {
+			DRM_ERROR("Failed to allocate cliprect memory\n");
+			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+			return DRM_ERR(ENOMEM);
+		}
+
+		if (DRM_COPY_FROM_USER(new_data,
+				       (drm_clip_rect_t __user *) 
+				       (unsigned long)update.data,
+				       update.num * sizeof(drm_clip_rect_t))) {
+			DRM_ERROR("Failed to copy cliprects from userspace\n");
+			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+			return DRM_ERR(EFAULT);
+		}
+
+		drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t),
+			 DRM_MEM_BUFS);
+
+		info->rects = new_data;
+		info->num_rects = update.num;
+		break;
+	}
+
+	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+
+	return 0;
+}
+
+/**
+ * Caller must hold the drawable spinlock!
+ */
+drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
+	unsigned int idx = id / 32, mod = id % 32;
+
+	if (idx >= dev->drw_bitfield_length ||
+	    !(dev->drw_bitfield[idx] & (1 << mod))) {
+		DRM_DEBUG("No such drawable %d\n", id);
+		return NULL;
+	}
+
+	return dev->drw_info[id];
+}
diff-tree d817cc1f30060fcc4a85a05b2de8a2a1687421b5 (from \
                0c7d7f43610f705e8536a949cf2407efaa5ec217)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Wed Aug 16 15:47:22 2006 +0200

    Add support for interrupt triggered driver callback with lock held to DRM core.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 200b649..e61be1a 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -739,6 +739,8 @@ typedef struct drm_device {
 	drm_vbl_sig_t vbl_sigs;		/**< signal list to send on VBLANK */
 	drm_vbl_sig_t vbl_sigs2;	/**< signals to send on secondary VBLANK */
 	unsigned int vbl_pending;
+	spinlock_t tasklet_lock;	/**< For drm_locked_tasklet */
+	void (*locked_tasklet_func)(struct drm_device *dev);
 
 	/*@} */
 	cycles_t ctx_start;
@@ -984,6 +986,7 @@ extern int drm_wait_vblank(struct inode 
 			   unsigned int cmd, unsigned long arg);
 extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq);
 extern void drm_vbl_send_signals(drm_device_t * dev);
+extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*));
 
 				/* AGP/GART support (drm_agpsupport.h) */
 extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index d4e5fbd..b57fffb 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -118,6 +118,7 @@ static int drm_irq_install(drm_device_t 
 		init_waitqueue_head(&dev->vbl_queue);
 
 		spin_lock_init(&dev->vbl_lock);
+		spin_lock_init(&dev->tasklet_lock);
 
 		INIT_LIST_HEAD(&dev->vbl_sigs.head);
 		INIT_LIST_HEAD(&dev->vbl_sigs2.head);
@@ -396,3 +397,76 @@ void drm_vbl_send_signals(drm_device_t *
 	spin_unlock_irqrestore(&dev->vbl_lock, flags);
 }
 EXPORT_SYMBOL(drm_vbl_send_signals);
+
+/**
+ * Tasklet wrapper function.
+ *
+ * \param data DRM device in disguise.
+ *
+ * Attempts to grab the HW lock and calls the driver callback on success. On
+ * failure, leave the lock marked as contended so the callback can be called
+ * from drm_unlock().
+ */
+static void drm_locked_tasklet_func(unsigned long data)
+{
+	drm_device_t *dev = (drm_device_t*)data;
+	unsigned int irqflags;
+
+	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+	if (!dev->locked_tasklet_func ||
+	    !drm_lock_take(&dev->lock.hw_lock->lock,
+			   DRM_KERNEL_CONTEXT)) {
+		spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+		return;
+	}
+
+	dev->lock.lock_time = jiffies;
+	atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
+
+	dev->locked_tasklet_func(dev);
+
+	drm_lock_free(dev, &dev->lock.hw_lock->lock,
+		      DRM_KERNEL_CONTEXT);
+
+	dev->locked_tasklet_func = NULL;
+
+	spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+}
+
+/**
+ * Schedule a tasklet to call back a driver hook with the HW lock held.
+ *
+ * \param dev DRM device.
+ * \param func Driver callback.
+ *
+ * This is intended for triggering actions that require the HW lock from an
+ * interrupt handler. The lock will be grabbed ASAP after the interrupt handler
+ * completes. Note that the callback may be called from interrupt or process
+ * context, it must not make any assumptions about this. Also, the HW lock will
+ * be held with the kernel context or any client context.
+ */
+void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
+{
+	unsigned int irqflags;
+	static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
+
+	if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
+		return;
+
+	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+	if (dev->locked_tasklet_func) {
+		spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+		return;
+	}
+
+	dev->locked_tasklet_func = func;
+
+	spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
+	drm_tasklet.data = (unsigned long)dev;
+
+	tasklet_hi_schedule(&drm_tasklet);
+}
+EXPORT_SYMBOL(drm_locked_tasklet);
diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c
index 7aa00bc..fa677ba 100644
--- a/linux-core/drm_lock.c
+++ b/linux-core/drm_lock.c
@@ -152,6 +152,7 @@ int drm_unlock(struct inode *inode, stru
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
 	drm_lock_t lock;
+	unsigned int irqflags;
 
 	if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
 		return -EFAULT;
@@ -162,6 +163,16 @@ int drm_unlock(struct inode *inode, stru
 		return -EINVAL;
 	}
 
+	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+	if (dev->locked_tasklet_func) {
+		dev->locked_tasklet_func(dev);
+
+		dev->locked_tasklet_func = NULL;
+	}
+
+	spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
 	atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
 	/* kernel_context_switch isn't used by any of the x86 drm
diff-tree 0c7d7f43610f705e8536a949cf2407efaa5ec217 (from \
                ab351505f36a6c66405ea7604378268848340a42)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Aug 11 18:06:46 2006 +0200

    Add support for secondary vertical blank interrupt to i915 driver.
    
    When the vertical blank interrupt is enabled for both pipes, pipe A is
    considered primary and pipe B secondary. When it's only enabled for one pipe,
    it's always considered primary for backwards compatibility.

diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index c6e25f9..209500b 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -45,12 +45,14 @@ static struct drm_driver driver = {
 	 */
 	.driver_features =
 	    DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */
-	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
+	    DRIVER_IRQ_VBL2,
 	.load = i915_driver_load,
 	.lastclose = i915_driver_lastclose,
 	.preclose = i915_driver_preclose,
 	.device_is_agp = i915_driver_device_is_agp,
 	.vblank_wait = i915_driver_vblank_wait,
+	.vblank_wait2 = i915_driver_vblank_wait2,
 	.irq_preinstall = i915_driver_irq_preinstall,
 	.irq_postinstall = i915_driver_irq_postinstall,
 	.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index a87075b..69cf811 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -117,6 +117,7 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS)
 extern int i915_irq_wait(DRM_IOCTL_ARGS);
 
 extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
+extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
 extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(drm_device_t * dev);
 extern void i915_driver_irq_postinstall(drm_device_t * dev);
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 14213b5..2eac29f 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -60,7 +60,16 @@ irqreturn_t i915_driver_irq_handler(DRM_
 		DRM_WAKEUP(&dev_priv->irq_queue);
 
 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-		atomic_inc(&dev->vbl_received);
+		if ((dev_priv->vblank_pipe &
+		     (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
+		    == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
+			if (temp & VSYNC_PIPEA_FLAG)
+				atomic_inc(&dev->vbl_received);
+			if (temp & VSYNC_PIPEB_FLAG)
+				atomic_inc(&dev->vbl_received2);
+		} else
+			atomic_inc(&dev->vbl_received);
+
 		DRM_WAKEUP(&dev->vbl_queue);
 		drm_vbl_send_signals(dev);
 	}
@@ -124,7 +133,8 @@ static int i915_wait_irq(drm_device_t * 
 	return ret;
 }
 
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
+				      atomic_t *counter)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned int cur_vblank;
@@ -136,7 +146,7 @@ int i915_driver_vblank_wait(drm_device_t
 	}
 
 	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-		    (((cur_vblank = atomic_read(&dev->vbl_received))
+		    (((cur_vblank = atomic_read(counter))
 			- *sequence) <= (1<<23)));
 	
 	*sequence = cur_vblank;
@@ -144,6 +154,16 @@ int i915_driver_vblank_wait(drm_device_t
 	return ret;
 }
 
+int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+{
+	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
+}
+
+int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
+{
+	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
+}
+
 /* Needs the lock as it touches the ring.
  */
 int i915_irq_emit(DRM_IOCTL_ARGS)
diff-tree ab351505f36a6c66405ea7604378268848340a42 (from \
                62f6ea225615392098dedee47d4ccdd69e126a43)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Aug 11 17:57:59 2006 +0200

    Add support for secondary vertical blank interrupt to DRM core.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index fd48059..200b649 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -110,6 +110,7 @@
 #define DRIVER_IRQ_VBL     0x100
 #define DRIVER_DMA_QUEUE   0x200
 #define DRIVER_FB_DMA      0x400
+#define DRIVER_IRQ_VBL2    0x800
 
 
 /*@}*/
@@ -582,6 +583,7 @@ struct drm_driver {
 				      int new);
 	void (*kernel_context_switch_unlock) (struct drm_device * dev);
 	int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
+	int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence);
 	int (*dri_library_name) (struct drm_device * dev, char * buf);
 
 	/**
@@ -732,8 +734,10 @@ typedef struct drm_device {
 
 	wait_queue_head_t vbl_queue;	/**< VBLANK wait queue */
 	atomic_t vbl_received;
+	atomic_t vbl_received2;		/**< number of secondary VBLANK interrupts */
 	spinlock_t vbl_lock;
 	drm_vbl_sig_t vbl_sigs;		/**< signal list to send on VBLANK */
+	drm_vbl_sig_t vbl_sigs2;	/**< signals to send on secondary VBLANK */
 	unsigned int vbl_pending;
 
 	/*@} */
diff --git a/linux-core/drm_core.h b/linux-core/drm_core.h
index f5405fd..705bbff 100644
--- a/linux-core/drm_core.h
+++ b/linux-core/drm_core.h
@@ -25,11 +25,11 @@
 
 #define CORE_NAME		"drm"
 #define CORE_DESC		"DRM shared core routines"
-#define CORE_DATE		"20051102"
+#define CORE_DATE		"20060810"
 
 #define DRM_IF_MAJOR	1
-#define DRM_IF_MINOR	2
+#define DRM_IF_MINOR	3
 
 #define CORE_MAJOR	1
-#define CORE_MINOR	0
-#define CORE_PATCHLEVEL 1
+#define CORE_MINOR	1
+#define CORE_PATCHLEVEL 0
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index c2a9e3d..d4e5fbd 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -120,6 +120,7 @@ static int drm_irq_install(drm_device_t 
 		spin_lock_init(&dev->vbl_lock);
 
 		INIT_LIST_HEAD(&dev->vbl_sigs.head);
+		INIT_LIST_HEAD(&dev->vbl_sigs2.head);
 
 		dev->vbl_pending = 0;
 	}
@@ -246,9 +247,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	struct timeval now;
 	int ret = 0;
 	unsigned int flags;
-
-	if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
-		return -EINVAL;
+	atomic_t *seq;
 
 	if ((!dev->irq) || (!dev->irq_enabled))
 		return -EINVAL;
@@ -256,9 +255,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
 		return -EFAULT;
 
-	switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
+	if (vblwait.request.type &
+	    ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+		DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
+			  vblwait.request.type,
+			  (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
+		return -EINVAL;
+	}
+
+	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+
+	if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
+				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+		return -EINVAL;
+
+	seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 :
+	      &dev->vbl_received;
+
+	switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
 	case _DRM_VBLANK_RELATIVE:
-		vblwait.request.sequence += atomic_read(&dev->vbl_received);
+		vblwait.request.sequence += atomic_read(seq);
 		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
 	case _DRM_VBLANK_ABSOLUTE:
 		break;
@@ -266,13 +282,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		return -EINVAL;
 	}
 
-	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
-
 	if (flags & _DRM_VBLANK_SIGNAL) {
 		unsigned long irqflags;
+		drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
+				      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
 		drm_vbl_sig_t *vbl_sig;
 
-		vblwait.reply.sequence = atomic_read(&dev->vbl_received);
+		vblwait.reply.sequence = atomic_read(seq);
 
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
@@ -280,7 +296,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		 * for the same vblank sequence number; nothing to be done in
 		 * that case
 		 */
-		list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) {
+		list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
 			if (vbl_sig->sequence == vblwait.request.sequence
 			    && vbl_sig->info.si_signo == vblwait.request.signal
 			    && vbl_sig->task == current) {
@@ -313,11 +329,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
-		list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head);
+		list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
 
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 	} else {
-		if (dev->driver->vblank_wait)
+		if (flags & _DRM_VBLANK_SECONDARY) {
+			if (dev->driver->vblank_wait2)
+				ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+		} else if (dev->driver->vblank_wait)
 			ret =
 			    dev->driver->vblank_wait(dev,
 						     &vblwait.request.sequence);
@@ -345,25 +364,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
  */
 void drm_vbl_send_signals(drm_device_t * dev)
 {
-	struct list_head *list, *tmp;
-	drm_vbl_sig_t *vbl_sig;
-	unsigned int vbl_seq = atomic_read(&dev->vbl_received);
 	unsigned long flags;
+	int i;
 
 	spin_lock_irqsave(&dev->vbl_lock, flags);
 
-	list_for_each_safe(list, tmp, &dev->vbl_sigs.head) {
-		vbl_sig = list_entry(list, drm_vbl_sig_t, head);
-		if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
-			vbl_sig->info.si_code = vbl_seq;
-			send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info,
-				      vbl_sig->task);
+	for (i = 0; i < 2; i++) {
+		struct list_head *list, *tmp;
+		drm_vbl_sig_t *vbl_sig;
+		drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+		unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
+						   &dev->vbl_received);
+
+		list_for_each_safe(list, tmp, &vbl_sigs->head) {
+			vbl_sig = list_entry(list, drm_vbl_sig_t, head);
+			if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+				vbl_sig->info.si_code = vbl_seq;
+				send_sig_info(vbl_sig->info.si_signo,
+					      &vbl_sig->info, vbl_sig->task);
 
-			list_del(list);
+				list_del(list);
 
-			drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
+				drm_free(vbl_sig, sizeof(*vbl_sig),
+					 DRM_MEM_DRIVER);
 
-			dev->vbl_pending--;
+				dev->vbl_pending--;
+			}
 		}
 	}
 
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 87f8da6..eaeb21e 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -529,10 +529,12 @@ typedef struct drm_irq_busid {
 typedef enum {
 	_DRM_VBLANK_ABSOLUTE = 0x0,	/**< Wait for specific vblank sequence number */
 	_DRM_VBLANK_RELATIVE = 0x1,	/**< Wait for given number of vblanks */
+	_DRM_VBLANK_SECONDARY = 0x20000000,	/**< Secondary display controller */
 	_DRM_VBLANK_SIGNAL = 0x40000000	/**< Send signal instead of blocking */
 } drm_vblank_seq_type_t;
 
-#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
+#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY)
 
 struct drm_wait_vblank_request {
 	drm_vblank_seq_type_t type;
diff-tree 62f6ea225615392098dedee47d4ccdd69e126a43 (from \
                255f3e6f76dfd267a14765dd1293229184298d89)
Author: Felix Kuhling <fxkuehl@gmx.de>
Date:   Fri Sep 22 03:46:54 2006 +1000

    bug 5942: add stubs for drm_mtrr_add/del for non-MTRR configured linux

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index a955c3d..fd48059 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -810,6 +810,18 @@ static inline int drm_mtrr_del(int handl
 }
 
 #else
+static inline int drm_mtrr_add(unsigned long offset, unsigned long size,
+			       unsigned int flags)
+{
+	return -ENODEV;
+}
+
+static inline int drm_mtrr_del(int handle, unsigned long offset,
+			       unsigned long size, unsigned int flags)
+{
+	return -ENODEV;
+}
+
 #define drm_core_has_MTRR(dev) (0)
 #endif
 
diff-tree 255f3e6f76dfd267a14765dd1293229184298d89 (from \
                1f71b8d7a456fe3ec4bfc2fed70b7420cdd0d55a)
Author: Anish Mistry <mistry.7@osu.edu>
Date:   Fri Sep 22 03:43:34 2006 +1000

    bug 7092 : add pci ids for mach64 in Dell poweredge 4200

diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt
index 9e0c099..c597708 100644
--- a/shared-core/drm_pciids.txt
+++ b/shared-core/drm_pciids.txt
@@ -186,6 +186,7 @@
 0x1002 0x4c51 0 "3D Rage LT Pro"
 0x1002 0x4c42 0 "3D Rage LT Pro AGP-133"
 0x1002 0x4c44 0 "3D Rage LT Pro AGP-66"
+0x1002 0x4759 0 "Rage 3D IICATI 3D RAGE IIC AGP(A12/A13)
 0x1002 0x474c 0 "Rage XC"
 0x1002 0x474f 0 "Rage XL"
 0x1002 0x4752 0 "Rage XL"
diff-tree 1f71b8d7a456fe3ec4bfc2fed70b7420cdd0d55a (from \
                ef98a8e20dad8ae7e38f397d63c13bd24105ce53)
Author: Roland Scheidegger <zak@ZakTower.(none)>
Date:   Wed Sep 20 19:44:57 2006 +0200

    do a TCL state flush before accessing VAP_CNTL to prevent lockups on r200 when \
enabling/disabling vertex programs

diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index 5b1ca53..b447801 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -174,6 +174,14 @@ static __inline__ int radeon_check_and_f
 		}
 		break;
 
+	case R200_EMIT_VAP_CTL: {
+			RING_LOCALS;
+			BEGIN_RING(2);
+			OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
+			ADVANCE_RING();
+		}
+		break;
+
 	case RADEON_EMIT_RB3D_COLORPITCH:
 	case RADEON_EMIT_RE_LINE_PATTERN:
 	case RADEON_EMIT_SE_LINE_WIDTH:
@@ -201,7 +209,6 @@ static __inline__ int radeon_check_and_f
 	case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
 	case R200_EMIT_TFACTOR_0:
 	case R200_EMIT_VTX_FMT_0:
-	case R200_EMIT_VAP_CTL:
 	case R200_EMIT_MATRIX_SELECT_0:
 	case R200_EMIT_TEX_PROC_CTL_2:
 	case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
diff-tree ef98a8e20dad8ae7e38f397d63c13bd24105ce53 (from \
                6ba9127753eff7615ba553fbc567aec98ecf8104)
Author: Dave Airlie <airlied@starflyer-ubuntu.(none)>
Date:   Mon Sep 18 21:22:12 2006 +1000

    drm: put domain number back to 0, domain support is seriously fubar..

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 70bf349..a955c3d 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -777,7 +777,7 @@ static __inline__ int drm_core_check_fea
 #ifdef __alpha__
 #define drm_get_pci_domain(dev) dev->hose->bus->number
 #else
-#define drm_get_pci_domain(dev) pci_domain_nr(dev->pdev->bus)
+#define drm_get_pci_domain(dev) 0
 #endif
 
 #if __OS_HAS_AGP
diff-tree 6ba9127753eff7615ba553fbc567aec98ecf8104 (from \
                3cc64a943a7240c73c92ab103ba0502b9ec07fee)
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Sep 15 16:37:47 2006 +0200

    Use register writes instead of BITBLT_MULTI packets for buffer swap blits.
    
    This takes up two more ring buffer entries per rectangle blitted but makes sure
    the blit is performed top to bottom, reducing the likelyhood of tearing.

diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 5fc9331..6ea2a17 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -423,6 +423,8 @@ extern int r300_do_cp_cmdbuf(drm_device_
 #define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
+#define	RADEON_SRC_X_Y			0x1590
+
 #define RADEON_DP_GUI_MASTER_CNTL	0x146c
 #	define RADEON_GMC_SRC_PITCH_OFFSET_CNTL	(1 << 0)
 #	define RADEON_GMC_DST_PITCH_OFFSET_CNTL	(1 << 1)
@@ -440,6 +442,7 @@ extern int r300_do_cp_cmdbuf(drm_device_
 #	define RADEON_ROP3_S			0x00cc0000
 #	define RADEON_ROP3_P			0x00f00000
 #define RADEON_DP_WRITE_MASK		0x16cc
+#define RADEON_SRC_PITCH_OFFSET		0x1428
 #define RADEON_DST_PITCH_OFFSET		0x142c
 #define RADEON_DST_PITCH_OFFSET_C	0x1c80
 #	define RADEON_DST_TILE_LINEAR		(0 << 30)
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index 0a196c0..5b1ca53 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -1262,9 +1262,9 @@ static void radeon_cp_dispatch_swap(drm_
 
 		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
 
-		BEGIN_RING(7);
+		BEGIN_RING(9);
 
-		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+		OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
 		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
 			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
 			 RADEON_GMC_BRUSH_NONE |
@@ -1276,6 +1276,7 @@ static void radeon_cp_dispatch_swap(drm_
 
 		/* Make this work even if front & back are flipped:
 		 */
+		OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
 		if (dev_priv->current_page == 0) {
 			OUT_RING(dev_priv->back_pitch_offset);
 			OUT_RING(dev_priv->front_pitch_offset);
@@ -1284,6 +1285,7 @@ static void radeon_cp_dispatch_swap(drm_
 			OUT_RING(dev_priv->back_pitch_offset);
 		}
 
+		OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
 		OUT_RING((x << 16) | y);
 		OUT_RING((x << 16) | y);
 		OUT_RING((w << 16) | h);
diff-tree 3cc64a943a7240c73c92ab103ba0502b9ec07fee (from \
                dddacd7a3a4bd0c453b346cee70d1d36a401e539)
Author: Dave Airlie <airlied@starflyer-ubuntu.(none)>
Date:   Tue Sep 12 06:13:14 2006 +1000

    drm: use radeon specific names for radeon flags

diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c
index fca2d4e..b15e983 100644
--- a/linux-core/radeon_drv.c
+++ b/linux-core/radeon_drv.c
@@ -45,7 +45,7 @@ module_param_named(no_wb, radeon_no_wb, 
 static int dri_library_name(struct drm_device * dev, char * buf)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	int family = dev_priv->flags & CHIP_FAMILY_MASK;
+	int family = dev_priv->flags & RADEON_FAMILY_MASK;
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 		(family < CHIP_R200) ? "radeon" :
diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt
index 9ef2c00..9e0c099 100644
--- a/shared-core/drm_pciids.txt
+++ b/shared-core/drm_pciids.txt
@@ -1,11 +1,11 @@
 [radeon]
-0x1002 0x3150 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X600 M24"
-0x1002 0x3152 CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X300 \
                M24"
-0x1002 0x3154 CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI FireGL M24 GL"
-0x1002 0x3E50 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV380 X600"
-0x1002 0x3E54 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireGL V3200 RV380"
-0x1002 0x4136 CHIP_RS100|CHIP_IS_IGP "ATI Radeon RS100 IGP 320"
-0x1002 0x4137 CHIP_RS200|CHIP_IS_IGP "ATI Radeon RS200 IGP 340"
+0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24"
+0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility \
X300 M24" +0x1002 0x3154 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI FireGL \
M24 GL" +0x1002 0x3E50 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV380 X600"
+0x1002 0x3E54 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireGL V3200 RV380"
+0x1002 0x4136 CHIP_RS100|RADEON_IS_IGP "ATI Radeon RS100 IGP 320"
+0x1002 0x4137 CHIP_RS200|RADEON_IS_IGP "ATI Radeon RS200 IGP 340"
 0x1002 0x4144 CHIP_R300 "ATI Radeon AD 9500"
 0x1002 0x4145 CHIP_R300 "ATI Radeon AE 9700 Pro"
 0x1002 0x4146 CHIP_R300 "ATI Radeon AF R300 9600TX"
@@ -21,35 +21,35 @@
 0x1002 0x4154 CHIP_RV350 "ATI FireGL AT T2"
 0x1002 0x4155 CHIP_RV350 "ATI Radeon 9650"
 0x1002 0x4156 CHIP_RV350 "ATI FireGL AV RV360 T2"
-0x1002 0x4237 CHIP_RS200|CHIP_IS_IGP "ATI Radeon RS250 IGP"
+0x1002 0x4237 CHIP_RS200|RADEON_IS_IGP "ATI Radeon RS250 IGP"
 0x1002 0x4242 CHIP_R200 "ATI Radeon BB R200 AIW 8500DV"
 0x1002 0x4243 CHIP_R200 "ATI Radeon BC R200"
-0x1002 0x4336 CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS100 Mobility U1"
-0x1002 0x4337 CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS200 Mobility IGP \
                340M"
-0x1002 0x4437 CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS250 Mobility \
IGP" +0x1002 0x4336 CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS100 \
Mobility U1" +0x1002 0x4337 CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon \
RS200 Mobility IGP 340M" +0x1002 0x4437 CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY \
"ATI Radeon RS250 Mobility IGP"  0x1002 0x4966 CHIP_RV250 "ATI Radeon If RV250 9000"
 0x1002 0x4967 CHIP_RV250 "ATI Radeon Ig RV250 9000"
-0x1002 0x4A48 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JH R420 X800"
-0x1002 0x4A49 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JI R420 X800 Pro"
-0x1002 0x4A4A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JJ R420 X800 SE"
-0x1002 0x4A4B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JK R420 X800 XT"
-0x1002 0x4A4C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JL R420 X800"
-0x1002 0x4A4D CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL JM X3-256"
-0x1002 0x4A4E CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon JN R420 \
                Mobility M18"
-0x1002 0x4A4F CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JO R420 X800 SE"
-0x1002 0x4A50 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JP R420 X800 XT PE"
-0x1002 0x4A54 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JT R420 AIW X800 VE"
-0x1002 0x4B49 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 XT"
-0x1002 0x4B4A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 SE"
-0x1002 0x4B4B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 Pro"
-0x1002 0x4B4C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 XT PE"
-0x1002 0x4C57 CHIP_RV200|CHIP_IS_MOBILITY "ATI Radeon LW RV200 Mobility 7500 M7"
-0x1002 0x4C58 CHIP_RV200|CHIP_IS_MOBILITY "ATI Radeon LX RV200 Mobility FireGL 7800 \
                M7"
-0x1002 0x4C59 CHIP_RV100|CHIP_IS_MOBILITY "ATI Radeon LY RV100 Mobility M6"
-0x1002 0x4C5A CHIP_RV100|CHIP_IS_MOBILITY "ATI Radeon LZ RV100 Mobility M6"
-0x1002 0x4C64 CHIP_RV250|CHIP_IS_MOBILITY "ATI Radeon Ld RV250 Mobility 9000 M9"
+0x1002 0x4A48 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JH R420 X800"
+0x1002 0x4A49 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JI R420 X800 Pro"
+0x1002 0x4A4A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JJ R420 X800 SE"
+0x1002 0x4A4B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JK R420 X800 XT"
+0x1002 0x4A4C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JL R420 X800"
+0x1002 0x4A4D CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL JM X3-256"
+0x1002 0x4A4E CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon JN R420 \
Mobility M18" +0x1002 0x4A4F CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JO R420 X800 SE"
+0x1002 0x4A50 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JP R420 X800 XT PE"
+0x1002 0x4A54 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JT R420 AIW X800 VE"
+0x1002 0x4B49 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 XT"
+0x1002 0x4B4A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 SE"
+0x1002 0x4B4B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 Pro"
+0x1002 0x4B4C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 XT PE"
+0x1002 0x4C57 CHIP_RV200|RADEON_IS_MOBILITY "ATI Radeon LW RV200 Mobility 7500 M7"
+0x1002 0x4C58 CHIP_RV200|RADEON_IS_MOBILITY "ATI Radeon LX RV200 Mobility FireGL \
7800 M7" +0x1002 0x4C59 CHIP_RV100|RADEON_IS_MOBILITY "ATI Radeon LY RV100 Mobility \
M6" +0x1002 0x4C5A CHIP_RV100|RADEON_IS_MOBILITY "ATI Radeon LZ RV100 Mobility M6"
+0x1002 0x4C64 CHIP_RV250|RADEON_IS_MOBILITY "ATI Radeon Ld RV250 Mobility 9000 M9"
 0x1002 0x4C66 CHIP_RV250 "ATI Radeon Lf RV250 Mobility 9000 M9 / FireMV 2400 PCI"
-0x1002 0x4C67 CHIP_RV250|CHIP_IS_MOBILITY "ATI Radeon Lg RV250 Mobility 9000 M9"
+0x1002 0x4C67 CHIP_RV250|RADEON_IS_MOBILITY "ATI Radeon Lg RV250 Mobility 9000 M9"
 0x1002 0x4E44 CHIP_R300 "ATI Radeon ND R300 9700 Pro"
 0x1002 0x4E45 CHIP_R300 "ATI Radeon NE R300 9500 Pro / 9700"
 0x1002 0x4E46 CHIP_R300 "ATI Radeon NF R300 9600TX"
@@ -58,16 +58,16 @@
 0x1002 0x4E49 CHIP_R350 "ATI Radeon NI R350 9800"
 0x1002 0x4E4A CHIP_R350 "ATI Radeon NJ R360 9800 XT"
 0x1002 0x4E4B CHIP_R350 "ATI FireGL NK X2"
-0x1002 0x4E50 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NP"
-0x1002 0x4E51 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NQ"
-0x1002 0x4E52 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M11 NR"
-0x1002 0x4E53 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NS"
-0x1002 0x4E54 CHIP_RV350|CHIP_IS_MOBILITY "ATI FireGL T2/T2e"
-0x1002 0x4E56 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon Mobility 9550"
-0x1002 0x5144 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QD R100"
-0x1002 0x5145 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QE R100"
-0x1002 0x5146 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QF R100"
-0x1002 0x5147 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QG R100"
+0x1002 0x4E50 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NP"
+0x1002 0x4E51 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NQ"
+0x1002 0x4E52 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M11 NR"
+0x1002 0x4E53 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NS"
+0x1002 0x4E54 CHIP_RV350|RADEON_IS_MOBILITY "ATI FireGL T2/T2e"
+0x1002 0x4E56 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon Mobility 9550"
+0x1002 0x5144 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QD R100"
+0x1002 0x5145 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QE R100"
+0x1002 0x5146 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QF R100"
+0x1002 0x5147 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QG R100"
 0x1002 0x5148 CHIP_R200 "ATI Radeon QH R200 8500"
 0x1002 0x514C CHIP_R200 "ATI Radeon QL R200 8500 LE"
 0x1002 0x514D CHIP_R200 "ATI Radeon QM R200 9100"
@@ -76,59 +76,59 @@
 0x1002 0x5159 CHIP_RV100 "ATI Radeon QY RV100 7000/VE"
 0x1002 0x515A CHIP_RV100 "ATI Radeon QZ RV100 7000/VE"
 0x1002 0x515E CHIP_RV100 "ATI ES1000 RN50"
-0x1002 0x5460 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X300 M22"
-0x1002 0x5462 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C"
-0x1002 0x5464 CHIP_RV380|CHIP_IS_MOBILITY "ATI FireGL M22 GL 5464"
-0x1002 0x5548 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800"
-0x1002 0x5549 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 Pro"
-0x1002 0x554A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 XT PE"
-0x1002 0x554B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 SE"
-0x1002 0x554C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 XTP"
-0x1002 0x554D CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 XL"
-0x1002 0x554E CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 SE"
-0x1002 0x554F CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800"
-0x1002 0x5550 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL V7100 R423"
-0x1002 0x5551 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL V5100 R423 UQ"
-0x1002 0x5552 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL unknown R423 UR"
-0x1002 0x5554 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL unknown R423 UT"
-0x1002 0x564A CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5000 \
                M26"
-0x1002 0x564B CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5000 \
                M26"
-0x1002 0x564F CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 \
                XL M26"
-0x1002 0x5652 CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 \
                M26"
-0x1002 0x5653 CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 \
                M26"
-0x1002 0x5834 CHIP_RS300|CHIP_IS_IGP "ATI Radeon RS300 9100 IGP"
-0x1002 0x5835 CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS300 Mobility \
IGP" +0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22"
+0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C"
+0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464"
+0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800"
+0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro"
+0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE"
+0x1002 0x554B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 SE"
+0x1002 0x554C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XTP"
+0x1002 0x554D CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XL"
+0x1002 0x554E CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 SE"
+0x1002 0x554F CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800"
+0x1002 0x5550 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V7100 R423"
+0x1002 0x5551 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V5100 R423 UQ"
+0x1002 0x5552 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UR"
+0x1002 0x5554 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UT"
+0x1002 0x564A CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL \
V5000 M26" +0x1002 0x564B CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI \
Mobility FireGL V5000 M26" +0x1002 0x564F \
CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 XL M26" \
+0x1002 0x5652 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility \
X700 M26" +0x1002 0x5653 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon \
Mobility X700 M26" +0x1002 0x5834 CHIP_RS300|RADEON_IS_IGP "ATI Radeon RS300 9100 \
IGP" +0x1002 0x5835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS300 \
Mobility IGP"  0x1002 0x5960 CHIP_RV280 "ATI Radeon RV280 9250"
 0x1002 0x5961 CHIP_RV280 "ATI Radeon RV280 9200"
 0x1002 0x5962 CHIP_RV280 "ATI Radeon RV280 9200"
 0x1002 0x5964 CHIP_RV280 "ATI Radeon RV280 9200 SE"
 0x1002 0x5965 CHIP_RV280 "ATI FireMV 2200 PCI"
 0x1002 0x5969 CHIP_RV100 "ATI ES1000 RN50"
-0x1002 0x5b60 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X300 SE"
-0x1002 0x5b62 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X600 Pro"
-0x1002 0x5b63 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X550"
-0x1002 0x5b64 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireGL V3100 (RV370) 5B64"
-0x1002 0x5b65 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireMV 2200 PCIE (RV370) 5B65"
-0x1002 0x5c61 CHIP_RV280|CHIP_IS_MOBILITY "ATI Radeon RV280 Mobility"
-0x1002 0x5c63 CHIP_RV280|CHIP_IS_MOBILITY "ATI Radeon RV280 Mobility"
-0x1002 0x5d48 CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility Radeon X800 \
                XT M28"
-0x1002 0x5d49 CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5100 \
                M28"
-0x1002 0x5d4a CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility Radeon X800 \
                M28"
-0x1002 0x5d4c CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850"
-0x1002 0x5d4d CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 XT PE"
-0x1002 0x5d4e CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 SE"
-0x1002 0x5d4f CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 Pro"
-0x1002 0x5d50 CHIP_R420|CHIP_NEW_MEMMAP "ATI unknown Radeon / FireGL R480"
-0x1002 0x5d52 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 XT"
-0x1002 0x5d57 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 XT"
-0x1002 0x5e48 CHIP_RV410|CHIP_NEW_MEMMAP "ATI FireGL V5000 RV410"
-0x1002 0x5e4a CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 XT"
-0x1002 0x5e4b CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 Pro"
-0x1002 0x5e4c CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 SE"
-0x1002 0x5e4d CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700"
-0x1002 0x5e4f CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 SE"
-0x1002 0x7834 CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP "ATI Radeon RS350 9000/9100 \
                IGP"
-0x1002 0x7835 CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon \
RS350 Mobility IGP" +0x1002 0x5b60 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 \
X300 SE" +0x1002 0x5b62 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X600 Pro"
+0x1002 0x5b63 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550"
+0x1002 0x5b64 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireGL V3100 (RV370) 5B64"
+0x1002 0x5b65 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireMV 2200 PCIE (RV370) 5B65"
+0x1002 0x5c61 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility"
+0x1002 0x5c63 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility"
+0x1002 0x5d48 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon \
X800 XT M28" +0x1002 0x5d49 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI \
Mobility FireGL V5100 M28" +0x1002 0x5d4a \
CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 M28" +0x1002 \
0x5d4c CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850" +0x1002 0x5d4d \
CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT PE" +0x1002 0x5d4e \
CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 SE" +0x1002 0x5d4f \
CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 Pro" +0x1002 0x5d50 \
CHIP_R420|RADEON_NEW_MEMMAP "ATI unknown Radeon / FireGL R480" +0x1002 0x5d52 \
CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT" +0x1002 0x5d57 \
CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT" +0x1002 0x5e48 \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI FireGL V5000 RV410" +0x1002 0x5e4a \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 XT" +0x1002 0x5e4b \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 Pro" +0x1002 0x5e4c \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 SE" +0x1002 0x5e4d \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700" +0x1002 0x5e4f \
CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 SE" +0x1002 0x7834 \
CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP "ATI Radeon RS350 9000/9100 IGP" +0x1002 \
0x7835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon \
RS350 Mobility IGP"  
 [r128]
 0x1002 0x4c45 0 "ATI Rage 128 Mobility LE (PCI)"
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
index 4e7b282..4135f4d 100644
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(d
 			     | (dev_priv->fb_location >> 16));
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
 			     (((dev_priv->gart_vm_start - 1 +
@@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(d
 	dev_priv->ring.tail = cur_read_ptr;
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
 			     dev_priv->ring_rptr->offset
 			     - dev->agp->base + dev_priv->gart_vm_start);
@@ -1301,7 +1301,7 @@ static void radeon_set_pcigart(drm_radeo
 {
 	u32 tmp;
 
-	if (dev_priv->flags & CHIP_IS_PCIE) {
+	if (dev_priv->flags & RADEON_IS_PCIE) {
 		radeon_set_pciegart(dev_priv, on);
 		return;
 	}
@@ -1339,26 +1339,26 @@ static int radeon_do_init_cp(drm_device_
 	DRM_DEBUG("\n");
 
 	/* if we require new memory map but we don't have it fail */
-	if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
+	if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap)
 	{
 		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX \
for 3D\n");  radeon_do_cleanup_cp(dev);
 		return DRM_ERR(EINVAL);
 	}
 
-	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
+	if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP))
 	{
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
-		dev_priv->flags &= ~CHIP_IS_AGP;
+		dev_priv->flags &= ~RADEON_IS_AGP;
 	}
-	else if (!(dev_priv->flags & (CHIP_IS_AGP | CHIP_IS_PCI | CHIP_IS_PCIE))
+	else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
 		 && !init->is_pci)
 	{
 		DRM_DEBUG("Restoring AGP flag\n");
-		dev_priv->flags |= CHIP_IS_AGP;
+		dev_priv->flags |= RADEON_IS_AGP;
 	}
 
-	if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) {
+	if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
 		DRM_ERROR("PCI GART memory not allocated!\n");
 		radeon_do_cleanup_cp(dev);
 		return DRM_ERR(EINVAL);
@@ -1501,7 +1501,7 @@ static int radeon_do_init_cp(drm_device_
 				    init->sarea_priv_offset);
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		drm_core_ioremap(dev_priv->cp_ring, dev);
 		drm_core_ioremap(dev_priv->ring_rptr, dev);
 		drm_core_ioremap(dev->agp_buffer_map, dev);
@@ -1560,7 +1560,7 @@ static int radeon_do_init_cp(drm_device_
 		 * align it down.
 		 */
 #if __OS_HAS_AGP
-		if (dev_priv->flags & CHIP_IS_AGP) {
+		if (dev_priv->flags & RADEON_IS_AGP) {
 			base = dev->agp->base;
 			/* Check if valid */
 			if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
@@ -1590,7 +1590,7 @@ static int radeon_do_init_cp(drm_device_
 	}
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP)
+	if (dev_priv->flags & RADEON_IS_AGP)
 		dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
 						 - dev->agp->base
 						 + dev_priv->gart_vm_start);
@@ -1616,7 +1616,7 @@ static int radeon_do_init_cp(drm_device_
 	dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		/* Turn off PCI GART */
 		radeon_set_pcigart(dev_priv, 0);
 	} else
@@ -1636,7 +1636,7 @@ static int radeon_do_init_cp(drm_device_
 			    dev_priv->gart_info.mapping.handle;
 
 			dev_priv->gart_info.is_pcie =
-			    !!(dev_priv->flags & CHIP_IS_PCIE);
+			    !!(dev_priv->flags & RADEON_IS_PCIE);
 			dev_priv->gart_info.gart_table_location =
 			    DRM_ATI_GART_FB;
 
@@ -1648,7 +1648,7 @@ static int radeon_do_init_cp(drm_device_
 			    DRM_ATI_GART_MAIN;
 			dev_priv->gart_info.addr = NULL;
 			dev_priv->gart_info.bus_addr = 0;
-			if (dev_priv->flags & CHIP_IS_PCIE) {
+			if (dev_priv->flags & RADEON_IS_PCIE) {
 				DRM_ERROR
 				    ("Cannot use PCI Express without GART in FB memory\n");
 				radeon_do_cleanup_cp(dev);
@@ -1690,7 +1690,7 @@ static int radeon_do_cleanup_cp(drm_devi
 		drm_irq_uninstall(dev);
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		if (dev_priv->cp_ring != NULL) {
 			drm_core_ioremapfree(dev_priv->cp_ring, dev);
 			dev_priv->cp_ring = NULL;
@@ -1745,7 +1745,7 @@ static int radeon_do_resume_cp(drm_devic
 	DRM_DEBUG("Starting radeon_do_resume_cp()\n");
 
 #if __OS_HAS_AGP
-	if (dev_priv->flags & CHIP_IS_AGP) {
+	if (dev_priv->flags & RADEON_IS_AGP) {
 		/* Turn off PCI GART */
 		radeon_set_pcigart(dev_priv, 0);
 	} else
@@ -2194,7 +2194,7 @@ int radeon_driver_load(struct drm_device
 	dev->dev_private = (void *)dev_priv;
 	dev_priv->flags = flags;
 
-	switch (flags & CHIP_FAMILY_MASK) {
+	switch (flags & RADEON_FAMILY_MASK) {
 	case CHIP_R100:
 	case CHIP_RV200:
 	case CHIP_R200:
@@ -2202,7 +2202,7 @@ int radeon_driver_load(struct drm_device
 	case CHIP_R350:
 	case CHIP_R420:
 	case CHIP_RV410:
-		dev_priv->flags |= CHIP_HAS_HIERZ;
+		dev_priv->flags |= RADEON_HAS_HIERZ;
 		break;
 	default:
 		/* all other chips have no hierarchical z buffer */
@@ -2210,14 +2210,14 @@ int radeon_driver_load(struct drm_device
 	}
 
 	if (drm_device_is_agp(dev))
-		dev_priv->flags |= CHIP_IS_AGP;
+		dev_priv->flags |= RADEON_IS_AGP;
 	else if (drm_device_is_pcie(dev))
-		dev_priv->flags |= CHIP_IS_PCIE;
+		dev_priv->flags |= RADEON_IS_PCIE;
 	else
-		dev_priv->flags |= CHIP_IS_PCI;
+		dev_priv->flags |= RADEON_IS_PCI;
 
 	DRM_DEBUG("%s card detected\n",
-		  ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? \
"PCIE" : "PCI")))); +		  ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : \
(((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));  return ret;
 }
 
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 5fa8254..5fc9331 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -134,16 +134,16 @@ enum radeon_cp_microcode_version {
  * Chip flags
  */
 enum radeon_chip_flags {
-	CHIP_FAMILY_MASK = 0x0000ffffUL,
-	CHIP_FLAGS_MASK = 0xffff0000UL,
-	CHIP_IS_MOBILITY = 0x00010000UL,
-	CHIP_IS_IGP = 0x00020000UL,
-	CHIP_SINGLE_CRTC = 0x00040000UL,
-	CHIP_IS_AGP = 0x00080000UL,
-	CHIP_HAS_HIERZ = 0x00100000UL,
-	CHIP_IS_PCIE = 0x00200000UL,
-	CHIP_NEW_MEMMAP = 0x00400000UL,
-	CHIP_IS_PCI = 0x00800000UL,
+	RADEON_FAMILY_MASK = 0x0000ffffUL,
+	RADEON_FLAGS_MASK = 0xffff0000UL,
+	RADEON_IS_MOBILITY = 0x00010000UL,
+	RADEON_IS_IGP = 0x00020000UL,
+	RADEON_SINGLE_CRTC = 0x00040000UL,
+	RADEON_IS_AGP = 0x00080000UL,
+	RADEON_HAS_HIERZ = 0x00100000UL,
+	RADEON_IS_PCIE = 0x00200000UL,
+	RADEON_NEW_MEMMAP = 0x00400000UL,
+	RADEON_IS_PCI = 0x00800000UL,
 };
 
 #define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index 8c1a406..0a196c0 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm
 		 */
 		dev_priv->sarea_priv->ctx_owner = 0;
 
-		if ((dev_priv->flags & CHIP_HAS_HIERZ)
+		if ((dev_priv->flags & RADEON_HAS_HIERZ)
 		    && (flags & RADEON_USE_HIERZ)) {
 			/* FIXME : reverse engineer that for Rx00 cards */
 			/* FIXME : the mask supposedly contains low-res z values. So can't set
@@ -906,7 +906,7 @@ static void radeon_cp_dispatch_clear(drm
 		for (i = 0; i < nbox; i++) {
 			int tileoffset, nrtilesx, nrtilesy, j;
 			/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
-			if ((dev_priv->flags & CHIP_HAS_HIERZ)
+			if ((dev_priv->flags & RADEON_HAS_HIERZ)
 			    && !(dev_priv->microcode_version == UCODE_R200)) {
 				/* FIXME : figure this out for r200 (when hierz is enabled). Or
 				   maybe r200 actually doesn't need to put the low-res z value into
@@ -990,7 +990,7 @@ static void radeon_cp_dispatch_clear(drm
 		}
 
 		/* TODO don't always clear all hi-level z tiles */
-		if ((dev_priv->flags & CHIP_HAS_HIERZ)
+		if ((dev_priv->flags & RADEON_HAS_HIERZ)
 		    && (dev_priv->microcode_version == UCODE_R200)
 		    && (flags & RADEON_USE_HIERZ))
 			/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
@@ -3031,9 +3031,9 @@ static int radeon_cp_getparam(DRM_IOCTL_
 		break;
 	
 	case RADEON_PARAM_CARD_TYPE:
-		if (dev_priv->flags & CHIP_IS_PCIE)
+		if (dev_priv->flags & RADEON_IS_PCIE)
 			value = RADEON_CARD_PCIE;
-		else if (dev_priv->flags & CHIP_IS_AGP)
+		else if (dev_priv->flags & RADEON_IS_AGP)
 			value = RADEON_CARD_AGP;
 		else
 			value = RADEON_CARD_PCI;
diff-tree dddacd7a3a4bd0c453b346cee70d1d36a401e539 (from \
                55057660f035a03078910d678e5fd9b0cb0b795a)
Author: Eric Anholt <eric@anholt.net>
Date:   Wed Sep 6 23:26:50 2006 -0700

    Use the DRM_INIT_WAITQUEUE argument (needed on Linux) to avoid a warning.

diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index 6fa3973..9ebb12a 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -170,7 +170,7 @@ MALLOC_DECLARE(M_DRM);
 #define wait_queue_head_t	atomic_t
 #define DRM_WAKEUP(w)		wakeup((void *)w)
 #define DRM_WAKEUP_INT(w)	wakeup(w)
-#define DRM_INIT_WAITQUEUE(queue) do {} while (0)
+#define DRM_INIT_WAITQUEUE(queue) do {(void)(queue);} while (0)
 
 #if defined(__FreeBSD__) && __FreeBSD_version < 502109
 #define bus_alloc_resource_any(dev, type, rid, flags) \
diff-tree 55057660f035a03078910d678e5fd9b0cb0b795a (from \
                d5726761858b1ff0fd6e6ee92ec1648fbb958a53)
Author: Eric Anholt <eric@anholt.net>
Date:   Wed Sep 6 23:25:14 2006 -0700

    Put the PCI device/vendor id in the drm_device_t.
    
    This helps us unbreak FreeBSD DRM from the 965 changes.

diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index e6c1d06..6fa3973 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -714,6 +714,9 @@ struct drm_device {
 	struct drm_driver_info driver;
 	drm_pci_id_list_t *id_entry;	/* PCI ID, name, and chipset private */
 
+	u_int16_t pci_device;		/* PCI device id */
+	u_int16_t pci_vendor;		/* PCI vendor id */
+
 	char		  *unique;	/* Unique identifier: e.g., busid  */
 	int		  unique_len;	/* Length of unique field	   */
 #ifdef __FreeBSD__
diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c
index 3f53a72..9fb10c5 100644
--- a/bsd-core/drm_drv.c
+++ b/bsd-core/drm_drv.c
@@ -516,6 +516,9 @@ static int drm_load(drm_device_t *dev)
 	dev->pci_slot = pci_get_slot(dev->device);
 	dev->pci_func = pci_get_function(dev->device);
 
+	dev->pci_vendor = pci_get_vendor(dev->device);
+	dev->pci_device = pci_get_device(dev->device);
+
 	TAILQ_INIT(&dev->maplist);
 
 	drm_mem_init();
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 6046dde..70bf349 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -747,6 +747,8 @@ typedef struct drm_device {
 	drm_agp_head_t *agp;		/**< AGP data */
 
 	struct pci_dev *pdev;		/**< PCI device structure */
+	int pci_vendor;			/**< PCI vendor id */
+	int pci_device;			/**< PCI device id */
 #ifdef __alpha__
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
 	struct pci_controler *hose;
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index bdc3655..4708222 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -66,6 +66,8 @@ static int drm_fill_in_dev(drm_device_t 
 	mutex_init(&dev->ctxlist_mutex);
 
 	dev->pdev = pdev;
+	dev->pci_device = pdev->device;
+	dev->pci_vendor = pdev->vendor;
 
 #ifdef __alpha__
 	dev->hose = pdev->sysdata;
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index ba8c56e..3863490 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -31,10 +31,10 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#define IS_I965G(dev)  (dev->pdev->device == 0x2972 || \
-			dev->pdev->device == 0x2982 || \
-			dev->pdev->device == 0x2992 || \
-			dev->pdev->device == 0x29A2)
+#define IS_I965G(dev)  (dev->pci_device == 0x2972 || \
+			dev->pci_device == 0x2982 || \
+			dev->pci_device == 0x2992 || \
+			dev->pci_device == 0x29A2)
 
 
 /* Really want an OS-independent resettable timer.  Would like to have
diff-tree d5726761858b1ff0fd6e6ee92ec1648fbb958a53 (from \
                9b984b34e99f694e10251e15bc2ec1bc844dcca4)
Author: Eric Anholt <eric@anholt.net>
Date:   Wed Sep 6 23:08:29 2006 -0700

    Add a typedef for u64.

diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index 074e1d2..e6c1d06 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -270,6 +270,7 @@ extern struct cfdriver drm_cd;
 #endif
 
 typedef unsigned long dma_addr_t;
+typedef u_int64_t u64;
 typedef u_int32_t u32;
 typedef u_int16_t u16;
 typedef u_int8_t u8;



-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

--
_______________________________________________
Dri-patches mailing list
Dri-patches@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-patches


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic