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

List:       dri-patches
Subject:    drm: Branch 'master' - 30 commits
From:       jbarnes () kemper ! freedesktop ! org (Jesse Barnes)
Date:       2008-01-23 2:24:50
Message-ID: 20080123022450.E30CB10096 () kemper ! freedesktop ! org
[Download RAW message or body]

linux-core/drmP.h         |   91 +++++++++--
 linux-core/drm_drv.c      |    4 
 linux-core/drm_irq.c      |  356 ++++++++++++++++++++++++++++++++++++++--------
 linux-core/i915_drv.c     |    8 -
 linux-core/mach64_drv.c   |    6 
 linux-core/mga_drv.c      |    7 
 linux-core/r128_drv.c     |    7 
 linux-core/radeon_drv.c   |    8 -
 shared-core/drm.h         |   17 ++
 shared-core/i915_drv.h    |   49 +++++-
 shared-core/i915_irq.c    |  252 +++++++++++++++++++++++---------
 shared-core/mach64_drv.h  |   13 +
 shared-core/mach64_irq.c  |   88 ++++++-----
 shared-core/mga_drv.h     |   10 -
 shared-core/mga_irq.c     |   69 ++++++--
 shared-core/nouveau_drv.h |    2 
 shared-core/nouveau_irq.c |    4 
 shared-core/r128_drv.h    |    9 -
 shared-core/r128_irq.c    |   55 ++++---
 shared-core/radeon_drv.h  |   19 +-
 shared-core/radeon_irq.c  |  171 ++++++++++------------
 shared-core/via_drv.c     |    6 
 shared-core/via_drv.h     |    7 
 shared-core/via_irq.c     |   71 ++++-----
 24 files changed, 933 insertions(+), 396 deletions(-)

New commits:
commit 531f25cfe9d0319f78fe58260bfed08d5e3e8bcc
Author: Jesse Barnes <jbarnes@nietzche.virtuousgeek.org>
Date:   Tue Jan 22 15:16:01 2008 -0800

    Correct vblank count value
    
    The frame count registers don't increment until the start of the next
    frame, so make sure we return an incremented count if called during the
    actual vblank period.

diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index b8d027d..2c1f2c2 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -471,6 +471,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const \
char *caller);  #define I915REG_INT_ENABLE_R	0x020a0
 #define I915REG_INSTPM	        0x020c0
 
+#define PIPEADSL		0x70000
+#define PIPEBDSL		0x71000
+
 #define I915REG_PIPEASTAT	0x70024
 #define I915REG_PIPEBSTAT	0x71024
 /*
@@ -790,6 +793,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const \
char *caller);  #define BCLRPAT_B	0x61020
 #define VSYNCSHIFT_B	0x61028
 
+#define HACTIVE_MASK	0x00000fff
+#define VBLANK_START_MASK 0x00001fff
+
 #define PP_STATUS	0x61200
 # define PP_ON					(1 << 31)
 /**
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index bef73b6..7ad21a9 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -69,8 +69,6 @@ i915_get_pipe(struct drm_device *dev, int plane)
 static int
 i915_get_plane(struct drm_device *dev, int pipe)
 {
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
 	if (i915_get_pipe(dev, 0) == pipe)
 		return 0;
 	return 1;
@@ -349,12 +347,16 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long high_frame;
 	unsigned long low_frame;
+	unsigned long pipedsl, vblank, htotal;
 	u32 high1, high2, low, count;
 	int pipe;
 
 	pipe = i915_get_pipe(dev, plane);
 	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
 	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	pipedsl = pipe ? PIPEBDSL : PIPEADSL;
+	vblank = pipe ? VBLANK_B : VBLANK_A;
+	htotal = pipe ? HTOTAL_B : HTOTAL_A;
 
 	if (!i915_pipe_enabled(dev, pipe)) {
 	    printk(KERN_ERR "trying to get vblank count for disabled "
@@ -378,6 +380,15 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
 
 	count = (high1 << 8) | low;
 
+	/*
+	 * If we're in the middle of the vblank period, the
+	 * above regs won't have been updated yet, so return
+	 * an incremented count to stay accurate
+	 */
+	if ((I915_READ(pipedsl) >= (I915_READ(vblank) & VBLANK_START_MASK)) ||
+	    (I915_READ(pipedsl) < (I915_READ(htotal) & HACTIVE_MASK)))
+		count++;
+
 	return count;
 }
 
commit 893e311999d1565943899d73c56c674fc9b6e502
Author: Jesse Barnes <jbarnes@nietzche.virtuousgeek.org>
Date:   Tue Jan 22 13:11:29 2008 -0800

    i915 irq fixes
    
    Ack the IRQs correctly (PIPExSTAT first followed by IIR).  Don't read
    vblank counter registers on disabled pipes (might hang otherwise).  And
    deal with flipped pipe/plane mappings if present.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 9b46b12..bef73b6 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -42,9 +42,9 @@
  * @dev: DRM device
  * @plane: plane to look for
  *
- * We need to get the pipe associated with a given plane to correctly perform
- * vblank driven swapping, and they may not always be equal.  So look up the
- * pipe associated with @plane here.
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a pipe number, since they may not always be equal.  This routine
+ * maps the given @plane back to a pipe number.
  */
 static int
 i915_get_pipe(struct drm_device *dev, int plane)
@@ -58,6 +58,46 @@ i915_get_pipe(struct drm_device *dev, int plane)
 }
 
 /**
+ * i915_get_plane - return the the plane associated with a given pipe
+ * @dev: DRM device
+ * @pipe: pipe to look for
+ *
+ * The Intel Mesa & 2D drivers call the vblank routines with a plane number
+ * rather than a plane number, since they may not always be equal.  This routine
+ * maps the given @pipe back to a plane number.
+ */
+static int
+i915_get_plane(struct drm_device *dev, int pipe)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	if (i915_get_pipe(dev, 0) == pipe)
+		return 0;
+	return 1;
+}
+
+/**
+ * i915_pipe_enabled - check if a pipe is enabled
+ * @dev: DRM device
+ * @pipe: pipe to check
+ *
+ * Reading certain registers when the pipe is disabled can hang the chip.
+ * Use this routine to make sure the PLL is running and the pipe is active
+ * before reading such registers if unsure.
+ */
+static int
+i915_pipe_enabled(struct drm_device *dev, int pipe)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
+
+	if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
+		return 1;
+
+	return 0;
+}
+
+/**
  * Emit a synchronous flip.
  *
  * This function must be called with the drawable spinlock held.
@@ -146,14 +186,14 @@ static void i915_vblank_tasklet(struct drm_device *dev)
 	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);
-		int crtc = i915_get_pipe(dev, vbl_swap->plane);
+		int pipe = i915_get_pipe(dev, vbl_swap->plane);
 
-		if ((counter[crtc] - vbl_swap->sequence) > (1<<23))
+		if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
 			continue;
 
 		list_del(list);
 		dev_priv->swaps_pending--;
-		drm_vblank_put(dev, crtc);
+		drm_vblank_put(dev, pipe);
 
 		DRM_SPINUNLOCK(&dev_priv->swaps_lock);
 		DRM_SPINLOCK(&dev->drw_lock);
@@ -304,12 +344,23 @@ static void i915_vblank_tasklet(struct drm_device *dev)
 	}
 }
 
-u32 i915_get_vblank_counter(struct drm_device *dev, int crtc)
+u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	unsigned long high_frame;
+	unsigned long low_frame;
 	u32 high1, high2, low, count;
+	int pipe;
+
+	pipe = i915_get_pipe(dev, plane);
+	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
+	if (!i915_pipe_enabled(dev, pipe)) {
+	    printk(KERN_ERR "trying to get vblank count for disabled "
+		   "pipe %d\n", pipe);
+	    return 0;
+	}
 
 	/*
 	 * High & low register fields aren't synchronized, so make sure
@@ -348,6 +399,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 	if (temp == 0)
 		return IRQ_NONE;
 
+	/*
+	 * Clear the PIPE(A|B)STAT regs before the IIR otherwise
+	 * we may get extra interrupts.
+	 */
+	if (temp & VSYNC_PIPEA_FLAG) {
+		drm_handle_vblank(dev, i915_get_plane(dev, 0));
+		I915_WRITE(I915REG_PIPEASTAT,
+			   pipea_stats | I915_VBLANK_INTERRUPT_ENABLE |
+			   I915_VBLANK_CLEAR);
+	}
+	if (temp & VSYNC_PIPEB_FLAG) {
+		drm_handle_vblank(dev, i915_get_plane(dev, 1));
+		I915_WRITE(I915REG_PIPEBSTAT,
+			   pipeb_stats | I915_VBLANK_INTERRUPT_ENABLE |
+			   I915_VBLANK_CLEAR);
+	}
+
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 	(void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */
 
@@ -363,24 +431,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 #endif
 	}
 
-	/*
-	 * Use drm_update_vblank_counter here to deal with potential lost
-	 * interrupts
-	 */
-	if (temp & VSYNC_PIPEA_FLAG)
-		drm_handle_vblank(dev, 0);
-	if (temp & VSYNC_PIPEB_FLAG)
-		drm_handle_vblank(dev, 1);
-
 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
 		if (dev_priv->swaps_pending > 0)
 			drm_locked_tasklet(dev, i915_vblank_tasklet);
-		I915_WRITE(I915REG_PIPEASTAT,
-			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
-			I915_VBLANK_CLEAR);
-		I915_WRITE(I915REG_PIPEBSTAT,
-			pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
-			I915_VBLANK_CLEAR);
 	}
 
 	return IRQ_HANDLED;
@@ -494,11 +547,12 @@ int i915_irq_wait(struct drm_device *dev, void *data,
 	return i915_wait_irq(dev, irqwait->irq_seq);
 }
 
-int i915_enable_vblank(struct drm_device *dev, int crtc)
+int i915_enable_vblank(struct drm_device *dev, int plane)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	int pipe = i915_get_pipe(dev, plane);
 
-	switch (crtc) {
+	switch (pipe) {
 	case 0:
 		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
 		break;
@@ -506,8 +560,8 @@ int i915_enable_vblank(struct drm_device *dev, int crtc)
 		dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
 		break;
 	default:
-		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
-			  crtc);
+		DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
+			  pipe);
 		break;
 	}
 
@@ -516,11 +570,12 @@ int i915_enable_vblank(struct drm_device *dev, int crtc)
 	return 0;
 }
 
-void i915_disable_vblank(struct drm_device *dev, int crtc)
+void i915_disable_vblank(struct drm_device *dev, int plane)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	int pipe = i915_get_pipe(dev, plane);
 
-	switch (crtc) {
+	switch (pipe) {
 	case 0:
 		dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
 		break;
@@ -528,8 +583,8 @@ void i915_disable_vblank(struct drm_device *dev, int crtc)
 		dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG;
 		break;
 	default:
-		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
-			  crtc);
+		DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
+			  pipe);
 		break;
 	}
 
commit 0cd4cbc9a6330bd619608f274592082de7c05bcf
Merge: 128a8f7... 5231a52...
Author: Jesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Date:   Tue Jan 22 09:42:37 2008 -0800

    Merge branch 'master' into vblank-rework, including mach64 support
    
    Conflicts:
    
    	linux-core/drmP.h
    	linux-core/drm_drv.c
    	shared-core/i915_drv.h
    	shared-core/i915_irq.c
    	shared-core/mga_irq.c
    	shared-core/radeon_irq.c
    	shared-core/via_irq.c
    
    Mostly trivial conflicts.
    
    mach64 support from Mathieu BĂ©rard.

diff --cc linux-core/drmP.h
index 332ee1c,dbf2a92..4e8b087
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@@ -631,56 -624,14 +622,56 @@@ struct drm_driver 
  	int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
  	void (*dma_ready) (struct drm_device *);
  	int (*dma_quiescent) (struct drm_device *);
- 	int (*context_ctor) (struct drm_device * dev, int context);
- 	int (*context_dtor) (struct drm_device * dev, int context);
- 	int (*kernel_context_switch) (struct drm_device * dev, int old,
+ 	int (*context_ctor) (struct drm_device *dev, int context);
+ 	int (*context_dtor) (struct drm_device *dev, int context);
+ 	int (*kernel_context_switch) (struct drm_device *dev, int old,
  				      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);
 +	void (*kernel_context_switch_unlock) (struct drm_device * dev);
 +	/**
 +	 * get_vblank_counter - get raw hardware vblank counter
 +	 * @dev: DRM device
 +	 * @crtc: counter to fetch
 +	 *
 +	 * Driver callback for fetching a raw hardware vblank counter
 +	 * for @crtc.  If a device doesn't have a hardware counter, the
 +	 * driver can simply return the value of drm_vblank_count and
 +	 * make the enable_vblank() and disable_vblank() hooks into no-ops,
 +	 * leaving interrupts enabled at all times.
 +	 *
 +	 * Wraparound handling and loss of events due to modesetting is dealt
 +	 * with in the DRM core code.
 +	 *
 +	 * RETURNS
 +	 * Raw vblank counter value.
 +	 */
 +	u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
 +
 +	/**
 +	 * enable_vblank - enable vblank interrupt events
 +	 * @dev: DRM device
 +	 * @crtc: which irq to enable
 +	 *
 +	 * Enable vblank interrupts for @crtc.  If the device doesn't have
 +	 * a hardware vblank counter, this routine should be a no-op, since
 +	 * interrupts will have to stay on to keep the count accurate.
 +	 *
 +	 * RETURNS
 +	 * Zero on success, appropriate errno if the given @crtc's vblank
 +	 * interrupt cannot be enabled.
 +	 */
 +	int (*enable_vblank) (struct drm_device *dev, int crtc);
 +
 +	/**
 +	 * disable_vblank - disable vblank interrupt events
 +	 * @dev: DRM device
 +	 * @crtc: which irq to enable
 +	 *
 +	 * Disable vblank interrupts for @crtc.  If the device doesn't have
 +	 * a hardware vblank counter, this routine should be a no-op, since
 +	 * interrupts will have to stay on to keep the count accurate.
 +	 */
 +	void (*disable_vblank) (struct drm_device *dev, int crtc);
- 	int (*dri_library_name) (struct drm_device * dev, char * buf);
+ 	int (*dri_library_name) (struct drm_device *dev, char * buf);
  
  	/**
  	 * Called by \c drm_device_is_agp.  Typically used to determine if a
@@@ -697,9 -648,9 +688,9 @@@
  
  /* these have to be filled in */
  	 irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
- 	void (*irq_preinstall) (struct drm_device * dev);
- 	int (*irq_postinstall) (struct drm_device * dev);
- 	void (*irq_uninstall) (struct drm_device * dev);
+ 	void (*irq_preinstall) (struct drm_device *dev);
 -	void (*irq_postinstall) (struct drm_device *dev);
++	int (*irq_postinstall) (struct drm_device *dev);
+ 	void (*irq_uninstall) (struct drm_device *dev);
  	void (*reclaim_buffers) (struct drm_device *dev,
  				 struct drm_file *file_priv);
  	void (*reclaim_buffers_locked) (struct drm_device *dev,
diff --cc linux-core/drm_drv.c
index 296a326,343d5f3..3c2794d
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@@ -121,13 -122,14 +121,13 @@@ static struct drm_ioctl_desc drm_ioctls
  
  	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  
- 	DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, 
 -
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- 	DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl,
  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- 	DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl, 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl,
  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- 	DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl, 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl,
  		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
  
  	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH),
diff --cc linux-core/drm_irq.c
index 4aa58d7,866878a..2a5a453
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@@ -188,8 -106,19 +188,8 @@@ int drm_irq_install(struct drm_device 
  	dev->irq_enabled = 1;
  	mutex_unlock(&dev->struct_mutex);
  
- 	DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
+ 	DRM_DEBUG("irq=%d\n", dev->irq);
  
 -	if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
 -		init_waitqueue_head(&dev->vbl_queue);
 -
 -		spin_lock_init(&dev->vbl_lock);
 -
 -		INIT_LIST_HEAD(&dev->vbl_sigs);
 -		INIT_LIST_HEAD(&dev->vbl_sigs2);
 -
 -		dev->vbl_pending = 0;
 -	}
 -
  	/* Before installing handler */
  	dev->driver->irq_preinstall(dev);
  
diff --cc linux-core/mach64_drv.c
index 9709934,9709934..16bc9ff
--- a/linux-core/mach64_drv.c
+++ b/linux-core/mach64_drv.c
@@@ -42,9 -42,9 +42,11 @@@ static int probe(struct pci_dev *pdev, 
  static struct drm_driver driver = {
  	.driver_features =
  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA
--	    | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
++	    | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
  	.lastclose = mach64_driver_lastclose,
--	.vblank_wait = mach64_driver_vblank_wait,
++	.get_vblank_counter = mach64_get_vblank_counter,
++	.enable_vblank = mach64_enable_vblank,
++	.disable_vblank = mach64_disable_vblank,
  	.irq_preinstall = mach64_driver_irq_preinstall,
  	.irq_postinstall = mach64_driver_irq_postinstall,
  	.irq_uninstall = mach64_driver_irq_uninstall,
diff --cc shared-core/i915_irq.c
index 46d0966,4a96800..9b46b12
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@@ -339,11 -310,12 +339,11 @@@ irqreturn_t i915_driver_irq_handler(DRM
  
  	pipea_stats = I915_READ(I915REG_PIPEASTAT);
  	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- 		
+ 
  	temp = I915_READ16(I915REG_INT_IDENTITY_R);
 -	temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
  
  #if 0
- 	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+ 	DRM_DEBUG("flag=%08x\n", temp);
  #endif
  	if (temp == 0)
  		return IRQ_NONE;
@@@ -363,19 -333,28 +363,19 @@@
  #endif
  	}
  
 -	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
 -		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 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);
 -		drm_vbl_send_signals(dev);
 +	/*
 +	 * Use drm_update_vblank_counter here to deal with potential lost
 +	 * interrupts
 +	 */
 +	if (temp & VSYNC_PIPEA_FLAG)
 +		drm_handle_vblank(dev, 0);
 +	if (temp & VSYNC_PIPEB_FLAG)
 +		drm_handle_vblank(dev, 1);
  
 +	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
  		if (dev_priv->swaps_pending > 0)
  			drm_locked_tasklet(dev, i915_vblank_tasklet);
- 		I915_WRITE(I915REG_PIPEASTAT, 
+ 		I915_WRITE(I915REG_PIPEASTAT,
  			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
  			I915_VBLANK_CLEAR);
  		I915_WRITE(I915REG_PIPEBSTAT,
@@@ -458,9 -431,42 +452,10 @@@ static int i915_wait_irq(struct drm_dev
  	return ret;
  }
  
 -static int i915_driver_vblank_do_wait(struct drm_device *dev,
 -				      unsigned int *sequence,
 -				      atomic_t *counter)
 -{
 -	drm_i915_private_t *dev_priv = dev->dev_private;
 -	unsigned int cur_vblank;
 -	int ret = 0;
 -
 -	if (!dev_priv) {
 -		DRM_ERROR("called with no initialization\n");
 -		return -EINVAL;
 -	}
 -
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(counter))
 -			- *sequence) <= (1<<23)));
 -
 -	*sequence = cur_vblank;
 -
 -	return ret;
 -}
 -
 -int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
 -{
 -	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
 -}
 -
 -int i915_driver_vblank_wait2(struct drm_device *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(struct drm_device *dev, void *data, struct drm_file *file_priv)
+ int i915_irq_emit(struct drm_device *dev, void *data,
+ 			 struct drm_file *file_priv)
  {
  	drm_i915_private_t *dev_priv = dev->dev_private;
  	drm_i915_irq_emit_t *emit = data;
@@@ -788,8 -741,7 +782,8 @@@ int i915_driver_irq_postinstall(struct 
  	 * Initialize the hardware status page IRQ location.
  	 */
  
- 	I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21));
+ 	I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
 +	return 0;
  }
  
  void i915_driver_irq_uninstall(struct drm_device * dev)
diff --cc shared-core/mach64_drv.h
index cebd4c6,91553ce..fb8a772
--- a/shared-core/mach64_drv.h
+++ b/shared-core/mach64_drv.h
@@@ -96,6 -96,6 +96,8 @@@ typedef struct drm_mach64_private 
  	unsigned int depth_bpp;
  	unsigned int depth_offset, depth_pitch;
  
++	atomic_t vbl_received;          /**< Number of vblanks received. */
++
  	u32 front_offset_pitch;
  	u32 back_offset_pitch;
  	u32 depth_offset_pitch;
@@@ -155,13 -160,13 +162,14 @@@ extern int mach64_dma_blit(struct drm_d
  			   struct drm_file *file_priv);
  extern int mach64_get_param(struct drm_device *dev, void *data,
  			    struct drm_file *file_priv);
--extern int mach64_driver_vblank_wait(struct drm_device * dev,
--				     unsigned int *sequence);
  
++extern u32 mach64_get_vblank_counter(struct drm_device *dev, int crtc);
++extern int mach64_enable_vblank(struct drm_device *dev, int crtc);
++extern void mach64_disable_vblank(struct drm_device *dev, int crtc);
  extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS);
--extern void mach64_driver_irq_preinstall(struct drm_device * dev);
--extern void mach64_driver_irq_postinstall(struct drm_device * dev);
--extern void mach64_driver_irq_uninstall(struct drm_device * dev);
++extern void mach64_driver_irq_preinstall(struct drm_device *dev);
++extern int mach64_driver_irq_postinstall(struct drm_device *dev);
++extern void mach64_driver_irq_uninstall(struct drm_device *dev);
  
  /* ================================================================
   * Registers
diff --cc shared-core/mach64_irq.c
index 4122dd9,4122dd9..2d522a6
--- a/shared-core/mach64_irq.c
+++ b/shared-core/mach64_irq.c
@@@ -42,9 -42,9 +42,8 @@@
  
  irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
  {
--	struct drm_device *dev = (struct drm_device *) arg;
--	drm_mach64_private_t *dev_priv =
--	    (drm_mach64_private_t *) dev->dev_private;
++	struct drm_device *dev = arg;
++	drm_mach64_private_t *dev_priv = dev->dev_private;
  	int status;
  
  	status = MACH64_READ(MACH64_CRTC_INT_CNTL);
@@@ -62,74 -62,74 +61,81 @@@
  			     (status & ~MACH64_CRTC_INT_ACKS)
  			     | MACH64_CRTC_VBLANK_INT);
  
--		atomic_inc(&dev->vbl_received);
--		DRM_WAKEUP(&dev->vbl_queue);
--		drm_vbl_send_signals(dev);
++		atomic_inc(&dev_priv->vbl_received);
++		drm_handle_vblank(dev, 0);
  		return IRQ_HANDLED;
  	}
  	return IRQ_NONE;
  }
  
--int mach64_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
++u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc)
  {
--	unsigned int cur_vblank;
--	int ret = 0;
--
--	/* Assume that the user has missed the current sequence number
--	 * by about a day rather than she wants to wait for years
--	 * using vertical blanks...
--	 */
--	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
--		    (((cur_vblank = atomic_read(&dev->vbl_received))
--		      - *sequence) <= (1 << 23)));
++	const drm_mach64_private_t *const dev_priv = dev->dev_private;
++		
++	if (crtc != 0) {
++		return 0;
++	}
++	
++	return atomic_read(&dev_priv->vbl_received);
++}
  
--	*sequence = cur_vblank;
++int mach64_enable_vblank(struct drm_device * dev, int crtc)
++{
++	drm_mach64_private_t *dev_priv = dev->dev_private;
++	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
++	
++	if (crtc != 0) {
++		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc);
++		return 0;
++	}
++	
++	DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
++	
++	/* Turn on VBLANK interrupt */
++	MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
++		     | MACH64_CRTC_VBLANK_INT_EN);
  
--	return ret;
++	return 0;
  }
  
--/* drm_dma.h hooks
--*/
--void mach64_driver_irq_preinstall(struct drm_device * dev)
--{
--	drm_mach64_private_t *dev_priv =
--	    (drm_mach64_private_t *) dev->dev_private;
  
++void mach64_disable_vblank(struct drm_device * dev, int crtc)
++{
++	drm_mach64_private_t *dev_priv = dev->dev_private;
  	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
  
--	DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
++	DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
  
  	/* Disable and clear VBLANK interrupt */
  	MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
  		     | MACH64_CRTC_VBLANK_INT);
  }
  
--void mach64_driver_irq_postinstall(struct drm_device * dev)
++/* drm_dma.h hooks
++*/
++void mach64_driver_irq_preinstall(struct drm_device * dev)
  {
--	drm_mach64_private_t *dev_priv =
--	    (drm_mach64_private_t *) dev->dev_private;
++	drm_mach64_private_t *dev_priv = dev->dev_private;
  
--	/* Turn on VBLANK interrupt */
--	MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
--		     | MACH64_CRTC_VBLANK_INT_EN);
++	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
  
--	DRM_DEBUG("after install CRTC_INT_CTNL: 0x%08x\n",
--		  MACH64_READ(MACH64_CRTC_INT_CNTL));
++	DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
  
++	mach64_disable_vblank(dev,0);
++}
++
++int mach64_driver_irq_postinstall(struct drm_device * dev)
++{
++	return drm_vblank_init(dev, 1);
  }
  
  void mach64_driver_irq_uninstall(struct drm_device * dev)
  {
--	drm_mach64_private_t *dev_priv =
--	    (drm_mach64_private_t *) dev->dev_private;
++	drm_mach64_private_t *dev_priv = dev->dev_private;
  	if (!dev_priv)
  		return;
  
--	/* Disable and clear VBLANK interrupt */
--	MACH64_WRITE(MACH64_CRTC_INT_CNTL,
--		     (MACH64_READ(MACH64_CRTC_INT_CNTL) &
--		      ~MACH64_CRTC_VBLANK_INT_EN)
--		     | MACH64_CRTC_VBLANK_INT);
++	mach64_disable_vblank(dev, 0);
  
  	DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
  		  MACH64_READ(MACH64_CRTC_INT_CNTL));
diff --cc shared-core/mga_irq.c
index 0d4b473,0f83577..4fe8632
--- a/shared-core/mga_irq.c
+++ b/shared-core/mga_irq.c
@@@ -87,37 -74,27 +87,39 @@@ irqreturn_t mga_driver_irq_handler(DRM_
  		handled = 1;
  	}
  
- 	return (handled) ? IRQ_HANDLED : IRQ_NONE;
+ 	if (handled)
+ 		return IRQ_HANDLED;
+ 	return IRQ_NONE;
  }
  
 -int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
 +int mga_enable_vblank(struct drm_device *dev, int crtc)
  {
 -	unsigned int cur_vblank;
 -	int ret = 0;
 +	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
  
 -	/* Assume that the user has missed the current sequence number
 -	 * by about a day rather than she wants to wait for years
 -	 * using vertical blanks...
 -	 */
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(&dev->vbl_received))
 -		      - *sequence) <= (1 << 23)));
 +	if (crtc != 0) {
 +		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 +			  crtc);
 +		return 0;
 +	}
  
 -	*sequence = cur_vblank;
 +	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
 +	return 0;
 +}
  
 -	return ret;
 +
 +void mga_disable_vblank(struct drm_device *dev, int crtc)
 +{
 +	if (crtc != 0) {
 +		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
 +			  crtc);
 +	}
 +
 +	/* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
 +	 * a nice hardware counter that tracks the number of refreshes when
 +	 * the interrupt is disabled, and the kernel doesn't know the refresh
 +	 * rate to calculate an estimate.
 +	 */
 +	/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
  }
  
  int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
diff --cc shared-core/radeon_drv.h
index a71b0be,c727880..bd51de1
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@@ -299,11 -305,9 +305,12 @@@ typedef struct drm_radeon_private 
  
  	u32 scratch_ages[5];
  
 +	unsigned int crtc_last_cnt;
 +	unsigned int crtc2_last_cnt;
 +
  	/* starting from here on, data is preserved accross an open */
  	uint32_t flags;		/* see radeon_chip_flags */
+ 	unsigned long fb_aper_offset;
  
  } drm_radeon_private_t;
  
