patch-2.4.23 linux-2.4.23/drivers/char/drm/i830_dma.c

Next file: linux-2.4.23/drivers/char/drm/i830_drm.h
Previous file: linux-2.4.23/drivers/char/drm/i830.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/char/drm/i830_dma.c linux-2.4.23/drivers/char/drm/i830_dma.c
@@ -26,20 +26,22 @@
  *
  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
  *	    Jeff Hartmann <jhartmann@valinux.com>
- *      Keith Whitwell <keithw@valinux.com>
- *      Abraham vd Merwe <abraham@2d3d.co.za>
+ *	    Keith Whitwell <keith@tungstengraphics.com>
+ *	    Abraham vd Merwe <abraham@2d3d.co.za>
  *
  */
 
+
 #include "i830.h"
 #include "drmP.h"
+#include "drm.h"
+#include "i830_drm.h"
 #include "i830_drv.h"
 #include <linux/interrupt.h>	/* For task queue support */
+#include <linux/pagemap.h>     /* For FASTCALL on unlock_page() */
 #include <linux/delay.h>
-/* in case we don't have a 2.3.99-pre6 kernel or later: */
-#ifndef VM_DONTCOPY
-#define VM_DONTCOPY 0
-#endif
+
+#define DO_MUNMAP(m, a, l)	do_munmap(m, a, l)
 
 #define I830_BUF_FREE		2
 #define I830_BUF_CLIENT		1
@@ -48,54 +50,24 @@
 #define I830_BUF_UNMAPPED 0
 #define I830_BUF_MAPPED   1
 
-#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
 
 
-#define DO_IDLE_WORKAROUND()					\
-do {								\
-   int _head;							\
-   int _tail;							\
-   do { 							\
-      _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;	\
-      _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;	\
-      udelay(1);						\
-   } while(_head != _tail);					\
-} while(0)
-
-#define I830_SYNC_WORKAROUND 0
-
-#define BEGIN_LP_RING(n) do {				\
-	if (I830_VERBOSE)				\
-		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
-			  n, __FUNCTION__);		\
-	if (I830_SYNC_WORKAROUND)			\
-		DO_IDLE_WORKAROUND();			\
-	if (dev_priv->ring.space < n*4) 		\
-		i830_wait_ring(dev, n*4);		\
-	dev_priv->ring.space -= n*4;			\
-	outring = dev_priv->ring.tail;			\
-	ringmask = dev_priv->ring.tail_mask;		\
-	virt = dev_priv->ring.virtual_start;		\
-} while (0)
-
-#define ADVANCE_LP_RING() do {					\
-	if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\
-	dev_priv->ring.tail = outring;				\
-	I830_WRITE(LP_RING + RING_TAIL, outring);		\
-} while(0)
-
-#define OUT_RING(n) do {						\
-	if (I830_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
-	*(volatile unsigned int *)(virt + outring) = n;			\
-	outring += 4;							\
-	outring &= ringmask;						\
-} while (0);
+
+
+
+
+
+
+
+
+
+
 
 static inline void i830_print_status_page(drm_device_t *dev)
 {
    	drm_device_dma_t *dma = dev->dma;
       	drm_i830_private_t *dev_priv = dev->dev_private;
-	u8 *temp = dev_priv->hw_status_page;
+	u32 *temp = (u32 *)dev_priv->hw_status_page;
    	int i;
 
    	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
@@ -149,14 +121,14 @@
 }
 
 static struct file_operations i830_buffer_fops = {
-	open:	 DRM(open),
-	flush:	 DRM(flush),
-	release: DRM(release),
-	ioctl:	 DRM(ioctl),
-	mmap:	 i830_mmap_buffers,
-	read:	 DRM(read),
-	fasync:	 DRM(fasync),
-      	poll:	 DRM(poll),
+	.open	 = DRM(open),
+	.flush	 = DRM(flush),
+	.release = DRM(release),
+	.ioctl	 = DRM(ioctl),
+	.mmap	 = i830_mmap_buffers,
+	.read	 = DRM(read),
+	.fasync  = DRM(fasync),
+      	.poll	 = DRM(poll),
 };
 
 int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
@@ -179,7 +151,7 @@
    	buf_priv->currently_mapped = I830_BUF_MAPPED;
 	unlock_kernel();
 
-	if (remap_page_range(vma->vm_start,
+	if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
 			     VM_OFFSET(vma),
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot)) return -EAGAIN;
@@ -197,28 +169,24 @@
 
 	if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
 
