diff --git a/src/uxa/intel.h b/src/uxa/intel.h
index 131f18c..f05b160 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -401,6 +401,15 @@ extern int intel_crtc_id(xf86CrtcPtr crtc);
 extern int intel_output_dpms_status(xf86OutputPtr output);
 extern void intel_copy_fb(ScrnInfoPtr scrn);
 
+int
+intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust);
+
+uint32_t
+intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect);
+
+uint64_t
+intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence);
+
 enum DRI2FrameEventType {
 	DRI2_SWAP,
 	DRI2_SWAP_CHAIN,
diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
index 3c2f964..09cd48f 100644
--- a/src/uxa/intel_display.c
+++ b/src/uxa/intel_display.c
@@ -71,9 +71,8 @@ struct intel_mode {
 	DRI2FrameEventPtr flip_info;
 	int old_fb_id;
 	int flip_count;
-	unsigned int fe_frame;
-	unsigned int fe_tv_sec;
-	unsigned int fe_tv_usec;
+	uint64_t fe_msc;
+        uint64_t fe_usec;
 
 	struct list outputs;
 	struct list crtcs;
@@ -97,6 +96,9 @@ struct intel_crtc {
 	struct list link;
 	PixmapPtr scanout_pixmap;
 	uint32_t scanout_fb_id;
+        int32_t vblank_offset;
+        uint32_t msc_prev;
+        uint64_t msc_high;
 };
 
 struct intel_property {
@@ -1647,9 +1649,8 @@ intel_do_pageflip(intel_screen_private *intel,
 	 * Also, flips queued on disabled or incorrectly configured displays
 	 * may never complete; this is a configuration error.
 	 */
-	mode->fe_frame = 0;
-	mode->fe_tv_sec = 0;
-	mode->fe_tv_usec = 0;
+	mode->fe_msc = 0;
+	mode->fe_usec = 0;
 
 	for (i = 0; i < config->num_crtc; i++) {
 		if (!intel_crtc_on(config->crtc[i]))
@@ -1705,6 +1706,102 @@ static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
 	intel_xf86crtc_resize
 };
 
+static uint32_t pipe_select(int pipe)
+{
+	if (pipe > 1)
+		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
+	else if (pipe > 0)
+		return DRM_VBLANK_SECONDARY;
+	else
+		return 0;
+}
+
+/*
+ * Get the current msc/ust value from the kernel
+ */
+static int
+intel_get_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint32_t *msc, uint64_t *ust)
+{
+	intel_screen_private    *intel = intel_get_screen_private(scrn);
+        drmVBlank               vbl;
+        int                     ret;
+
+        /* Get current count */
+        vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(intel_crtc_to_pipe(crtc));
+        vbl.request.sequence = 0;
+        vbl.request.signal = 0;
+        ret = drmWaitVBlank(intel->drmSubFD, &vbl);
+        if (ret) {
+                *msc = 0;
+                *ust = 0;
+                return BadMatch;
+        } else {
+                *msc = vbl.reply.sequence;
+                *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec;
+        }
+        return Success;
+}
+
+/*
+ * Convert a 32-bit kernel MSC sequence number to a 64-bit local sequence
+ * number, adding in the vblank_offset and high 32 bits, and dealing
+ * with 64-bit wrapping
+ */
+uint64_t
+intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence)
+{
+	struct intel_crtc       *intel_crtc = crtc->driver_private;
+        sequence += intel_crtc->vblank_offset;
+
+        if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000)
+                intel_crtc->msc_high += 0x100000000L;
+        intel_crtc->msc_prev = sequence;
+        return intel_crtc->msc_high + sequence;
+}
+
+/*
+ * Get the current 64-bit adjust MSC and UST value
+ */
+int
+intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust)
+{
+        uint32_t                sequence;
+        int                     ret;
+
+        ret = intel_get_msc_ust(scrn, crtc, &sequence, ust);
+        *msc = intel_sequence_to_crtc_msc(crtc, sequence);
+        return ret;
+}
+
+/*
+ * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number,
+ * removing the high 32 bits and subtracting out the vblank_offset term.
+ *
+ * This also updates the vblank_offset when it notices that the value should
+ * change.
+ */
+uint32_t
+intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
+{
+	struct intel_crtc       *intel_crtc = crtc->driver_private;
+        uint64_t                msc;
+        uint64_t                ust;
+        int64_t                 diff;
+
+        intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust);
+        diff = expect - msc;
+
+        /* We're way off here, assume that the kernel has lost its mind
+         * and smack the vblank back to something sensible
+         */
+        if (diff < -200 || 200 < diff) {
+                intel_crtc->vblank_offset += (int32_t) diff;
+                if (-200 < intel_crtc->vblank_offset && intel_crtc->vblank_offset < 200)
+                        intel_crtc->vblank_offset = 0;
+        }
+        return (uint32_t) (expect - intel_crtc->vblank_offset);
+}
+
 static void
 intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
 		       unsigned int tv_usec, void *event)