diff --cc shared-core/radeon_irq.c
index 6ba3c14,7e202d2..79e4e86
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@@ -175,13 -144,17 +175,13 @@@ static int radeon_wait_irq(struct drm_d
  	return ret;
  }
  
 -static int radeon_driver_vblank_do_wait(struct drm_device * dev,
 -					unsigned int *sequence, int crtc)
 +u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
  {
 -	drm_radeon_private_t *dev_priv =
 -	    (drm_radeon_private_t *) dev->dev_private;
 -	unsigned int cur_vblank;
 -	int ret = 0;
 -	int ack = 0;
 -	atomic_t *counter;
 +	drm_radeon_private_t *dev_priv = dev->dev_private;
 +	u32 crtc_cnt_reg, crtc_status_reg;
 +
  	if (!dev_priv) {
- 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ 		DRM_ERROR("called with no initialization\n");
  		return -EINVAL;
  	}
  
diff --cc shared-core/via_irq.c
index a1d3324,2f9b203..b8e652e
--- a/shared-core/via_irq.c
+++ b/shared-core/via_irq.c
@@@ -90,22 -89,13 +89,22 @@@ static int via_num_unichrome = ARRAY_SI
  static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
  
  
- static unsigned time_diff(struct timeval *now,struct timeval *then) 
+ static unsigned time_diff(struct timeval *now,struct timeval *then)
  {
-     return (now->tv_usec >= then->tv_usec) ?
- 	now->tv_usec - then->tv_usec :
- 	1000000 - (then->tv_usec - now->tv_usec);
+ 	return (now->tv_usec >= then->tv_usec) ?
+ 		now->tv_usec - then->tv_usec :
+ 		1000000 - (then->tv_usec - now->tv_usec);
  }
  
 +u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
 +{
 +	drm_via_private_t *dev_priv = dev->dev_private;
 +	if (crtc != 0)
 +		return 0;
 +
 +	return atomic_read(&dev_priv->vbl_received);
 +}
 +
  irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
  {
  	struct drm_device *dev = (struct drm_device *) arg;
@@@ -133,18 -123,19 +132,18 @@@
  			dev_priv->last_vblank = cur_vblank;
  			dev_priv->last_vblank_valid = 1;
  		}
 -		if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
 +		if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
  			DRM_DEBUG("US per vblank is: %u\n",
- 				dev_priv->usec_per_vblank);
+ 				  dev_priv->usec_per_vblank);
  		}
 -		DRM_WAKEUP(&dev->vbl_queue);
 -		drm_vbl_send_signals(dev);
 +		drm_handle_vblank(dev, 0);
  		handled = 1;
  	}
- 	
- 	for (i=0; i<dev_priv->num_irqs; ++i) {
+ 
+ 	for (i = 0; i < dev_priv->num_irqs; ++i) {
  		if (status & cur_irq->pending_mask) {
- 			atomic_inc( &cur_irq->irq_received );
- 			DRM_WAKEUP( &cur_irq->irq_queue );
+ 			atomic_inc(&cur_irq->irq_received);
+ 			DRM_WAKEUP(&cur_irq->irq_queue);
  			handled = 1;
  #ifdef VIA_HAVE_DMABLIT
  			if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
@@@ -189,20 -182,19 +188,15 @@@ int via_enable_vblank(struct drm_devic
  		return -EINVAL;
  	}
  
 -	viadrv_acknowledge_irqs(dev_priv);
 -
 -	/* Assume that the user has missed the current sequence number
 -	 * by about a day rather than she wants to wait for years
 -	 * using vertical blanks...
 -	 */
 -
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(&dev->vbl_received)) -
 -		      *sequence) <= (1 << 23)));
 +	status = VIA_READ(VIA_REG_INTERRUPT);
 +	VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
 +	return 0;
 +}
  
 -	*sequence = cur_vblank;
 -	return ret;
 +void via_disable_vblank(struct drm_device *dev, int crtc)
 +{
 +	if (crtc != 0)
 +		DRM_ERROR("%s:  bad crtc %d\n", __FUNCTION__, crtc);
- 
- 	/*
- 	 * FIXME: implement proper interrupt disable by using the vblank
- 	 * counter register (if available).
- 	 */
  }
  
  static int
commit 128a8f7ea20af2549e448157b431d5c1f90f37c3
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Thu Nov 1 15:02:26 2007 -0700

    Use unsigned long instead of u64 in drm_modeset_ctl_t
    
    A bad idea, ABI-wise, but we're going to be changing this structure anyway
    before we merge upstream, so just fix the build for now.

diff --git a/shared-core/drm.h b/shared-core/drm.h
index 3092e53..cbd6a94 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -565,7 +565,7 @@ typedef enum {
  * \sa drmModesetCtl().
  */
 typedef struct drm_modeset_ctl {
-	u64 arg;
+	unsigned long arg;
 	drm_modeset_ctl_cmd_t cmd;
 } drm_modeset_ctl_t;
 
commit 00d60265570c866261c09fd3397d5853a1ce196a
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Thu Nov 1 12:50:03 2007 -0700

    Cleanup vblank_init and fix drm_irq_install
    
    The vblank_init function wanted a couple of cleanups.
    
    Also, drm_irq_install wasn't checking the new return value of irq_postinstall.
    If it returns a failure, assume IRQs didn't get set up and take appropriate
    action.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index e917e7e..4aa58d7 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -85,7 +85,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
 {
 	int i, ret = -ENOMEM;
 
-	setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\
+	setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
 		    (unsigned long)dev);
 	spin_lock_init(&dev->vbl_lock);
 	atomic_set(&dev->vbl_signal_pending, 0);
@@ -111,18 +111,16 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
 	if (!dev->vblank_refcount)
 		goto err;
 
-	dev->last_vblank = drm_calloc(1, sizeof(u32) * num_crtcs,
-				      DRM_MEM_DRIVER);
+	dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
 	if (!dev->last_vblank)
 		goto err;
 
-	dev->vblank_premodeset = drm_calloc(1, sizeof(u32) * num_crtcs,
+	dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32),
 					    DRM_MEM_DRIVER);
 	if (!dev->vblank_premodeset)
 		goto err;
 
-	dev->vblank_offset = drm_calloc(1, sizeof(u32) * num_crtcs,
-					DRM_MEM_DRIVER);
+	dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
 	if (!dev->vblank_offset)
 		goto err;
 
@@ -210,6 +208,11 @@ int drm_irq_install(struct drm_device * dev)
 
 	/* After installing handler */
 	ret = dev->driver->irq_postinstall(dev);
+	if (ret < 0) {
+		mutex_lock(&dev->struct_mutex);
+		dev->irq_enabled = 0;
+		mutex_unlock(&dev->struct_mutex);
+	}
 
 	return ret;
 }
commit 91aae7e683786a48547872b0a5fa92b2232e02c0
Merge: 7e9ea55... 79744d7...
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Tue Oct 30 12:52:46 2007 -0700

    Merge branch 'master' into vblank-rework, fixup remaining drivers
    
    Conflicts:
    
    	linux-core/drmP.h
    	linux-core/drm_drv.c
    	linux-core/drm_irq.c
    	shared-core/i915_drv.h
    	shared-core/i915_irq.c
    	shared-core/mga_drv.h
    	shared-core/mga_irq.c
    	shared-core/radeon_drv.h
    	shared-core/radeon_irq.c
    
    Merge in the latest master bits and update the remaining drivers (except
    mach64 which math_b is working on).  Also remove the 9xx hack from the i915
    driver; it seems to be correct.

diff --cc linux-core/drmP.h
index 0ab69fe,ac3ca4d..332ee1c
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@@ -687,16 -658,17 +698,17 @@@ struct drm_driver 
  /* these have to be filled in */
  	 irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
  	void (*irq_preinstall) (struct drm_device * dev);
 -	void (*irq_postinstall) (struct drm_device * dev);
 +	int (*irq_postinstall) (struct drm_device * dev);
  	void (*irq_uninstall) (struct drm_device * dev);
- 	void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
+ 	void (*reclaim_buffers) (struct drm_device *dev,
+ 				 struct drm_file *file_priv);
  	void (*reclaim_buffers_locked) (struct drm_device *dev,
- 					struct file * filp);
+ 					struct drm_file *file_priv);
  	void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
- 					struct file * filp);
- 	unsigned long (*get_map_ofs) (drm_map_t * map);
+ 					    struct drm_file *file_priv);
+ 	unsigned long (*get_map_ofs) (struct drm_map * map);
  	unsigned long (*get_reg_ofs) (struct drm_device * dev);
- 	void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
+ 	void (*set_version) (struct drm_device * dev, struct drm_set_version * sv);
  
  	struct drm_fence_driver *fence_driver;
  	struct drm_bo_driver *bo_driver;
@@@ -854,10 -821,9 +867,10 @@@ struct drm_device 
  #ifdef __alpha__
  	struct pci_controller *hose;
  #endif
 +	int num_crtcs;			/**< Number of CRTCs on this device */
- 	drm_sg_mem_t *sg;		/**< Scatter gather memory */
+ 	struct drm_sg_mem *sg;		/**< Scatter gather memory */
  	void *dev_private;		/**< device private data */
- 	drm_sigdata_t sigdata;		/**< For block_all_signals */
+ 	struct drm_sigdata sigdata;		/**< For block_all_signals */
  	sigset_t sigmask;
  
  	struct drm_driver *driver;
@@@ -1072,94 -1040,90 +1087,98 @@@ extern void drm_idlelock_release(struc
   * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
   */
  
- extern int drm_i_have_hw_lock(struct file *filp);
- extern int drm_kernel_take_hw_lock(struct file *filp);
+ extern int drm_i_have_hw_lock(struct drm_device *dev,
+ 			      struct drm_file *file_priv);
  
  				/* Buffer management support (drm_bufs.h) */
- extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
- extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request);
- extern int drm_addbufs_fb (drm_device_t * dev, drm_buf_desc_t * request);
- extern int drm_addmap(drm_device_t * dev, unsigned int offset,
- 		      unsigned int size, drm_map_type_t type,
- 		      drm_map_flags_t flags, drm_local_map_t ** map_ptr);
- extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
- 			    unsigned int cmd, unsigned long arg);
- extern int drm_rmmap(drm_device_t *dev, drm_local_map_t *map);
- extern int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map);
- extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
- 			   unsigned int cmd, unsigned long arg);
- extern int drm_addbufs(struct inode *inode, struct file *filp,
- 		       unsigned int cmd, unsigned long arg);
- extern int drm_infobufs(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
- extern int drm_markbufs(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
- extern int drm_freebufs(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
- extern int drm_mapbufs(struct inode *inode, struct file *filp,
- 		       unsigned int cmd, unsigned long arg);
+ extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
+ extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request);
+ extern int drm_addbufs_fb (struct drm_device *dev, struct drm_buf_desc * request);
+ extern int drm_addmap(struct drm_device *dev, unsigned int offset,
+ 		      unsigned int size, enum drm_map_type type,
+ 		      enum drm_map_flags flags, drm_local_map_t ** map_ptr);
+ extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
+ 			    struct drm_file *file_priv);
+ extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
+ extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map);
+ extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+ 			   struct drm_file *file_priv);
+ extern int drm_addbufs(struct drm_device *dev, void *data,
+ 		       struct drm_file *file_priv);
+ extern int drm_infobufs(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
+ extern int drm_markbufs(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
+ extern int drm_freebufs(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
+ extern int drm_mapbufs(struct drm_device *dev, void *data,
+ 		       struct drm_file *file_priv);
  extern int drm_order(unsigned long size);
- extern unsigned long drm_get_resource_start(drm_device_t *dev,
+ extern unsigned long drm_get_resource_start(struct drm_device *dev,
  					    unsigned int resource);
- extern unsigned long drm_get_resource_len(drm_device_t *dev,
+ extern unsigned long drm_get_resource_len(struct drm_device *dev,
  					  unsigned int resource);
+ extern struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
+ 						  drm_local_map_t *map);
+ 
  
  				/* DMA support (drm_dma.h) */
- extern int drm_dma_setup(drm_device_t * dev);
- extern void drm_dma_takedown(drm_device_t * dev);
- extern void drm_free_buffer(drm_device_t * dev, drm_buf_t * buf);
- extern void drm_core_reclaim_buffers(drm_device_t *dev, struct file *filp);
+ extern int drm_dma_setup(struct drm_device *dev);
+ extern void drm_dma_takedown(struct drm_device *dev);
+ extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
+ extern void drm_core_reclaim_buffers(struct drm_device *dev,
+ 				     struct drm_file *filp);
  
  				/* IRQ support (drm_irq.h) */
- extern int drm_control(struct inode *inode, struct file *filp,
- 		       unsigned int cmd, unsigned long arg);
+ extern int drm_control(struct drm_device *dev, void *data,
+ 		       struct drm_file *file_priv);
  extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
- extern int drm_irq_uninstall(drm_device_t *dev);
- extern void drm_driver_irq_preinstall(drm_device_t * dev);
- extern void drm_driver_irq_postinstall(drm_device_t * dev);
- extern void drm_driver_irq_uninstall(drm_device_t * dev);
- 
- extern int drm_vblank_init(drm_device_t *dev, int num_crtcs);
- extern int drm_wait_vblank(struct inode *inode, struct file *filp,
- 			   unsigned int cmd, unsigned long arg);
- extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq);
- extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*));
- extern u32 drm_vblank_count(drm_device_t *dev, int crtc);
- extern void drm_update_vblank_count(drm_device_t *dev, int crtc);
- extern void drm_handle_vblank(drm_device_t *dev, int crtc);
- extern int drm_vblank_get(drm_device_t *dev, int crtc);
- extern void drm_vblank_put(drm_device_t *dev, int crtc);
+ extern int drm_irq_install(struct drm_device *dev);
+ extern int drm_irq_uninstall(struct drm_device *dev);
+ extern void drm_driver_irq_preinstall(struct drm_device *dev);
+ extern void drm_driver_irq_postinstall(struct drm_device *dev);
+ extern void drm_driver_irq_uninstall(struct drm_device *dev);
+ 
 -extern int drm_wait_vblank(struct drm_device *dev, void *data,
 -			   struct drm_file *file_priv);
 -extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
 -extern void drm_vbl_send_signals(struct drm_device *dev);
++extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
++extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file \
*filp); ++extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq);
+ extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct \
drm_device*)); ++extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
++extern void drm_update_vblank_count(struct drm_device *dev, int crtc);
++extern void drm_handle_vblank(struct drm_device *dev, int crtc);
++extern int drm_vblank_get(struct drm_device *dev, int crtc);
++extern void drm_vblank_put(struct drm_device *dev, int crtc);
 +
 +				/* Modesetting support */
- extern int drm_modeset_ctl(struct inode *inode, struct file *filp,
- 			   unsigned int cmd, unsigned long arg);
++extern int drm_modeset_ctl(struct drm_device *dev, void *data,
++			   struct drm_file *file_priv);
  
  				/* AGP/GART support (drm_agpsupport.h) */
- extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
- extern int drm_agp_acquire(drm_device_t * dev);
- extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
- 			   unsigned int cmd, unsigned long arg);
- extern int drm_agp_release(drm_device_t *dev);
- extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
- 			   unsigned int cmd, unsigned long arg);
- extern int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode);
- extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
- 			  unsigned int cmd, unsigned long arg);
- extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info);
- extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
- extern int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request);
- extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
- 			 unsigned int cmd, unsigned long arg);
- extern int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request);
- extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
- extern int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request);
- extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
- 			  unsigned int cmd, unsigned long arg);
- extern int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request);
- extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
- 			unsigned int cmd, unsigned long arg);
+ extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
+ extern int drm_agp_acquire(struct drm_device *dev);
+ extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+ 				 struct drm_file *file_priv);
+ extern int drm_agp_release(struct drm_device *dev);
+ extern int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+ 				 struct drm_file *file_priv);
+ extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
+ extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+ 				struct drm_file *file_priv);
+ extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info);
+ extern int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
+ extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
+ extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+ 			 struct drm_file *file_priv);
+ extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
+ extern int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
+ extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
+ extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+ 			  struct drm_file *file_priv);
+ extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
+ extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+ 			struct drm_file *file_priv);
  #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)
  extern DRM_AGP_MEM *drm_agp_allocate_memory(size_t pages, u32 type);
  #else
diff --cc linux-core/drm_drv.c
index 1b37ee4,47d1765..296a326
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@@ -48,82 -48,108 +48,106 @@@
  #include "drmP.h"
  #include "drm_core.h"
  
- static void drm_cleanup(drm_device_t * dev);
+ static void drm_cleanup(struct drm_device * dev);
  int drm_fb_loaded = 0;
  
- static int drm_version(struct inode *inode, struct file *filp,
- 		unsigned int cmd, unsigned long arg);
+ static int drm_version(struct drm_device *dev, void *data,
+ 		       struct drm_file *file_priv);
  
  /** Ioctl table */
- static drm_ioctl_desc_t drm_ioctls[] = {
- 	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, \
                DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0},
- 	[DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, \
                DRM_MASTER|DRM_ROOT_ONLY},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH},
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH},
+ static struct drm_ioctl_desc drm_ioctls[] = {
+ 	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, \
drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, \
drm_rmmap_ioctl, DRM_AUTH), + 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, \
drm_getsareactx, DRM_AUTH), + 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, \
DRM_AUTH), + 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, \
drm_infobufs, DRM_AUTH), + 	DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
  	/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
- 	[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH},
+ 	DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH),
  
- 	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + 	DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  
  #if __OS_HAS_AGP
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + 	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, \
drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + \
DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, \
drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + \
DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), + \
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, \
drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + \
DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, \
drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  #endif
  
- 	[DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[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_FENCE)] = {drm_fence_ioctl, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH},
- 	[DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, 
- 					     DRM_AUTH },
- 
- 	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- 	[DRM_IOCTL_NR(DRM_IOCTL_MODESET_CTL)] = {drm_modeset_ctl, 0},
+ 	DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 	DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, \
                DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 -
+ 	DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
+ 
 -	//	DRM_IOCTL_DEF(DRM_IOCTL_BUFOBJ, drm_bo_ioctl, DRM_AUTH),
++	DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + 
 -
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, 
+ 		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, 
+ 		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl, 
+ 		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl, 
+ 		      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_REFERENCE, drm_fence_reference_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_UNREFERENCE, drm_fence_unreference_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_SIGNALED, drm_fence_signaled_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_FLUSH, drm_fence_flush_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_WAIT, drm_fence_wait_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_EMIT, drm_fence_emit_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_FENCE_BUFFERS, drm_fence_buffers_ioctl, DRM_AUTH),
+ 
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_CREATE, drm_bo_create_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_MAP, drm_bo_map_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_UNMAP, drm_bo_unmap_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_REFERENCE, drm_bo_reference_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_UNREFERENCE, drm_bo_unreference_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_SETSTATUS, drm_bo_setstatus_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH),
+ 	DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0),
  };
  
  #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --cc linux-core/drm_irq.c
index eea00ac,25166b6..e917e7e
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@@ -74,93 -71,6 +71,90 @@@ int drm_irq_by_busid(struct drm_device 
- 	DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq);
- 	if (copy_to_user(argp, &p, sizeof(p)))
- 		return -EFAULT;
  	return 0;
  }
  
 +static void vblank_disable_fn(unsigned long arg)
 +{
- 	drm_device_t *dev = (drm_device_t *)arg;
++	struct drm_device *dev = (struct drm_device *)arg;
 +	int i;
 +
 +	for (i = 0; i < dev->num_crtcs; i++)
 +		if (atomic_read(&dev->vblank_refcount[i]) == 0)
 +			dev->driver->disable_vblank(dev, i);
 +}
 +
- int drm_vblank_init(drm_device_t *dev, int num_crtcs)
++int drm_vblank_init(struct drm_device *dev, int num_crtcs)
 +{
 +	int i, ret = -ENOMEM;
 +
 +	setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\
 +		    (unsigned long)dev);
 +	spin_lock_init(&dev->vbl_lock);
 +	atomic_set(&dev->vbl_signal_pending, 0);
 +	dev->num_crtcs = num_crtcs;
 +
 +	dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
 +				   DRM_MEM_DRIVER);
 +	if (!dev->vbl_queue)
 +		goto err;
 +
 +	dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
 +				  DRM_MEM_DRIVER);
 +	if (!dev->vbl_sigs)
 +		goto err;
 +
 +	dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
 +				      DRM_MEM_DRIVER);
 +	if (!dev->_vblank_count)
 +		goto err;
 +
 +	dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
 +					 DRM_MEM_DRIVER);
 +	if (!dev->vblank_refcount)
 +		goto err;
 +
 +	dev->last_vblank = drm_calloc(1, sizeof(u32) * num_crtcs,
 +				      DRM_MEM_DRIVER);
 +	if (!dev->last_vblank)
 +		goto err;
 +
 +	dev->vblank_premodeset = drm_calloc(1, sizeof(u32) * num_crtcs,
 +					    DRM_MEM_DRIVER);
 +	if (!dev->vblank_premodeset)
 +		goto err;
 +
 +	dev->vblank_offset = drm_calloc(1, sizeof(u32) * num_crtcs,
 +					DRM_MEM_DRIVER);
 +	if (!dev->vblank_offset)
 +		goto err;
 +
 +	/* Zero per-crtc vblank stuff */
 +	for (i = 0; i < num_crtcs; i++) {
 +		init_waitqueue_head(&dev->vbl_queue[i]);
 +		INIT_LIST_HEAD(&dev->vbl_sigs[i]);
 +		atomic_set(&dev->_vblank_count[i], 0);
 +		atomic_set(&dev->vblank_refcount[i], 0);
 +	}
 +
 +	return 0;
 +
 +err:
 +	drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * num_crtcs,
 +		 DRM_MEM_DRIVER);
 +	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs,
 +		 DRM_MEM_DRIVER);
 +	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs,
 +		 DRM_MEM_DRIVER);
 +	drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
 +		 num_crtcs, DRM_MEM_DRIVER);
 +	drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs,
 +		 DRM_MEM_DRIVER);
 +	drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
 +		 num_crtcs, DRM_MEM_DRIVER);
 +	drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * num_crtcs,
 +		 DRM_MEM_DRIVER);
 +	return ret;
 +}
 +EXPORT_SYMBOL(drm_vblank_init);
 +
  /**
   * Install IRQ handler.
   *
@@@ -170,9 -80,9 +164,9 @@@
   * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
   * before and after the installation.
   */
- static int drm_irq_install(drm_device_t * dev)
+ int drm_irq_install(struct drm_device * dev)
  {
 -	int ret;
 +	int ret = 0;
  	unsigned long sh_flags = 0;
  
  	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
@@@ -215,10 -136,11 +209,11 @@@
  	}
  
  	/* After installing handler */
 -	dev->driver->irq_postinstall(dev);
 +	ret = dev->driver->irq_postinstall(dev);
  
 -	return 0;
 +	return ret;
  }
+ EXPORT_SYMBOL(drm_irq_install);
  
  /**
   * Uninstall the IRQ handler.
@@@ -295,150 -213,6 +286,149 @@@ int drm_control(struct drm_device *dev
  }
  
  /**
 + * drm_vblank_count - retrieve "cooked" vblank counter value
 + * @dev: DRM device
 + * @crtc: which counter to retrieve
 + *
 + * Fetches the "cooked" vblank count value that represents the number of
 + * vblank events since the system was booted, including lost events due to
 + * modesetting activity.
 + */
- u32 drm_vblank_count(drm_device_t *dev, int crtc)
++u32 drm_vblank_count(struct drm_device *dev, int crtc)
 +{
 +	return atomic_read(&dev->_vblank_count[crtc]) +
 +		dev->vblank_offset[crtc];
 +}
 +EXPORT_SYMBOL(drm_vblank_count);
 +
 +/**
 + * drm_update_vblank_count - update the master vblank counter
 + * @dev: DRM device
 + * @crtc: counter to update
 + *
 + * Call back into the driver to update the appropriate vblank counter
 + * (specified by @crtc).  Deal with wraparound, if it occurred, and
 + * update the last read value so we can deal with wraparound on the next
 + * call if necessary.
 + */
- void drm_update_vblank_count(drm_device_t *dev, int crtc)
++void drm_update_vblank_count(struct drm_device *dev, int crtc)
 +{
 +	unsigned long irqflags;
 +	u32 cur_vblank, diff;
 +
 +	/*
 +	 * Interrupts were disabled prior to this call, so deal with counter
 +	 * wrap if needed.
 +	 * NOTE!  It's possible we lost a full dev->max_vblank_count events
 +	 * here if the register is small or we had vblank interrupts off for
 +	 * a long time.
 +	 */
 +	cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
 +	spin_lock_irqsave(&dev->vbl_lock, irqflags);
 +	if (cur_vblank < dev->last_vblank[crtc]) {
 +		diff = dev->max_vblank_count -
 +			dev->last_vblank[crtc];
 +		diff += cur_vblank;
 +	} else {
 +		diff = cur_vblank - dev->last_vblank[crtc];
 +	}
 +	dev->last_vblank[crtc] = cur_vblank;
 +	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 +
 +	atomic_add(diff, &dev->_vblank_count[crtc]);
 +}
 +EXPORT_SYMBOL(drm_update_vblank_count);
 +
 +/**
 + * drm_vblank_get - get a reference count on vblank events
 + * @dev: DRM device
 + * @crtc: which CRTC to own
 + *
 + * Acquire a reference count on vblank events to avoid having them disabled
 + * while in use.  Note callers will probably want to update the master counter
 + * using drm_update_vblank_count() above before calling this routine so that
 + * wakeups occur on the right vblank event.
 + *
 + * RETURNS
 + * Zero on success, nonzero on failure.
 + */
- int drm_vblank_get(drm_device_t *dev, int crtc)
++int drm_vblank_get(struct drm_device *dev, int crtc)
 +{
 +	int ret = 0;
 +
 +	/* Going from 0->1 means we have to enable interrupts again */
 +	if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
 +		ret = dev->driver->enable_vblank(dev, crtc);
 +		if (ret)
 +			atomic_dec(&dev->vblank_refcount[crtc]);
 +	}
 +
 +	return ret;
 +}
 +EXPORT_SYMBOL(drm_vblank_get);
 +
 +/**
 + * drm_vblank_put - give up ownership of vblank events
 + * @dev: DRM device
 + * @crtc: which counter to give up
 + *
 + * Release ownership of a given vblank counter, turning off interrupts
 + * if possible.
 + */
- void drm_vblank_put(drm_device_t *dev, int crtc)
++void drm_vblank_put(struct drm_device *dev, int crtc)
 +{
 +	/* Last user schedules interrupt disable */
 +	if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
 +		mod_timer(&dev->vblank_disable_timer,
 +			  round_jiffies_relative(DRM_HZ));
 +}
 +EXPORT_SYMBOL(drm_vblank_put);
 +
 +/**
 + * drm_modeset_ctl - handle vblank event counter changes across mode switch
 + * @DRM_IOCTL_ARGS: standard ioctl arguments
 + *
 + * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
 + * ioctls around modesetting so that any lost vblank events are accounted for.
 + */
- int drm_modeset_ctl(DRM_IOCTL_ARGS)
++int drm_modeset_ctl(struct drm_device *dev, void *data,
++		    struct drm_file *file_priv)
 +{
- 	drm_file_t *priv = filp->private_data;
- 	drm_device_t *dev = priv->head->dev;
 +	drm_modeset_ctl_t __user *argp = (void __user *)data;
 +	drm_modeset_ctl_t modeset;
 +	int crtc, ret = 0;
 +	u32 new;
 +
 +	if (copy_from_user(&modeset, argp, sizeof(modeset))) {
 +		ret = -EFAULT;
 +		goto out;
 +	}
 +
 +	crtc = modeset.arg;
 +	if (crtc >= dev->num_crtcs) {
 +		ret = -EINVAL;
 +		goto out;
 +	}
 +
 +	switch (modeset.cmd) {
 +	case _DRM_PRE_MODESET:
 +		dev->vblank_premodeset[crtc] =
 +			dev->driver->get_vblank_counter(dev, crtc);
 +		break;
 +	case _DRM_POST_MODESET:
 +		new = dev->driver->get_vblank_counter(dev, crtc);
 +		dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new;
 +		break;
 +	default:
 +		ret = -EINVAL;
 +		break;
 +	}
 +
 +out:
 +	return ret;
 +}
 +
 +/**
   * Wait for VBLANK.
   *
   * \param inode device inode.
@@@ -457,15 -231,12 +447,13 @@@
   *
   * If a signal is not requested, then calls vblank_wait().
   */
- int drm_wait_vblank(DRM_IOCTL_ARGS)
 -int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
++int drm_wait_vblank(struct drm_device *dev, void *data,
++		    struct drm_file *file_priv)
  {
- 	drm_file_t *priv = filp->private_data;
- 	drm_device_t *dev = priv->head->dev;
- 	drm_wait_vblank_t __user *argp = (void __user *)data;
- 	drm_wait_vblank_t vblwait;
+ 	union drm_wait_vblank *vblwait = data;
  	struct timeval now;
  	int ret = 0;
 -	unsigned int flags, seq;
 +	unsigned int flags, seq, crtc;
  
  	if ((!dev->irq) || (!dev->irq_enabled))
  		return -EINVAL;
@@@ -481,19 -249,19 +466,19 @@@
  		return -EINVAL;
  	}
  