-	if(VM_DONTCOPY != 0) {
-		down_write( &current->mm->mmap_sem );
-		old_fops = filp->f_op;
-		filp->f_op = &i830_buffer_fops;
-		dev_priv->mmap_buffer = buf;
-		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
-						    PROT_READ|PROT_WRITE,
-						    MAP_SHARED, 
-						    buf->bus_address);
-		dev_priv->mmap_buffer = NULL;
-   		filp->f_op = old_fops;
-		if ((unsigned long)buf_priv->virtual > -1024UL) {
-			/* Real error */
-			DRM_DEBUG("mmap error\n");
-			retcode = (signed int)buf_priv->virtual;
-			buf_priv->virtual = 0;
-		}
-		up_write( &current->mm->mmap_sem );
-	} else {
-		buf_priv->virtual = buf_priv->kernel_virtual;
-   		buf_priv->currently_mapped = I830_BUF_MAPPED;
+	down_write( &current->mm->mmap_sem );
+	old_fops = filp->f_op;
+	filp->f_op = &i830_buffer_fops;
+	dev_priv->mmap_buffer = buf;
+	buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+					    PROT_READ|PROT_WRITE,
+					    MAP_SHARED, 
+					    buf->bus_address);
+	dev_priv->mmap_buffer = NULL;
+	filp->f_op = old_fops;
+	if ((unsigned long)buf_priv->virtual > -1024UL) {
+		/* Real error */
+		DRM_ERROR("mmap error\n");
+		retcode = (signed int)buf_priv->virtual;
+		buf_priv->virtual = 0;
 	}
+	up_write( &current->mm->mmap_sem );
+
 	return retcode;
 }
 
@@ -227,15 +195,15 @@
 	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
 	int retcode = 0;
 
-	if(VM_DONTCOPY != 0) {
-		if(buf_priv->currently_mapped != I830_BUF_MAPPED) 
-			return -EINVAL;
-		down_write( &current->mm->mmap_sem );
-        	retcode = do_munmap(current->mm, 
-				    (unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
-   		up_write( &current->mm->mmap_sem );
-	}
+	if(buf_priv->currently_mapped != I830_BUF_MAPPED) 
+		return -EINVAL;
+
+	down_write(&current->mm->mmap_sem);
+	retcode = DO_MUNMAP(current->mm,
+			    (unsigned long)buf_priv->virtual,
+			    (size_t) buf->total);
+	up_write(&current->mm->mmap_sem);
+
    	buf_priv->currently_mapped = I830_BUF_UNMAPPED;
    	buf_priv->virtual = 0;
 
@@ -260,7 +228,7 @@
 	retcode = i830_map_buffer(buf, filp);
 	if(retcode) {
 		i830_freelist_put(dev, buf);
-	   	DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+	   	DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
 		return retcode;
 	}
 	buf->pid     = priv->pid;
@@ -286,12 +254,22 @@
 		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
 					 dev_priv->ring.Size);
 		}
-	   	if(dev_priv->hw_status_page != NULL) {
-	   		pci_free_consistent(dev->pdev, PAGE_SIZE, 
-	   		    dev_priv->hw_status_page, dev_priv->dma_status_page);
+	   	if(dev_priv->hw_status_page != 0UL) {
+			pci_free_consistent(dev->pdev, PAGE_SIZE,
+					    (void *)dev_priv->hw_status_page,
+					    dev_priv->dma_status_page);
 		   	/* Need to rewrite hardware status page */
 		   	I830_WRITE(0x02080, 0x1ffff000);
 		}
+
+		/* Disable interrupts here because after dev_private
+		 * is freed, it's too late.
+		 */
+		if (dev->irq) {
+			I830_WRITE16( I830REG_INT_MASK_R, 0xffff );
+			I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 );
+		}
+
 	   	DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), 
 			 DRM_MEM_DRIVER);
 	   	dev->dev_private = NULL;
@@ -305,7 +283,7 @@
    	return 0;
 }
 
-static int i830_wait_ring(drm_device_t *dev, int n)
+int i830_wait_ring(drm_device_t *dev, int n, const char *caller)
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
    	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
@@ -314,7 +292,7 @@
 	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 
 	end = jiffies + (HZ*3);
-   	while (ring->space < n) {
+   	while (ring->space < n) {	
 	   	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
 	   	ring->space = ring->head - (ring->tail+8);
 		if (ring->space < 0) ring->space += ring->Size;
@@ -325,13 +303,13 @@
 		}
 	  
 	   	iters++;
-		if(time_before(end,jiffies)) {
+		if(time_before(end, jiffies)) {
 		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
 		   	DRM_ERROR("lockup\n");
 		   	goto out_wait_ring;
 		}
-
-	   	udelay(1);
+		udelay(1);
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
 	}
 
 out_wait_ring:   
@@ -344,9 +322,12 @@
    	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
       
    	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-     	ring->tail = I830_READ(LP_RING + RING_TAIL);
+     	ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
      	ring->space = ring->head - (ring->tail+8);
      	if (ring->space < 0) ring->space += ring->Size;
+
+	if (ring->head == ring->tail)
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
 }
 
 static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
@@ -420,9 +401,6 @@
 		((u8 *)dev_priv->sarea_map->handle +
 		 init->sarea_priv_offset);
 
-   	atomic_set(&dev_priv->flush_done, 0);
-	init_waitqueue_head(&dev_priv->flush_queue);
-
    	dev_priv->ring.Start = init->ring_start;
    	dev_priv->ring.End = init->ring_end;
    	dev_priv->ring.Size = init->ring_size;