@@ -1722,9 +1819,8 @@ intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
 	/* Is this the event whose info shall be delivered to higher level? */
 	if (flip->dispatch_me) {
 		/* Yes: Cache msc, ust for later delivery. */
-		mode->fe_frame = frame;
-		mode->fe_tv_sec = tv_sec;
-		mode->fe_tv_usec = tv_usec;
+		mode->fe_msc = frame;
+		mode->fe_usec = (uint64_t) tv_sec * 1000000 + tv_usec;
 	}
 	free(flip);
 
@@ -1740,8 +1836,8 @@ intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
 		return;
 
 	/* Deliver cached msc, ust from reference crtc to flip event handler */
-	I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec,
-				 mode->fe_tv_usec, mode->flip_info);
+	I830DRI2FlipEventHandler((uint32_t) mode->fe_msc, mode->fe_usec / 1000000,
+				 mode->fe_usec % 1000000, mode->flip_info);
 }
 
 static void
diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
index acedd0b..9c2aafd 100644
--- a/src/uxa/intel_dri.c
+++ b/src/uxa/intel_dri.c
@@ -575,14 +575,13 @@ static void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
 	}
 }
 
-static int
-I830DRI2DrawablePipe(DrawablePtr pDraw)
+static xf86CrtcPtr
+I830DRI2DrawableCrtc(DrawablePtr pDraw)
 {
 	ScreenPtr pScreen = pDraw->pScreen;
 	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 	BoxRec box, crtcbox;
 	xf86CrtcPtr crtc;
-	int pipe = -1;
 
 	box.x1 = pDraw->x;
 	box.y1 = pDraw->y;
@@ -593,9 +592,9 @@ I830DRI2DrawablePipe(DrawablePtr pDraw)
 
 	/* Make sure the CRTC is valid and this is the real front buffer */
 	if (crtc != NULL && !crtc->rotatedData)
-		pipe = intel_crtc_to_pipe(crtc);
+		return crtc;
 
-	return pipe;
+	return NULL;
 }
 
 static RESTYPE	frame_event_client_type, frame_event_drawable_type;
@@ -953,7 +952,7 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
 	if (!pScrn->vtSema)
 		return FALSE;
 
-	if (I830DRI2DrawablePipe(drawable) < 0)
+	if (I830DRI2DrawableCrtc(drawable) == NULL)
 		return FALSE;
 
 	if (!DRI2CanFlip(drawable))
@@ -1160,21 +1159,19 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 	intel_screen_private *intel = intel_get_screen_private(scrn);
 	drmVBlank vbl;
-	int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0;
+	int ret;
+        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
+        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
+        int flip = 0;
 	DRI2FrameEventPtr swap_info = NULL;
 	enum DRI2FrameEventType swap_type = DRI2_SWAP;
-	CARD64 current_msc;
+	uint64_t current_msc, current_ust;
+        uint64_t request_msc;
 
 	/* Drawable not displayed... just complete the swap */
 	if (pipe == -1)
 	    goto blit_fallback;
 
-	/* Truncate to match kernel interfaces; means occasional overflow
-	 * misses, but that's generally not a big deal */
-	*target_msc &= 0xffffffff;
-	divisor &= 0xffffffff;
-	remainder &= 0xffffffff;
-
 	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
 	if (!swap_info)
 	    goto blit_fallback;
@@ -1197,18 +1194,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	I830DRI2ReferenceBuffer(front);
 	I830DRI2ReferenceBuffer(back);
 