- 	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+ 	flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
 +	crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
  
 -	if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
 -				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
 +	if (crtc >= dev->num_crtcs)
  		return -EINVAL;
  
 -	seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
 -			  : &dev->vbl_received);
 +	drm_update_vblank_count(dev, crtc);
 +	seq = drm_vblank_count(dev, crtc);
  
- 	switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
+ 	switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
  	case _DRM_VBLANK_RELATIVE:
- 		vblwait.request.sequence += seq;
- 		vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ 		vblwait->request.sequence += seq;
+ 		vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
  	case _DRM_VBLANK_ABSOLUTE:
  		break;
  	default:
@@@ -507,8 -275,9 +492,8 @@@
  
  	if (flags & _DRM_VBLANK_SIGNAL) {
  		unsigned long irqflags;
 -		struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
 -				      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
 +		struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
- 		drm_vbl_sig_t *vbl_sig;
+ 		struct drm_vbl_sig *vbl_sig;
  
  		spin_lock_irqsave(&dev->vbl_lock, irqflags);
  
@@@ -532,24 -302,20 +518,24 @@@
  			return -EBUSY;
  		}
  
 -		dev->vbl_pending++;
 -
  		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  
- 		vbl_sig = drm_calloc(1, sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER);
- 		if (!vbl_sig) {
 -		if (!
 -		    (vbl_sig =
 -		     drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
++		vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
++				     DRM_MEM_DRIVER);
++		if (!vbl_sig)
  			return -ENOMEM;
- 		}
 +
 +		ret = drm_vblank_get(dev, crtc);
 +		if (ret) {
- 			drm_free(vbl_sig, sizeof(drm_vbl_sig_t),
++			drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
 +				 DRM_MEM_DRIVER);
 +			return ret;
  		}
  
 -		memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
 +		atomic_inc(&dev->vbl_signal_pending);
  
- 		vbl_sig->sequence = vblwait.request.sequence;
- 		vbl_sig->info.si_signo = vblwait.request.signal;
+ 		vbl_sig->sequence = vblwait->request.sequence;
+ 		vbl_sig->info.si_signo = vblwait->request.signal;
  		vbl_sig->task = current;
  
  		spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@@ -558,21 -324,19 +544,22 @@@
  
  		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  
- 		vblwait.reply.sequence = seq;
+ 		vblwait->reply.sequence = seq;
  	} else {
 -		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);
 -
 +		unsigned long cur_vblank;
 +
 +		ret = drm_vblank_get(dev, crtc);
 +		if (ret)
 +			return ret;
 +		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
 +			    (((cur_vblank = drm_vblank_count(dev, crtc))
- 			      - vblwait.request.sequence) <= (1 << 23)));
++			      - vblwait->request.sequence) <= (1 << 23)));
 +		drm_vblank_put(dev, crtc);
  		do_gettimeofday(&now);
- 		vblwait.reply.tval_sec = now.tv_sec;
- 		vblwait.reply.tval_usec = now.tv_usec;
- 		vblwait.reply.sequence = cur_vblank;
++
+ 		vblwait->reply.tval_sec = now.tv_sec;
+ 		vblwait->reply.tval_usec = now.tv_usec;
++		vblwait->reply.sequence = cur_vblank;
  	}
  
        done:
@@@ -592,12 -352,10 +576,12 @@@
   *
   * If a signal is not requested, then calls vblank_wait().
   */
- static void drm_vbl_send_signals(drm_device_t * dev, int crtc)
 -void drm_vbl_send_signals(struct drm_device * dev)
++static void drm_vbl_send_signals(struct drm_device * dev, int crtc)
  {
- 	drm_vbl_sig_t *vbl_sig, *tmp;
++	struct drm_vbl_sig *vbl_sig, *tmp;
 +	struct list_head *vbl_sigs;
 +	unsigned int vbl_seq;
  	unsigned long flags;
 -	int i;
  
  	spin_lock_irqsave(&dev->vbl_lock, flags);
  
@@@ -621,22 -383,7 +605,22 @@@
  
  	spin_unlock_irqrestore(&dev->vbl_lock, flags);
  }
 -EXPORT_SYMBOL(drm_vbl_send_signals);
 +
 +/**
 + * drm_handle_vblank - handle a vblank event
 + * @dev: DRM device
 + * @crtc: where this event occurred
 + *
 + * Drivers should call this routine in their vblank interrupt handlers to
 + * update the vblank counter and send any signals that may be pending.
 + */
- void drm_handle_vblank(drm_device_t *dev, int crtc)
++void drm_handle_vblank(struct drm_device *dev, int crtc)
 +{
 +	drm_update_vblank_count(dev, crtc);
 +	DRM_WAKEUP(&dev->vbl_queue[crtc]);
 +	drm_vbl_send_signals(dev, crtc);
 +}
 +EXPORT_SYMBOL(drm_handle_vblank);
  
  /**
   * Tasklet wrapper function.
diff --cc linux-core/i915_drv.c
index e7f69e6,124db68..84df64a
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@@ -76,15 -529,18 +529,18 @@@ 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_IRQ_VBL2,
 +	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
  	.load = i915_driver_load,
+ 	.unload = i915_driver_unload,
  	.firstopen = i915_driver_firstopen,
  	.lastclose = i915_driver_lastclose,
  	.preclose = i915_driver_preclose,
+ 	.suspend = i915_suspend,
+ 	.resume = i915_resume,
  	.device_is_agp = i915_driver_device_is_agp,
 -	.vblank_wait = i915_driver_vblank_wait,
 -	.vblank_wait2 = i915_driver_vblank_wait2,
 +	.get_vblank_counter = i915_get_vblank_counter,
 +	.enable_vblank = i915_enable_vblank,
 +	.disable_vblank = i915_disable_vblank,
  	.irq_preinstall = i915_driver_irq_preinstall,
  	.irq_postinstall = i915_driver_irq_postinstall,
  	.irq_uninstall = i915_driver_irq_uninstall,
diff --cc linux-core/r128_drv.c
index ef4a5cb,ef4a5cb..7b6159b
--- a/linux-core/r128_drv.c
+++ b/linux-core/r128_drv.c
@@@ -44,12 -44,12 +44,13 @@@ static int probe(struct pci_dev *pdev, 
  static struct drm_driver driver = {
  	.driver_features =
  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
--	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
--	    DRIVER_IRQ_VBL,
++	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
  	.dev_priv_size = sizeof(drm_r128_buf_priv_t),
  	.preclose = r128_driver_preclose,
  	.lastclose = r128_driver_lastclose,
--	.vblank_wait = r128_driver_vblank_wait,
++	.get_vblank_counter = r128_get_vblank_counter,
++	.enable_vblank = r128_enable_vblank,
++	.disable_vblank = r128_disable_vblank,
  	.irq_preinstall = r128_driver_irq_preinstall,
  	.irq_postinstall = r128_driver_irq_postinstall,
  	.irq_uninstall = r128_driver_irq_uninstall,
diff --cc shared-core/drm.h
index eae25c6,3a10273..3092e53
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@@ -582,26 -549,11 +549,26 @@@ struct drm_wait_vblank_reply 
   *
   * \sa drmWaitVBlank().
   */
- typedef union drm_wait_vblank {
+ union drm_wait_vblank {
  	struct drm_wait_vblank_request request;
  	struct drm_wait_vblank_reply reply;
- } drm_wait_vblank_t;
+ };
  
 +typedef enum {
 +	_DRM_PRE_MODESET = 1,
 +	_DRM_POST_MODESET = 2,
 +} drm_modeset_ctl_cmd_t;
 +
 +/**
 + * DRM_IOCTL_MODESET_CTL ioctl argument type
 + *
 + * \sa drmModesetCtl().
 + */
 +typedef struct drm_modeset_ctl {
- 	drm_u64_t arg;
++	u64 arg;
 +	drm_modeset_ctl_cmd_t cmd;
 +} drm_modeset_ctl_t;
 +
  /**
   * DRM_IOCTL_AGP_ENABLE ioctl argument type.
   *
@@@ -950,26 -939,45 +954,47 @@@ struct drm_mm_init_arg 
  
  #define DRM_IOCTL_AGP_ACQUIRE		DRM_IO(  0x30)
  #define DRM_IOCTL_AGP_RELEASE		DRM_IO(  0x31)
- #define DRM_IOCTL_AGP_ENABLE		DRM_IOW( 0x32, drm_agp_mode_t)
- #define DRM_IOCTL_AGP_INFO		DRM_IOR( 0x33, drm_agp_info_t)
- #define DRM_IOCTL_AGP_ALLOC		DRM_IOWR(0x34, drm_agp_buffer_t)
- #define DRM_IOCTL_AGP_FREE		DRM_IOW( 0x35, drm_agp_buffer_t)
- #define DRM_IOCTL_AGP_BIND		DRM_IOW( 0x36, drm_agp_binding_t)
- #define DRM_IOCTL_AGP_UNBIND		DRM_IOW( 0x37, drm_agp_binding_t)
- 
- #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, drm_scatter_gather_t)
- #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, drm_scatter_gather_t)
- 
- #define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, drm_wait_vblank_t)
+ #define DRM_IOCTL_AGP_ENABLE		DRM_IOW( 0x32, struct drm_agp_mode)
+ #define DRM_IOCTL_AGP_INFO		DRM_IOR( 0x33, struct drm_agp_info)
+ #define DRM_IOCTL_AGP_ALLOC		DRM_IOWR(0x34, struct drm_agp_buffer)
+ #define DRM_IOCTL_AGP_FREE		DRM_IOW( 0x35, struct drm_agp_buffer)
+ #define DRM_IOCTL_AGP_BIND		DRM_IOW( 0x36, struct drm_agp_binding)
+ #define DRM_IOCTL_AGP_UNBIND		DRM_IOW( 0x37, struct drm_agp_binding)
+ 
+ #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, struct drm_scatter_gather)
+ #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, struct drm_scatter_gather)
+ 
+ #define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, union drm_wait_vblank)
+ 
+ #define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, struct drm_update_draw)
+ 
+ #define DRM_IOCTL_MM_INIT               DRM_IOWR(0xc0, struct drm_mm_init_arg)
+ #define DRM_IOCTL_MM_TAKEDOWN           DRM_IOWR(0xc1, struct drm_mm_type_arg)
+ #define DRM_IOCTL_MM_LOCK               DRM_IOWR(0xc2, struct drm_mm_type_arg)
+ #define DRM_IOCTL_MM_UNLOCK             DRM_IOWR(0xc3, struct drm_mm_type_arg)
+ 
+ #define DRM_IOCTL_FENCE_CREATE          DRM_IOWR(0xc4, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_REFERENCE       DRM_IOWR(0xc6, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_UNREFERENCE     DRM_IOWR(0xc7, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_SIGNALED        DRM_IOWR(0xc8, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_FLUSH           DRM_IOWR(0xc9, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_WAIT            DRM_IOWR(0xca, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_EMIT            DRM_IOWR(0xcb, struct drm_fence_arg)
+ #define DRM_IOCTL_FENCE_BUFFERS         DRM_IOWR(0xcc, struct drm_fence_arg)
+ 
+ #define DRM_IOCTL_BO_CREATE             DRM_IOWR(0xcd, struct drm_bo_create_arg)
+ #define DRM_IOCTL_BO_MAP                DRM_IOWR(0xcf, struct \
drm_bo_map_wait_idle_arg) + #define DRM_IOCTL_BO_UNMAP              DRM_IOWR(0xd0, \
struct drm_bo_handle_arg) + #define DRM_IOCTL_BO_REFERENCE          DRM_IOWR(0xd1, \
struct drm_bo_reference_info_arg) + #define DRM_IOCTL_BO_UNREFERENCE        \
DRM_IOWR(0xd2, struct drm_bo_handle_arg) + #define DRM_IOCTL_BO_SETSTATUS          \
DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg) + #define DRM_IOCTL_BO_INFO           \
DRM_IOWR(0xd4, struct drm_bo_reference_info_arg) + #define DRM_IOCTL_BO_WAIT_IDLE     \
DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) + #define DRM_IOCTL_BO_VERSION        \
DRM_IOR(0xd6, struct drm_bo_version_arg)  
- #define DRM_IOCTL_FENCE                 DRM_IOWR(0x3b, drm_fence_arg_t)
- #define DRM_IOCTL_BUFOBJ                DRM_IOWR(0x3d, drm_bo_arg_t)
- #define DRM_IOCTL_MM_INIT               DRM_IOWR(0x3e, drm_mm_init_arg_t)
- 
- #define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, drm_update_draw_t)
  
 +#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0xa0, drm_modeset_ctl_t)
 +
  /*@}*/
  
  /**
diff --cc shared-core/i915_drv.h
index c8961c0,9f69d84..d34621e
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@@ -158,31 -252,40 +252,41 @@@ extern int i915_emit_mi_flush(struct dr
  extern int i915_driver_firstopen(struct drm_device *dev);
  
  /* i915_irq.c */
- extern int i915_irq_emit(DRM_IOCTL_ARGS);
- extern int i915_irq_wait(DRM_IOCTL_ARGS);
+ extern int i915_irq_emit(struct drm_device *dev, void *data,
+ 			 struct drm_file *file_priv);
+ extern int i915_irq_wait(struct drm_device *dev, void *data,
+ 			 struct drm_file *file_priv);
  
 -extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
 -extern int i915_driver_vblank_wait2(struct drm_device *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 int i915_driver_irq_postinstall(drm_device_t * dev);
- 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_emit_irq(drm_device_t * dev);
+ extern void i915_driver_irq_preinstall(struct drm_device * dev);
 -extern void i915_driver_irq_postinstall(struct drm_device * dev);
++extern int i915_driver_irq_postinstall(struct drm_device * dev);
+ extern void i915_driver_irq_uninstall(struct drm_device * dev);
+ extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+ 				struct drm_file *file_priv);
+ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ 				struct drm_file *file_priv);
+ extern int i915_emit_irq(struct drm_device * dev);
 -extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
 -extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
++extern int i915_enable_vblank(struct drm_device *dev, int crtc);
++extern void i915_disable_vblank(struct drm_device *dev, int crtc);
++extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
+ extern int i915_vblank_swap(struct drm_device *dev, void *data,
+ 			    struct drm_file *file_priv);
 +extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
 +extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
- extern int i915_vblank_swap(DRM_IOCTL_ARGS);
- extern int i915_enable_vblank(drm_device_t *dev, int crtc);
- extern void i915_disable_vblank(drm_device_t *dev, int crtc);
- extern u32 i915_get_vblank_counter(drm_device_t *dev, int crtc);
  
  /* i915_mem.c */
- extern int i915_mem_alloc(DRM_IOCTL_ARGS);
- extern int i915_mem_free(DRM_IOCTL_ARGS);
- extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
- extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
+ extern int i915_mem_alloc(struct drm_device *dev, void *data,
+ 			  struct drm_file *file_priv);
+ extern int i915_mem_free(struct drm_device *dev, void *data,
+ 			 struct drm_file *file_priv);
+ extern int i915_mem_init_heap(struct drm_device *dev, void *data,
+ 			      struct drm_file *file_priv);
+ extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
+ 				 struct drm_file *file_priv);
  extern void i915_mem_takedown(struct mem_block **heap);
- extern void i915_mem_release(drm_device_t * dev,
- 			     DRMFILE filp, struct mem_block *heap);
+ extern void i915_mem_release(struct drm_device * dev,
+ 			     struct drm_file *file_priv,
+ 			     struct mem_block *heap);
  #ifdef I915_HAVE_FENCE
  /* i915_fence.c */
  
diff --cc shared-core/i915_irq.c
index c0c1bf9,db18a89..46d0966
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@@ -86,14 -109,14 +109,13 @@@ i915_dispatch_vsync_flip(struct drm_dev
   *
   * This function will be called with the HW lock held.
   */
- static void i915_vblank_tasklet(drm_device_t *dev)
+ static void i915_vblank_tasklet(struct drm_device *dev)
  {
  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- 	unsigned long irqflags;
  	struct list_head *list, *tmp, hits, *hit;
  	int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
 -	unsigned counter[2] = { atomic_read(&dev->vbl_received),
 -				atomic_read(&dev->vbl_received2) };
 +	unsigned counter[2];
- 	drm_drawable_info_t *drw;
+ 	struct drm_drawable_info *drw;
  	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
  	u32 cpp = dev_priv->cpp,  offsets[3];
  	u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
@@@ -119,17 -144,16 +146,17 @@@
  	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);
- 		int crtc = vbl_swap->pipe;
 -		int pipe = i915_get_pipe(dev, vbl_swap->plane);
++		int crtc = i915_get_pipe(dev, vbl_swap->plane);
  
- 		if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
 -		if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
++		if ((counter[crtc] - vbl_swap->sequence) > (1<<23))
  			continue;
  
  		list_del(list);
  		dev_priv->swaps_pending--;
 +		drm_vblank_put(dev, crtc);
  
- 		spin_unlock(&dev_priv->swaps_lock);
- 		spin_lock(&dev->drw_lock);
+ 		DRM_SPINUNLOCK(&dev_priv->swaps_lock);
+ 		DRM_SPINLOCK(&dev->drw_lock);
  
  		drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
  
@@@ -278,38 -301,9 +304,35 @@@
  	}
  }
  
- u32 i915_get_vblank_counter(drm_device_t *dev, int crtc)
++u32 i915_get_vblank_counter(struct drm_device *dev, int crtc)
 +{
 +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +	unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
 +	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
 +	u32 high1, high2, low, count;
 +
- 	if (!IS_I965G(dev))
- 		return 0;
- 
 +	/*
 +	 * High & low register fields aren't synchronized, so make sure
 +	 * we get a low value that's stable across two reads of the high
 +	 * register.
 +	 */
 +	do {
 +		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
 +			 PIPE_FRAME_HIGH_SHIFT);
 +		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
 +			PIPE_FRAME_LOW_SHIFT);
 +		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
 +			 PIPE_FRAME_HIGH_SHIFT);
 +	} while (high1 != high2);
 +
 +	count = (high1 << 8) | low;
 +
 +	return count;
 +}
 +
  irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
  {
- 	drm_device_t *dev = (drm_device_t *) arg;
+ 	struct drm_device *dev = (struct drm_device *) arg;
  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
  	u16 temp;
  	u32 pipea_stats, pipeb_stats;
@@@ -340,23 -333,25 +363,16 @@@
  #endif
  	}
  
- 	if (!IS_I965G(dev)) {
- 		if (temp & VSYNC_PIPEA_FLAG)
- 			atomic_inc(&dev->_vblank_count[0]);
- 		if (temp & VSYNC_PIPEB_FLAG)
- 			atomic_inc(&dev->_vblank_count[1]);
- 	}
- 
 -	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
 -		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 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);
 -		drm_vbl_send_signals(dev);
 +	/*
 +	 * Use drm_update_vblank_counter here to deal with potential lost
 +	 * interrupts
 +	 */
 +	if (temp & VSYNC_PIPEA_FLAG)
 +		drm_handle_vblank(dev, 0);
 +	if (temp & VSYNC_PIPEB_FLAG)
 +		drm_handle_vblank(dev, 1);
  
 +	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
  		if (dev_priv->swaps_pending > 0)
  			drm_locked_tasklet(dev, i915_vblank_tasklet);
  		I915_WRITE(I915REG_PIPEASTAT, 
@@@ -442,16 -437,47 +458,15 @@@ static int i915_wait_irq(struct drm_dev
  	return ret;
  }
  
 -static int i915_driver_vblank_do_wait(struct drm_device *dev,
 -				      unsigned int *sequence,
 -				      atomic_t *counter)
 -{
 -	drm_i915_private_t *dev_priv = dev->dev_private;
 -	unsigned int cur_vblank;
 -	int ret = 0;
 -
 -	if (!dev_priv) {
 -		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
 -		return -EINVAL;
 -	}
 -
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(counter))
 -			- *sequence) <= (1<<23)));
 -	
 -	*sequence = cur_vblank;
 -
 -	return ret;
 -}
 -
 -int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
 -{
 -	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
 -}
 -
 -int i915_driver_vblank_wait2(struct drm_device *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)
+ int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
  {
- 	DRM_DEVICE;
  	drm_i915_private_t *dev_priv = dev->dev_private;
- 	drm_i915_irq_emit_t emit;
+ 	drm_i915_irq_emit_t *emit = data;
  	int result;
  
- 	LOCK_TEST_WITH_RETURN(dev, filp);
+ 	LOCK_TEST_WITH_RETURN(dev, file_priv);
  
  	if (!dev_priv) {
  		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
@@@ -481,68 -504,21 +493,59 @@@ int i915_irq_wait(struct drm_device *de
  
  	if (!dev_priv) {
  		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- 		return DRM_ERR(EINVAL);
+ 		return -EINVAL;
  	}
  
- 	DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
- 				 sizeof(irqwait));
- 
- 	return i915_wait_irq(dev, irqwait.irq_seq);
+ 	return i915_wait_irq(dev, irqwait->irq_seq);
  }
  
- int i915_enable_vblank(drm_device_t *dev, int crtc)
 -static void i915_enable_interrupt (struct drm_device *dev)
++int i915_enable_vblank(struct drm_device *dev, int crtc)
  {
  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 -	
 -	dev_priv->irq_enable_reg = USER_INT_FLAG; 
 -	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
 +
- 	if (!IS_I965G(dev))
- 		return 0;
- 
 +	switch (crtc) {
 +	case 0:
  		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
 -	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
 +		break;
 +	case 1:
  		dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
 +		break;
 +	default:
 +		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 +			  crtc);
 +		break;
 +	}
 +
 +	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 +
 +	return 0;
 +}
 +
- void i915_disable_vblank(drm_device_t *dev, int crtc)
++void i915_disable_vblank(struct drm_device *dev, int crtc)
 +{
 +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +
- 	if (!IS_I965G(dev))
- 		return;
- 
 +	switch (crtc) {
 +	case 0:
 +		dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
 +		break;
 +	case 1:
 +		dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG;
 +		break;
 +	default:
 +		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
 +			  crtc);
 +		break;
 +	}
 +
 +	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 +}
 +
- static void i915_enable_interrupt (drm_device_t *dev)
++static void i915_enable_interrupt (struct drm_device *dev)
 +{
 +	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +	
 +	dev_priv->irq_enable_reg |= USER_INT_FLAG;
  
  	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
  	dev_priv->irq_enabled = 1;
@@@ -558,20 -534,19 +561,17 @@@ int i915_vblank_pipe_set(struct drm_dev
  
  	if (!dev_priv) {
  		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- 		return DRM_ERR(EINVAL);
+ 		return -EINVAL;
  	}
  
- 	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)) {
+ 	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);
+ 			  __FUNCTION__, pipe->pipe);
+ 		return -EINVAL;
  	}
  
- 	dev_priv->vblank_pipe = pipe.pipe;
+ 	dev_priv->vblank_pipe = pipe->pipe;
  
 -	i915_enable_interrupt (dev);
 -
  	return 0;
  }
  
@@@ -601,16 -575,15 +600,16 @@@ int i915_vblank_pipe_get(struct drm_dev
  /**
   * Schedule buffer swap at given vertical blank.
   */
- int i915_vblank_swap(DRM_IOCTL_ARGS)
+ int i915_vblank_swap(struct drm_device *dev, void *data,
+ 		     struct drm_file *file_priv)
  {
- 	DRM_DEVICE;
  	drm_i915_private_t *dev_priv = dev->dev_private;
- 	drm_i915_vblank_swap_t swap;
+ 	drm_i915_vblank_swap_t *swap = data;
  	drm_i915_vbl_swap_t *vbl_swap;
- 	unsigned int pipe, seqtype, curseq;
+ 	unsigned int pipe, seqtype, curseq, plane;
  	unsigned long irqflags;
  	struct list_head *list;
 +	int ret;
  
  	if (!dev_priv) {
  		DRM_ERROR("%s called with no initialization\n", __func__);
@@@ -638,31 -609,35 +635,36 @@@
  
  	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
  		DRM_ERROR("Invalid pipe %d\n", pipe);
- 		return DRM_ERR(EINVAL);
+ 		return -EINVAL;
  	}
  
- 	spin_lock_irqsave(&dev->drw_lock, irqflags);
+ 	DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags);
  
- 	if (!drm_get_drawable_info(dev, swap.drawable)) {
- 		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- 		DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
- 		return DRM_ERR(EINVAL);
+ 	/* It makes no sense to schedule a swap for a drawable that doesn't have
+ 	 * valid information at this point. E.g. this could mean that the X
+ 	 * server is too old to push drawable information to the DRM, in which
+ 	 * case all such swaps would become ineffective.
+ 	 */
+ 	if (!drm_get_drawable_info(dev, swap->drawable)) {
+ 		DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
+ 		DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+ 		return -EINVAL;
  	}
  
- 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ 	DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags);
  
 -	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
 +	drm_update_vblank_count(dev, pipe);
 +	curseq = drm_vblank_count(dev, pipe);
  
  	if (seqtype == _DRM_VBLANK_RELATIVE)
- 		swap.sequence += curseq;
+ 		swap->sequence += curseq;
  
- 	if ((curseq - swap.sequence) <= (1<<23)) {
- 		if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
- 			swap.sequence = curseq + 1;
+ 	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);
+ 			return -EINVAL;
  		}
  	}
  
@@@ -724,21 -700,15 +727,21 @@@
  
  	DRM_DEBUG("\n");
  
 +	ret = drm_vblank_get(dev, pipe);
 +	if (ret) {
 +		drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
 +		return ret;
 +	}
 +
- 	vbl_swap->drw_id = swap.drawable;
- 	vbl_swap->pipe = pipe;
- 	vbl_swap->sequence = swap.sequence;
- 	vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
+ 	vbl_swap->drw_id = swap->drawable;
+ 	vbl_swap->plane = plane;
+ 	vbl_swap->sequence = swap->sequence;
+ 	vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
  
  	if (vbl_swap->flip)
- 		swap.sequence++;
+ 		swap->sequence++;
  
- 	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
+ 	DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags);
  
  	list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
  	dev_priv->swaps_pending++;
@@@ -762,30 -729,17 +762,25 @@@ void i915_driver_irq_preinstall(struct 
  	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
  }
  
- int i915_driver_irq_postinstall(drm_device_t * dev)
 -void i915_driver_irq_postinstall(struct drm_device * dev)
++int i915_driver_irq_postinstall(struct drm_device * dev)
  {
  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 +	int ret, num_pipes = 2;
  
- 	spin_lock_init(&dev_priv->swaps_lock);
+ 	DRM_SPININIT(&dev_priv->swaps_lock, "swap");
  	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
  	dev_priv->swaps_pending = 0;
  
- 	dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
+ 	DRM_SPININIT(&dev_priv->user_irq_lock, "userirq");
  	dev_priv->user_irq_refcount = 0;
 +	dev_priv->irq_enable_reg = 0;
 +
 +	ret = drm_vblank_init(dev, num_pipes);
 +	if (ret)
 +		return ret;
 +
 +	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
  
- 	if (!IS_I965G(dev)) {
- 		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG;
- 		I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- 	}
- 
  	i915_enable_interrupt(dev);
  	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
  
@@@ -794,10 -748,9 +789,10 @@@
  	 */
  
  	I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21));
 +	return 0;
  }
  