@@ -446,11 +424,17 @@
 	dev_priv->pitch = init->pitch;
 	dev_priv->back_offset = init->back_offset;
 	dev_priv->depth_offset = init->depth_offset;
+	dev_priv->front_offset = init->front_offset;
 
 	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
 	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
 	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
 
+	DRM_DEBUG("front_di1 %x\n",    dev_priv->front_di1);
+	DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
+	DRM_DEBUG("back_di1 %x\n",    dev_priv->back_di1);
+	DRM_DEBUG("pitch_bits %x\n",    init->pitch_bits);
+
 	dev_priv->cpp = init->cpp;
 	/* We are using seperate values as placeholders for mechanisms for
 	 * private backbuffer/depthbuffer usage.
@@ -458,20 +442,23 @@
 
 	dev_priv->back_pitch = init->back_pitch;
 	dev_priv->depth_pitch = init->depth_pitch;
+	dev_priv->do_boxes = 0;
+	dev_priv->use_mi_batchbuffer_start = 0;
 
    	/* Program Hardware Status Page */
-   	dev_priv->hw_status_page = pci_alloc_consistent(dev->pdev, PAGE_SIZE, 
+   	dev_priv->hw_status_page =
+		(unsigned long) pci_alloc_consistent(dev->pdev, PAGE_SIZE,
 						&dev_priv->dma_status_page);
-   	if(dev_priv->hw_status_page == NULL) {
+   	if(dev_priv->hw_status_page == 0UL) {
 		dev->dev_private = (void *)dev_priv;
 		i830_dma_cleanup(dev);
 		DRM_ERROR("Can not allocate hardware status page\n");
 		return -ENOMEM;
 	}
-   	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+   	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
    
-   	I830_WRITE(0x02080, dev_priv->dma_status_page);
+	I830_WRITE(0x02080, dev_priv->dma_status_page);
 	DRM_DEBUG("Enabled hardware status page\n");
    
    	/* Now we need to init our freelist */
@@ -517,83 +504,107 @@
    	return retcode;
 }
 
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define ST1_ENABLE               (1<<16)
+#define ST1_MASK                 (0xffff)
+
 /* Most efficient way to verify state for the i830 is as it is
  * emitted.  Non-conformant state is silently dropped.
- *
- * Use 'volatile' & local var tmp to force the emitted values to be
- * identical to the verified ones.
  */
-static void i830EmitContextVerified( drm_device_t *dev, 
-				     volatile unsigned int *code )
+static void i830EmitContextVerified( drm_device_t *dev,
+				     unsigned int *code )
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_CTX_SETUP_SIZE );
-	for ( i = 0 ; i < I830_CTX_SETUP_SIZE ; i++ ) {
+	BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 4 );
+
+	for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) {
 		tmp = code[i];
+		if ((tmp & (7<<29)) == CMD_3D &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) {
+			OUT_RING( tmp ); 
+			j++;
+		} else {
+			DRM_ERROR("Skipping %d\n", i);
+		}
+	}
 
-#if 0
-		if ((tmp & (7<<29)) == (3<<29) &&
+	OUT_RING( STATE3D_CONST_BLEND_COLOR_CMD ); 
+	OUT_RING( code[I830_CTXREG_BLENDCOLR] ); 
+	j += 2;
+
+	for ( i = I830_CTXREG_VF ; i < I830_CTXREG_MCSB0 ; i++ ) {
+		tmp = code[i];
+		if ((tmp & (7<<29)) == CMD_3D &&
 		    (tmp & (0x1f<<24)) < (0x1d<<24)) {
 			OUT_RING( tmp ); 
 			j++;
 		} else {
-			printk("Skipping %d\n", i);
+			DRM_ERROR("Skipping %d\n", i);
 		}
-#else
-		OUT_RING( tmp ); 
-		j++;
-#endif
 	}
 
+	OUT_RING( STATE3D_MAP_COORD_SETBIND_CMD ); 
+	OUT_RING( code[I830_CTXREG_MCSB1] ); 
+	j += 2;
+
 	if (j & 1) 
 		OUT_RING( 0 ); 
 
 	ADVANCE_LP_RING();
 }
 
