drm: Add support for Intel i965G chipsets.

This is a patch prepared by Guangdeng Liao based off of Tungsten Graphics's
final code drop.

From: Alan Hourihane <alanh@tungstengraphics.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index a94233b..99e9d07 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -31,6 +31,11 @@
 #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)
+
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
  * the head pointer changes, so that EBUSY only happens if the ring
@@ -347,7 +352,7 @@
 	if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
 		return DRM_ERR(EINVAL);
 
-	BEGIN_LP_RING(((dwords+1)&~1));
+	BEGIN_LP_RING((dwords+1)&~1);
 
 	for (i = 0; i < dwords;) {
 		int cmd, sz;
@@ -395,24 +400,40 @@
 		return DRM_ERR(EINVAL);
 	}
 
-	BEGIN_LP_RING(6);
-	OUT_RING(GFX_OP_DRAWRECT_INFO);
-	OUT_RING(DR1);
-	OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
-	OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
-	OUT_RING(DR4);
-	OUT_RING(0);
-	ADVANCE_LP_RING();
+	if (IS_I965G(dev)) {
+		BEGIN_LP_RING(4);
+		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+		OUT_RING(((box.x2 - 1) & 0xffff) ((box.y2 - 1) << 16));
+		OUT_RING(DR4);
+		ADVANCE_LP_RING();
+	} else {
+		BEGIN_LP_RING(6);
+		OUT_RING(GFX_OP_DRAWRECT_INFO);
+		OUT_RING(DR1);
+		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+		OUT_RING(DR4);
+		OUT_RING(0);
+		ADVANCE_LP_RING();
+	}
 
 	return 0;
 }
 
+/* XXX: Emitting the counter should really be moved to part of the IRQ
+ * emit. For now, do it in both places:
+ */
+
 static void i915_emit_breadcrumb(drm_device_t *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	RING_LOCALS;
 
-	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+
+	if (dev_priv->counter > 0x7FFFFFFFUL)
+		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
 
 	BEGIN_LP_RING(4);
 	OUT_RING(CMD_STORE_DWORD_IDX);