- void i915_driver_irq_uninstall(drm_device_t * dev)
+ void i915_driver_irq_uninstall(struct drm_device * dev)
  {
  	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
  	u16 temp;
diff --cc shared-core/mga_drv.h
index 4764eda,8254c3f..b961155
--- a/shared-core/mga_drv.h
+++ b/shared-core/mga_drv.h
@@@ -177,14 -181,12 +182,15 @@@ extern int mga_warp_install_microcode(d
  extern int mga_warp_init(drm_mga_private_t * dev_priv);
  
  				/* mga_irq.c */
- extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
- extern int mga_enable_vblank(drm_device_t *dev, int crtc);
- extern void mga_disable_vblank(drm_device_t *dev, int crtc);
- extern u32 mga_get_vblank_counter(drm_device_t *dev, int crtc);
++extern int mga_enable_vblank(struct drm_device *dev, int crtc);
++extern void mga_disable_vblank(struct drm_device *dev, int crtc);
++extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
+ extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
+ extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
  extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
- extern void mga_driver_irq_preinstall(drm_device_t * dev);
- extern int mga_driver_irq_postinstall(drm_device_t * dev);
- extern void mga_driver_irq_uninstall(drm_device_t * dev);
+ extern void mga_driver_irq_preinstall(struct drm_device * dev);
 -extern void mga_driver_irq_postinstall(struct drm_device * dev);
++extern int mga_driver_irq_postinstall(struct drm_device * dev);
+ extern void mga_driver_irq_uninstall(struct drm_device * dev);
  extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
  			     unsigned long arg);
  
diff --cc shared-core/mga_irq.c
index a49a9b6,8b555e2..0d4b473
--- a/shared-core/mga_irq.c
+++ b/shared-core/mga_irq.c
@@@ -36,23 -36,9 +36,23 @@@
  #include "mga_drm.h"
  #include "mga_drv.h"
  
- u32 mga_get_vblank_counter(drm_device_t *dev, int crtc)
++u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
 +{
 +	const drm_mga_private_t *const dev_priv = 
 +		(drm_mga_private_t *) dev->dev_private;
 +
 +	if (crtc != 0) {
 +		return 0;
 +	}
 +
 +
 +	return atomic_read(&dev_priv->vbl_received);
 +}
 +
 +
  irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
  {
- 	drm_device_t *dev = (drm_device_t *) arg;
+ 	struct drm_device *dev = (struct drm_device *) arg;
  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
  	int status;
  	int handled = 0;
@@@ -87,42 -74,31 +87,40 @@@
  		handled = 1;
  	}
  
 -	if ( handled ) {
 -		return IRQ_HANDLED;
 -	}
 -	return IRQ_NONE;
 +	return (handled) ? IRQ_HANDLED : IRQ_NONE;
  }
  
- 
- int mga_enable_vblank(drm_device_t *dev, int crtc)
 -int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
++int mga_enable_vblank(struct drm_device *dev, int crtc)
  {
 -	unsigned int cur_vblank;
 -	int ret = 0;
 +	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
  
 -	/* Assume that the user has missed the current sequence number
 -	 * by about a day rather than she wants to wait for years
 -	 * using vertical blanks...
 -	 */
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(&dev->vbl_received))
 -		      - *sequence) <= (1 << 23)));
 +	if (crtc != 0) {
 +		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 +			  crtc);
 +		return 0;
 +	}
  
 -	*sequence = cur_vblank;
 +	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
 +	return 0;
 +}
  
 -	return ret;
 +
- void mga_disable_vblank(drm_device_t *dev, int crtc)
++void mga_disable_vblank(struct drm_device *dev, int crtc)
 +{
 +	if (crtc != 0) {
 +		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
 +			  crtc);
 +	}
 +
 +	/* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
 +	 * a nice hardware counter that tracks the number of refreshes when
 +	 * the interrupt is disabled, and the kernel doesn't know the refresh
 +	 * rate to calculate an estimate.
 +	 */
 +	/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
  }
  
- 
- int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
+ int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
  {
  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
  	unsigned int cur_fence;
@@@ -151,26 -127,17 +149,25 @@@ void mga_driver_irq_preinstall(struct d
  	MGA_WRITE(MGA_ICLEAR, ~0);
  }
  
- int mga_driver_irq_postinstall(drm_device_t * dev)
 -void mga_driver_irq_postinstall(struct drm_device * dev)
++int mga_driver_irq_postinstall(struct drm_device * dev)
  {
  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 +	int ret;
  
 -	DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
 +	ret = drm_vblank_init(dev, 1);
 +	if (ret)
 +		return ret;
  
 -	/* Turn on vertical blank interrupt and soft trap interrupt. */
 -	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
 +	DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
 +
 +	/* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
 +	 * in mga_enable_vblank.
 +	 */
 +	MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
 +	return 0;
  }
  
- 
- void mga_driver_irq_uninstall(drm_device_t * dev)
+ void mga_driver_irq_uninstall(struct drm_device * dev)
  {
  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
  	if (!dev_priv)
diff --cc shared-core/nouveau_drv.h
index debee8e,e5cef07..9587834
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@@ -228,66 -415,143 +415,143 @@@ extern int nouveau_ioctl_gpuobj_free(st
  
  /* nouveau_irq.c */
  extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
- extern void        nouveau_irq_preinstall(drm_device_t*);
- extern void        nouveau_irq_postinstall(drm_device_t*);
- extern void        nouveau_irq_uninstall(drm_device_t*);
+ extern void        nouveau_irq_preinstall(struct drm_device *);
 -extern void        nouveau_irq_postinstall(struct drm_device *);
++extern int         nouveau_irq_postinstall(struct drm_device *);
+ extern void        nouveau_irq_uninstall(struct drm_device *);
+ 
+ /* nouveau_sgdma.c */
+ extern int nouveau_sgdma_init(struct drm_device *);
+ extern void nouveau_sgdma_takedown(struct drm_device *);
+ extern int nouveau_sgdma_get_page(struct drm_device *, uint32_t offset,
+ 				  uint32_t *page);
+ extern struct drm_ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *);
+ extern int nouveau_sgdma_nottm_hack_init(struct drm_device *);
+ extern void nouveau_sgdma_nottm_hack_takedown(struct drm_device *);
+ 
+ /* nouveau_dma.c */
+ extern int  nouveau_dma_channel_init(struct drm_device *);
+ extern void nouveau_dma_channel_takedown(struct drm_device *);
+ extern int  nouveau_dma_wait(struct drm_device *, int size);
  
  /* nv04_fb.c */
- extern int  nv04_fb_init(drm_device_t *dev);
- extern void nv04_fb_takedown(drm_device_t *dev);
+ extern int  nv04_fb_init(struct drm_device *);
+ extern void nv04_fb_takedown(struct drm_device *);
  
  /* nv10_fb.c */
- extern int  nv10_fb_init(drm_device_t *dev);
- extern void nv10_fb_takedown(drm_device_t *dev);
+ extern int  nv10_fb_init(struct drm_device *);
+ extern void nv10_fb_takedown(struct drm_device *);
  
  /* nv40_fb.c */
- extern int  nv40_fb_init(drm_device_t *dev);
- extern void nv40_fb_takedown(drm_device_t *dev);
+ extern int  nv40_fb_init(struct drm_device *);
+ extern void nv40_fb_takedown(struct drm_device *);
+ 
+ /* nv04_fifo.c */
+ extern int  nv04_fifo_create_context(struct nouveau_channel *);
+ extern void nv04_fifo_destroy_context(struct nouveau_channel *);
+ extern int  nv04_fifo_load_context(struct nouveau_channel *);
+ extern int  nv04_fifo_save_context(struct nouveau_channel *);
+ 
+ /* nv10_fifo.c */
+ extern int  nv10_fifo_create_context(struct nouveau_channel *);
+ extern void nv10_fifo_destroy_context(struct nouveau_channel *);
+ extern int  nv10_fifo_load_context(struct nouveau_channel *);
+ extern int  nv10_fifo_save_context(struct nouveau_channel *);
+ 
+ /* nv40_fifo.c */
+ extern int  nv40_fifo_init(struct drm_device *);
+ extern int  nv40_fifo_create_context(struct nouveau_channel *);
+ extern void nv40_fifo_destroy_context(struct nouveau_channel *);
+ extern int  nv40_fifo_load_context(struct nouveau_channel *);
+ extern int  nv40_fifo_save_context(struct nouveau_channel *);
+ 
+ /* nv50_fifo.c */
+ extern int  nv50_fifo_init(struct drm_device *);
+ extern void nv50_fifo_takedown(struct drm_device *);
+ extern int  nv50_fifo_create_context(struct nouveau_channel *);
+ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
+ extern int  nv50_fifo_load_context(struct nouveau_channel *);
+ extern int  nv50_fifo_save_context(struct nouveau_channel *);
  
  /* nv04_graph.c */
- extern void nouveau_nv04_context_switch(drm_device_t *dev);
- extern int nv04_graph_init(drm_device_t *dev);
- extern void nv04_graph_takedown(drm_device_t *dev);
- extern int nv04_graph_context_create(drm_device_t *dev, int channel);
+ extern void nouveau_nv04_context_switch(struct drm_device *);
+ extern int  nv04_graph_init(struct drm_device *);
+ extern void nv04_graph_takedown(struct drm_device *);
+ extern int  nv04_graph_create_context(struct nouveau_channel *);
+ extern void nv04_graph_destroy_context(struct nouveau_channel *);
+ extern int  nv04_graph_load_context(struct nouveau_channel *);
+ extern int  nv04_graph_save_context(struct nouveau_channel *);
  
  /* nv10_graph.c */
- extern void nouveau_nv10_context_switch(drm_device_t *dev);
- extern int nv10_graph_init(drm_device_t *dev);
- extern void nv10_graph_takedown(drm_device_t *dev);
- extern int nv10_graph_context_create(drm_device_t *dev, int channel);
+ extern void nouveau_nv10_context_switch(struct drm_device *);
+ extern int  nv10_graph_init(struct drm_device *);
+ extern void nv10_graph_takedown(struct drm_device *);
+ extern int  nv10_graph_create_context(struct nouveau_channel *);
+ extern void nv10_graph_destroy_context(struct nouveau_channel *);
+ extern int  nv10_graph_load_context(struct nouveau_channel *);
+ extern int  nv10_graph_save_context(struct nouveau_channel *);
  
  /* nv20_graph.c */
- extern void nouveau_nv20_context_switch(drm_device_t *dev);
- extern int nv20_graph_init(drm_device_t *dev);
- extern void nv20_graph_takedown(drm_device_t *dev);
- extern int nv20_graph_context_create(drm_device_t *dev, int channel);
- 
- /* nv30_graph.c */
- extern int nv30_graph_init(drm_device_t *dev);
- extern void nv30_graph_takedown(drm_device_t *dev);
- extern int nv30_graph_context_create(drm_device_t *dev, int channel);
+ extern int  nv20_graph_create_context(struct nouveau_channel *);
+ extern void nv20_graph_destroy_context(struct nouveau_channel *);
+ extern int  nv20_graph_load_context(struct nouveau_channel *);
+ extern int  nv20_graph_save_context(struct nouveau_channel *);
+ extern int  nv20_graph_init(struct drm_device *);
+ extern void nv20_graph_takedown(struct drm_device *);
+ extern int  nv30_graph_init(struct drm_device *);
  
  /* nv40_graph.c */
- extern int  nv40_graph_init(drm_device_t *dev);
- extern void nv40_graph_takedown(drm_device_t *dev);
- extern int  nv40_graph_context_create(drm_device_t *dev, int channel);
- extern void nv40_graph_context_save_current(drm_device_t *dev);
- extern void nv40_graph_context_restore(drm_device_t *dev, int channel);
+ extern int  nv40_graph_init(struct drm_device *);
+ extern void nv40_graph_takedown(struct drm_device *);
+ extern int  nv40_graph_create_context(struct nouveau_channel *);
+ extern void nv40_graph_destroy_context(struct nouveau_channel *);
+ extern int  nv40_graph_load_context(struct nouveau_channel *);
+ extern int  nv40_graph_save_context(struct nouveau_channel *);
+ 
+ /* nv50_graph.c */
+ extern int  nv50_graph_init(struct drm_device *);
+ extern void nv50_graph_takedown(struct drm_device *);
+ extern int  nv50_graph_create_context(struct nouveau_channel *);
+ extern void nv50_graph_destroy_context(struct nouveau_channel *);
+ extern int  nv50_graph_load_context(struct nouveau_channel *);
+ extern int  nv50_graph_save_context(struct nouveau_channel *);
+ 
+ /* nv04_instmem.c */
+ extern int  nv04_instmem_init(struct drm_device *);
+ extern void nv04_instmem_takedown(struct drm_device *);
+ extern int  nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+ 				  uint32_t *size);
+ extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
+ extern int  nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
+ extern int  nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+ 
+ /* nv50_instmem.c */
+ extern int  nv50_instmem_init(struct drm_device *);
+ extern void nv50_instmem_takedown(struct drm_device *);
+ extern int  nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+ 				  uint32_t *size);
+ extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
+ extern int  nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
+ extern int  nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
  
  /* nv04_mc.c */
- extern int  nv04_mc_init(drm_device_t *dev);
- extern void nv04_mc_takedown(drm_device_t *dev);
+ extern int  nv04_mc_init(struct drm_device *);
+ extern void nv04_mc_takedown(struct drm_device *);
  
  /* nv40_mc.c */
- extern int  nv40_mc_init(drm_device_t *dev);
- extern void nv40_mc_takedown(drm_device_t *dev);
+ extern int  nv40_mc_init(struct drm_device *);
+ extern void nv40_mc_takedown(struct drm_device *);
+ 
+ /* nv50_mc.c */
+ extern int  nv50_mc_init(struct drm_device *);
+ extern void nv50_mc_takedown(struct drm_device *);
  
  /* nv04_timer.c */
- extern int  nv04_timer_init(drm_device_t *dev);
- extern void nv04_timer_takedown(drm_device_t *dev);
+ extern int  nv04_timer_init(struct drm_device *);
+ extern uint64_t nv04_timer_read(struct drm_device *);
+ extern void nv04_timer_takedown(struct drm_device *);
  
- extern long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
- 				unsigned long arg);
+ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
+ 				 unsigned long arg);
  
  #if defined(__powerpc__)
  #define NV_READ(reg)        in_be32((void __iomem *)(dev_priv->mmio)->handle + \
                (reg) )
diff --cc shared-core/nouveau_irq.c
index 8de6e70,ac50729..e4b7676
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@@ -71,89 -46,20 +46,22 @@@ nouveau_irq_preinstall(struct drm_devic
  	NV_WRITE(NV03_PMC_INTR_EN_0, 0);
  }
  
- void nouveau_irq_postinstall(drm_device_t *dev)
 -void
++int
+ nouveau_irq_postinstall(struct drm_device *dev)
  {
- 	drm_nouveau_private_t *dev_priv = dev->dev_private;
- 
- 	if (!dev_priv) {
- 		DRM_ERROR("AIII, no dev_priv\n");
- 		return;
- 	}
- 	if (!dev_priv->mmio) {
- 		DRM_ERROR("AIII, no dev_priv->mmio\n");
- 		return;
- 	}
- 
- 	DRM_DEBUG("IRQ: postinst\n");
- 
- 	/* Enable PFIFO error reporting */
- 	NV_WRITE(NV03_PFIFO_INTR_EN_0 , 
- 			NV_PFIFO_INTR_CACHE_ERROR |
- 			NV_PFIFO_INTR_RUNOUT |
- 			NV_PFIFO_INTR_RUNOUT_OVERFLOW |
- 			NV_PFIFO_INTR_DMA_PUSHER |
- 			NV_PFIFO_INTR_DMA_PT |
- 			NV_PFIFO_INTR_SEMAPHORE |
- 			NV_PFIFO_INTR_ACQUIRE_TIMEOUT
- 			);
- 	NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF);
- 
- 	/* Enable PGRAPH interrupts */
- 	if (dev_priv->card_type<NV_40)
- 		NV_WRITE(NV03_PGRAPH_INTR_EN,
- 				NV_PGRAPH_INTR_NOTIFY |
- 				NV_PGRAPH_INTR_MISSING_HW |
- 				NV_PGRAPH_INTR_CONTEXT_SWITCH |
- 				NV_PGRAPH_INTR_BUFFER_NOTIFY |
- 				NV_PGRAPH_INTR_ERROR
- 				);
- 	else
- 		NV_WRITE(NV40_PGRAPH_INTR_EN,
- 				NV_PGRAPH_INTR_NOTIFY |
- 				NV_PGRAPH_INTR_MISSING_HW |
- 				NV_PGRAPH_INTR_CONTEXT_SWITCH |
- 				NV_PGRAPH_INTR_BUFFER_NOTIFY |
- 				NV_PGRAPH_INTR_ERROR
- 				);
- 	NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF);
- 
- #if 0
- 	/* Enable CRTC0/1 interrupts */
- 	NV_WRITE(NV_CRTC0_INTEN, NV_CRTC_INTR_VBLANK);
- 	NV_WRITE(NV_CRTC1_INTEN, NV_CRTC_INTR_VBLANK);
- #endif
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
  
  	/* Master enable */
  	NV_WRITE(NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
++
++	return 0;
  }
  
- void nouveau_irq_uninstall(drm_device_t *dev)
+ void
+ nouveau_irq_uninstall(struct drm_device *dev)
  {
- 	drm_nouveau_private_t *dev_priv = dev->dev_private;
+ 	struct drm_nouveau_private *dev_priv = dev->dev_private;
  
- 	if (!dev_priv) {
- 		DRM_ERROR("AIII, no dev_priv\n");
- 		return;
- 	}
- 	if (!dev_priv->mmio) {
- 		DRM_ERROR("AIII, no dev_priv->mmio\n");
- 		return;
- 	}
- 
- 	DRM_DEBUG("IRQ: uninst\n");
- 
- 	/* Disable PFIFO interrupts */
- 	NV_WRITE(NV03_PFIFO_INTR_EN_0, 0);
- 	/* Disable PGRAPH interrupts */
- 	if (dev_priv->card_type<NV_40)
- 		NV_WRITE(NV03_PGRAPH_INTR_EN, 0);
- 	else
- 		NV_WRITE(NV40_PGRAPH_INTR_EN, 0);
- #if 0
- 	/* Disable CRTC0/1 interrupts */
- 	NV_WRITE(NV_CRTC0_INTEN, 0);
- 	NV_WRITE(NV_CRTC1_INTEN, 0);
- #endif
  	/* Master disable */
  	NV_WRITE(NV03_PMC_INTR_EN_0, 0);
  }
diff --cc shared-core/r128_drv.h
index 9086835,abb9989..cb0c41c
--- a/shared-core/r128_drv.h
+++ b/shared-core/r128_drv.h
@@@ -97,6 -97,6 +97,8 @@@ typedef struct drm_r128_private 
  	u32 crtc_offset;
  	u32 crtc_offset_cntl;
  
++	atomic_t vbl_received;
++
  	u32 color_fmt;
  	unsigned int front_offset;
  	unsigned int front_pitch;
@@@ -147,16 -147,17 +149,18 @@@ extern void r128_freelist_reset(struct 
  extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
  
  extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
- extern int r128_do_cleanup_cce(drm_device_t * dev);
- 
- extern int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+ extern int r128_do_cleanup_cce(struct drm_device * dev);
  
 -extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int \
                *sequence);
 -
++extern int r128_enable_vblank(struct drm_device *dev, int crtc);
++extern void r128_disable_vblank(struct drm_device *dev, int crtc);
++extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
  extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
- extern void r128_driver_irq_preinstall(drm_device_t * dev);
- extern void r128_driver_irq_postinstall(drm_device_t * dev);
- extern void r128_driver_irq_uninstall(drm_device_t * dev);
- extern void r128_driver_lastclose(drm_device_t * dev);
- extern void r128_driver_preclose(drm_device_t * dev, DRMFILE filp);
+ extern void r128_driver_irq_preinstall(struct drm_device * dev);
 -extern void r128_driver_irq_postinstall(struct drm_device * dev);
++extern int r128_driver_irq_postinstall(struct drm_device * dev);
+ extern void r128_driver_irq_uninstall(struct drm_device * dev);
+ extern void r128_driver_lastclose(struct drm_device * dev);
+ extern void r128_driver_preclose(struct drm_device * dev,
+ 				 struct drm_file *file_priv);
  
  extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
  			      unsigned long arg);
diff --cc shared-core/r128_irq.c
index 87f8ca2,c76fdca..5b95bd8
--- a/shared-core/r128_irq.c
+++ b/shared-core/r128_irq.c
@@@ -35,9 -35,9 +35,19 @@@
  #include "r128_drm.h"
  #include "r128_drv.h"
  
++u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
++{
++	const drm_r128_private_t *dev_priv = dev->dev_private;
++
++	if (crtc != 0)
++		return 0;
++
++	return atomic_read(&dev_priv->vbl_received);
++}
++
  irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
  {
- 	drm_device_t *dev = (drm_device_t *) arg;
+ 	struct drm_device *dev = (struct drm_device *) arg;
  	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
  	int status;
  
@@@ -46,33 -46,33 +56,41 @@@
  	/* VBLANK interrupt */
  	if (status & R128_CRTC_VBLANK_INT) {
  		R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
--		atomic_inc(&dev->vbl_received);
--		DRM_WAKEUP(&dev->vbl_queue);
--		drm_vbl_send_signals(dev);
++		atomic_inc(&dev_priv->vbl_received);
++		drm_handle_vblank(dev, 0);
  		return IRQ_HANDLED;
  	}
  	return IRQ_NONE;
  }
  
- int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
 -int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
++int r128_enable_vblank(struct drm_device *dev, int crtc)
  {
--	unsigned int cur_vblank;
--	int ret = 0;
++	drm_r128_private_t *dev_priv = dev->dev_private;
  
--	/* Assume that the user has missed the current sequence number
--	 * by about a day rather than she wants to wait for years
--	 * using vertical blanks...
--	 */
--	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
--		    (((cur_vblank = atomic_read(&dev->vbl_received))
--		      - *sequence) <= (1 << 23)));
++	if (crtc != 0) {
++		DRM_ERROR("%s:  bad crtc %d\n", __FUNCTION__, crtc);
++		return -EINVAL;
++	}
  
--	*sequence = cur_vblank;
++	R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
++	return 0;
++}
++
++void r128_disable_vblank(struct drm_device *dev, int crtc)
++{
++	if (crtc != 0)
++		DRM_ERROR("%s:  bad crtc %d\n", __FUNCTION__, crtc);
  
--	return ret;
++	/*
++	 * FIXME: implement proper interrupt disable by using the vblank
++	 * counter register (if available)
++	 *
++	 * R128_WRITE(R128_GEN_INT_CNTL,
++	 *            R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
++	 */
  }
  
- void r128_driver_irq_preinstall(drm_device_t * dev)
+ void r128_driver_irq_preinstall(struct drm_device * dev)
  {
  	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
  
@@@ -82,15 -82,15 +100,12 @@@
  	R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
  }
  
- void r128_driver_irq_postinstall(drm_device_t * dev)
 -void r128_driver_irq_postinstall(struct drm_device * dev)
++int r128_driver_irq_postinstall(struct drm_device * dev)
  {
--	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
--
--	/* Turn on VBL interrupt */
--	R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
++	return drm_vblank_init(dev, 1);
  }
  
- void r128_driver_irq_uninstall(drm_device_t * dev)
+ void r128_driver_irq_uninstall(struct drm_device * dev)
  {
  	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
  	if (!dev_priv)
diff --cc shared-core/radeon_drv.h
index 418b6e7,006559d..a71b0be
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@@ -355,26 -352,28 +355,28 @@@ extern int radeon_wait_ring(drm_radeon_
  
  extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv);
  
- extern int radeon_mem_alloc(DRM_IOCTL_ARGS);
- extern int radeon_mem_free(DRM_IOCTL_ARGS);
- extern int radeon_mem_init_heap(DRM_IOCTL_ARGS);
+ extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file \
*file_priv); + extern int radeon_mem_free(struct drm_device *dev, void *data, struct \
drm_file *file_priv); + extern int radeon_mem_init_heap(struct drm_device *dev, void \
*data, struct drm_file *file_priv);  extern void radeon_mem_takedown(struct mem_block \
                **heap);
- extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap);
+ extern void radeon_mem_release(struct drm_file *file_priv,
+ 			       struct mem_block *heap);
  
  				/* radeon_irq.c */
- extern int radeon_irq_emit(DRM_IOCTL_ARGS);
- extern int radeon_irq_wait(DRM_IOCTL_ARGS);
- 
- extern void radeon_do_release(drm_device_t * dev);
- extern u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc);
- extern int radeon_enable_vblank(drm_device_t *dev, int crtc);
- extern void radeon_disable_vblank(drm_device_t *dev, int crtc);
+ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file \
*file_priv); + extern int radeon_irq_wait(struct drm_device *dev, void *data, struct \
drm_file *file_priv); + 
+ extern void radeon_do_release(struct drm_device * dev);
 -extern int radeon_driver_vblank_wait(struct drm_device * dev,
 -				     unsigned int *sequence);
 -extern int radeon_driver_vblank_wait2(struct drm_device * dev,
 -				      unsigned int *sequence);
++extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
++extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
++extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
++extern void radeon_do_release(struct drm_device * dev);
  extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
- extern void radeon_driver_irq_preinstall(drm_device_t * dev);
- extern int radeon_driver_irq_postinstall(drm_device_t * dev);
- extern void radeon_driver_irq_uninstall(drm_device_t * dev);
- extern int radeon_vblank_crtc_get(drm_device_t *dev);
- extern int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value);
+ extern void radeon_driver_irq_preinstall(struct drm_device * dev);
 -extern void radeon_driver_irq_postinstall(struct drm_device * dev);
++extern int radeon_driver_irq_postinstall(struct drm_device * dev);
+ extern void radeon_driver_irq_uninstall(struct drm_device * dev);
+ extern int radeon_vblank_crtc_get(struct drm_device *dev);
+ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
  
  extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
  extern int radeon_driver_unload(struct drm_device *dev);
diff --cc shared-core/radeon_irq.c
index 4ff8a5c,1ece639..6ba3c14
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@@ -35,61 -35,12 +35,61 @@@
  #include "radeon_drm.h"
  #include "radeon_drv.h"
  
- static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int state)
 -static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
 -					      u32 mask)
++static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
  {
 -	u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
 +	drm_radeon_private_t *dev_priv = dev->dev_private;
 +
 +	if (state)
 +		dev_priv->irq_enable_reg |= mask;
 +	else
 +		dev_priv->irq_enable_reg &= ~mask;
 +
 +	RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
 +}
 +
- int radeon_enable_vblank(drm_device_t *dev, int crtc)
++int radeon_enable_vblank(struct drm_device *dev, int crtc)
 +{
 +	switch (crtc) {
 +	case 0:
 +		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
 +		break;
 +	case 1:
 +		radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
 +		break;
 +	default:
 +		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 +			  crtc);
- 		return DRM_ERR(EINVAL);
++		return EINVAL;
 +	}
 +
 +	return 0;
 +}
 +
- void radeon_disable_vblank(drm_device_t *dev, int crtc)
++void radeon_disable_vblank(struct drm_device *dev, int crtc)
 +{
 +	switch (crtc) {
 +	case 0:
 +		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
 +		break;
 +	case 1:
 +		radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
 +		break;
 +	default:
 +		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 +			  crtc);
 +		break;
 +	}
 +}
 +
 +static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
 +{
 +	u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
 +		(RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
 +		 RADEON_CRTC2_VBLANK_STAT);
 +
  	if (irqs)
  		RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
 +
  	return irqs;
  }
  
@@@ -175,21 -144,55 +175,27 @@@ static int radeon_wait_irq(struct drm_d
  	return ret;
  }
  
- u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 -static int radeon_driver_vblank_do_wait(struct drm_device * dev,
 -					unsigned int *sequence,
 -					int crtc)
++u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
  {
 -	drm_radeon_private_t *dev_priv =
 -	    (drm_radeon_private_t *) dev->dev_private;
 -	unsigned int cur_vblank;
 -	int ret = 0;
 -	int ack = 0;
 -	atomic_t *counter;
 +	drm_radeon_private_t *dev_priv = dev->dev_private;
 +	u32 crtc_cnt_reg, crtc_status_reg;
 +
+ 	if (!dev_priv) {
+ 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ 		return -EINVAL;
+ 	}
+ 
 -	if (crtc == DRM_RADEON_VBLANK_CRTC1) {
 -		counter = &dev->vbl_received;
 -		ack |= RADEON_CRTC_VBLANK_STAT;
 -	} else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
 -		counter = &dev->vbl_received2;
 -		ack |= RADEON_CRTC2_VBLANK_STAT;
 -	} else
 +	if (crtc == 0) {
 +		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
 +		crtc_status_reg = RADEON_CRTC_STATUS;
 +	} else if (crtc == 1) {
 +		crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
 +		crtc_status_reg = RADEON_CRTC2_STATUS;
- 	} else
- 		return 0;
++	} else {
+ 		return -EINVAL;
++	}
  
 -	radeon_acknowledge_irqs(dev_priv, ack);
 -
 -	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 -
 -	/* Assume that the user has missed the current sequence number
 -	 * by about a day rather than she wants to wait for years
 -	 * using vertical blanks...
 -	 */
 -	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 -		    (((cur_vblank = atomic_read(counter))
 -		      - *sequence) <= (1 << 23)));
 -
 -	*sequence = cur_vblank;
 -
 -	return ret;
 -}
 -
 -int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
 -{
 -	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
 -}
 -
 -int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
 -{
 -	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
 +	return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
  }
  
  /* Needs the lock as it touches the ring.
@@@ -231,20 -229,30 +232,15 @@@ int radeon_irq_wait(struct drm_device *
  
  	if (!dev_priv) {
  		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- 		return DRM_ERR(EINVAL);
+ 		return -EINVAL;
  	}
  
- 	DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data,
- 				 sizeof(irqwait));
- 
- 	return radeon_wait_irq(dev, irqwait.irq_seq);
+ 	return radeon_wait_irq(dev, irqwait->irq_seq);
  }
  
- 
- 
 -static void radeon_enable_interrupt(struct drm_device *dev)
 -{
 -	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
 -
 -	dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
 -	if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
 -		dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
 -
 -	if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
 -		dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
 -
 -	RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
 -	dev_priv->irq_enabled = 1;
 -}
 -
  /* drm_dma.h hooks
  */