-static void i830EmitTexVerified( drm_device_t *dev, 
-				 volatile unsigned int *code ) 
+static void i830EmitTexVerified( drm_device_t *dev, unsigned int *code ) 
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
-
-	OUT_RING( GFX_OP_MAP_INFO );
-	OUT_RING( code[I830_TEXREG_MI1] );
-	OUT_RING( code[I830_TEXREG_MI2] );
-	OUT_RING( code[I830_TEXREG_MI3] );
-	OUT_RING( code[I830_TEXREG_MI4] );
-	OUT_RING( code[I830_TEXREG_MI5] );
-
-	for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
-		tmp = code[i];
-		OUT_RING( tmp ); 
-		j++;
-	} 
+	if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
+	    (code[I830_TEXREG_MI0] & ~(0xf*LOAD_TEXTURE_MAP0)) == 
+	    (STATE3D_LOAD_STATE_IMMEDIATE_2|4)) {
+
+		BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
+
+		OUT_RING( code[I830_TEXREG_MI0] ); /* TM0LI */
+		OUT_RING( code[I830_TEXREG_MI1] ); /* TM0S0 */
+		OUT_RING( code[I830_TEXREG_MI2] ); /* TM0S1 */
+		OUT_RING( code[I830_TEXREG_MI3] ); /* TM0S2 */
+		OUT_RING( code[I830_TEXREG_MI4] ); /* TM0S3 */
+		OUT_RING( code[I830_TEXREG_MI5] ); /* TM0S4 */
+		
+		for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
+			tmp = code[i];
+			OUT_RING( tmp ); 
+			j++;
+		} 
 
-	if (j & 1) 
-		OUT_RING( 0 ); 
+		if (j & 1) 
+			OUT_RING( 0 ); 
 
-	ADVANCE_LP_RING();
+		ADVANCE_LP_RING();
+	}
+	else
+		printk("rejected packet %x\n", code[0]);
 }
 
 static void i830EmitTexBlendVerified( drm_device_t *dev, 
-				     volatile unsigned int *code,
-				     volatile unsigned int num)
+				      unsigned int *code,
+				      unsigned int num)
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	int i, j = 0;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( num );
+	if (!num)
+		return;
+
+	BEGIN_LP_RING( num + 1 );
 
 	for ( i = 0 ; i < num ; i++ ) {
 		tmp = code[i];
@@ -616,6 +627,8 @@
 	int i;
 	RING_LOCALS;
 
+	return; /* Is this right ? -- Arjan */
+
 	BEGIN_LP_RING( 258 );
 
 	if(is_shared == 1) {
@@ -629,44 +642,43 @@
 		OUT_RING(palette[i]);
 	}
 	OUT_RING(0);
+	/* KW:  WHERE IS THE ADVANCE_LP_RING?  This is effectively a noop! 
+	 */
 }
 
 /* Need to do some additional checking when setting the dest buffer.
  */
 static void i830EmitDestVerified( drm_device_t *dev, 
-				  volatile unsigned int *code ) 
+				  unsigned int *code ) 
 {	
    	drm_i830_private_t *dev_priv = dev->dev_private;
 	unsigned int tmp;
 	RING_LOCALS;
 
-	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 );
+	BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 10 );
+
 
 	tmp = code[I830_DESTREG_CBUFADDR];
-	if (tmp == dev_priv->front_di1) {
-		/* Don't use fence when front buffer rendering */
-		OUT_RING( CMD_OP_DESTBUFFER_INFO );
-		OUT_RING( BUF_3D_ID_COLOR_BACK | 
-			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) );
-		OUT_RING( tmp );
+	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
+		if (((int)outring) & 8) {
+			OUT_RING(0);
+			OUT_RING(0);
+		}
 
 		OUT_RING( CMD_OP_DESTBUFFER_INFO );
-		OUT_RING( BUF_3D_ID_DEPTH |
-			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
-		OUT_RING( dev_priv->zi1 );
-	} else if(tmp == dev_priv->back_di1) {
-		OUT_RING( CMD_OP_DESTBUFFER_INFO );
 		OUT_RING( BUF_3D_ID_COLOR_BACK | 
 			  BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
 			  BUF_3D_USE_FENCE);
 		OUT_RING( tmp );
+		OUT_RING( 0 );
 
 		OUT_RING( CMD_OP_DESTBUFFER_INFO );
 		OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | 
 			  BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
 		OUT_RING( dev_priv->zi1 );
+		OUT_RING( 0 );
 	} else {
-		DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+		DRM_ERROR("bad di1 %x (allow %x or %x)\n",
 			  tmp, dev_priv->front_di1, dev_priv->back_di1);
 	}
 
@@ -688,25 +700,39 @@
 	if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
 		OUT_RING( tmp );
 	} else {
-		DRM_DEBUG("bad scissor enable\n");
+		DRM_ERROR("bad scissor enable\n");
 		OUT_RING( 0 );
 	}
 
-	OUT_RING( code[I830_DESTREG_SENABLE] );
-
 	OUT_RING( GFX_OP_SCISSOR_RECT );
 	OUT_RING( code[I830_DESTREG_SR1] );
 	OUT_RING( code[I830_DESTREG_SR2] );
+	OUT_RING( 0 );
 
 	ADVANCE_LP_RING();
 }
 