-	/* Get current count */
-	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
-	vbl.request.sequence = 0;
-	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
-	if (ret) {
-		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-			   "first get vblank counter failed: %s\n",
-			   strerror(errno));
-		goto blit_fallback;
-	}
-
-	current_msc = vbl.reply.sequence;
+        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
 
 	/* Flips need to be submitted one frame before */
 	if (can_exchange(draw, front, back)) {
@@ -1257,7 +1243,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		if (current_msc >= *target_msc)
 			*target_msc = current_msc;
 
-		vbl.request.sequence = *target_msc;
+		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
 		vbl.request.signal = (unsigned long)swap_info;
 		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
 		if (ret) {
@@ -1267,7 +1253,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 			goto blit_fallback;
 		}
 
-		*target_msc = vbl.reply.sequence + flip;
+                *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
 		swap_info->frame = *target_msc;
 
 		return TRUE;
@@ -1283,8 +1269,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	if (flip == 0)
 		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
 
-	vbl.request.sequence = current_msc - (current_msc % divisor) +
-		remainder;
+        request_msc = current_msc - (current_msc % divisor) +
+                remainder;
 
 	/*
 	 * If the calculated deadline vbl.request.sequence is smaller than
@@ -1297,8 +1283,10 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
 	 * if we are blitting/exchanging instead of flipping.
 	 */
-	if (vbl.request.sequence <= current_msc)
-		vbl.request.sequence += divisor;
+	if (request_msc <= current_msc)
+		request_msc += divisor;
+
+        vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
 
 	/* Account for 1 frame extra pageflip delay if flip > 0 */
 	vbl.request.sequence -= flip;
@@ -1313,7 +1301,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	}
 
 	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
-	*target_msc = vbl.reply.sequence + flip;
+	*target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
 	swap_info->frame = *target_msc;
 
 	return TRUE;
@@ -1346,35 +1334,20 @@ I830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
-	intel_screen_private *intel = intel_get_screen_private(scrn);
-	drmVBlank vbl;
-	int ret, pipe = I830DRI2DrawablePipe(draw);
+	int ret;
+        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
 
 	/* Drawable not displayed, make up a *monotonic* value */
-	if (pipe == -1) {
+	if (crtc == NULL) {
 		*ust = gettime_us();
 		*msc = 0;
 		return TRUE;
 	}
 
-	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
-	vbl.request.sequence = 0;
+        ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
 
-	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
-	if (ret) {
-		static int limit = 5;
-		if (limit) {
-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-				   "%s:%d get vblank counter failed: %s\n",
-				   __FUNCTION__, __LINE__,
-				   strerror(errno));
-			limit--;
-		}
-		return FALSE;
-	}
-
-	*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
-	*msc = vbl.reply.sequence;
+        if (ret)
+                return FALSE;
 
 	return TRUE;
 }
@@ -1394,14 +1367,10 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	intel_screen_private *intel = intel_get_screen_private(scrn);
 	DRI2FrameEventPtr wait_info;
 	drmVBlank vbl;
-	int ret, pipe = I830DRI2DrawablePipe(draw);
-	CARD64 current_msc;
-
-	/* Truncate to match kernel interfaces; means occasional overflow
-	 * misses, but that's generally not a big deal */
-	target_msc &= 0xffffffff;
-	divisor &= 0xffffffff;
-	remainder &= 0xffffffff;
+	int ret;
+        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
+        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
+	CARD64 current_msc, current_ust, request_msc;
 
 	/* Drawable not visible, return immediately */
 	if (pipe == -1)
@@ -1423,22 +1392,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	}
 
 	/* Get current count */
-	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
-	vbl.request.sequence = 0;
-	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
-	if (ret) {
-		static int limit = 5;
-		if (limit) {
-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-				   "%s:%d get vblank counter failed: %s\n",
-				   __FUNCTION__, __LINE__,
-				   strerror(errno));
-			limit--;
-		}
-		goto out_free;
-	}
-
-	current_msc = vbl.reply.sequence;
+        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
 
 	/*
 	 * If divisor is zero, or current_msc is smaller than target_msc,
@@ -1456,7 +1410,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 			target_msc = current_msc;
 		vbl.request.type =
 			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
-		vbl.request.sequence = target_msc;
+		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
 		vbl.request.signal = (unsigned long)wait_info;
 		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
 		if (ret) {
@@ -1471,7 +1425,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 			goto out_free;
 		}
 
-		wait_info->frame = vbl.reply.sequence;
+		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
 		DRI2BlockClient(client, draw);
 		return TRUE;
 	}
@@ -1483,9 +1437,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	vbl.request.type =
 		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
 
-	vbl.request.sequence = current_msc - (current_msc % divisor) +
-	    remainder;
-
+        request_msc = current_msc - (current_msc % divisor) +
+                remainder;
 	/*
 	 * If calculated remainder is larger than requested remainder,
 	 * it means we've passed the last point where
@@ -1493,7 +1446,9 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	 * that will happen.
 	 */
 	if ((current_msc % divisor) >= remainder)
-	    vbl.request.sequence += divisor;
+                request_msc += divisor;
+
+	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
 
 	vbl.request.signal = (unsigned long)wait_info;
 	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
@@ -1509,7 +1464,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 		goto out_free;
 	}
 
-	wait_info->frame = vbl.reply.sequence;
+	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
 	DRI2BlockClient(client, draw);
 
 	return TRUE;