- void radeon_driver_irq_preinstall(drm_device_t * dev)
+ void radeon_driver_irq_preinstall(struct drm_device * dev)
  {
  	drm_radeon_private_t *dev_priv =
  	    (drm_radeon_private_t *) dev->dev_private;
@@@ -253,10 -261,12 +249,10 @@@
  	RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
  
  	/* Clear bits if they're already high */
 -	radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
 -					   RADEON_CRTC_VBLANK_STAT |
 -					   RADEON_CRTC2_VBLANK_STAT));
 +	radeon_acknowledge_irqs(dev_priv);
  }
  
- int radeon_driver_irq_postinstall(drm_device_t * dev)
 -void radeon_driver_irq_postinstall(struct drm_device * dev)
++int radeon_driver_irq_postinstall(struct drm_device * dev)
  {
  	drm_radeon_private_t *dev_priv =
  	    (drm_radeon_private_t *) dev->dev_private;
@@@ -265,18 -274,10 +261,18 @@@
  	atomic_set(&dev_priv->swi_emitted, 0);
  	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
  
 -	radeon_enable_interrupt(dev);
 +	ret = drm_vblank_init(dev, 2);
 +	if (ret)
 +		return ret;
 +
 +	dev->max_vblank_count = 0x001fffff;
 +
 +	radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
 +
 +	return 0;
  }
  
- void radeon_driver_irq_uninstall(drm_device_t * dev)
+ void radeon_driver_irq_uninstall(struct drm_device * dev)
  {
  	drm_radeon_private_t *dev_priv =
  	    (drm_radeon_private_t *) dev->dev_private;
@@@ -312,8 -313,9 +308,8 @@@ int radeon_vblank_crtc_set(struct drm_d
  	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
  	if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
  		DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
- 		return DRM_ERR(EINVAL);
+ 		return -EINVAL;
  	}
  	dev_priv->vblank_crtc = (unsigned int)value;
 -	radeon_enable_interrupt(dev);
  	return 0;
  }
diff --cc shared-core/via_drv.c
index 0a478fe,9f09955..3a6f27f
--- a/shared-core/via_drv.c
+++ b/shared-core/via_drv.c
@@@ -83,14 -83,14 +83,16 @@@ static int probe(struct pci_dev *pdev, 
  static struct drm_driver driver = {
  	.driver_features =
  	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
--	    DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
++	    DRIVER_IRQ_SHARED,
  	.load = via_driver_load,
  	.unload = via_driver_unload,
  #ifndef VIA_HAVE_CORE_MM
  	.context_ctor = via_init_context,
  #endif
  	.context_dtor = via_final_context,
--	.vblank_wait = via_driver_vblank_wait,
++	.get_vblank_counter = via_get_vblank_counter,
++	.enable_vblank = via_enable_vblank,
++	.disable_vblank = via_disable_vblank,
  	.irq_preinstall = via_driver_irq_preinstall,
  	.irq_postinstall = via_driver_irq_postinstall,
  	.irq_uninstall = via_driver_irq_uninstall,
diff --cc shared-core/via_drv.h
index baafbbf,0b47484..bb1c485
--- a/shared-core/via_drv.h
+++ b/shared-core/via_drv.h
@@@ -102,6 -102,6 +102,7 @@@ typedef struct drm_via_private 
  	struct timeval last_vblank;
  	int last_vblank_valid;
  	unsigned usec_per_vblank;
++	atomic_t vbl_received;
  	drm_via_state_t hc_state;
  	char pci_buf[VIA_PCI_BUF_SIZE];
  	const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@@ -148,34 -148,34 +149,36 @@@ enum via_family 
  #define VIA_READ8(reg)		DRM_READ8(VIA_BASE, reg)
  #define VIA_WRITE8(reg,val)	DRM_WRITE8(VIA_BASE, reg, val)
  
- extern drm_ioctl_desc_t via_ioctls[];
+ extern struct drm_ioctl_desc via_ioctls[];
  extern int via_max_ioctl;
  
- extern int via_fb_init(DRM_IOCTL_ARGS);
- extern int via_mem_alloc(DRM_IOCTL_ARGS);
- extern int via_mem_free(DRM_IOCTL_ARGS);
- extern int via_agp_init(DRM_IOCTL_ARGS);
- extern int via_map_init(DRM_IOCTL_ARGS);
- extern int via_decoder_futex(DRM_IOCTL_ARGS);
- extern int via_wait_irq(DRM_IOCTL_ARGS);
- extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
- extern int via_dma_blit( DRM_IOCTL_ARGS );
- 
- extern int via_driver_load(drm_device_t *dev, unsigned long chipset);
- extern int via_driver_unload(drm_device_t *dev);
- extern int via_final_context(drm_device_t * dev, int context);
- 
- extern int via_do_cleanup_map(drm_device_t * dev);
- extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+ extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file \
*file_priv); + extern int via_mem_alloc(struct drm_device *dev, void *data, struct \
drm_file *file_priv); + extern int via_mem_free(struct drm_device *dev, void *data, \
struct drm_file *file_priv); + extern int via_agp_init(struct drm_device *dev, void \
*data, struct drm_file *file_priv); + extern int via_map_init(struct drm_device *dev, \
void *data, struct drm_file *file_priv); + extern int via_decoder_futex(struct \
drm_device *dev, void *data, struct drm_file *file_priv); + extern int \
via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv); + \
extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file \
*file_priv ); + extern int via_dma_blit( struct drm_device *dev, void *data, struct \
drm_file *file_priv ); + 
+ extern int via_driver_load(struct drm_device *dev, unsigned long chipset);
+ extern int via_driver_unload(struct drm_device *dev);
+ extern int via_final_context(struct drm_device * dev, int context);
+ 
+ extern int via_do_cleanup_map(struct drm_device * dev);
 -extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
++extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
++extern int via_enable_vblank(struct drm_device *dev, int crtc);
++extern void via_disable_vblank(struct drm_device *dev, int crtc);
  
  extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
- extern void via_driver_irq_preinstall(drm_device_t * dev);
- extern void via_driver_irq_postinstall(drm_device_t * dev);
- extern void via_driver_irq_uninstall(drm_device_t * dev);
+ extern void via_driver_irq_preinstall(struct drm_device * dev);
 -extern void via_driver_irq_postinstall(struct drm_device * dev);
++extern int via_driver_irq_postinstall(struct drm_device * dev);
+ extern void via_driver_irq_uninstall(struct drm_device * dev);
  
- extern int via_dma_cleanup(drm_device_t * dev);
+ extern int via_dma_cleanup(struct drm_device * dev);
  extern void via_init_command_verifier(void);
- extern int via_driver_dma_quiescent(drm_device_t * dev);
+ extern int via_driver_dma_quiescent(struct drm_device * dev);
  extern void via_init_futex(drm_via_private_t *dev_priv);
  extern void via_cleanup_futex(drm_via_private_t *dev_priv);
  extern void via_release_futex(drm_via_private_t *dev_priv, int context);
diff --cc shared-core/via_irq.c
index 2ac8697,475b646..a1d3324
--- a/shared-core/via_irq.c
+++ b/shared-core/via_irq.c
@@@ -97,9 -97,9 +97,18 @@@ static unsigned time_diff(struct timeva
  	1000000 - (then->tv_usec - now->tv_usec);
  }
  
++u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
++{
++	drm_via_private_t *dev_priv = dev->dev_private;
++	if (crtc != 0)
++		return 0;
++
++	return atomic_read(&dev_priv->vbl_received);
++}
++
  irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
  {
- 	drm_device_t *dev = (drm_device_t *) arg;
+ 	struct drm_device *dev = (struct drm_device *) arg;
  	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
  	u32 status;
  	int handled = 0;
@@@ -109,8 -109,8 +118,8 @@@
  
  	status = VIA_READ(VIA_REG_INTERRUPT);
  	if (status & VIA_IRQ_VBLANK_PENDING) {
--		atomic_inc(&dev->vbl_received);
--		if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
++		atomic_inc(&dev_priv->vbl_received);
++		if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
  #ifdef __linux__
  			do_gettimeofday(&cur_vblank);
  #else
@@@ -124,12 -124,12 +133,11 @@@
  			dev_priv->last_vblank = cur_vblank;
  			dev_priv->last_vblank_valid = 1;
  		}
--		if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
++		if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
  			DRM_DEBUG("US per vblank is: %u\n",
  				dev_priv->usec_per_vblank);
  		}
--		DRM_WAKEUP(&dev->vbl_queue);
--		drm_vbl_send_signals(dev);
++		drm_handle_vblank(dev, 0);
  		handled = 1;
  	}
  	
@@@ -171,31 -171,31 +179,30 @@@ static __inline__ void viadrv_acknowled
  	}
  }
  
- int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
 -int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
++int via_enable_vblank(struct drm_device *dev, int crtc)
  {
--	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
--	unsigned int cur_vblank;
--	int ret = 0;
++	drm_via_private_t *dev_priv = dev->dev_private;
++	u32 status;
  
--	DRM_DEBUG("viadrv_vblank_wait\n");
--	if (!dev_priv) {
--		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
++	if (crtc != 0) {
++		DRM_ERROR("%s:  bad crtc %d\n", __FUNCTION__, crtc);
  		return -EINVAL;
  	}
  
--	viadrv_acknowledge_irqs(dev_priv);
++	status = VIA_READ(VIA_REG_INTERRUPT);
++	VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
++	return 0;
++}
  
--	/* Assume that the user has missed the current sequence number
--	 * by about a day rather than she wants to wait for years
--	 * using vertical blanks...
--	 */
++void via_disable_vblank(struct drm_device *dev, int crtc)
++{
++	if (crtc != 0)
++		DRM_ERROR("%s:  bad crtc %d\n", __FUNCTION__, crtc);
  
--	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
--		    (((cur_vblank = atomic_read(&dev->vbl_received)) -
--		      *sequence) <= (1 << 23)));
--	
--	*sequence = cur_vblank;
--	return ret;
++	/*
++	 * FIXME: implement proper interrupt disable by using the vblank
++	 * counter register (if available).
++	 */
  }
  
  static int
@@@ -302,26 -302,26 +309,27 @@@ void via_driver_irq_preinstall(struct d
  	}
  }
  
- void via_driver_irq_postinstall(drm_device_t * dev)
 -void via_driver_irq_postinstall(struct drm_device * dev)
++int via_driver_irq_postinstall(struct drm_device * dev)
  {
  	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
  	u32 status;
  
  	DRM_DEBUG("via_driver_irq_postinstall\n");
--	if (dev_priv) {
--		status = VIA_READ(VIA_REG_INTERRUPT);
--		VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
--			  | dev_priv->irq_enable_mask);
++	if (!dev_priv)
++		return -EINVAL;
  
--		/* Some magic, oh for some data sheets ! */
++	status = VIA_READ(VIA_REG_INTERRUPT);
++	VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
++		  | dev_priv->irq_enable_mask);
  
--		VIA_WRITE8(0x83d4, 0x11);
--		VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
--		
--	}
++	/* Some magic, oh for some data sheets ! */
++	VIA_WRITE8(0x83d4, 0x11);
++	VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
++
++	return 0;
  }
  
- void via_driver_irq_uninstall(drm_device_t * dev)
+ void via_driver_irq_uninstall(struct drm_device * dev)
  {
  	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
  	u32 status;
commit 7e9ea55a2f052cc939ba9bbf9edac39798344b7a
Author: Ian Romanick <idr@us.ibm.com>
Date:   Thu Oct 25 17:14:53 2007 -0700

    Initial pass at porting MGA to vblank-rework
    
    This is currently only compile tested.

diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c
index ef6f1e4..6419cbd 100644
--- a/linux-core/mga_drv.c
+++ b/linux-core/mga_drv.c
@@ -46,15 +46,16 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id \
*ent);  static struct drm_driver driver = {
 	.driver_features =
 	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
-	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
-	    DRIVER_IRQ_VBL,
+	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
 	.dev_priv_size = sizeof (drm_mga_buf_priv_t),
 	.load = mga_driver_load,
 	.unload = mga_driver_unload,
 	.lastclose = mga_driver_lastclose,
 	.dma_quiescent = mga_driver_dma_quiescent,
 	.device_is_agp = mga_driver_device_is_agp,
-	.vblank_wait = mga_driver_vblank_wait,
+	.get_vblank_counter = mga_get_vblank_counter,
+	.enable_vblank = mga_enable_vblank,
+	.disable_vblank = mga_disable_vblank,
 	.irq_preinstall = mga_driver_irq_preinstall,
 	.irq_postinstall = mga_driver_irq_postinstall,
 	.irq_uninstall = mga_driver_irq_uninstall,
diff --git a/shared-core/mga_drv.h b/shared-core/mga_drv.h
index bce8213..4764eda 100644
--- a/shared-core/mga_drv.h
+++ b/shared-core/mga_drv.h
@@ -113,13 +113,14 @@ typedef struct drm_mga_private {
 	 * \sa drm_mga_private_t::mmio
 	 */
 	/*@{*/
-	u32 mmio_base;             /**< Bus address of base of MMIO. */
-	u32 mmio_size;             /**< Size of the MMIO region. */
+	u32 mmio_base;			/**< Bus address of base of MMIO. */
+	u32 mmio_size;			/**< Size of the MMIO region. */
 	/*@}*/
 
 	u32 clear_cmd;
 	u32 maccess;
 
+	atomic_t vbl_received;		/**< Number of vblanks received. */
 	wait_queue_head_t fence_queue;
 	atomic_t last_fence_retired;
 	u32 next_fence_to_post;
@@ -177,10 +178,12 @@ extern int mga_warp_init(drm_mga_private_t * dev_priv);
 
 				/* mga_irq.c */
 extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
-extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern int mga_enable_vblank(drm_device_t *dev, int crtc);
+extern void mga_disable_vblank(drm_device_t *dev, int crtc);
+extern u32 mga_get_vblank_counter(drm_device_t *dev, int crtc);
 extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
 extern void mga_driver_irq_preinstall(drm_device_t * dev);
-extern void mga_driver_irq_postinstall(drm_device_t * dev);
+extern int mga_driver_irq_postinstall(drm_device_t * dev);
 extern void mga_driver_irq_uninstall(drm_device_t * dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
 			     unsigned long arg);
diff --git a/shared-core/mga_irq.c b/shared-core/mga_irq.c
index 490d1fb..a49a9b6 100644
--- a/shared-core/mga_irq.c
+++ b/shared-core/mga_irq.c
@@ -36,6 +36,20 @@
 #include "mga_drm.h"
 #include "mga_drv.h"
 
+u32 mga_get_vblank_counter(drm_device_t *dev, int crtc)
+{
+	const drm_mga_private_t *const dev_priv = 
+		(drm_mga_private_t *) dev->dev_private;
+
+	if (crtc != 0) {
+		return 0;
+	}
+
+
+	return atomic_read(&dev_priv->vbl_received);
+}
+
+
 irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
 {
 	drm_device_t *dev = (drm_device_t *) arg;
@@ -48,9 +62,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
 	/* VBLANK interrupt */
 	if (status & MGA_VLINEPEN) {
 		MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
-		atomic_inc(&dev->vbl_received);
-		DRM_WAKEUP(&dev->vbl_queue);
-		drm_vbl_send_signals(dev);
+		atomic_inc(&dev_priv->vbl_received);
+		drm_handle_vblank(dev, 0);
 		handled = 1;
 	}
 
@@ -74,30 +87,41 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
 		handled = 1;
 	}
 
-	if ( handled ) {
-		return IRQ_HANDLED;
-	}
-	return IRQ_NONE;
+	return (handled) ? IRQ_HANDLED : IRQ_NONE;
 }
 
-int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+
+int mga_enable_vblank(drm_device_t *dev, int crtc)
 {
-	unsigned int cur_vblank;
-	int ret = 0;
+	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
-	/* Assume that the user has missed the current sequence number
-	 * by about a day rather than she wants to wait for years
-	 * using vertical blanks...
-	 */
-	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-		    (((cur_vblank = atomic_read(&dev->vbl_received))
-		      - *sequence) <= (1 << 23)));
+	if (crtc != 0) {
+		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+			  crtc);
+		return 0;
+	}
+
+	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+	return 0;
+}
 
-	*sequence = cur_vblank;
 
-	return ret;
+void mga_disable_vblank(drm_device_t *dev, int crtc)
+{
+	if (crtc != 0) {
+		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+			  crtc);
+	}
+
+	/* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
+	 * a nice hardware counter that tracks the number of refreshes when
+	 * the interrupt is disabled, and the kernel doesn't know the refresh
+	 * rate to calculate an estimate.
+	 */
+	/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
 }
 
+
 int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
 {
 	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -127,16 +151,25 @@ void mga_driver_irq_preinstall(drm_device_t * dev)
 	MGA_WRITE(MGA_ICLEAR, ~0);
 }
 
-void mga_driver_irq_postinstall(drm_device_t * dev)
+int mga_driver_irq_postinstall(drm_device_t * dev)
 {
 	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+	int ret;
 
-	DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
+	ret = drm_vblank_init(dev, 1);
+	if (ret)
+		return ret;
 
-	/* Turn on vertical blank interrupt and soft trap interrupt. */
-	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+	DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
+
+	/* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
+	 * in mga_enable_vblank.
+	 */
+	MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
+	return 0;
 }
 
+
 void mga_driver_irq_uninstall(drm_device_t * dev)
 {
 	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
commit 5b726b63906419ccb3de2e065f9bf7ae875ccdf3
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jul 6 09:50:50 2007 +0200

    radeon: Improve vblank counter.
    
    The frame counter seems to increase only at the end of vertical blank, so we
    need to add 1 while in vertical blank.

diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index bb69c10..418b6e7 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -512,6 +512,9 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp,
 #define RADEON_CRTC_CRNT_FRAME 0x0214
 #define RADEON_CRTC2_CRNT_FRAME 0x0314
 
+#define RADEON_CRTC_STATUS		0x005c
+#define RADEON_CRTC2_STATUS		0x03fc
+
 #define RADEON_GEN_INT_CNTL		0x0040
 #	define RADEON_CRTC_VBLANK_MASK		(1 << 0)
 #	define RADEON_CRTC2_VBLANK_MASK		(1 << 9)
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index d7f10f9..4ff8a5c 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -178,16 +178,18 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
 u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	u32 crtc_cnt_reg;
+	u32 crtc_cnt_reg, crtc_status_reg;
 
-	if (crtc == 0)
+	if (crtc == 0) {
 		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
-	else if (crtc == 1)
+		crtc_status_reg = RADEON_CRTC_STATUS;
+	} else if (crtc == 1) {
 		crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
-	else
+		crtc_status_reg = RADEON_CRTC2_STATUS;
+	} else
 		return 0;
 
-	return RADEON_READ(crtc_cnt_reg);
+	return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
 }
 
 /* Needs the lock as it touches the ring.
commit 7f2a1cf2753c0c97b1290469a15322f7549f78ae
Merge: d2d5302... 97dcd7f...
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Fri Jun 22 11:12:02 2007 -0700

    Merge branch 'vblank-rework' into vblank

commit 97dcd7fd25c18d5148619254229f8d94efb55b44
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Fri Jun 22 11:06:51 2007 -0700

    more vblank rework
      - use a timer for disabling vblank events to avoid enable/disable calls too
        often
      - make i915 work with pre-965 chips again (would like to structure this
        better, but this hack works on my test system)

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index cf1c0fd..0ab69fe 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -832,6 +832,7 @@ typedef struct drm_device {
 					/* for wraparound handling */
 	u32 *vblank_offset;		/* used to track how many vblanks */
 	u32 *vblank_premodeset;		/*  were lost during modeset */
+	struct timer_list vblank_disable_timer;
 
 	unsigned long max_vblank_count; /**< size of vblank counter register */
 	spinlock_t tasklet_lock;	/**< For drm_locked_tasklet */
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index c9d1c0d..1e1b7f4 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -77,10 +77,22 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
 	return 0;
 }
 
+static void vblank_disable_fn(unsigned long arg)
+{
+	drm_device_t *dev = (drm_device_t *)arg;
+	int i;
+
+	for (i = 0; i < dev->num_crtcs; i++)
+		if (atomic_read(&dev->vblank_refcount[i]) == 0)
+			dev->driver->disable_vblank(dev, i);
+}
+
 int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 {
 	int i, ret = -ENOMEM;
 
+	setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\
+		    (unsigned long)dev);
 	spin_lock_init(&dev->vbl_lock);
 	atomic_set(&dev->vbl_signal_pending, 0);
 	dev->num_crtcs = num_crtcs;
@@ -377,9 +389,10 @@ EXPORT_SYMBOL(drm_vblank_get);
  */
 void drm_vblank_put(drm_device_t *dev, int crtc)
 {
-	/* Last user can disable interrupts */
+	/* Last user schedules interrupt disable */
 	if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
-		dev->driver->disable_vblank(dev, crtc);
+		mod_timer(&dev->vblank_disable_timer,
+			  round_jiffies_relative(DRM_HZ));
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index ebb184c..b239889 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -31,17 +31,6 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#define IS_I965G(dev)  (dev->pci_device == 0x2972 || \
-			dev->pci_device == 0x2982 || \
-			dev->pci_device == 0x2992 || \
-			dev->pci_device == 0x29A2 || \
-			dev->pci_device == 0x2A02 || \
-			dev->pci_device == 0x2A12)
-
-#define IS_G33(dev)    (dev->pci_device == 0x29C2 || \
-		   	dev->pci_device == 0x29B2 || \
-			dev->pci_device == 0x29D2) 
-
 /* 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
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 213759a..c8961c0 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -396,4 +396,17 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char \
*caller);  
 #define READ_BREADCRUMB(dev_priv)  (((volatile u32*)(dev_priv->hw_status_page))[5])
 #define READ_HWSP(dev_priv, reg)  (((volatile u32*)(dev_priv->hw_status_page))[reg])
+
+#define IS_I965G(dev)  (dev->pci_device == 0x2972 || \
+			dev->pci_device == 0x2982 || \
+			dev->pci_device == 0x2992 || \
+			dev->pci_device == 0x29A2 || \
+			dev->pci_device == 0x2A02 || \
+			dev->pci_device == 0x2A12)
+
+#define IS_G33(dev)    (dev->pci_device == 0x29C2 || \
+		   	dev->pci_device == 0x29B2 || \
+			dev->pci_device == 0x29D2) 
+
+
 #endif
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 713ec65..c0c1bf9 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -285,6 +285,9 @@ u32 i915_get_vblank_counter(drm_device_t *dev, int crtc)
 	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
 	u32 high1, high2, low, count;
 
+	if (!IS_I965G(dev))
+		return 0;
+
 	/*
 	 * High & low register fields aren't synchronized, so make sure
 	 * we get a low value that's stable across two reads of the high
@@ -315,7 +318,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
 		
 	temp = I915_READ16(I915REG_INT_IDENTITY_R);
-	temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
 
 #if 0
 	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@@ -324,7 +326,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 		return IRQ_NONE;
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
-	(void) I915_READ16(I915REG_INT_IDENTITY_R);
+	(void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */
+
+	temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG |
+		 VSYNC_PIPEB_FLAG);
 
 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
 
@@ -335,6 +340,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 #endif
 	}
 
+	if (!IS_I965G(dev)) {
+		if (temp & VSYNC_PIPEA_FLAG)
+			atomic_inc(&dev->_vblank_count[0]);
+		if (temp & VSYNC_PIPEB_FLAG)
+			atomic_inc(&dev->_vblank_count[1]);
+	}
+
 	/*
 	 * Use drm_update_vblank_counter here to deal with potential lost
 	 * interrupts
@@ -482,6 +494,9 @@ int i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+	if (!IS_I965G(dev))
+		return 0;
+
 	switch (crtc) {
 	case 0:
 		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
@@ -504,6 +519,9 @@ void i915_disable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+	if (!IS_I965G(dev))
+		return;
+
 	switch (crtc) {
 	case 0:
 		dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
@@ -763,6 +781,11 @@ int i915_driver_irq_postinstall(drm_device_t * dev)
 
 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
+	if (!IS_I965G(dev)) {
+		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG;
+		I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+	}
+
 	i915_enable_interrupt(dev);
 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
commit d2d53024fb4003a6b86a3ea1ea33c76ac20bebc9
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 22 11:45:23 2007 +0200

    Fix vblank wait condition.
    
    Sync-to-vblank actually works again for me with radeon.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 01e970f..5d8d71b 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -554,7 +554,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 			return ret;
 		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
 			    (((cur_vblank = drm_vblank_count(dev, crtc))
-			      - seq) <= (1 << 23)));
+			      - vblwait.request.sequence) <= (1 << 23)));
 		drm_vblank_put(dev, crtc);
 		do_gettimeofday(&now);
 		vblwait.reply.tval_sec = now.tv_sec;
commit 2738bca6f52e236a2d9a0e456a78b10442ededdd
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 22 11:44:38 2007 +0200

    Use drm_calloc instead of assigning 0.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index c9d1c0d..01e970f 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -105,18 +105,18 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 	if (!dev->vblank_refcount)
 		goto err;
 
-	dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs,
-				     DRM_MEM_DRIVER);
+	dev->last_vblank = drm_calloc(1, sizeof(u32) * num_crtcs,
+				      DRM_MEM_DRIVER);
 	if (!dev->last_vblank)
 		goto err;
 
-	dev->vblank_premodeset = drm_alloc(sizeof(u32) * num_crtcs,
-					   DRM_MEM_DRIVER);
+	dev->vblank_premodeset = drm_calloc(1, sizeof(u32) * num_crtcs,
+					    DRM_MEM_DRIVER);
 	if (!dev->vblank_premodeset)
 		goto err;
 
-	dev->vblank_offset = drm_alloc(sizeof(u32) * num_crtcs,
-				       DRM_MEM_DRIVER);
+	dev->vblank_offset = drm_calloc(1, sizeof(u32) * num_crtcs,
+					DRM_MEM_DRIVER);
 	if (!dev->vblank_offset)
 		goto err;
 
@@ -126,9 +126,6 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 		INIT_LIST_HEAD(&dev->vbl_sigs[i]);
 		atomic_set(&dev->_vblank_count[i], 0);
 		atomic_set(&dev->vblank_refcount[i], 0);
-		dev->last_vblank[i] = 0;
-		dev->vblank_premodeset[i] = 0;
-		dev->vblank_offset[i] = 0;
 	}
 
 	return 0;
commit 6e2cd7c16331b07c395732d132a6a4cdc1fad481
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 22 11:44:19 2007 +0200

    drm_modeset_ctl_t fixes.
    
    s/u64/drm_u64_t/ to allow userspace code using drm.h to compile.
    
    Move 64 bit arg member to the beginning to avoid alignment issues with 32
    bit userspace on 64 bit kernels.

diff --git a/shared-core/drm.h b/shared-core/drm.h
index 3cd6d50..eae25c6 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -598,8 +598,8 @@ typedef enum {
  * \sa drmModesetCtl().
  */
 typedef struct drm_modeset_ctl {
+	drm_u64_t arg;
 	drm_modeset_ctl_cmd_t cmd;
-	u64 arg;
 } drm_modeset_ctl_t;
 
 /**
commit b8dd31487551ff83b63205a5cefbd06de7d4fbca
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 22 11:42:54 2007 +0200

    Remove mask parameter from radeon_acknowledge_irqs().
    
    Simply always acknowledge all interrupts we're interested in, to avoid hard
    hangs when an unexpected interrupt is flagged.

diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index a1b7971..d7f10f9 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -81,13 +81,15 @@ void radeon_disable_vblank(drm_device_t *dev, int crtc)
 	}
 }
 
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
-					      u32 mask)
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
 {
 	u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
-		(mask | RADEON_CRTC_VBLANK_MASK | RADEON_CRTC2_VBLANK_MASK);
+		(RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
+		 RADEON_CRTC2_VBLANK_STAT);
+
 	if (irqs)
 		RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+
 	return irqs;
 }
 
@@ -119,10 +121,12 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
 	/* Only consider the bits we're interested in - others could be used
 	 * outside the DRM
 	 */