+static void i830EmitStippleVerified( drm_device_t *dev, 
+				     unsigned int *code ) 
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( 2 );
+	OUT_RING( GFX_OP_STIPPLE );
+	OUT_RING( code[1] );
+	ADVANCE_LP_RING();	
+}
+
+
 static void i830EmitState( drm_device_t *dev )
 {
    	drm_i830_private_t *dev_priv = dev->dev_private;
       	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	unsigned int dirty = sarea_priv->dirty;
 
+	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+
 	if (dirty & I830_UPLOAD_BUFFERS) {
 		i830EmitDestVerified( dev, sarea_priv->BufferState );
 		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
@@ -740,17 +766,154 @@
 	}
 
 	if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
-	   i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+		i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+	} else {
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
+		}
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
+		}
+
+		/* 1.3:
+		 */
+#if 0
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
+		}
+		if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
+			i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
+			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
+		}
+#endif
+	}
+
+	/* 1.3:
+	 */
+	if (dirty & I830_UPLOAD_STIPPLE) {
+		i830EmitStippleVerified( dev, 
+					 sarea_priv->StippleState);
+		sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
+	}
+
+	if (dirty & I830_UPLOAD_TEX2) {
+		i830EmitTexVerified( dev, sarea_priv->TexState2 );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
+	}
+
+	if (dirty & I830_UPLOAD_TEX3) {
+		i830EmitTexVerified( dev, sarea_priv->TexState3 );
+		sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
+	}
+
+
+	if (dirty & I830_UPLOAD_TEXBLEND2) {
+		i830EmitTexBlendVerified( 
+			dev, 
+			sarea_priv->TexBlendState2,
+			sarea_priv->TexBlendStateWordsUsed2);
+
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
+	}
+
+	if (dirty & I830_UPLOAD_TEXBLEND3) {
+		i830EmitTexBlendVerified( 
+			dev, 
+			sarea_priv->TexBlendState3,
+			sarea_priv->TexBlendStateWordsUsed3);
+		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
+	}
+}
+
+/* ================================================================
+ * Performance monitoring functions
+ */
+
+static void i830_fill_box( drm_device_t *dev,
+			   int x, int y, int w, int h,
+			   int r, int g, int b )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	u32 color;
+	unsigned int BR13, CMD;
+	RING_LOCALS;
+
+	BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1<<24);
+	CMD = XY_COLOR_BLT_CMD;
+	x += dev_priv->sarea_priv->boxes[0].x1;
+	y += dev_priv->sarea_priv->boxes[0].y1;
+
+	if (dev_priv->cpp == 4) {
+		BR13 |= (1<<25);
+		CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
+		color = (((0xff) << 24) | (r << 16) | (g <<  8) | b);	
 	} else {
-	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
-	      i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
-	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
-	   }
-	   if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
-	      i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
-	      sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
-	   }
+		color = (((r & 0xf8) << 8) |
+			 ((g & 0xfc) << 3) |
+			 ((b & 0xf8) >> 3));
+	}
+
+	BEGIN_LP_RING( 6 );	    
+	OUT_RING( CMD );
+	OUT_RING( BR13 );
+	OUT_RING( (y << 16) | x );
+	OUT_RING( ((y+h) << 16) | (x+w) );
+
+ 	if ( dev_priv->current_page == 1 ) { 
+		OUT_RING( dev_priv->front_offset );
+ 	} else {	 
+		OUT_RING( dev_priv->back_offset );
+ 	} 
+
+	OUT_RING( color );
+	ADVANCE_LP_RING();
+}
+
+static void i830_cp_performance_boxes( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	/* Purple box for page flipping
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP ) 
+		i830_fill_box( dev, 4, 4, 8, 8, 255, 0, 255 );
+
+	/* Red box if we have to wait for idle at any point
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT ) 
+		i830_fill_box( dev, 16, 4, 8, 8, 255, 0, 0 );
+
+	/* Blue box: lost context?
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT ) 
+		i830_fill_box( dev, 28, 4, 8, 8, 0, 0, 255 );
+
+	/* Yellow box for texture swaps
+	 */
+	if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD ) 
+		i830_fill_box( dev, 40, 4, 8, 8, 255, 255, 0 );
+
+	/* Green box if hardware never idles (as far as we can tell)
+	 */
+	if ( !(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY) ) 
+		i830_fill_box( dev, 64, 4, 8, 8, 0, 255, 0 );
+
+
+	/* Draw bars indicating number of buffers allocated 
+	 * (not a great measure, easily confused)
+	 */
+	if (dev_priv->dma_used) {
+		int bar = dev_priv->dma_used / 10240;
+		if (bar > 100) bar = 100;
+		if (bar < 1) bar = 1;
+		i830_fill_box( dev, 4, 16, bar, 4, 196, 128, 128 );
+		dev_priv->dma_used = 0;
 	}
+
+	dev_priv->sarea_priv->perf_boxes = 0;
 }
 
 static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, 
@@ -768,6 +931,15 @@
 	unsigned int BR13, CMD, D_CMD;
 	RING_LOCALS;
 
+
+	if ( dev_priv->current_page == 1 ) {
+		unsigned int tmp = flags;
+
+		flags &= ~(I830_FRONT | I830_BACK);
+		if ( tmp & I830_FRONT ) flags |= I830_BACK;
+		if ( tmp & I830_BACK )  flags |= I830_FRONT;
+	}
+
   	i830_kernel_lost_context(dev);
 
 	switch(cpp) {
@@ -808,7 +980,7 @@
 			OUT_RING( BR13 );
 			OUT_RING( (pbox->y1 << 16) | pbox->x1 );
 			OUT_RING( (pbox->y2 << 16) | pbox->x2 );
-			OUT_RING( 0 );
+			OUT_RING( dev_priv->front_offset );
 			OUT_RING( clear_color );
 			ADVANCE_LP_RING();
 		}