-	stat = radeon_acknowledge_irqs(dev_priv, dev_priv->irq_enable_reg);
+	stat = radeon_acknowledge_irqs(dev_priv);
 	if (!stat)
 		return IRQ_NONE;
 
+	stat &= dev_priv->irq_enable_reg;
+
 	/* SW interrupt */
 	if (stat & RADEON_SW_INT_TEST)
 		DRM_WAKEUP(&dev_priv->swi_queue);
@@ -247,9 +251,7 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
 	RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
 
 	/* Clear bits if they're already high */
-	radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-					   RADEON_CRTC_VBLANK_STAT |
-					   RADEON_CRTC2_VBLANK_STAT));
+	radeon_acknowledge_irqs(dev_priv);
 }
 
 int radeon_driver_irq_postinstall(drm_device_t * dev)
commit 24c09faec1c47260cd280221fa72fe18a12efef9
Merge: 2d24455... afe8422...
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Thu Jun 21 15:26:34 2007 -0700

    Merge branch 'vblank-rework' into vblank

commit afe842297f7117cf80718de78ce706f6fd83584b
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Thu Jun 21 15:23:20 2007 -0700

    RADEON: fix race in vblank interrupt handling
    It's possible that we disable vblank interrupts and clear the
    corresponding flag in irq_enable_reg, but receive an interrupt at just
    the wrong time, causing us to not ack it properly, nor report to the
    core kernel that it was handled.  Fix that case by always handling
    vblank interrupts, even if the irq_enable_reg field is clear.

diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index d1f0e31..4409026 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -37,7 +37,7 @@
 
 static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int state)
 {
-	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
 
 	if (state)
 		dev_priv->irq_enable_reg |= mask;
@@ -49,8 +49,6 @@ static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int \
state)  
 int radeon_enable_vblank(drm_device_t *dev, int crtc)
 {
-	drm_radeon_private_t *dev_priv = dev->dev_private;
-
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
@@ -69,8 +67,6 @@ int radeon_enable_vblank(drm_device_t *dev, int crtc)
 
 void radeon_disable_vblank(drm_device_t *dev, int crtc)
 {
-	drm_radeon_private_t *dev_priv = dev->dev_private;
-
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
@@ -88,7 +84,8 @@ void radeon_disable_vblank(drm_device_t *dev, int crtc)
 static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
 					      u32 mask)
 {
-	u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+	u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
+		(mask | RADEON_CRTC_VBLANK_MASK | RADEON_CRTC2_VBLANK_MASK);
 	if (irqs)
 		RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
 	return irqs;
commit 2d24455ed8b12df6d06d135cb70f02473d11f4b0
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Mon Jun 18 17:43:58 2007 -0700

    Remove broken CRTC enable checks and incorrect user irq enable in set_pipe
    routine.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 00400fa..713ec65 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -482,9 +482,6 @@ int i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	if (!(dev_priv->vblank_pipe & (1 << crtc)))
-		return -EINVAL;
-	
 	switch (crtc) {
 	case 0:
 		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
@@ -507,9 +504,6 @@ void i915_disable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	if (!(dev_priv->vblank_pipe & (1 << crtc)))
-		return;
-	
 	switch (crtc) {
 	case 0:
 		dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
@@ -560,8 +554,6 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
 
 	dev_priv->vblank_pipe = pipe.pipe;
 
-	i915_enable_interrupt (dev);
-
 	return 0;
 }
 
commit d8ed021d29951b17cfbda0ade968c73a52ac7ec7
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Mon Jun 18 13:08:21 2007 +0200

    radeon: VBlank rework fixups.
    
    Fix range of frame counter registers.
    
    Use DRM_ERR() instead of Linux specific error codes in shared code.
    
    Remove duplicate register definitions and superfluous local variables.

diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 5f671df..bb69c10 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -512,9 +512,6 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp,
 #define RADEON_CRTC_CRNT_FRAME 0x0214
 #define RADEON_CRTC2_CRNT_FRAME 0x0314
 
-#define RADEON_CRTC_CRNT_FRAME              0x0214
-#define RADEON_CRTC2_CRNT_FRAME              0x0314
-
 #define RADEON_GEN_INT_CNTL		0x0040
 #	define RADEON_CRTC_VBLANK_MASK		(1 << 0)
 #	define RADEON_CRTC2_VBLANK_MASK		(1 << 9)
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index d1f0e31..cf72fc5 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -49,8 +49,6 @@ static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int \
state)  
 int radeon_enable_vblank(drm_device_t *dev, int crtc)
 {
-	drm_radeon_private_t *dev_priv = dev->dev_private;
-
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
@@ -61,7 +59,7 @@ int radeon_enable_vblank(drm_device_t *dev, int crtc)
 	default:
 		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 			  crtc);
-		return -EINVAL;
+		return DRM_ERR(EINVAL);
 	}
 
 	return 0;
@@ -69,8 +67,6 @@ int radeon_enable_vblank(drm_device_t *dev, int crtc)
 
 void radeon_disable_vblank(drm_device_t *dev, int crtc)
 {
-	drm_radeon_private_t *dev_priv = dev->dev_private;
-
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
@@ -177,7 +173,7 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
 u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	u32 crtc_cnt_reg, current_cnt;
+	u32 crtc_cnt_reg;
 
 	if (crtc == 0)
 		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
@@ -186,9 +182,7 @@ u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 	else
 		return 0;
 
-	current_cnt = RADEON_READ(crtc_cnt_reg);
-
-	return current_cnt;
+	return RADEON_READ(crtc_cnt_reg);
 }
 
 /* Needs the lock as it touches the ring.
@@ -261,16 +255,16 @@ int radeon_driver_irq_postinstall(drm_device_t * dev)
 {
 	drm_radeon_private_t *dev_priv =
 	    (drm_radeon_private_t *) dev->dev_private;
-	int num_pipes = 2, ret;
+	int ret;
 
 	atomic_set(&dev_priv->swi_emitted, 0);
 	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
-	ret = drm_vblank_init(dev, num_pipes);
+	ret = drm_vblank_init(dev, 2);
 	if (ret)
 		return ret;
 
-	dev->max_vblank_count = 0xffffffff;
+	dev->max_vblank_count = 0x001fffff;
 
 	radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
 
commit 741d1c80314de6f30bcc7eca7a7720b0aac3c56c
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Fri Jun 15 17:06:46 2007 -0700

    Remove broken crtc enable checks, radeon does it slightly differently
    (this makes get_vblank_counter return an actual value).

diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 46ec035..d1f0e31 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -51,9 +51,6 @@ int radeon_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 
-	if (!(dev_priv->vblank_crtc & (1 << crtc)))
-		return -EINVAL;
-	
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
@@ -64,7 +61,7 @@ int radeon_enable_vblank(drm_device_t *dev, int crtc)
 	default:
 		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 			  crtc);
-		break;
+		return -EINVAL;
 	}
 
 	return 0;
@@ -74,9 +71,6 @@ void radeon_disable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 
-	if (!(dev_priv->vblank_crtc & (1 << crtc)))
-		return;
-	
 	switch (crtc) {
 	case 0:
 		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
@@ -185,9 +179,9 @@ u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	u32 crtc_cnt_reg, current_cnt;
 
-	if (crtc == DRM_RADEON_VBLANK_CRTC1)
+	if (crtc == 0)
 		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
-	else if (crtc == DRM_RADEON_VBLANK_CRTC2)
+	else if (crtc == 1)
 		crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
 	else
 		return 0;
commit b6610363e373c13a2e7fdee8691756e1768bdd57
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Fri Jun 15 11:21:57 2007 -0700

    First cut at radeon support for the vblank rework.

diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c
index 327a6a9..39c3513 100644
--- a/linux-core/radeon_drv.c
+++ b/linux-core/radeon_drv.c
@@ -60,8 +60,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id \
*ent);  static struct drm_driver driver = {
 	.driver_features =
 	    DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
-	    DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
-	    DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
+	    DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
 	.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
 	.load = radeon_driver_load,
 	.firstopen = radeon_driver_firstopen,
@@ -70,8 +69,9 @@ static struct drm_driver driver = {
 	.postclose = radeon_driver_postclose,
 	.lastclose = radeon_driver_lastclose,
 	.unload = radeon_driver_unload,
-	.vblank_wait = radeon_driver_vblank_wait,
-	.vblank_wait2 = radeon_driver_vblank_wait2,
+	.get_vblank_counter = radeon_get_vblank_counter,
+	.enable_vblank = radeon_enable_vblank,
+	.disable_vblank = radeon_disable_vblank,
 	.dri_library_name = dri_library_name,
 	.irq_preinstall = radeon_driver_irq_preinstall,
 	.irq_postinstall = radeon_driver_irq_postinstall,
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 283dee3..5f671df 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -366,13 +366,12 @@ extern int radeon_irq_emit(DRM_IOCTL_ARGS);
 extern int radeon_irq_wait(DRM_IOCTL_ARGS);
 
 extern void radeon_do_release(drm_device_t * dev);
-extern int radeon_driver_vblank_wait(drm_device_t * dev,
-				     unsigned int *sequence, int relative);
-extern int radeon_driver_vblank_wait2(drm_device_t * dev,
-				      unsigned int *sequence, int relative);
+extern u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc);
+extern int radeon_enable_vblank(drm_device_t *dev, int crtc);
+extern void radeon_disable_vblank(drm_device_t *dev, int crtc);
 extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
 extern void radeon_driver_irq_preinstall(drm_device_t * dev);
-extern void radeon_driver_irq_postinstall(drm_device_t * dev);
+extern int radeon_driver_irq_postinstall(drm_device_t * dev);
 extern void radeon_driver_irq_uninstall(drm_device_t * dev);
 extern int radeon_vblank_crtc_get(drm_device_t *dev);
 extern int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value);
@@ -513,6 +512,9 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp,
 #define RADEON_CRTC_CRNT_FRAME 0x0214
 #define RADEON_CRTC2_CRNT_FRAME 0x0314
 
+#define RADEON_CRTC_CRNT_FRAME              0x0214
+#define RADEON_CRTC2_CRNT_FRAME              0x0314
+
 #define RADEON_GEN_INT_CNTL		0x0040
 #	define RADEON_CRTC_VBLANK_MASK		(1 << 0)
 #	define RADEON_CRTC2_VBLANK_MASK		(1 << 9)
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 2534ff1..46ec035 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -47,6 +47,50 @@ static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int \
state)  RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
 }
 
+int radeon_enable_vblank(drm_device_t *dev, int crtc)
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+
+	if (!(dev_priv->vblank_crtc & (1 << crtc)))
+		return -EINVAL;
+	
+	switch (crtc) {
+	case 0:
+		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
+		break;
+	case 1:
+		radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
+		break;
+	default:
+		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+			  crtc);
+		break;
+	}
+
+	return 0;
+}
+
+void radeon_disable_vblank(drm_device_t *dev, int crtc)
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+
+	if (!(dev_priv->vblank_crtc & (1 << crtc)))
+		return;
+	
+	switch (crtc) {
+	case 0:
+		radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
+		break;
+	case 1:
+		radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
+		break;
+	default:
+		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+			  crtc);
+		break;
+	}
+}
+
 static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
 					      u32 mask)
 {
@@ -89,30 +133,14 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
 		return IRQ_NONE;
 
 	/* SW interrupt */
-	if (stat & RADEON_SW_INT_TEST) {
+	if (stat & RADEON_SW_INT_TEST)
 		DRM_WAKEUP(&dev_priv->swi_queue);
-	}
 
 	/* VBLANK interrupt */
-	if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
-		int vblank_crtc = dev_priv->vblank_crtc;
-
-		if ((vblank_crtc &
-		     (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
-		    (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
-			if (stat & RADEON_CRTC_VBLANK_STAT)
-				atomic_inc(&dev->vbl_received);
-			if (stat & RADEON_CRTC2_VBLANK_STAT)
-				atomic_inc(&dev->vbl_received2);
-		} else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
-			   (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
-			   ((stat & RADEON_CRTC2_VBLANK_STAT) &&
-			    (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
-			atomic_inc(&dev->vbl_received);
-
-		DRM_WAKEUP(&dev->vbl_queue);
-		drm_vbl_send_signals(dev);
-	}
+	if (stat & RADEON_CRTC_VBLANK_STAT)
+		drm_handle_vblank(dev, 0);
+	if (stat & RADEON_CRTC2_VBLANK_STAT)
+		drm_handle_vblank(dev, 1);
 
 	return IRQ_HANDLED;
 }
@@ -152,80 +180,21 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
 	return ret;
 }
 
-int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned int *sequence,
-				 int crtc, int relative)
+u32 radeon_get_vblank_counter(drm_device_t *dev, int crtc)
 {
-	drm_radeon_private_t *dev_priv =
-	    (drm_radeon_private_t *) dev->dev_private;
-	unsigned int cur_vblank, diff, irqflags, current_cnt;
-	int ret = 0;
-	int ack = 0;
-	atomic_t *counter;
-	unsigned int *last_cnt;
-	int crtc_cnt_reg;
-	
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	u32 crtc_cnt_reg, current_cnt;
 
-	if (crtc == DRM_RADEON_VBLANK_CRTC1) {
-		counter = &dev->vbl_received;
-		ack = RADEON_CRTC_VBLANK_STAT;
-		last_cnt = &dev_priv->crtc_last_cnt;
+	if (crtc == DRM_RADEON_VBLANK_CRTC1)
 		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
-	} else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
-		counter = &dev->vbl_received2;
-		ack = RADEON_CRTC2_VBLANK_STAT;
-		last_cnt = &dev_priv->crtc2_last_cnt;
+	else if (crtc == DRM_RADEON_VBLANK_CRTC2)
 		crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
-	} else
-		return DRM_ERR(EINVAL);
-
-	radeon_acknowledge_irqs(dev_priv, ack);
-
-	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
-
-	if (!relative) {
-		/*
-		 * Assume we haven't missed more than several hours of vblank
-		 * events, or that it won't matter if they're not accounted
-		 * for in the master counter.
-		 */
-		spin_lock_irqsave(&dev->vbl_lock, irqflags);
-		current_cnt = RADEON_READ(crtc_cnt_reg);
-		if (current_cnt < *last_cnt) {
-			current_cnt += (1 << 21) - *last_cnt;
-			*last_cnt = 0;
-		}
-		diff = current_cnt - *last_cnt;
-		*last_cnt = RADEON_READ(crtc_cnt_reg);
-		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-		atomic_add(diff, counter);
-	}
-
-	/* Assume that the user has missed the current sequence number
-	 * by about a day rather than she wants to wait for years
-	 * using vertical blanks...
-	 */
-	radeon_irq_set_state(dev, ack, 1);
-	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-		    (((cur_vblank = atomic_read(counter))
-		      - *sequence) <= (1 << 23)));
-	radeon_irq_set_state(dev, ack, 0);
-	*sequence = cur_vblank;
-
-	return ret;
-}
+	else
+		return 0;
 
-int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence, int \
                relative)
-{
-	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1, \
                relative);
-}
+	current_cnt = RADEON_READ(crtc_cnt_reg);
 
-int radeon_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence, int \
                relative)
-{
-	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2, \
relative); +	return current_cnt;
 }
 
 /* Needs the lock as it touches the ring.
@@ -294,15 +263,24 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
 					   RADEON_CRTC2_VBLANK_STAT));
 }
 
-void radeon_driver_irq_postinstall(drm_device_t * dev)
+int radeon_driver_irq_postinstall(drm_device_t * dev)
 {
 	drm_radeon_private_t *dev_priv =
 	    (drm_radeon_private_t *) dev->dev_private;
+	int num_pipes = 2, ret;
 
 	atomic_set(&dev_priv->swi_emitted, 0);
 	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
+	ret = drm_vblank_init(dev, num_pipes);
+	if (ret)
+		return ret;
+
+	dev->max_vblank_count = 0xffffffff;
+
 	radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
+
+	return 0;
 }
 
 void radeon_driver_irq_uninstall(drm_device_t * dev)
commit 0f5334be2bc6ceca971a7a6ab3ca1c23a707867c
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 11:01:51 2007 +0200

    Remove DRIVER_IRQ_VBL(2).
    
    If the driver doesn't support vertical blank interrupts, it won't call
    drm_vblank_init(), and dev->num_crtcs will be 0.
    
    Also fix an off-by-one test against dev->num_crtcs.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index 5bc8a6c..cf1c0fd 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -100,10 +100,8 @@
 #define DRIVER_HAVE_DMA    0x20
 #define DRIVER_HAVE_IRQ    0x40
 #define DRIVER_IRQ_SHARED  0x80
-#define DRIVER_IRQ_VBL     0x100
-#define DRIVER_DMA_QUEUE   0x200
-#define DRIVER_FB_DMA      0x400
-#define DRIVER_IRQ_VBL2    0x800
+#define DRIVER_DMA_QUEUE   0x100
+#define DRIVER_FB_DMA      0x200
 
 
 /*@}*/
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index f673a97..c9d1c0d 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -405,7 +405,7 @@ int drm_modeset_ctl(DRM_IOCTL_ARGS)
 	}
 
 	crtc = modeset.arg;
-	if (crtc > dev->num_crtcs) {
+	if (crtc >= dev->num_crtcs) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -474,8 +474,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
 	crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
 
-	if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
-				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
+	if (crtc >= dev->num_crtcs)
 		return -EINVAL;
 
 	drm_update_vblank_count(dev, crtc);
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index e7a9bfd..e7f69e6 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -76,8 +76,7 @@ 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_IRQ_VBL2,
+	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
 	.load = i915_driver_load,
 	.firstopen = i915_driver_firstopen,
 	.lastclose = i915_driver_lastclose,
commit fbee089aca727c92e0aa5d7a2ae7a8c5cf9c3076
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 10:49:16 2007 +0200

    Make vblank waitqueue per CRTC.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index b6cc7cb..5bc8a6c 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -824,7 +824,7 @@ typedef struct drm_device {
 	/** \name VBLANK IRQ support */
 	/*@{ */
 
-	wait_queue_head_t vbl_queue;	/**< VBLANK wait queue */
+	wait_queue_head_t *vbl_queue;	/**< VBLANK wait queue */
 	atomic_t *_vblank_count;	/**< number of VBLANK interrupts (driver must alloc the \
right number of counters) */  spinlock_t vbl_lock;
 	struct list_head *vbl_sigs;		/**< signal list to send on VBLANK */
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 3dcde9a..f673a97 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -81,11 +81,15 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 {
 	int i, ret = -ENOMEM;
 
-	init_waitqueue_head(&dev->vbl_queue);
 	spin_lock_init(&dev->vbl_lock);
 	atomic_set(&dev->vbl_signal_pending, 0);
 	dev->num_crtcs = num_crtcs;
 
+	dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
+				   DRM_MEM_DRIVER);
+	if (!dev->vbl_queue)
+		goto err;
+
 	dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
 				  DRM_MEM_DRIVER);
 	if (!dev->vbl_sigs)
@@ -118,6 +122,7 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 
 	/* Zero per-crtc vblank stuff */
 	for (i = 0; i < num_crtcs; i++) {
+		init_waitqueue_head(&dev->vbl_queue[i]);
 		INIT_LIST_HEAD(&dev->vbl_sigs[i]);
 		atomic_set(&dev->_vblank_count[i], 0);
 		atomic_set(&dev->vblank_refcount[i], 0);
@@ -129,6 +134,8 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 	return 0;
 
 err:
+	drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * num_crtcs,
+		 DRM_MEM_DRIVER);
 	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs,
 		 DRM_MEM_DRIVER);
 	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs,
@@ -150,7 +157,7 @@ EXPORT_SYMBOL(drm_vblank_init);
  *
  * \param dev DRM device.
  *
- * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the \
handler, calling the driver + * Initializes the IRQ related data. Installs the \
                handler, calling the driver
  * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
  * before and after the installation.
  */
@@ -549,7 +556,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		ret = drm_vblank_get(dev, crtc);
 		if (ret)
 			return ret;
-		DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
 			    (((cur_vblank = drm_vblank_count(dev, crtc))
 			      - seq) <= (1 << 23)));
 		drm_vblank_put(dev, crtc);
@@ -617,7 +624,7 @@ static void drm_vbl_send_signals(drm_device_t * dev, int crtc)
 void drm_handle_vblank(drm_device_t *dev, int crtc)
 {
 	drm_update_vblank_count(dev, crtc);
-	DRM_WAKEUP(&dev->vbl_queue);
+	DRM_WAKEUP(&dev->vbl_queue[crtc]);
 	drm_vbl_send_signals(dev, crtc);
 }
 EXPORT_SYMBOL(drm_handle_vblank);
commit 82e2c3304d3f1697537b73a2c888c8c6b1b6cdc8
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 10:25:50 2007 +0200

    Wake up vblank waitqueue in drm_handle_vblank().

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index b4e3c10..3dcde9a 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -617,6 +617,7 @@ static void drm_vbl_send_signals(drm_device_t * dev, int crtc)
 void drm_handle_vblank(drm_device_t *dev, int crtc)
 {
 	drm_update_vblank_count(dev, crtc);
+	DRM_WAKEUP(&dev->vbl_queue);
 	drm_vbl_send_signals(dev, crtc);
 }
 EXPORT_SYMBOL(drm_handle_vblank);
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 9861af9..00400fa 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -345,8 +345,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 		drm_handle_vblank(dev, 1);
 
 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-		DRM_WAKEUP(&dev->vbl_queue);
-
 		if (dev_priv->swaps_pending > 0)
 			drm_locked_tasklet(dev, i915_vblank_tasklet);
 		I915_WRITE(I915REG_PIPEASTAT, 
commit 914a810a82af6f82e69a94448570772f20a94953
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 10:21:44 2007 +0200

    i915: Fix tests for vblank interrupts being enabled on CRTC by X server.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index ad2cf9c..9861af9 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -484,7 +484,7 @@ int i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	if (dev_priv->vblank_pipe != (1 << crtc))
+	if (!(dev_priv->vblank_pipe & (1 << crtc)))
 		return -EINVAL;
 	
 	switch (crtc) {
@@ -509,7 +509,7 @@ void i915_disable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	if (crtc > dev_priv->vblank_pipe)
+	if (!(dev_priv->vblank_pipe & (1 << crtc)))
 		return;
 	
 	switch (crtc) {
commit 7f95a06c61f585cbc4b5fefc833432178550fe31
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 10:12:23 2007 +0200

    Return current sequence number to userspace after blocking wait for vblank.

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index f73d067..b4e3c10 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -556,6 +556,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 		do_gettimeofday(&now);
 		vblwait.reply.tval_sec = now.tv_sec;
 		vblwait.reply.tval_usec = now.tv_usec;
+		vblwait.reply.sequence = cur_vblank;
 	}
 
       done:
commit 1000d88ddfcd0ae769125db37d4e78643a430caf
Author: Michel Dänzer <michel@tungstengraphics.com>
Date:   Fri Jun 15 10:10:33 2007 +0200

    Fix memory leaks in vblank error paths.
    
    Also use drm_calloc instead of drm_alloc and memset, and use the size of the
    struct instead of the size of the pointer for allocation...

diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 7bdb01b..f73d067 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -518,18 +518,19 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-		if (!
-		    (vbl_sig =
-		     drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
+		vbl_sig = drm_calloc(1, sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER);
+		if (!vbl_sig) {
 			return -ENOMEM;
 		}
 
 		ret = drm_vblank_get(dev, crtc);
-		if (ret)
+		if (ret) {
+			drm_free(vbl_sig, sizeof(drm_vbl_sig_t),
+				 DRM_MEM_DRIVER);
 			return ret;
-		atomic_inc(&dev->vbl_signal_pending);
+		}
 
-		memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
+		atomic_inc(&dev->vbl_signal_pending);
 
 		vbl_sig->sequence = vblwait.request.sequence;
 		vbl_sig->info.si_signo = vblwait.request.signal;
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index e91add9..ad2cf9c 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -707,7 +707,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 		return DRM_ERR(EBUSY);
 	}
 
-	vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+	vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
 
 	if (!vbl_swap) {
 		DRM_ERROR("Failed to allocate memory to queue swap\n");
@@ -717,8 +717,10 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	DRM_DEBUG("\n");
 
 	ret = drm_vblank_get(dev, pipe);
-	if (ret)
+	if (ret) {
+		drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
 		return ret;
+	}
 
 	vbl_swap->drw_id = swap.drawable;
 	vbl_swap->pipe = pipe;
commit b06268294afb47e62949984d73905344dd160262
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Thu Jun 14 11:32:31 2007 -0700

    Comment new vblank routines and fixup several issues:
      - use correct refcount variable in get/put routines
      - extract counter update from drm_vblank_get
      - make signal handling callback per-crtc
      - update interrupt handling logic, drivers should use drm_handle_vblank
      - move wakeup and counter update logic to new drm_handle_vblank routine
      - fixup usage of get/put in light of counter update extraction
      - fix longstanding bug in signal code, update pending counter only
        *after* we're sure we'll setup signal handling

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index c8b7225..b6cc7cb 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -627,8 +627,49 @@ struct drm_driver {
 	int (*kernel_context_switch) (struct drm_device * dev, int old,
 				      int new);
 	void (*kernel_context_switch_unlock) (struct drm_device * dev);
+	/**
+	 * get_vblank_counter - get raw hardware vblank counter
+	 * @dev: DRM device
+	 * @crtc: counter to fetch
+	 *
+	 * Driver callback for fetching a raw hardware vblank counter
+	 * for @crtc.  If a device doesn't have a hardware counter, the
+	 * driver can simply return the value of drm_vblank_count and
+	 * make the enable_vblank() and disable_vblank() hooks into no-ops,
+	 * leaving interrupts enabled at all times.
+	 *
+	 * Wraparound handling and loss of events due to modesetting is dealt
+	 * with in the DRM core code.
+	 *
+	 * RETURNS
+	 * Raw vblank counter value.
+	 */
 	u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
-	void (*enable_vblank) (struct drm_device *dev, int crtc);
+
+	/**
+	 * enable_vblank - enable vblank interrupt events
+	 * @dev: DRM device
+	 * @crtc: which irq to enable
+	 *
+	 * Enable vblank interrupts for @crtc.  If the device doesn't have
+	 * a hardware vblank counter, this routine should be a no-op, since
+	 * interrupts will have to stay on to keep the count accurate.
+	 *
+	 * RETURNS
+	 * Zero on success, appropriate errno if the given @crtc's vblank
+	 * interrupt cannot be enabled.
+	 */
+	int (*enable_vblank) (struct drm_device *dev, int crtc);
+
+	/**
+	 * disable_vblank - disable vblank interrupt events
+	 * @dev: DRM device
+	 * @crtc: which irq to enable
+	 *
+	 * Disable vblank interrupts for @crtc.  If the device doesn't have
+	 * a hardware vblank counter, this routine should be a no-op, since
+	 * interrupts will have to stay on to keep the count accurate.
+	 */
 	void (*disable_vblank) (struct drm_device *dev, int crtc);
 	int (*dri_library_name) (struct drm_device * dev, char * buf);
 
@@ -784,11 +825,11 @@ typedef struct drm_device {
 	/*@{ */
 
 	wait_queue_head_t vbl_queue;	/**< VBLANK wait queue */
-	atomic_t *vblank_count;		/**< number of VBLANK interrupts (driver must alloc the \
right number of counters) */ +	atomic_t *_vblank_count;	/**< number of VBLANK \
interrupts (driver must alloc the right number of counters) */  spinlock_t vbl_lock;
 	struct list_head *vbl_sigs;		/**< signal list to send on VBLANK */
-	atomic_t vbl_pending;		/* number of signals pending on all crtcs*/
-	atomic_t *vblank_usage;		/* number of users of vblank interrupts per crtc */
+	atomic_t vbl_signal_pending;	/* number of signals pending on all crtcs*/
+	atomic_t *vblank_refcount;	/* number of users of vblank interrupts per crtc */
 	u32 *last_vblank;		/* protected by dev->vbl_lock, used */
 					/* for wraparound handling */
 	u32 *vblank_offset;		/* used to track how many vblanks */
@@ -1083,9 +1124,11 @@ extern int drm_vblank_init(drm_device_t *dev, int num_crtcs);
 extern int drm_wait_vblank(struct inode *inode, struct file *filp,
 			   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*));
-extern void drm_vblank_get(drm_device_t *dev, int crtc);
+extern u32 drm_vblank_count(drm_device_t *dev, int crtc);
+extern void drm_update_vblank_count(drm_device_t *dev, int crtc);
+extern void drm_handle_vblank(drm_device_t *dev, int crtc);
+extern int drm_vblank_get(drm_device_t *dev, int crtc);
 extern void drm_vblank_put(drm_device_t *dev, int crtc);
 
 				/* Modesetting support */
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 8125b75..7bdb01b 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -83,7 +83,7 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 
 	init_waitqueue_head(&dev->vbl_queue);
 	spin_lock_init(&dev->vbl_lock);
-	atomic_set(&dev->vbl_pending, 0);
+	atomic_set(&dev->vbl_signal_pending, 0);
 	dev->num_crtcs = num_crtcs;
 
 	dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
@@ -91,14 +91,14 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 	if (!dev->vbl_sigs)
 		goto err;
 
-	dev->vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
+	dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
 				      DRM_MEM_DRIVER);
-	if (!dev->vblank_count)
+	if (!dev->_vblank_count)
 		goto err;
 
-	dev->vblank_usage = drm_alloc(sizeof(atomic_t) * num_crtcs,
-				      DRM_MEM_DRIVER);
-	if (!dev->vblank_count)
+	dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
+					 DRM_MEM_DRIVER);
+	if (!dev->vblank_refcount)
 		goto err;
 
 	dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs,
@@ -119,24 +119,28 @@ int drm_vblank_init(drm_device_t *dev, int num_crtcs)
 	/* Zero per-crtc vblank stuff */
 	for (i = 0; i < num_crtcs; i++) {
 		INIT_LIST_HEAD(&dev->vbl_sigs[i]);
-		atomic_set(&dev->vblank_count[i], 0);
-		atomic_set(&dev->vblank_usage[i], 0);
+		atomic_set(&dev->_vblank_count[i], 0);
+		atomic_set(&dev->vblank_refcount[i], 0);
 		dev->last_vblank[i] = 0;
 		dev->vblank_premodeset[i] = 0;
 		dev->vblank_offset[i] = 0;
 	}
 
-	ret = 0;
-	goto out;
+	return 0;
 
 err:
-	kfree(dev->vbl_sigs);
-	kfree(dev->vblank_count);
-	kfree(dev->vblank_usage);
-	kfree(dev->last_vblank);
-	kfree(dev->vblank_premodeset);
-	kfree(dev->vblank_offset);
-out:
+	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * num_crtcs,
+		 DRM_MEM_DRIVER);
+	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * num_crtcs,
+		 DRM_MEM_DRIVER);
+	drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
+		 num_crtcs, DRM_MEM_DRIVER);
+	drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs,
+		 DRM_MEM_DRIVER);
+	drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
+		 num_crtcs, DRM_MEM_DRIVER);
+	drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * num_crtcs,
+		 DRM_MEM_DRIVER);
 	return ret;
 }
 EXPORT_SYMBOL(drm_vblank_init);
@@ -274,14 +278,37 @@ int drm_control(struct inode *inode, struct file *filp,
 	}
 }
 
-void drm_vblank_get(drm_device_t *dev, int crtc)
+/**
+ * drm_vblank_count - retrieve "cooked" vblank counter value
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ */
+u32 drm_vblank_count(drm_device_t *dev, int crtc)
+{
+	return atomic_read(&dev->_vblank_count[crtc]) +
+		dev->vblank_offset[crtc];
+}
+EXPORT_SYMBOL(drm_vblank_count);
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc).  Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ */
+void drm_update_vblank_count(drm_device_t *dev, int crtc)
 {
 	unsigned long irqflags;
 	u32 cur_vblank, diff;
 
-	if (atomic_add_return(1, &dev->vblank_count[crtc]) != 1)
-		return;
-
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
 	 * wrap if needed.
@@ -301,18 +328,61 @@ void drm_vblank_get(drm_device_t *dev, int crtc)
 	dev->last_vblank[crtc] = cur_vblank;
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-	atomic_add(diff, &dev->vblank_count[crtc]);
-	dev->driver->enable_vblank(dev, crtc);
+	atomic_add(diff, &dev->_vblank_count[crtc]);
+}
+EXPORT_SYMBOL(drm_update_vblank_count);
+
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @crtc: which CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use.  Note callers will probably want to update the master counter
+ * using drm_update_vblank_count() above before calling this routine so that
+ * wakeups occur on the right vblank event.
+ *
+ * RETURNS
+ * Zero on success, nonzero on failure.
+ */
+int drm_vblank_get(drm_device_t *dev, int crtc)
+{
+	int ret = 0;
+
+	/* Going from 0->1 means we have to enable interrupts again */
+	if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+		ret = dev->driver->enable_vblank(dev, crtc);
+		if (ret)
+			atomic_dec(&dev->vblank_refcount[crtc]);
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_vblank_get);
 
+/**
+ * drm_vblank_put - give up ownership of vblank events
+ * @dev: DRM device
+ * @crtc: which counter to give up
+ *
+ * Release ownership of a given vblank counter, turning off interrupts
+ * if possible.
+ */
 void drm_vblank_put(drm_device_t *dev, int crtc)
 {
-	if (atomic_dec_and_test(&dev->vblank_count[crtc]))
+	/* Last user can disable interrupts */
+	if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
 		dev->driver->disable_vblank(dev, crtc);
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
+/**
+ * drm_modeset_ctl - handle vblank event counter changes across mode switch
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
+ * ioctls around modesetting so that any lost vblank events are accounted for.
+ */
 int drm_modeset_ctl(DRM_IOCTL_ARGS)
 {
 	drm_file_t *priv = filp->private_data;
@@ -401,8 +471,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
 		return -EINVAL;
 
-	drm_vblank_get(dev, crtc);
-	seq = atomic_read(&dev->vblank_count[crtc]);
+	drm_update_vblank_count(dev, crtc);
+	seq = drm_vblank_count(dev, crtc);
 
 	switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
 	case _DRM_VBLANK_RELATIVE:
@@ -437,28 +507,28 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 				spin_unlock_irqrestore(&dev->vbl_lock,
 						       irqflags);
 				vblwait.reply.sequence = seq;
-				drm_vblank_put(dev, crtc);
 				goto done;
 			}
 		}
 
-		if (atomic_read(&dev->vbl_pending) >= 100) {
+		if (atomic_read(&dev->vbl_signal_pending) >= 100) {
 			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-			drm_vblank_put(dev, crtc);
 			return -EBUSY;
 		}
 
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-		atomic_inc(&dev->vbl_pending);
-
 		if (!
 		    (vbl_sig =
 		     drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
-			drm_vblank_put(dev, crtc);
 			return -ENOMEM;
 		}
 
+		ret = drm_vblank_get(dev, crtc);
+		if (ret)
+			return ret;
+		atomic_inc(&dev->vbl_signal_pending);
+
 		memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
 
 		vbl_sig->sequence = vblwait.request.sequence;
@@ -475,8 +545,11 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	} else {
 		unsigned long cur_vblank;
 
+		ret = drm_vblank_get(dev, crtc);
+		if (ret)
+			return ret;
 		DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-			    (((cur_vblank = atomic_read(&dev->vblank_count[crtc]))
+			    (((cur_vblank = drm_vblank_count(dev, crtc))
 			      - seq) <= (1 << 23)));
 		drm_vblank_put(dev, crtc);
 		do_gettimeofday(&now);
@@ -495,42 +568,56 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
  * Send the VBLANK signals.
  *
  * \param dev DRM device.
+ * \param crtc CRTC where the vblank event occurred
  *
  * Sends a signal for each task in drm_device::vbl_sigs and empties the list.
  *
  * If a signal is not requested, then calls vblank_wait().
  */
-void drm_vbl_send_signals(drm_device_t * dev)
+static void drm_vbl_send_signals(drm_device_t * dev, int crtc)
 {
+	drm_vbl_sig_t *vbl_sig, *tmp;
+	struct list_head *vbl_sigs;
+	unsigned int vbl_seq;
 	unsigned long flags;
-	int i;
 
 	spin_lock_irqsave(&dev->vbl_lock, flags);
 
-	for (i = 0; i < dev->num_crtcs; i++) {
-		drm_vbl_sig_t *vbl_sig, *tmp;
-		struct list_head *vbl_sigs = &dev->vbl_sigs[i];
-		unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]);
+	vbl_sigs = &dev->vbl_sigs[crtc];
+	vbl_seq = drm_vblank_count(dev, crtc);
 
-		list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, 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_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, 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(&vbl_sig->head);
+		list_del(&vbl_sig->head);
 
-				drm_free(vbl_sig, sizeof(*vbl_sig),
-					 DRM_MEM_DRIVER);
-				atomic_dec(&dev->vbl_pending);
-				drm_vblank_put(dev, i);
-			}
-		}
+		drm_free(vbl_sig, sizeof(*vbl_sig),
+			 DRM_MEM_DRIVER);
+		atomic_dec(&dev->vbl_signal_pending);
+		drm_vblank_put(dev, crtc);
+	    }
 	}
 
 	spin_unlock_irqrestore(&dev->vbl_lock, flags);
 }
-EXPORT_SYMBOL(drm_vbl_send_signals);
+
+/**
+ * drm_handle_vblank - handle a vblank event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ */
+void drm_handle_vblank(drm_device_t *dev, int crtc)
+{
+	drm_update_vblank_count(dev, crtc);
+	drm_vbl_send_signals(dev, crtc);
+}
+EXPORT_SYMBOL(drm_handle_vblank);
 
 /**
  * Tasklet wrapper function.
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 15081f9..3cd6d50 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -599,7 +599,7 @@ typedef enum {
  */
 typedef struct drm_modeset_ctl {
 	drm_modeset_ctl_cmd_t cmd;
-	unsigned long arg;
+	u64 arg;
 } drm_modeset_ctl_t;
 
 /**
@@ -968,7 +968,7 @@ typedef union drm_mm_init_arg{
 
 #define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, drm_update_draw_t)
 
-#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0x40, drm_modeset_ctl_t)
+#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0xa0, drm_modeset_ctl_t)
 
 /*@}*/
 
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 079e901..213759a 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -171,7 +171,7 @@ extern int i915_emit_irq(drm_device_t * dev);
 extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
 extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
 extern int i915_vblank_swap(DRM_IOCTL_ARGS);
-extern void i915_enable_vblank(drm_device_t *dev, int crtc);
+extern int i915_enable_vblank(drm_device_t *dev, int crtc);
 extern void i915_disable_vblank(drm_device_t *dev, int crtc);
 extern u32 i915_get_vblank_counter(drm_device_t *dev, int crtc);
 
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 46b97e3..e91add9 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -92,8 +92,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
 	unsigned long irqflags;
 	struct list_head *list, *tmp, hits, *hit;
 	int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
-	unsigned counter[2] = { atomic_read(&dev->vblank_count[0]),
-				atomic_read(&dev->vblank_count[1]) };
+	unsigned counter[2];
 	drm_drawable_info_t *drw;
 	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	u32 cpp = dev_priv->cpp,  offsets[3];
@@ -105,6 +104,9 @@ static void i915_vblank_tasklet(drm_device_t *dev)
 			  (cpp << 23) | (1 << 24);
 	RING_LOCALS;
 
+	counter[0] = drm_vblank_count(dev, 0);
+	counter[1] = drm_vblank_count(dev, 1);
+
 	DRM_DEBUG("\n");
 
 	INIT_LIST_HEAD(&hits);
@@ -333,16 +335,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 #endif
 	}
 
+	/*
+	 * Use drm_update_vblank_counter here to deal with potential lost
+	 * interrupts
+	 */
 	if (temp & VSYNC_PIPEA_FLAG)
-		atomic_add(i915_get_vblank_counter(dev, 0),
-			   &dev->vblank_count[0]);
+		drm_handle_vblank(dev, 0);
 	if (temp & VSYNC_PIPEB_FLAG)
-		atomic_add(i915_get_vblank_counter(dev, 1),
-			   &dev->vblank_count[1]);
+		drm_handle_vblank(dev, 1);
 
 	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
 		DRM_WAKEUP(&dev->vbl_queue);
-		drm_vbl_send_signals(dev);
 
 		if (dev_priv->swaps_pending > 0)
 			drm_locked_tasklet(dev, i915_vblank_tasklet);
@@ -477,12 +480,12 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
 	return i915_wait_irq(dev, irqwait.irq_seq);
 }
 
-void i915_enable_vblank(drm_device_t *dev, int crtc)
+int i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-	if (crtc > dev_priv->vblank_pipe)
-		return;
+	if (dev_priv->vblank_pipe != (1 << crtc))
+		return -EINVAL;
 	
 	switch (crtc) {
 	case 0:
@@ -498,6 +501,8 @@ void i915_enable_vblank(drm_device_t *dev, int crtc)
 	}
 
 	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+
+	return 0;
 }
 
 void i915_disable_vblank(drm_device_t *dev, int crtc)
@@ -597,6 +602,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 	unsigned int pipe, seqtype, curseq;
 	unsigned long irqflags;
 	struct list_head *list;
+	int ret;
 
 	if (!dev_priv) {
 		DRM_ERROR("%s called with no initialization\n", __func__);
@@ -637,8 +643,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-	drm_vblank_get(dev, pipe);
-	curseq = atomic_read(&dev->vblank_count[pipe]);
+	drm_update_vblank_count(dev, pipe);
+	curseq = drm_vblank_count(dev, pipe);
 
 	if (seqtype == _DRM_VBLANK_RELATIVE)
 		swap.sequence += curseq;
@@ -648,7 +654,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 			swap.sequence = curseq + 1;
 		} else {
 			DRM_DEBUG("Missed target sequence\n");
-			drm_vblank_put(dev, pipe);
 			return DRM_ERR(EINVAL);
 		}
 	}
@@ -669,7 +674,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 				DRM_DEBUG("Invalid drawable ID %d\n",
 					  swap.drawable);
-				drm_vblank_put(dev, pipe);
 				return DRM_ERR(EINVAL);
 			}
 
@@ -677,7 +681,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-			drm_vblank_put(dev, pipe);
 			return 0;
 		}
 	}
@@ -693,7 +696,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 			vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
 			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 			DRM_DEBUG("Already scheduled\n");
-			drm_vblank_put(dev, pipe);
 			return 0;
 		}
 	}
@@ -702,7 +704,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	if (dev_priv->swaps_pending >= 100) {
 		DRM_DEBUG("Too many swaps queued\n");
-		drm_vblank_put(dev, pipe);
 		return DRM_ERR(EBUSY);
 	}
 
@@ -710,12 +711,15 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	if (!vbl_swap) {
 		DRM_ERROR("Failed to allocate memory to queue swap\n");
-		drm_vblank_put(dev, pipe);
 		return DRM_ERR(ENOMEM);
 	}
 
 	DRM_DEBUG("\n");
 
+	ret = drm_vblank_get(dev, pipe);
+	if (ret)
+		return ret;
+
 	vbl_swap->drw_id = swap.drawable;
 	vbl_swap->pipe = pipe;
 	vbl_swap->sequence = swap.sequence;
commit 1a4b9294a29379ea6e9fd6fb315317f391232d4b
Author: Jesse Barnes <jbarnes@jbarnes-mobile.amr.corp.intel.com>
Date:   Tue Jun 12 16:29:09 2007 -0700

    Remove unnecessary (and uncommented!) read barrier from the interrupt
    path.  It doesn't appear to serve any useful purpose.

diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 0f4d1a8..46b97e3 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -323,7 +323,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 	(void) I915_READ16(I915REG_INT_IDENTITY_R);
-	DRM_READMEMORYBARRIER();
 
 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
 
commit ca47fa90b73d0eac73fb7d1ba712d81e180eae7d
Author: Jesse Barnes <jesse.barnes@intel.com>
Date:   Tue Jun 12 13:35:41 2007 -0700

    Update vblank code:
      - move pre/post modeset ioctl to core
      - fixup i915 buffer swap
      - fix outstanding signal count code
      - create new core vblank init routine
      - test (works with glxgears)
      - simplify i915 interrupt handler

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index c3f2031..c8b7225 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -648,7 +648,7 @@ struct drm_driver {
 /* these have to be filled in */
 	 irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
 	void (*irq_preinstall) (struct drm_device * dev);
-	void (*irq_postinstall) (struct drm_device * dev);
+	int (*irq_postinstall) (struct drm_device * dev);
 	void (*irq_uninstall) (struct drm_device * dev);
 	void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
 	void (*reclaim_buffers_locked) (struct drm_device *dev,
@@ -786,10 +786,14 @@ typedef struct drm_device {
 	wait_queue_head_t vbl_queue;	/**< VBLANK wait queue */
 	atomic_t *vblank_count;		/**< number of VBLANK interrupts (driver must alloc the \
right number of counters) */  spinlock_t vbl_lock;
-	struct list_head vbl_sigs;		/**< signal list to send on VBLANK */
-	struct list_head vbl_sigs2;	/**< signals to send on secondary VBLANK */
-	atomic_t *vbl_pending;
-	u32 *last_vblank; /* protected by dev->vbl_lock */
+	struct list_head *vbl_sigs;		/**< signal list to send on VBLANK */
+	atomic_t vbl_pending;		/* number of signals pending on all crtcs*/
+	atomic_t *vblank_usage;		/* number of users of vblank interrupts per crtc */
+	u32 *last_vblank;		/* protected by dev->vbl_lock, used */
+					/* for wraparound handling */
+	u32 *vblank_offset;		/* used to track how many vblanks */
+	u32 *vblank_premodeset;		/*  were lost during modeset */
+
 	unsigned long max_vblank_count; /**< size of vblank counter register */
 	spinlock_t tasklet_lock;	/**< For drm_locked_tasklet */
 	void (*locked_tasklet_func)(struct drm_device *dev);
@@ -810,6 +814,7 @@ typedef struct drm_device {
 #ifdef __alpha__
 	struct pci_controller *hose;
 #endif
+	int num_crtcs;			/**< Number of CRTCs on this device */
 	drm_sg_mem_t *sg;		/**< Scatter gather memory */
 	void *dev_private;		/**< device private data */
 	drm_sigdata_t sigdata;		/**< For block_all_signals */
@@ -1074,11 +1079,18 @@ extern void drm_driver_irq_preinstall(drm_device_t * dev);
 extern void drm_driver_irq_postinstall(drm_device_t * dev);
 extern void drm_driver_irq_uninstall(drm_device_t * dev);
 
+extern int drm_vblank_init(drm_device_t *dev, int num_crtcs);
 extern int drm_wait_vblank(struct inode *inode, struct file *filp,
 			   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*));
+extern void drm_vblank_get(drm_device_t *dev, int crtc);
+extern void drm_vblank_put(drm_device_t *dev, int crtc);
+
+				/* Modesetting support */
+extern int drm_modeset_ctl(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
 
 				/* AGP/GART support (drm_agpsupport.h) */
 extern drm_agp_head_t *drm_agp_init(drm_device_t *dev);
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index d5eb971..1b37ee4 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -123,6 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
 					     DRM_AUTH },
 
 	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, \
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, +	[DRM_IOCTL_NR(DRM_IOCTL_MODESET_CTL)] = \
{drm_modeset_ctl, 0},  };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index f229f77..8125b75 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -77,6 +77,70 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
 	return 0;
 }
 
+int drm_vblank_init(drm_device_t *dev, int num_crtcs)
+{
+	int i, ret = -ENOMEM;
+
+	init_waitqueue_head(&dev->vbl_queue);
+	spin_lock_init(&dev->vbl_lock);
+	atomic_set(&dev->vbl_pending, 0);
+	dev->num_crtcs = num_crtcs;
+
+	dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
+				  DRM_MEM_DRIVER);
+	if (!dev->vbl_sigs)
+		goto err;
+
+	dev->vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
+				      DRM_MEM_DRIVER);
+	if (!dev->vblank_count)
+		goto err;
+
+	dev->vblank_usage = drm_alloc(sizeof(atomic_t) * num_crtcs,
+				      DRM_MEM_DRIVER);
+	if (!dev->vblank_count)
+		goto err;
+
+	dev->last_vblank = drm_alloc(sizeof(u32) * num_crtcs,
+				     DRM_MEM_DRIVER);
+	if (!dev->last_vblank)
+		goto err;
+
+	dev->vblank_premodeset = drm_alloc(sizeof(u32) * num_crtcs,
+					   DRM_MEM_DRIVER);
+	if (!dev->vblank_premodeset)
+		goto err;
+
+	dev->vblank_offset = drm_alloc(sizeof(u32) * num_crtcs,
+				       DRM_MEM_DRIVER);
+	if (!dev->vblank_offset)
+		goto err;
+
+	/* Zero per-crtc vblank stuff */
+	for (i = 0; i < num_crtcs; i++) {
+		INIT_LIST_HEAD(&dev->vbl_sigs[i]);
+		atomic_set(&dev->vblank_count[i], 0);
+		atomic_set(&dev->vblank_usage[i], 0);
+		dev->last_vblank[i] = 0;
+		dev->vblank_premodeset[i] = 0;
+		dev->vblank_offset[i] = 0;
+	}
+
+	ret = 0;
+	goto out;
+
+err:
+	kfree(dev->vbl_sigs);
+	kfree(dev->vblank_count);
+	kfree(dev->vblank_usage);
+	kfree(dev->last_vblank);
+	kfree(dev->vblank_premodeset);
+	kfree(dev->vblank_offset);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(drm_vblank_init);
+
 /**
  * Install IRQ handler.
  *
@@ -88,7 +152,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
  */
 static int drm_irq_install(drm_device_t * dev)
 {
-	int ret;
+	int ret = 0;
 	unsigned long sh_flags = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
@@ -114,17 +178,6 @@ static int drm_irq_install(drm_device_t * dev)
 
 	DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
 
-	if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
-		init_waitqueue_head(&dev->vbl_queue);
-
-		spin_lock_init(&dev->vbl_lock);
-
-		INIT_LIST_HEAD(&dev->vbl_sigs);
-		INIT_LIST_HEAD(&dev->vbl_sigs2);
-
-		dev->vbl_pending = 0;
-	}
-
 	/* Before installing handler */
 	dev->driver->irq_preinstall(dev);
 
@@ -142,9 +195,9 @@ static int drm_irq_install(drm_device_t * dev)
 	}
 
 	/* After installing handler */
-	dev->driver->irq_postinstall(dev);
+	ret = dev->driver->irq_postinstall(dev);
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -221,12 +274,12 @@ int drm_control(struct inode *inode, struct file *filp,
 	}
 }
 
-static void drm_vblank_get(drm_device_t *dev, int crtc)
+void drm_vblank_get(drm_device_t *dev, int crtc)
 {
 	unsigned long irqflags;
 	u32 cur_vblank, diff;
 
-	if (atomic_add_return(1, &dev->vbl_pending[crtc]) != 1)
+	if (atomic_add_return(1, &dev->vblank_count[crtc]) != 1)
 		return;
 
 	/*
@@ -243,21 +296,60 @@ static void drm_vblank_get(drm_device_t *dev, int crtc)
 			dev->last_vblank[crtc];
 		diff += cur_vblank;
 	} else {
-		diff = cur_vblank - last_vblank;
+		diff = cur_vblank - dev->last_vblank[crtc];
 	}
 	dev->last_vblank[crtc] = cur_vblank;
-	spin_lock_irqrestore(&dev->vbl_lock, irqflags);
+	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
 	atomic_add(diff, &dev->vblank_count[crtc]);
 	dev->driver->enable_vblank(dev, crtc);
 }
+EXPORT_SYMBOL(drm_vblank_get);
 
-static void drm_vblank_put(drm_device_t *dev, int crtc)
+void drm_vblank_put(drm_device_t *dev, int crtc)
 {
-	if (atomic_dec_and_test(&dev->vbl_pending[crtc]))
+	if (atomic_dec_and_test(&dev->vblank_count[crtc]))
 		dev->driver->disable_vblank(dev, crtc);
 }
+EXPORT_SYMBOL(drm_vblank_put);
 
+int drm_modeset_ctl(DRM_IOCTL_ARGS)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->head->dev;
+	drm_modeset_ctl_t __user *argp = (void __user *)data;
+	drm_modeset_ctl_t modeset;
+	int crtc, ret = 0;
+	u32 new;
+
+	if (copy_from_user(&modeset, argp, sizeof(modeset))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	crtc = modeset.arg;
+	if (crtc > dev->num_crtcs) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (modeset.cmd) {
+	case _DRM_PRE_MODESET:
+		dev->vblank_premodeset[crtc] =
+			dev->driver->get_vblank_counter(dev, crtc);
+		break;
+	case _DRM_POST_MODESET:
+		new = dev->driver->get_vblank_counter(dev, crtc);
+		dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	return ret;
+}
 
 /**
  * Wait for VBLANK.
@@ -329,8 +421,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
 	if (flags & _DRM_VBLANK_SIGNAL) {
 		unsigned long irqflags;
-		struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
-				      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+		struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
 		drm_vbl_sig_t *vbl_sig;
 
 		spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -351,7 +442,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 			}
 		}
 
-		if (atomic_read(&dev->vbl_pending[crtc]) >= 100) {
+		if (atomic_read(&dev->vbl_pending) >= 100) {
 			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 			drm_vblank_put(dev, crtc);
 			return -EBUSY;
@@ -359,6 +450,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
+		atomic_inc(&dev->vbl_pending);
+
 		if (!
 		    (vbl_sig =
 		     drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
@@ -414,9 +507,9 @@ void drm_vbl_send_signals(drm_device_t * dev)
 
 	spin_lock_irqsave(&dev->vbl_lock, flags);
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < dev->num_crtcs; i++) {
 		drm_vbl_sig_t *vbl_sig, *tmp;
-		struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+		struct list_head *vbl_sigs = &dev->vbl_sigs[i];
 		unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]);
 
 		list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
@@ -429,7 +522,7 @@ void drm_vbl_send_signals(drm_device_t * dev)
 
 				drm_free(vbl_sig, sizeof(*vbl_sig),
 					 DRM_MEM_DRIVER);
-
+				atomic_dec(&dev->vbl_pending);
 				drm_vblank_put(dev, i);
 			}
 		}
diff --git a/shared-core/drm.h b/shared-core/drm.h
index b419541..15081f9 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -587,6 +587,21 @@ typedef union drm_wait_vblank {
 	struct drm_wait_vblank_reply reply;
 } drm_wait_vblank_t;
 
+typedef enum {
+	_DRM_PRE_MODESET = 1,
+	_DRM_POST_MODESET = 2,
+} drm_modeset_ctl_cmd_t;
+
+/**
+ * DRM_IOCTL_MODESET_CTL ioctl argument type
+ *
+ * \sa drmModesetCtl().
+ */
+typedef struct drm_modeset_ctl {
+	drm_modeset_ctl_cmd_t cmd;
+	unsigned long arg;
+} drm_modeset_ctl_t;
+
 /**
  * DRM_IOCTL_AGP_ENABLE ioctl argument type.
  *
@@ -953,6 +968,8 @@ typedef union drm_mm_init_arg{
 
 #define DRM_IOCTL_UPDATE_DRAW           DRM_IOW(0x3f, drm_update_draw_t)
 
+#define DRM_IOCTL_MODESET_CTL           DRM_IOW(0x40, drm_modeset_ctl_t)
+
 /*@}*/
 
 /**
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 73972d5..ebb184c 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -833,20 +833,6 @@ static int i915_setparam(DRM_IOCTL_ARGS)
 	case I915_SETPARAM_ALLOW_BATCHBUFFER:
 		dev_priv->allow_batchbuffer = param.value;
 		break;
-	case I915_SETPARAM_PREMODESET:
-		if (param.value > 1) {
-			DRM_ERROR("bad crtc\n");
-			return -EINVAL;
-		}
-		i915_premodeset(dev, param.value);
-		break;
-	case I915_SETPARAM_POSTMODESET:
-		if (param.value > 1) {
-			DRM_ERROR("bad crtc\n");
-			return -EINVAL;
-		}
-		i915_postmodeset(dev, param.value);
-		break;
 	default:
 		DRM_ERROR("unknown parameter %d\n", param.param);
 		return DRM_ERR(EINVAL);
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index aea048f..1c6ff4d 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -235,8 +235,6 @@ typedef struct drm_i915_getparam {
 #define I915_SETPARAM_USE_MI_BATCHBUFFER_START            1
 #define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
 #define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
-#define I915_SETPARAM_PREMODESET                          4
-#define I915_SETPARAM_POSTMODESET                         5
 
 typedef struct drm_i915_setparam {
 	int param;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 88949ad..079e901 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -132,8 +132,6 @@ typedef struct drm_i915_private {
 	spinlock_t swaps_lock;
 	drm_i915_vbl_swap_t vbl_swaps;
 	unsigned int swaps_pending;
-	unsigned long vblank_offset[2];
-	unsigned long vblank_premodeset[2];
 } drm_i915_private_t;
 
 enum intel_chip_family {
@@ -165,7 +163,7 @@ extern int i915_irq_wait(DRM_IOCTL_ARGS);
 
 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);
+extern int i915_driver_irq_postinstall(drm_device_t * dev);
 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);
@@ -176,8 +174,6 @@ extern int i915_vblank_swap(DRM_IOCTL_ARGS);
 extern void i915_enable_vblank(drm_device_t *dev, int crtc);
 extern void i915_disable_vblank(drm_device_t *dev, int crtc);
 extern u32 i915_get_vblank_counter(drm_device_t *dev, int crtc);
-extern void i915_premodeset(drm_device_t *dev, int crtc);
-extern void i915_postmodeset(drm_device_t *dev, int crtc);
 
 /* i915_mem.c */
 extern int i915_mem_alloc(DRM_IOCTL_ARGS);
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 1019c94..0f4d1a8 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -117,12 +117,14 @@ static void i915_vblank_tasklet(drm_device_t *dev)
 	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);