@@ -847,13 +1019,17 @@
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int pitch = dev_priv->pitch;
 	int cpp = dev_priv->cpp;
-	int ofs = dev_priv->back_offset;
 	int i;
 	unsigned int CMD, BR13;
 	RING_LOCALS;
 
 	DRM_DEBUG("swapbuffers\n");
 
+  	i830_kernel_lost_context(dev);
+
+	if (dev_priv->do_boxes)
+		i830_cp_performance_boxes( dev );
+
 	switch(cpp) {
 	case 2: 
 		BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
@@ -870,7 +1046,6 @@
 		break;
 	}
 
-  	i830_kernel_lost_context(dev);
 
       	if (nbox > I830_NR_SAREA_CLIPRECTS)
      		nbox = I830_NR_SAREA_CLIPRECTS;
@@ -890,23 +1065,72 @@
 		BEGIN_LP_RING( 8 );
 		OUT_RING( CMD );
 		OUT_RING( BR13 );
+		OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+		OUT_RING( (pbox->y2 << 16) | pbox->x2 );
 
-		OUT_RING( (pbox->y1 << 16) |
-			  pbox->x1 );
-		OUT_RING( (pbox->y2 << 16) |
-			  pbox->x2 );
-
-		OUT_RING( 0 /* front ofs always zero */ );
-		OUT_RING( (pbox->y1 << 16) |
-			  pbox->x1 );
+		if (dev_priv->current_page == 0) 
+			OUT_RING( dev_priv->front_offset );
+		else
+			OUT_RING( dev_priv->back_offset );			
 
+		OUT_RING( (pbox->y1 << 16) | pbox->x1 );
 		OUT_RING( BR13 & 0xffff );
-		OUT_RING( ofs );
+
+		if (dev_priv->current_page == 0) 
+			OUT_RING( dev_priv->back_offset );			
+		else
+			OUT_RING( dev_priv->front_offset );
 
 		ADVANCE_LP_RING();
 	}
 }
 
+static void i830_dma_dispatch_flip( drm_device_t *dev )
+{
+   	drm_i830_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+		   __FUNCTION__, 
+		   dev_priv->current_page,
+		   dev_priv->sarea_priv->pf_current_page);
+
+  	i830_kernel_lost_context(dev);
+
+	if (dev_priv->do_boxes) {
+		dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
+		i830_cp_performance_boxes( dev );
+	}
+
+
+	BEGIN_LP_RING( 2 );
+    	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+
+	BEGIN_LP_RING( 6 );
+	OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP );	
+	OUT_RING( 0 );
+	if ( dev_priv->current_page == 0 ) {
+		OUT_RING( dev_priv->back_offset );
+		dev_priv->current_page = 1;
+	} else {
+		OUT_RING( dev_priv->front_offset );
+		dev_priv->current_page = 0;
+	}
+	OUT_RING(0);
+	ADVANCE_LP_RING();
+
+
+	BEGIN_LP_RING( 2 );
+	OUT_RING( MI_WAIT_FOR_EVENT |
+		  MI_WAIT_FOR_PLANE_A_FLIP );
+	OUT_RING( 0 );
+	ADVANCE_LP_RING();
+	
+
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
 
 static void i830_dma_dispatch_vertex(drm_device_t *dev, 
 				     drm_buf_t *buf,
@@ -936,7 +1160,7 @@
 		}
 	}
 
-	if (used > 4*1024) 
+	if (used > 4*1023) 
 		used = 0;
 
 	if (sarea_priv->dirty)
@@ -953,12 +1177,19 @@
    	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
 
 	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
-		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
-					     sarea_priv->vertex_prim |
-					     ((used/4)-2));
+		u32 *vp = buf_priv->virtual;
+
+		vp[0] = (GFX_OP_PRIMITIVE |
+			 sarea_priv->vertex_prim |
+			 ((used/4)-2));
+
+		if (dev_priv->use_mi_batchbuffer_start) {
+			vp[used/4] = MI_BATCH_BUFFER_END; 
+			used += 4; 
+		}
 		
 		if (used & 4) {
-			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			vp[used/4] = 0;
 			used += 4;
 		}
 
@@ -978,80 +1209,45 @@
 				ADVANCE_LP_RING();
 			}
 
-			BEGIN_LP_RING(4);
+			if (dev_priv->use_mi_batchbuffer_start) {
+				BEGIN_LP_RING(2);
+				OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
+				OUT_RING( start | MI_BATCH_NON_SECURE );
+				ADVANCE_LP_RING();
+			} 
+			else {
+				BEGIN_LP_RING(4);
+				OUT_RING( MI_BATCH_BUFFER );
+				OUT_RING( start | MI_BATCH_NON_SECURE );
+				OUT_RING( start + used - 4 );
+				OUT_RING( 0 );
+				ADVANCE_LP_RING();
+			}
 
-			OUT_RING( MI_BATCH_BUFFER );
-			OUT_RING( start | MI_BATCH_NON_SECURE );
-			OUT_RING( start + used - 4 );
-			OUT_RING( 0 );
-			ADVANCE_LP_RING();
-			
 		} while (++i < nbox);
 	}
 
-	BEGIN_LP_RING(10);
-	OUT_RING( CMD_STORE_DWORD_IDX );
-	OUT_RING( 20 );
-	OUT_RING( dev_priv->counter );
-	OUT_RING( 0 );
-
 	if (discard) {
+		dev_priv->counter++;
+
+		(void) cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
+			       I830_BUF_HARDWARE);
+
+		BEGIN_LP_RING(8);
+		OUT_RING( CMD_STORE_DWORD_IDX );
+		OUT_RING( 20 );
+		OUT_RING( dev_priv->counter );
 		OUT_RING( CMD_STORE_DWORD_IDX );
 		OUT_RING( buf_priv->my_use_idx );
 		OUT_RING( I830_BUF_FREE );
+		OUT_RING( CMD_REPORT_HEAD );
 		OUT_RING( 0 );
+		ADVANCE_LP_RING();
 	}
-
-      	OUT_RING( CMD_REPORT_HEAD );
-	OUT_RING( 0 );
-   	ADVANCE_LP_RING();
-}
-
-/* Interrupts are only for flushing */
-void i830_dma_service(int irq, void *device, struct pt_regs *regs)
-{
-	drm_device_t	 *dev = (drm_device_t *)device;
-      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
-   	u16 temp;
-   
-      	temp = I830_READ16(I830REG_INT_IDENTITY_R);
-   	temp = temp & ~(0x6000);
-   	if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R, 
-				   temp); /* Clear all interrupts */
-	else
-	   return;
- 
-   	queue_task(&dev->tq, &tq_immediate);
-   	mark_bh(IMMEDIATE_BH);
-}
-
-void DRM(dma_immediate_bh)(void *device)
-{
-	drm_device_t *dev = (drm_device_t *) device;
-      	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
-
-   	atomic_set(&dev_priv->flush_done, 1);
-   	wake_up_interruptible(&dev_priv->flush_queue);
 }
 