+		int crtc = vbl_swap->pipe;
 
 		if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
 			continue;
 
 		list_del(list);
 		dev_priv->swaps_pending--;
+		drm_vblank_put(dev, crtc);
 
 		spin_unlock(&dev_priv->swaps_lock);
 		spin_lock(&dev->drw_lock);
@@ -274,6 +276,32 @@ static void i915_vblank_tasklet(drm_device_t *dev)
 	}
 }
 
+u32 i915_get_vblank_counter(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	u32 high1, high2, low, count;
+
+	/*
+	 * High & low register fields aren't synchronized, so make sure
+	 * we get a low value that's stable across two reads of the high
+	 * register.
+	 */
+	do {
+		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+			PIPE_FRAME_LOW_SHIFT);
+		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+	} while (high1 != high2);
+
+	count = (high1 << 8) | low;
+
+	return count;
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
 	drm_device_t *dev = (drm_device_t *) arg;
@@ -306,22 +334,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 #endif
 	}
 
-	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
-		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->vblank_count[0]);
-			if (temp & VSYNC_PIPEB_FLAG)
-				atomic_inc(&dev->vblank_count[1]);
-		} 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->vblank_count[0]);
+	if (temp & VSYNC_PIPEA_FLAG)
+		atomic_add(i915_get_vblank_counter(dev, 0),
+			   &dev->vblank_count[0]);
+	if (temp & VSYNC_PIPEB_FLAG)
+		atomic_add(i915_get_vblank_counter(dev, 1),
+			   &dev->vblank_count[1]);
 
+	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
 		DRM_WAKEUP(&dev->vbl_queue);
 		drm_vbl_send_signals(dev);
 
@@ -461,6 +481,9 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
 void i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	if (crtc > dev_priv->vblank_pipe)
+		return;
 	
 	switch (crtc) {
 	case 0:
@@ -481,6 +504,9 @@ void i915_enable_vblank(drm_device_t *dev, int crtc)
 void i915_disable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	if (crtc > dev_priv->vblank_pipe)
+		return;
 	
 	switch (crtc) {
 	case 0:
@@ -498,54 +524,6 @@ void i915_disable_vblank(drm_device_t *dev, int crtc)
 	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 }
 
-static u32 i915_vblank_counter(drm_device_t *dev, int crtc)
-{
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
-	u32 high1, high2, low, count;
-
-	/*
-	 * High & low register fields aren't synchronized, so make sure
-	 * we get a low value that's stable across two reads of the high
-	 * register.
-	 */
-	do {
-		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
-		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
-			PIPE_FRAME_LOW_SHIFT);
-		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
-	} while (high1 != high2);
-
-	count = (high1 << 8) | low;
-
-	return count;
-}
-
-u32 i915_get_vblank_counter(drm_device_t *dev, int crtc)
-{
-	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	return i915_vblank_counter(dev, crtc) +	dev_priv->vblank_offset[crtc];
-}
-
-void i915_premodeset(drm_device_t *dev, int crtc)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-
-	dev_priv->vblank_premodeset[crtc] = i915_vblank_counter(dev, crtc);
-}
-
-void i915_postmodeset(drm_device_t *dev, int crtc)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 new;
-
-	new = i915_vblank_counter(dev, crtc);
-	dev_priv->vblank_offset[crtc] = dev_priv->vblank_premodeset[crtc] - new;
-}
-
 static void i915_enable_interrupt (drm_device_t *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -660,6 +638,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
+	drm_vblank_get(dev, pipe);
 	curseq = atomic_read(&dev->vblank_count[pipe]);
 
 	if (seqtype == _DRM_VBLANK_RELATIVE)
@@ -670,6 +649,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 			swap.sequence = curseq + 1;
 		} else {
 			DRM_DEBUG("Missed target sequence\n");
+			drm_vblank_put(dev, pipe);
 			return DRM_ERR(EINVAL);
 		}
 	}
@@ -690,6 +670,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 				spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 				DRM_DEBUG("Invalid drawable ID %d\n",
 					  swap.drawable);
+				drm_vblank_put(dev, pipe);
 				return DRM_ERR(EINVAL);
 			}
 
@@ -697,6 +678,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 			spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
+			drm_vblank_put(dev, pipe);
 			return 0;
 		}
 	}
@@ -712,6 +694,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 			vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
 			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
 			DRM_DEBUG("Already scheduled\n");
+			drm_vblank_put(dev, pipe);
 			return 0;
 		}
 	}
@@ -720,6 +703,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	if (dev_priv->swaps_pending >= 100) {
 		DRM_DEBUG("Too many swaps queued\n");
+		drm_vblank_put(dev, pipe);
 		return DRM_ERR(EBUSY);
 	}
 
@@ -727,6 +711,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	if (!vbl_swap) {
 		DRM_ERROR("Failed to allocate memory to queue swap\n");
+		drm_vblank_put(dev, pipe);
 		return DRM_ERR(ENOMEM);
 	}
 
@@ -764,10 +749,10 @@ void i915_driver_irq_preinstall(drm_device_t * dev)
 	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
 }
 
-void i915_driver_irq_postinstall(drm_device_t * dev)
+int i915_driver_irq_postinstall(drm_device_t * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	int i;
+	int ret, num_pipes = 2;
 
 	spin_lock_init(&dev_priv->swaps_lock);
 	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
@@ -776,31 +761,10 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
 	dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
 	dev_priv->user_irq_refcount = 0;
 	dev_priv->irq_enable_reg = 0;
-	dev->vblank_count = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
-	if (!dev->vblank_count) {
-		DRM_ERROR("out of memory\n");
-		return;
-	}
-	dev->vbl_pending = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
-	if (!dev->vbl_pending) {
-		DRM_ERROR("out of memory\n");
-		kfree(dev->vblank_count);
-		return;
-	}
-	dev->last_vblank = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
-	if (!dev->last_vblank) {
-		DRM_ERROR("out of memory\n");
-		kfree(dev->vblank_count);
-		return;
-	}
 
-	/* Zero per-crtc vblank stuff */
-	for (i = 0; i < 2; i++) {
-		atomic_set(&dev->vbl_pending[i], 0);
-		atomic_set(&dev->vblank_count[i], 0);
-		dev->last_vblank[i] = 0;
-		dev_priv->vblank_offset[i] = 0;
-	}
+	ret = drm_vblank_init(dev, num_pipes);
+	if (ret)
+		return ret;
 
 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
@@ -812,6 +776,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
 	 */
 
 	I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21));
+	return 0;
 }
 
 void i915_driver_irq_uninstall(drm_device_t * dev)
commit db689c7b95613237cec904c3f6ee27e8c2bf7ce0
Author: Jesse Barnes <jbarnes@hobbes.virtuousgeek.org>
Date:   Tue Jun 12 10:44:21 2007 -0700

    Initial checkin of vblank rework.  Code attempts to reduce the number
    of vblank interrupt in order to save power.

diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index dd3a69d..c3f2031 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -627,8 +627,9 @@ struct drm_driver {
 	int (*kernel_context_switch) (struct drm_device * dev, int old,
 				      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);
+	u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
+	void (*enable_vblank) (struct drm_device *dev, int crtc);
+	void (*disable_vblank) (struct drm_device *dev, int crtc);
 	int (*dri_library_name) (struct drm_device * dev, char * buf);
 
 	/**
@@ -783,12 +784,13 @@ 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 */
+	atomic_t *vblank_count;		/**< number of VBLANK interrupts (driver must alloc the \
right number of counters) */  spinlock_t vbl_lock;
 	struct list_head vbl_sigs;		/**< signal list to send on VBLANK */
 	struct list_head vbl_sigs2;	/**< signals to send on secondary VBLANK */
-	unsigned int vbl_pending;
+	atomic_t *vbl_pending;
+	u32 *last_vblank; /* protected by dev->vbl_lock */
+	unsigned long max_vblank_count; /**< size of vblank counter register */
 	spinlock_t tasklet_lock;	/**< For drm_locked_tasklet */
 	void (*locked_tasklet_func)(struct drm_device *dev);
 
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 8871671..f229f77 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -221,6 +221,44 @@ int drm_control(struct inode *inode, struct file *filp,
 	}
 }
 
+static void drm_vblank_get(drm_device_t *dev, int crtc)
+{
+	unsigned long irqflags;
+	u32 cur_vblank, diff;
+
+	if (atomic_add_return(1, &dev->vbl_pending[crtc]) != 1)
+		return;
+
+	/*
+	 * Interrupts were disabled prior to this call, so deal with counter
+	 * wrap if needed.
+	 * NOTE!  It's possible we lost a full dev->max_vblank_count events
+	 * here if the register is small or we had vblank interrupts off for
+	 * a long time.
+	 */
+	cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+	spin_lock_irqsave(&dev->vbl_lock, irqflags);
+	if (cur_vblank < dev->last_vblank[crtc]) {
+		diff = dev->max_vblank_count -
+			dev->last_vblank[crtc];
+		diff += cur_vblank;
+	} else {
+		diff = cur_vblank - last_vblank;
+	}
+	dev->last_vblank[crtc] = cur_vblank;
+	spin_lock_irqrestore(&dev->vbl_lock, irqflags);
+
+	atomic_add(diff, &dev->vblank_count[crtc]);
+	dev->driver->enable_vblank(dev, crtc);
+}
+
+static void drm_vblank_put(drm_device_t *dev, int crtc)
+{
+	if (atomic_dec_and_test(&dev->vbl_pending[crtc]))
+		dev->driver->disable_vblank(dev, crtc);
+}
+
+
 /**
  * Wait for VBLANK.
  *
@@ -248,7 +286,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	drm_wait_vblank_t vblwait;
 	struct timeval now;
 	int ret = 0;
-	unsigned int flags, seq;
+	unsigned int flags, seq, crtc;
 
 	if ((!dev->irq) || (!dev->irq_enabled))
 		return -EINVAL;
@@ -265,13 +303,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 	}
 
 	flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+	crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
 
 	if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
 				    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
 		return -EINVAL;
 
-	seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
-			  : &dev->vbl_received);
+	drm_vblank_get(dev, crtc);
+	seq = atomic_read(&dev->vblank_count[crtc]);
 
 	switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
 	case _DRM_VBLANK_RELATIVE:
@@ -307,22 +346,23 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 				spin_unlock_irqrestore(&dev->vbl_lock,
 						       irqflags);
 				vblwait.reply.sequence = seq;
+				drm_vblank_put(dev, crtc);
 				goto done;
 			}
 		}
 
-		if (dev->vbl_pending >= 100) {
+		if (atomic_read(&dev->vbl_pending[crtc]) >= 100) {
 			spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+			drm_vblank_put(dev, crtc);
 			return -EBUSY;
 		}
 
-		dev->vbl_pending++;
-
 		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
 		if (!
 		    (vbl_sig =
 		     drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
+			drm_vblank_put(dev, crtc);
 			return -ENOMEM;
 		}
 
@@ -340,14 +380,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
 		vblwait.reply.sequence = seq;
 	} else {
-		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);
+		unsigned long cur_vblank;
 
+		DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+			    (((cur_vblank = atomic_read(&dev->vblank_count[crtc]))
+			      - seq) <= (1 << 23)));
+		drm_vblank_put(dev, crtc);
 		do_gettimeofday(&now);
 		vblwait.reply.tval_sec = now.tv_sec;
 		vblwait.reply.tval_usec = now.tv_usec;
@@ -379,8 +417,7 @@ void drm_vbl_send_signals(drm_device_t * dev)
 	for (i = 0; i < 2; i++) {
 		drm_vbl_sig_t *vbl_sig, *tmp;
 		struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
-		unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
-						   &dev->vbl_received);
+		unsigned int vbl_seq = atomic_read(&dev->vblank_count[i]);
 
 		list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
 			if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
@@ -393,7 +430,7 @@ void drm_vbl_send_signals(drm_device_t * dev)
 				drm_free(vbl_sig, sizeof(*vbl_sig),
 					 DRM_MEM_DRIVER);
 
-				dev->vbl_pending--;
+				drm_vblank_put(dev, i);
 			}
 		}
 	}
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index 7fdb083..e7a9bfd 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -83,8 +83,9 @@ static struct drm_driver driver = {
 	.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,
+	.get_vblank_counter = i915_get_vblank_counter,
+	.enable_vblank = i915_enable_vblank,
+	.disable_vblank = i915_disable_vblank,
 	.irq_preinstall = i915_driver_irq_preinstall,
 	.irq_postinstall = i915_driver_irq_postinstall,
 	.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index ebb184c..73972d5 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -833,6 +833,20 @@ static int i915_setparam(DRM_IOCTL_ARGS)
 	case I915_SETPARAM_ALLOW_BATCHBUFFER:
 		dev_priv->allow_batchbuffer = param.value;
 		break;
+	case I915_SETPARAM_PREMODESET:
+		if (param.value > 1) {
+			DRM_ERROR("bad crtc\n");
+			return -EINVAL;
+		}
+		i915_premodeset(dev, param.value);
+		break;
+	case I915_SETPARAM_POSTMODESET:
+		if (param.value > 1) {
+			DRM_ERROR("bad crtc\n");
+			return -EINVAL;
+		}
+		i915_postmodeset(dev, param.value);
+		break;
 	default:
 		DRM_ERROR("unknown parameter %d\n", param.param);
 		return DRM_ERR(EINVAL);
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index 1c6ff4d..aea048f 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -235,6 +235,8 @@ typedef struct drm_i915_getparam {
 #define I915_SETPARAM_USE_MI_BATCHBUFFER_START            1
 #define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
 #define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
+#define I915_SETPARAM_PREMODESET                          4
+#define I915_SETPARAM_POSTMODESET                         5
 
 typedef struct drm_i915_setparam {
 	int param;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 9deee8e..88949ad 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -132,6 +132,8 @@ typedef struct drm_i915_private {
 	spinlock_t swaps_lock;
 	drm_i915_vbl_swap_t vbl_swaps;
 	unsigned int swaps_pending;
+	unsigned long vblank_offset[2];
+	unsigned long vblank_premodeset[2];
 } drm_i915_private_t;
 
 enum intel_chip_family {
@@ -161,8 +163,6 @@ extern int i915_driver_firstopen(struct drm_device *dev);
 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);
@@ -173,6 +173,11 @@ extern int i915_emit_irq(drm_device_t * dev);
 extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
 extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
 extern int i915_vblank_swap(DRM_IOCTL_ARGS);
+extern void i915_enable_vblank(drm_device_t *dev, int crtc);
+extern void i915_disable_vblank(drm_device_t *dev, int crtc);
+extern u32 i915_get_vblank_counter(drm_device_t *dev, int crtc);
+extern void i915_premodeset(drm_device_t *dev, int crtc);
+extern void i915_postmodeset(drm_device_t *dev, int crtc);
 
 /* i915_mem.c */
 extern int i915_mem_alloc(DRM_IOCTL_ARGS);
@@ -271,6 +276,36 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char \
*caller);  
 #define I915REG_PIPEASTAT	0x70024
 #define I915REG_PIPEBSTAT	0x71024
+/*
+ * The two pipe frame counter registers are not synchronized, so
+ * reading a stable value is somewhat tricky. The following code 
+ * should work:
+ *
+ *  do {
+ *    high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT;
+ *    low1 =  ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
+ *             PIPE_FRAME_LOW_SHIFT);
+ *    high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
+ *             PIPE_FRAME_HIGH_SHIFT);
+ *  } while (high1 != high2);
+ *  frame = (high1 << 8) | low1;
+ */
+#define PIPEAFRAMEHIGH          0x70040
+#define PIPEBFRAMEHIGH		0x71040
+#define PIPE_FRAME_HIGH_MASK    0x0000ffff
+#define PIPE_FRAME_HIGH_SHIFT   0
+#define PIPEAFRAMEPIXEL         0x70044
+#define PIPEBFRAMEPIXEL		0x71044
+
+#define PIPE_FRAME_LOW_MASK     0xff000000
+#define PIPE_FRAME_LOW_SHIFT    24
+/*
+ * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register
+ * and is 24 bits wide.
+ */
+#define PIPE_PIXEL_MASK         0x00ffffff
+#define PIPE_PIXEL_SHIFT        0
 
 #define I915_VBLANK_INTERRUPT_ENABLE	(1UL<<17)
 #define I915_VBLANK_CLEAR		(1UL<<1)
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index dc00f98..1019c94 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -92,8 +92,8 @@ static void i915_vblank_tasklet(drm_device_t *dev)
 	unsigned long irqflags;
 	struct list_head *list, *tmp, hits, *hit;
 	int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
-	unsigned counter[2] = { atomic_read(&dev->vbl_received),
-				atomic_read(&dev->vbl_received2) };
+	unsigned counter[2] = { atomic_read(&dev->vblank_count[0]),
+				atomic_read(&dev->vblank_count[1]) };
 	drm_drawable_info_t *drw;
 	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	u32 cpp = dev_priv->cpp,  offsets[3];
@@ -313,14 +313,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 		     (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);
+				atomic_inc(&dev->vblank_count[0]);
 			if (temp & VSYNC_PIPEB_FLAG)
-				atomic_inc(&dev->vbl_received2);
+				atomic_inc(&dev->vblank_count[1]);
 		} 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);
+			atomic_inc(&dev->vblank_count[0]);
 
 		DRM_WAKEUP(&dev->vbl_queue);
 		drm_vbl_send_signals(dev);
@@ -410,37 +410,6 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
 	return ret;
 }
 
-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;
-	int ret = 0;
-
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
-	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-		    (((cur_vblank = atomic_read(counter))
-			- *sequence) <= (1<<23)));
-	
-	*sequence = cur_vblank;
-
-	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)
@@ -489,15 +458,99 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
 	return i915_wait_irq(dev, irqwait.irq_seq);
 }
 
-static void i915_enable_interrupt (drm_device_t *dev)
+void i915_enable_vblank(drm_device_t *dev, int crtc)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	
-	dev_priv->irq_enable_reg = USER_INT_FLAG; 
-	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
+	switch (crtc) {
+	case 0:
 		dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
-	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
+		break;
+	case 1:
 		dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
+		break;
+	default:
+		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+			  crtc);
+		break;
+	}
+
+	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+}
+
+void i915_disable_vblank(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	
+	switch (crtc) {
+	case 0:
+		dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
+		break;
+	case 1:
+		dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG;
+		break;
+	default:
+		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+			  crtc);
+		break;
+	}
+
+	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+}
+
+static u32 i915_vblank_counter(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	unsigned long high_frame = crtc ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	u32 high1, high2, low, count;
+
+	/*
+	 * High & low register fields aren't synchronized, so make sure
+	 * we get a low value that's stable across two reads of the high
+	 * register.
+	 */
+	do {
+		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
+			PIPE_FRAME_LOW_SHIFT);
+		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
+			 PIPE_FRAME_HIGH_SHIFT);
+	} while (high1 != high2);
+
+	count = (high1 << 8) | low;
+
+	return count;
+}
+
+u32 i915_get_vblank_counter(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	return i915_vblank_counter(dev, crtc) +	dev_priv->vblank_offset[crtc];
+}
+
+void i915_premodeset(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	dev_priv->vblank_premodeset[crtc] = i915_vblank_counter(dev, crtc);
+}
+
+void i915_postmodeset(drm_device_t *dev, int crtc)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 new;
+
+	new = i915_vblank_counter(dev, crtc);
+	dev_priv->vblank_offset[crtc] = dev_priv->vblank_premodeset[crtc] - new;
+}
+
+static void i915_enable_interrupt (drm_device_t *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	
+	dev_priv->irq_enable_reg |= USER_INT_FLAG;
 
 	I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 	dev_priv->irq_enabled = 1;
@@ -607,7 +660,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
 
 	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
 
-	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
+	curseq = atomic_read(&dev->vblank_count[pipe]);
 
 	if (seqtype == _DRM_VBLANK_RELATIVE)
 		swap.sequence += curseq;
@@ -714,6 +767,7 @@ void i915_driver_irq_preinstall(drm_device_t * dev)
 void i915_driver_irq_postinstall(drm_device_t * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	int i;
 
 	spin_lock_init(&dev_priv->swaps_lock);
 	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
@@ -721,6 +775,34 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
 
 	dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
 	dev_priv->user_irq_refcount = 0;
+	dev_priv->irq_enable_reg = 0;
+	dev->vblank_count = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
+	if (!dev->vblank_count) {
+		DRM_ERROR("out of memory\n");
+		return;
+	}
+	dev->vbl_pending = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
+	if (!dev->vbl_pending) {
+		DRM_ERROR("out of memory\n");
+		kfree(dev->vblank_count);
+		return;
+	}
+	dev->last_vblank = kmalloc(sizeof(atomic_t) * 2, GFP_KERNEL);
+	if (!dev->last_vblank) {
+		DRM_ERROR("out of memory\n");
+		kfree(dev->vblank_count);
+		return;
+	}
+
+	/* Zero per-crtc vblank stuff */
+	for (i = 0; i < 2; i++) {
+		atomic_set(&dev->vbl_pending[i], 0);
+		atomic_set(&dev->vblank_count[i], 0);
+		dev->last_vblank[i] = 0;
+		dev_priv->vblank_offset[i] = 0;
+	}
+
+	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
 	i915_enable_interrupt(dev);
 	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 92a9b65..283dee3 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -299,6 +299,9 @@ typedef struct drm_radeon_private {
 
 	u32 scratch_ages[5];
 
+	unsigned int crtc_last_cnt;
+	unsigned int crtc2_last_cnt;
+
 	/* starting from here on, data is preserved accross an open */
 	uint32_t flags;		/* see radeon_chip_flags */
 
@@ -364,9 +367,9 @@ extern int radeon_irq_wait(DRM_IOCTL_ARGS);
 
 extern void radeon_do_release(drm_device_t * dev);
 extern int radeon_driver_vblank_wait(drm_device_t * dev,
-				     unsigned int *sequence);
+				     unsigned int *sequence, int relative);
 extern int radeon_driver_vblank_wait2(drm_device_t * dev,
-				      unsigned int *sequence);
+				      unsigned int *sequence, int relative);
 extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
 extern void radeon_driver_irq_preinstall(drm_device_t * dev);
 extern void radeon_driver_irq_postinstall(drm_device_t * dev);
@@ -507,6 +510,9 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp,
 				? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
 				: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
 
+#define RADEON_CRTC_CRNT_FRAME 0x0214
+#define RADEON_CRTC2_CRNT_FRAME 0x0314
+
 #define RADEON_GEN_INT_CNTL		0x0040
 #	define RADEON_CRTC_VBLANK_MASK		(1 << 0)
 #	define RADEON_CRTC2_VBLANK_MASK		(1 << 9)
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 5151b4d..2534ff1 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -35,6 +35,18 @@
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 
+static void radeon_irq_set_state(drm_device_t *dev, u32 mask, int state)
+{
+	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+
+	if (state)
+		dev_priv->irq_enable_reg |= mask;
+	else
+		dev_priv->irq_enable_reg &= ~mask;
+
+	RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+}
+
 static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
 					      u32 mask)
 {
@@ -141,14 +153,17 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
 }
 
 int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned int *sequence,
-				 int crtc)
+				 int crtc, int relative)
 {
 	drm_radeon_private_t *dev_priv =
 	    (drm_radeon_private_t *) dev->dev_private;
-	unsigned int cur_vblank;
+	unsigned int cur_vblank, diff, irqflags, current_cnt;
 	int ret = 0;
 	int ack = 0;
 	atomic_t *counter;
+	unsigned int *last_cnt;
+	int crtc_cnt_reg;
+	
 	if (!dev_priv) {
 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
 		return DRM_ERR(EINVAL);
@@ -156,10 +171,14 @@ int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned \
int *sequence,  
 	if (crtc == DRM_RADEON_VBLANK_CRTC1) {
 		counter = &dev->vbl_received;
-		ack |= RADEON_CRTC_VBLANK_STAT;
+		ack = RADEON_CRTC_VBLANK_STAT;
+		last_cnt = &dev_priv->crtc_last_cnt;
+		crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
 	} else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
 		counter = &dev->vbl_received2;
-		ack |= RADEON_CRTC2_VBLANK_STAT;
+		ack = RADEON_CRTC2_VBLANK_STAT;
+		last_cnt = &dev_priv->crtc2_last_cnt;
+		crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
 	} else
 		return DRM_ERR(EINVAL);
 
@@ -167,27 +186,46 @@ int radeon_driver_vblank_do_wait(drm_device_t * dev, unsigned \
int *sequence,  
 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
+	if (!relative) {
+		/*
+		 * Assume we haven't missed more than several hours of vblank
+		 * events, or that it won't matter if they're not accounted
+		 * for in the master counter.
+		 */
+		spin_lock_irqsave(&dev->vbl_lock, irqflags);
+		current_cnt = RADEON_READ(crtc_cnt_reg);
+		if (current_cnt < *last_cnt) {
+			current_cnt += (1 << 21) - *last_cnt;
+			*last_cnt = 0;
+		}
+		diff = current_cnt - *last_cnt;
+		*last_cnt = RADEON_READ(crtc_cnt_reg);
+		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+		atomic_add(diff, counter);
+	}
+
 	/* Assume that the user has missed the current sequence number
 	 * by about a day rather than she wants to wait for years
 	 * using vertical blanks...
 	 */
+	radeon_irq_set_state(dev, ack, 1);
 	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
 		    (((cur_vblank = atomic_read(counter))
 		      - *sequence) <= (1 << 23)));
-
+	radeon_irq_set_state(dev, ack, 0);
 	*sequence = cur_vblank;
 
 	return ret;
 }
 
-int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence, int \
relative)  {
-	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
+	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1, \
relative);  }
 
-int radeon_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
+int radeon_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence, int \
relative)  {
-	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
+	return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2, \
relative);  }
 
 /* Needs the lock as it touches the ring.
@@ -238,20 +276,7 @@ int radeon_irq_wait(DRM_IOCTL_ARGS)
 	return radeon_wait_irq(dev, irqwait.irq_seq);
 }
 
-static void radeon_enable_interrupt(drm_device_t *dev)
-{
-	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
-
-	dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
-	if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
-		dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
-
-	if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
-		dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
 
-	RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
-	dev_priv->irq_enabled = 1;
-}
 
 /* drm_dma.h hooks
 */
@@ -265,7 +290,8 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
 
 	/* Clear bits if they're already high */
 	radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
-					   RADEON_CRTC_VBLANK_STAT));
+					   RADEON_CRTC_VBLANK_STAT |
+					   RADEON_CRTC2_VBLANK_STAT));
 }
 
 void radeon_driver_irq_postinstall(drm_device_t * dev)
@@ -276,7 +302,7 @@ void radeon_driver_irq_postinstall(drm_device_t * dev)
 	atomic_set(&dev_priv->swi_emitted, 0);
 	DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
-	radeon_enable_interrupt(dev);
+	radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
 }
 
 void radeon_driver_irq_uninstall(drm_device_t * dev)
@@ -318,6 +344,5 @@ int radeon_vblank_crtc_set(drm_device_t *dev, int64_t value)
 		return DRM_ERR(EINVAL);
 	}
 	dev_priv->vblank_crtc = (unsigned int)value;
-	radeon_enable_interrupt(dev);
 	return 0;
 }



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

--
_______________________________________________
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