-static inline void i830_dma_emit_flush(drm_device_t *dev)
-{
-   	drm_i830_private_t *dev_priv = dev->dev_private;
-   	RING_LOCALS;
-
-   	i830_kernel_lost_context(dev);
 
-   	BEGIN_LP_RING(2);
-      	OUT_RING( CMD_REPORT_HEAD );
-      	OUT_RING( GFX_OP_USER_INTERRUPT );
-      	ADVANCE_LP_RING();
-
-	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
-	atomic_set(&dev_priv->flush_done, 1);
-	wake_up_interruptible(&dev_priv->flush_queue);
-}
-
-static inline void i830_dma_quiescent_emit(drm_device_t *dev)
+void i830_dma_quiescent(drm_device_t *dev)
 {
       	drm_i830_private_t *dev_priv = dev->dev_private;
    	RING_LOCALS;
@@ -1062,79 +1258,27 @@
    	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
    	OUT_RING( CMD_REPORT_HEAD );
       	OUT_RING( 0 );
-      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	OUT_RING( 0 );
    	ADVANCE_LP_RING();
 
-	i830_wait_ring( dev, dev_priv->ring.Size - 8 );
-	atomic_set(&dev_priv->flush_done, 1);
-	wake_up_interruptible(&dev_priv->flush_queue);
-}
-
-void i830_dma_quiescent(drm_device_t *dev)
-{
-      	DECLARE_WAITQUEUE(entry, current);
-  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
-	unsigned long end;      
-
-   	if(dev_priv == NULL) {
-	   	return;
-	}
-      	atomic_set(&dev_priv->flush_done, 0);
-   	add_wait_queue(&dev_priv->flush_queue, &entry);
-   	end = jiffies + (HZ*3);
-   
-   	for (;;) {
-		current->state = TASK_INTERRUPTIBLE;
-	      	i830_dma_quiescent_emit(dev);
-	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
-		if(time_before(end, jiffies)) {
-		   	DRM_ERROR("lockup\n");
-		   	break;
-		}	   
-	      	schedule_timeout(HZ*3);
-	      	if (signal_pending(current)) {
-		   	break;
-		}
-	}
-   
-   	current->state = TASK_RUNNING;
-   	remove_wait_queue(&dev_priv->flush_queue, &entry);
-   
-   	return;
+	i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
 }
 
 static int i830_flush_queue(drm_device_t *dev)
 {
-   	DECLARE_WAITQUEUE(entry, current);
-  	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+   	drm_i830_private_t *dev_priv = dev->dev_private;
 	drm_device_dma_t *dma = dev->dma;
-	unsigned long end;
-   	int i, ret = 0;      
+   	int i, ret = 0;
+   	RING_LOCALS;
+	
+   	i830_kernel_lost_context(dev);
 
-   	if(dev_priv == NULL) {
-	   	return 0;
-	}
-      	atomic_set(&dev_priv->flush_done, 0);
-   	add_wait_queue(&dev_priv->flush_queue, &entry);
-   	end = jiffies + (HZ*3);
-   	for (;;) {
-		current->state = TASK_INTERRUPTIBLE;
-	      	i830_dma_emit_flush(dev);
-	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
-		if(time_before(end, jiffies)) {
-		   	DRM_ERROR("lockup\n");
-		   	break;
-		}	   
-	      	schedule_timeout(HZ*3);
-	      	if (signal_pending(current)) {
-		   	ret = -EINTR; /* Can't restart */
-		   	break;
-		}
-	}
-   
-   	current->state = TASK_RUNNING;
-   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+   	BEGIN_LP_RING(2);
+      	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( 0 );
+      	ADVANCE_LP_RING();
 
+	i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
 
    	for (i = 0; i < dma->buf_count; i++) {
 	   	drm_buf_t *buf = dma->buflist[ i ];
@@ -1146,7 +1290,7 @@
 		if (used == I830_BUF_HARDWARE)
 			DRM_DEBUG("reclaimed from HARDWARE\n");
 		if (used == I830_BUF_CLIENT)
-			DRM_DEBUG("still on client HARDWARE\n");
+			DRM_DEBUG("still on client\n");
 	}
 
    	return ret;
@@ -1185,8 +1329,7 @@
 {
    	drm_file_t	  *priv	  = filp->private_data;
    	drm_device_t	  *dev	  = priv->dev;
-   
-   	DRM_DEBUG("i830_flush_ioctl\n");
+
    	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
 		DRM_ERROR("i830_flush_ioctl called without lock held\n");
 		return -EINVAL;
@@ -1275,6 +1418,53 @@
    	return 0;
 }
 
+
+
+/* Not sure why this isn't set all the time:
+ */ 
+static void i830_do_init_pageflip( drm_device_t *dev )
+{
+	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	dev_priv->page_flipping = 1;
+	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+}
+
+int i830_do_cleanup_pageflip( drm_device_t *dev )
+{
+	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	if (dev_priv->current_page != 0)
+		i830_dma_dispatch_flip( dev );
+
+	dev_priv->page_flipping = 0;
+	return 0;
+}
+
+int i830_flip_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i830_private_t *dev_priv = dev->dev_private;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i830_flip_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	if (!dev_priv->page_flipping) 
+		i830_do_init_pageflip( dev );
+
+	i830_dma_dispatch_flip( dev );
+   	return 0;
+}
+
 int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
@@ -1324,46 +1514,80 @@
 	return retcode;
 }
 
-int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+int i830_copybuf(struct inode *inode,
+		 struct file *filp, 
+		 unsigned int cmd,
+		 unsigned long arg)
+{
+	/* Never copy - 2.4.x doesn't need it */
+	return 0;
+}
+
+int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
 		unsigned long arg)
 {
+	return 0;
+}
+
+
+
+int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
+		      unsigned long arg )
+{
 	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
-	drm_i830_copy_t	  d;
-   	drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
-   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
-   	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
-     					dev_priv->sarea_priv; 
-	drm_buf_t *buf;
-	drm_i830_buf_priv_t *buf_priv;
-	drm_device_dma_t *dma = dev->dma;
+	drm_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_getparam_t param;
+	int value;
 
-	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-		DRM_ERROR("i830_dma called without lock held\n");
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
 		return -EINVAL;
 	}
-   
-   	if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d)))
-		return -EFAULT;
-
-	if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
-	buf = dma->buflist[ d.idx ];
-   	buf_priv = buf->dev_private;
-	if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM;
-
-	if(d.used < 0 || d.used > buf->total) return -EINVAL;
 
-   	if (copy_from_user(buf_priv->virtual, d.address, d.used))
+	if (copy_from_user(&param, (drm_i830_getparam_t *)arg, sizeof(param) ))
 		return -EFAULT;
 
-   	sarea_priv->last_dispatch = (int) hw_status[5];
+	switch( param.param ) {
+	case I830_PARAM_IRQ_ACTIVE:
+		value = dev->irq ? 1 : 0;
+		break;
+	default:
+		return -EINVAL;
+	}
 
+	if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return -EFAULT;
+	}
+	
 	return 0;
 }
 
-int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+
+int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg )
 {
-	if(VM_DONTCOPY == 0) return 1;
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_i830_private_t *dev_priv = dev->dev_private;
+	drm_i830_setparam_t param;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&param, (drm_i830_setparam_t *)arg, sizeof(param) ))
+		return -EFAULT;
+
+	switch( param.param ) {
+	case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
+		dev_priv->use_mi_batchbuffer_start = param.value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return 0;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)