xf86-video-intel: 10 commits - src/i830_common.h src/i830_dri.c src/i830_driver.c src/i830.h src/i830_memory.c src/i830_video.c

Eric Anholt anholt at kemper.freedesktop.org
Thu Oct 11 12:23:20 PDT 2007


 src/i830.h        |   23 +-
 src/i830_common.h |    2 
 src/i830_dri.c    |  361 +++++++++++++++++++++---------------------
 src/i830_driver.c |   96 +++--------
 src/i830_memory.c |  458 ++++++++++++++++++++++++++----------------------------
 src/i830_video.c  |    1 
 6 files changed, 452 insertions(+), 489 deletions(-)

New commits:
diff-tree 3af442ba52550a9d183e215d49cc12dac0cb9e4b (from 6c485ff5bd25e9aa6a3c1eb669843e6b969d94df)
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Oct 11 11:56:06 2007 -0700

    Don't double-free the memory manager allocation.

diff --git a/src/i830_memory.c b/src/i830_memory.c
index 0b046f6..9dfe43e 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -279,8 +279,18 @@ i830_reset_allocations(ScrnInfoPtr pScrn
     int	    p;
 
     /* While there is any memory between the start and end markers, free it. */
-    while (pI830->memory_list->next->next != NULL)
+    while (pI830->memory_list->next->next != NULL) {
+	i830_memory *mem = pI830->memory_list->next;
+
+	/* Don't reset BO allocator, which we set up at init. */
+	if (pI830->memory_manager == mem) {
+	    mem = mem->next;
+	    if (mem->next == NULL)
+		break;
+	}
+
 	i830_free_memory(pScrn, pI830->memory_list->next);
+    }
 
     /* Free any allocations in buffer objects */
 #ifdef XF86DRI_MM
diff-tree 6c485ff5bd25e9aa6a3c1eb669843e6b969d94df (from d47cf148776d74f9035863b23eefdc2b5893af08)
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Oct 5 15:52:56 2007 -0700

    Update memory manager sizing for the current set of LIFETIME_FIXED bufffers.

diff --git a/src/i830_memory.c b/src/i830_memory.c
index 277f698..0b046f6 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -403,7 +403,18 @@ i830_allocator_init(ScrnInfoPtr pScrn, u
 	 * physical-address allocations of cursor/overlay registers.
 	 */
 	mmsize = size;
-	/* Overlay is always set up as fixed, currently. */
+
+	/* EXA area is fixed. */
+	if (pI830->useEXA) {
+	    mmsize -= ROUND_TO_PAGE(3 * pScrn->displayWidth * pI830->cpp *
+				    pScrn->virtualY);
+	}
+	/* Classic textures are fixed. */
+	if (pI830->allocate_classic_textures)
+	    mmsize -= MB(32);
+	/* Overlay and cursors, if physical, need to be allocated outside
+	 * of the kernel memory manager.
+	 */
 	if (!OVERLAY_NOPHYSICAL(pI830) && !IS_I965G(pI830)) {
 	    mmsize -= ROUND_TO(OVERLAY_SIZE, GTT_PAGE_SIZE);
 	}
diff-tree d47cf148776d74f9035863b23eefdc2b5893af08 (from a6dc81a0864f9ab2f6fc1aa31002c0191f674ceb)
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Oct 5 15:45:51 2007 -0700

    Move tiling fence register setup to bind time instead of allocate time.
    
    This allows us to allocate tiled buffers in buffer objects.  In the process
    I removed the fence division that we had for tiled buffers on pre-965.  If we
    resurrect that code, it should probably be managed by just dividing all the
    objects in roughly half and fencing those halves (to reduce the alignment
    requirement), instead of using giant fences until we run out of space and then
    trying to deal with scarce space on the last (or not) buffer.  Halving
    our tiled objects would use 6/8 of our fence registers on that hardware.

diff --git a/src/i830.h b/src/i830.h
index a34be61..031781e 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -163,6 +163,13 @@ struct _i830_memory {
     unsigned long agp_offset;
 
     enum tile_format tiling;
+    /**
+     * Index of the fence register representing the tiled surface, when
+     * bound.
+     */
+    int fence_nr;
+    /** Pitch value in bytes for tiled surfaces */
+    unsigned int pitch;
 
     /** Description of the allocation, for logging */
     char *name;
@@ -393,17 +400,7 @@ typedef struct _I830Rec {
    int NumScanlineColorExpandBuffers;
    int nextColorExpandBuf;
 
-    /**
-     * Values to be programmed into the fence registers.
-     *
-     * Pre-965, this is a list of FENCE_NR (8) CARD32 registers that
-     * contain their start, size, and pitch.  On the 965, it is a list of
-     * FENCE_NEW_NR CARD32s for the start and pitch fields (low 32 bits) of
-     * the fence registers followed by FENCE_NEW_NR CARD32s for the end fields
-     * (high 32 bits) of the fence registers.
-     */
-   unsigned int fence[FENCE_NEW_NR * 2];
-   unsigned int next_fence;
+   Bool fence_used[FENCE_NEW_NR];
 
    Bool useEXA;
    Bool noAccel;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 339fe25..9ca1222 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1732,16 +1732,6 @@ ResetState(ScrnInfoPtr pScrn, Bool flush
    if (pI830->entityPrivate)
       pI830->entityPrivate->RingRunning = 0;
 
-   /* Reset the fence registers to 0 */
-   if (IS_I965G(pI830)) {
-      for (i = 0; i < FENCE_NEW_NR; i++) {
-	 OUTREG(FENCE_NEW + i * 8, 0);
-	 OUTREG(FENCE_NEW + 4 + i * 8, 0);
-      }
-   } else {
-      for (i = 0; i < FENCE_NR; i++)
-         OUTREG(FENCE + i * 4, 0);
-   }
    /* Flush the ring buffer (if enabled), then disable it. */
    /* God this is ugly */
 #define flush_ring() do { \
@@ -1770,34 +1760,6 @@ ResetState(ScrnInfoPtr pScrn, Bool flush
 }
 
 static void
-SetFenceRegs(ScrnInfoPtr pScrn)
-{
-   I830Ptr pI830 = I830PTR(pScrn);
-   int i;
-
-   DPRINTF(PFX, "SetFenceRegs\n");
-
-   if (!I830IsPrimary(pScrn)) return;
-
-   if (IS_I965G(pI830)) {
-      for (i = 0; i < FENCE_NEW_NR; i++) {
-         OUTREG(FENCE_NEW + i * 8, pI830->fence[i]);
-         OUTREG(FENCE_NEW + 4 + i * 8, pI830->fence[i+FENCE_NEW_NR]);
-         if (I810_DEBUG & DEBUG_VERBOSE_VGA) {
-	    ErrorF("Fence Start Register : %x\n", pI830->fence[i]);
-	    ErrorF("Fence End Register : %x\n", pI830->fence[i+FENCE_NEW_NR]);
-         }
-      }
-   } else {
-      for (i = 0; i < FENCE_NR; i++) {
-         OUTREG(FENCE + i * 4, pI830->fence[i]);
-         if (I810_DEBUG & DEBUG_VERBOSE_VGA)
-	    ErrorF("Fence Register : %x\n", pI830->fence[i]);
-      }
-   }
-}
-
-static void
 SetRingRegs(ScrnInfoPtr pScrn)
 {
    I830Ptr pI830 = I830PTR(pScrn);
@@ -1864,7 +1826,6 @@ SetHWOperatingState(ScrnInfoPtr pScrn)
 
    if (!pI830->noAccel)
       SetRingRegs(pScrn);
-   SetFenceRegs(pScrn);
    if (!pI830->SWCursor)
       I830InitHWCursor(pScrn);
 }
diff --git a/src/i830_memory.c b/src/i830_memory.c
index 4d55ca7..277f698 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -115,10 +115,12 @@ static i830_memory *
 i830_allocate_aperture(ScrnInfoPtr pScrn, const char *name,
 		       long size, unsigned long alignment, int flags);
 
-static void i830_set_fence(ScrnInfoPtr pScrn, int nr, unsigned int offset,
+static int i830_set_tiling(ScrnInfoPtr pScrn, unsigned int offset,
 			   unsigned int pitch, unsigned int size,
 			   enum tile_format tile_format);
 
+static void i830_clear_tiling(ScrnInfoPtr pScrn, unsigned int fence_nr);
+
 /**
  * Returns the fence size for a tiled area of the given size.
  */
@@ -162,26 +164,31 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830
 	int ret;
 
 	ret = drmBOSetPin(pI830->drmSubFD, &mem->bo, 1);
-	if (ret == 0) {
-	    mem->bound = TRUE;
-	    mem->offset = mem->bo.offset;
-	    mem->end = mem->bo.offset + mem->size;
-	    return TRUE;
-	} else {
+	if (ret != 0)
 	    return FALSE;
-	}
+
+	mem->bound = TRUE;
+	mem->offset = mem->bo.offset;
+	mem->end = mem->bo.offset + mem->size;
     }
 #endif
 
-    if (!pI830->gtt_acquired)
-	return TRUE;
+    if (!mem->bound) {
+	if (!pI830->gtt_acquired)
+	    return TRUE;
+
+	if (mem->key != -1 && 
+	    !xf86BindGARTMemory(pScrn->scrnIndex, mem->key, mem->agp_offset))
+	{
+	    return FALSE;
+	}
 
-    if (mem->key == -1 ||
-	xf86BindGARTMemory(pScrn->scrnIndex, mem->key, mem->agp_offset)) {
 	mem->bound = TRUE;
-	return TRUE;
-    } else {
-	return FALSE;
+    }
+
+    if (mem->tiling != TILE_NONE) {
+	mem->fence_nr = i830_set_tiling(pScrn, mem->offset, mem->pitch,
+					mem->size, mem->tiling);
     }
 
     return TRUE;
@@ -193,6 +200,9 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i8
     if (mem == NULL || !mem->bound)
 	return TRUE;
 
+    if (mem->tiling != TILE_NONE)
+	i830_clear_tiling(pScrn, mem->fence_nr);
+
 #ifdef XF86DRI_MM
     if (mem->bo.size != 0) {
 	I830Ptr pI830 = I830PTR(pScrn);
@@ -303,10 +313,6 @@ i830_reset_allocations(ScrnInfoPtr pScrn
     pI830->textures = NULL;
 #endif
     pI830->LpRing->mem = NULL;
-
-    /* Reset the fence register allocation. */
-    pI830->next_fence = 0;
-    memset(pI830->fence, 0, sizeof(pI830->fence));
 }
 
 void
@@ -797,17 +803,10 @@ i830_allocate_memory_tiled(ScrnInfoPtr p
     unsigned long aper_size;
     unsigned long aper_align;
     i830_memory *mem;
-    int fence_divide, i;
 
     if (tile_format == TILE_NONE)
 	return i830_allocate_memory(pScrn, name, size, alignment, flags);
 
-    /* XXX: for now, refuse to tile with movable buffer object allocations,
-     * until we can move the set_fence (and failure recovery) into bind time.
-     */
-    if (pI830->memory_manager != NULL && !(flags & NEED_LIFETIME_FIXED))
-	return NULL;
-
     /* Only allocate page-sized increments. */
     size = ALIGN(size, GTT_PAGE_SIZE);
 
@@ -832,51 +831,13 @@ i830_allocate_memory_tiled(ScrnInfoPtr p
     if (aper_align < alignment)
 	aper_align = alignment;
 
-    fence_divide = 1;
     mem = i830_allocate_memory(pScrn, name, aper_size, aper_align, flags);
-    if (mem == NULL && !IS_I965G(pI830)) {
-	/* For the older hardware with stricter fencing limits, if we
-	 * couldn't allocate with the large alignment, try relaxing the
-	 * alignment requirements and using more fences to cover the area.
-	 */
-	for (fence_divide = 2; fence_divide <= 4 && mem == NULL;
-	     fence_divide *= 2)
-	{
-	    /* Check that it's not too small for fencing. */
-	    if (i830_get_fence_size(pScrn, aper_align / fence_divide) !=
-		aper_align / fence_divide)
-	    {
-		break;
-	    }
-
-	    mem = i830_allocate_memory(pScrn, name, aper_size,
-				       aper_align / fence_divide, flags);
-	}
-    }
-
     if (mem == NULL)
 	return NULL;
-
-    /* Make sure we've got enough free fence regs.  It's pretty hard to run
-     * out, luckily, with 8 even on older hardware and us only tiling
-     * front/back/depth buffers.
-     */
-    if (pI830->next_fence + fence_divide >
-	(IS_I965G(pI830) ? FENCE_NEW_NR : FENCE_NR))
-    {
-	i830_free_memory(pScrn, mem);
-	return NULL;
-    }
-
-    /* Set up the fence registers. */
-    for (i = 0; i < fence_divide; i++) {
-	i830_set_fence(pScrn, pI830->next_fence++,
-		       mem->offset + mem->size * i / fence_divide, pitch,
-		       mem->size / fence_divide, tile_format);
-    }
-
     mem->size = size;
     mem->tiling = tile_format;
+    mem->pitch = pitch;
+    mem->fence_nr = -1;
 
     return mem;
 }
@@ -1222,9 +1183,6 @@ i830_allocate_cursor_buffers(ScrnInfoPtr
      */
     for (i = 0; i < xf86_config->num_crtc; i++)
     {
-	xf86CrtcPtr	    crtc = xf86_config->crtc[i];
-	I830CrtcPrivatePtr  intel_crtc = crtc->driver_private;
-	
 	pI830->cursor_mem_classic[i] = i830_allocate_memory (pScrn, 
 							     "Core cursor",
 							     HWCURSOR_SIZE,
@@ -1654,203 +1612,216 @@ i830_allocate_3d_memory(ScrnInfoPtr pScr
 #endif
 
 /**
- * Sets up a fence area for the hardware.
+ * Sets up tiled surface registers ("fences") for the hardware.
  *
  * The fences control automatic tiled address swizzling for CPU access of the
- * framebuffer.
+ * framebuffer, and may be used in many rendering operations instead of
+ * manually supplying tiling enables per surface.
  */
-static void
-i830_set_fence(ScrnInfoPtr pScrn, int nr, unsigned int offset,
-	       unsigned int pitch, unsigned int size,
-	       enum tile_format tile_format)
+static int
+i830_set_tiling(ScrnInfoPtr pScrn, unsigned int offset,
+		unsigned int pitch, unsigned int size,
+		enum tile_format tile_format)
 {
     I830Ptr pI830 = I830PTR(pScrn);
     CARD32 val;
     CARD32 fence_mask = 0;
     unsigned int fence_pitch;
+    unsigned int max_fence;
+    unsigned int fence_nr;
 
-    DPRINTF(PFX, "i830_set_fence(): %d, 0x%08x, %d, %d kByte\n",
-	    nr, offset, pitch, size / 1024);
+    DPRINTF(PFX, "i830_set_tiling(): 0x%08x, %d, %d kByte\n",
+	    offset, pitch, size / 1024);
 
     assert(tile_format != TILE_NONE);
 
+    if (IS_I965G(pI830))
+	max_fence = FENCE_NEW_NR;
+    else
+	max_fence = FENCE_NR;
+
+    for (fence_nr = 0; fence_nr < max_fence; fence_nr++) {
+	if (!pI830->fence_used[fence_nr])
+	    break;
+    }
+    if (fence_nr == max_fence)
+	FatalError("Ran out of fence registers at %d\n", fence_nr);
+
+    pI830->fence_used[fence_nr] = TRUE;
+
     if (IS_I965G(pI830)) {
-	if (nr < 0 || nr >= FENCE_NEW_NR) {
-	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		       "i830_set_fence(): fence %d out of range\n",nr);
-	    return;
-	}
+	uint32_t fence_start, fence_end;
 
 	switch (tile_format) {
 	case TILE_XMAJOR:
-            pI830->fence[nr] = (((pitch / 128) - 1) << 2) | offset | 1;
-	    pI830->fence[nr] |= I965_FENCE_X_MAJOR;
+	    fence_start = (((pitch / 128) - 1) << 2) | offset | 1;
+	    fence_start |= I965_FENCE_X_MAJOR;
             break;
 	case TILE_YMAJOR:
             /* YMajor can be 128B aligned but the current code dictates
              * otherwise. This isn't a problem apart from memory waste.
              * FIXME */
-            pI830->fence[nr] = (((pitch / 128) - 1) << 2) | offset | 1;
-	    pI830->fence[nr] |= I965_FENCE_Y_MAJOR;
-            break;
-	case TILE_NONE:
+	    fence_start = (((pitch / 128) - 1) << 2) | offset | 1;
+	    fence_start |= I965_FENCE_Y_MAJOR;
             break;
+	default:
+	    return -1;
 	}
 
 	/* The end marker is the address of the last page in the allocation. */
-	pI830->fence[FENCE_NEW_NR + nr] = offset + size - 4096;
-	return;
-    }
-
-    if (nr < 0 || nr >= FENCE_NR) {
-	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		   "i830_set_fence(): fence %d out of range\n",nr);
-	return;
-    }
-
-    pI830->fence[nr] = 0;
-
-    if (IS_I9XX(pI830))
-   	fence_mask = ~I915G_FENCE_START_MASK;
-    else
-   	fence_mask = ~I830_FENCE_START_MASK;
+	fence_end = offset + size - 4096;
 
-    if (offset & fence_mask) {
-	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		   "i830_set_fence(): %d: offset (0x%08x) is not %s aligned\n",
-		   nr, offset, (IS_I9XX(pI830)) ? "1MB" : "512k");
-	return;
-    }
+	OUTREG(FENCE_NEW + fence_nr * 8, fence_start);
+	OUTREG(FENCE_NEW + fence_nr * 8 + 4, fence_end);
+    } else {
+	if (IS_I9XX(pI830))
+	    fence_mask = ~I915G_FENCE_START_MASK;
+	else
+	    fence_mask = ~I830_FENCE_START_MASK;
 
-    if (offset % size) {
-	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		   "i830_set_fence(): %d: offset (0x%08x) is not size (%dk) "
-		   "aligned\n",
-		   nr, offset, size / 1024);
-	return;
-    }
+	if (offset & fence_mask) {
+	    FatalError("i830_set_tiling(): %d: offset (0x%08x) is not %s "
+		       "aligned\n",
+		       fence_nr, offset, (IS_I9XX(pI830)) ? "1MB" : "512k");
+	}
 
-    if (pitch & 127) {
-	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		   "i830_set_fence(): %d: pitch (%d) not a multiple of 128 "
-		   "bytes\n",
-		   nr, pitch);
-	return;
-    }
+	if (offset % size) {
+	    FatalError("i830_set_tiling(): %d: offset (0x%08x) is not "
+		       "size (%dk) aligned\n",
+		       fence_nr, offset, size / 1024);
+	}
 
-    val = offset | FENCE_VALID;
+	if (pitch & 127) {
+	    FatalError("i830_set_tiling(): %d: pitch (%d) not a multiple of "
+		       "128 bytes\n",
+		       fence_nr, pitch);
+	}
 
-    switch (tile_format) {
-    case TILE_XMAJOR:
-	val |= FENCE_X_MAJOR;
-	break;
-    case TILE_YMAJOR:
-	val |= FENCE_Y_MAJOR;
-	break;
-    case TILE_NONE:
-	break;
-    }
+	val = offset | FENCE_VALID;
 
-    if (IS_I9XX(pI830)) {
-   	switch (size) {
-	case MB(1):
-	    val |= I915G_FENCE_SIZE_1M;
-	    break;
-	case MB(2):
-	    val |= I915G_FENCE_SIZE_2M;
-	    break;
-	case MB(4):
-	    val |= I915G_FENCE_SIZE_4M;
-	    break;
-	case MB(8):
-	    val |= I915G_FENCE_SIZE_8M;
-	    break;
-	case MB(16):
-	    val |= I915G_FENCE_SIZE_16M;
-	    break;
-	case MB(32):
-	    val |= I915G_FENCE_SIZE_32M;
+	switch (tile_format) {
+	case TILE_XMAJOR:
+	    val |= FENCE_X_MAJOR;
 	    break;
-	case MB(64):
-	    val |= I915G_FENCE_SIZE_64M;
+	case TILE_YMAJOR:
+	    val |= FENCE_Y_MAJOR;
 	    break;
-	default:
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "i830_set_fence(): %d: illegal size (%d kByte)\n",
-		       nr, size / 1024);
-	    return;
-   	}
-    } else {
-   	switch (size) {
-	case KB(512):
-	    val |= FENCE_SIZE_512K;
+	case TILE_NONE:
 	    break;
-	case MB(1):
-	    val |= FENCE_SIZE_1M;
+	}
+
+	if (IS_I9XX(pI830)) {
+	    switch (size) {
+	    case MB(1):
+		val |= I915G_FENCE_SIZE_1M;
+		break;
+	    case MB(2):
+		val |= I915G_FENCE_SIZE_2M;
+		break;
+	    case MB(4):
+		val |= I915G_FENCE_SIZE_4M;
+		break;
+	    case MB(8):
+		val |= I915G_FENCE_SIZE_8M;
+		break;
+	    case MB(16):
+		val |= I915G_FENCE_SIZE_16M;
+		break;
+	    case MB(32):
+		val |= I915G_FENCE_SIZE_32M;
+		break;
+	    case MB(64):
+		val |= I915G_FENCE_SIZE_64M;
+		break;
+	    default:
+		FatalError("i830_set_tiling(): %d: illegal size (%d kByte)\n",
+			   fence_nr, size / 1024);
+	    }
+	} else {
+	    switch (size) {
+	    case KB(512):
+		val |= FENCE_SIZE_512K;
+		break;
+	    case MB(1):
+		val |= FENCE_SIZE_1M;
+		break;
+	    case MB(2):
+		val |= FENCE_SIZE_2M;
+		break;
+	    case MB(4):
+		val |= FENCE_SIZE_4M;
+		break;
+	    case MB(8):
+		val |= FENCE_SIZE_8M;
+		break;
+	    case MB(16):
+		val |= FENCE_SIZE_16M;
+		break;
+	    case MB(32):
+		val |= FENCE_SIZE_32M;
+		break;
+	    case MB(64):
+		val |= FENCE_SIZE_64M;
+		break;
+	    default:
+		FatalError("i830_set_tiling(): %d: illegal size (%d kByte)\n",
+			   fence_nr, size / 1024);
+	    }
+	}
+
+	if ((IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) &&
+	    tile_format == TILE_YMAJOR)
+	    fence_pitch = pitch / 128;
+	else if (IS_I9XX(pI830))
+	    fence_pitch = pitch / 512;
+	else
+	    fence_pitch = pitch / 128;
+
+	switch (fence_pitch) {
+	case 1:
+	    val |= FENCE_PITCH_1;
 	    break;
-	case MB(2):
-	    val |= FENCE_SIZE_2M;
+	case 2:
+	    val |= FENCE_PITCH_2;
 	    break;
-	case MB(4):
-	    val |= FENCE_SIZE_4M;
+	case 4:
+	    val |= FENCE_PITCH_4;
 	    break;
-	case MB(8):
-	    val |= FENCE_SIZE_8M;
+	case 8:
+	    val |= FENCE_PITCH_8;
 	    break;
-	case MB(16):
-	    val |= FENCE_SIZE_16M;
+	case 16:
+	    val |= FENCE_PITCH_16;
 	    break;
-	case MB(32):
-	    val |= FENCE_SIZE_32M;
+	case 32:
+	    val |= FENCE_PITCH_32;
 	    break;
-	case MB(64):
-	    val |= FENCE_SIZE_64M;
+	case 64:
+	    val |= FENCE_PITCH_64;
 	    break;
 	default:
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		       "i830_set_fence(): %d: illegal size (%d kByte)\n",
-		       nr, size / 1024);
-	    return;
-   	}
+	    FatalError("i830_set_tiling(): %d: illegal pitch (%d)\n",
+		       fence_nr, pitch);
+	}
+
+	OUTREG(FENCE + fence_nr * 4, val);
     }
 
-    if ((IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830))
-	    && tile_format == TILE_YMAJOR)
-	fence_pitch = pitch / 128;
-    else if (IS_I9XX(pI830))
-	fence_pitch = pitch / 512;
-    else
-	fence_pitch = pitch / 128;
+    return fence_nr;
+}
 
-    switch (fence_pitch) {
-    case 1:
-	val |= FENCE_PITCH_1;
-	break;
-    case 2:
-	val |= FENCE_PITCH_2;
-	break;
-    case 4:
-	val |= FENCE_PITCH_4;
-	break;
-    case 8:
-	val |= FENCE_PITCH_8;
-	break;
-    case 16:
-	val |= FENCE_PITCH_16;
-	break;
-    case 32:
-	val |= FENCE_PITCH_32;
-	break;
-    case 64:
-	val |= FENCE_PITCH_64;
-	break;
-    default:
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		   "i830_set_fence(): %d: illegal pitch (%d)\n", nr, pitch);
-	return;
-    }
+static void
+i830_clear_tiling(ScrnInfoPtr pScrn, unsigned int fence_nr)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
 
-    pI830->fence[nr] = val;
+    if (IS_I965G(pI830)) {
+	OUTREG(FENCE_NEW + fence_nr * 8, 0);
+	OUTREG(FENCE_NEW + fence_nr * 8 + 4, 0);
+    } else {
+	OUTREG(FENCE + fence_nr * 4, 0);
+    }
+    pI830->fence_used[fence_nr] = FALSE;
 }
 
 /**
diff-tree a6dc81a0864f9ab2f6fc1aa31002c0191f674ceb (from 132dce7565feeea1055899f8c1627766fe84c88c)
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Oct 5 12:37:19 2007 -0700

    Allow front/back/depth to move over the lifetime of the server.

diff --git a/src/i830_driver.c b/src/i830_driver.c
index abe70d7..339fe25 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -777,12 +777,8 @@ I830LoadPalette(ScrnInfoPtr pScrn, int n
    }
 }
 
-#if 0
-/* This code ended up unused, but will be at least a reference when we let the
- * front buffer move.
- */
 static void
-i830UpdateFrontOffset(ScrnInfoPtr pScrn)
+i830_update_front_offset(ScrnInfoPtr pScrn)
 {
    ScreenPtr pScreen = pScrn->pScreen;
    I830Ptr pI830 = I830PTR(pScrn);
@@ -820,11 +816,10 @@ i830CreateScreenResources(ScreenPtr pScr
    if (!(*pScreen->CreateScreenResources)(pScreen))
       return FALSE;
 
-   i830UpdateFrontOffset(pScrn);
+   i830_update_front_offset(pScrn);
 
    return TRUE;
 }
-#endif
 
 int
 i830_output_clones (ScrnInfoPtr pScrn, int type_mask)
@@ -2867,10 +2862,8 @@ I830ScreenInit(int scrnIndex, ScreenPtr 
    pScreen->SaveScreen = xf86SaveScreen;
    pI830->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = I830CloseScreen;
-#if 0
    pI830->CreateScreenResources = pScreen->CreateScreenResources;
    pScreen->CreateScreenResources = i830CreateScreenResources;
-#endif
 
    if (!xf86CrtcScreenInit (pScreen))
        return FALSE;
@@ -3035,9 +3028,8 @@ I830EnterVT(int scrnIndex, int flags)
 
    i830_describe_allocations(pScrn, 1, "");
 
-#if 0
-   i830UpdateFrontOffset(pScrn);
-#endif
+   /* Update the screen pixmap in case the buffer moved */
+   i830_update_front_offset(pScrn);
 
    if (i830_check_error_state(pScrn)) {
       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
diff --git a/src/i830_memory.c b/src/i830_memory.c
index 2ff1a0c..4d55ca7 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -1087,11 +1087,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pS
     i830_memory *front_buffer = NULL;
     Bool tiling;
 
-    /* The front buffer is currently marked as NEED_LIFETIME_FIXED because
-     * DRIDoMappings is the only caller of the rm/add map functions,
-     * and it's only called at startup.  This should be easily fixable.
-     */
-    flags = NEED_LIFETIME_FIXED | ALLOW_SHARING;
+    flags = ALLOW_SHARING;
 
     /* Clear everything first. */
     memset(FbMemBox, 0, sizeof(*FbMemBox));
@@ -1488,7 +1484,6 @@ i830_allocate_backbuffer(ScrnInfoPtr pSc
 	*buffer = i830_allocate_memory_tiled(pScrn, name, size, pitch,
 					     GTT_PAGE_SIZE,
 					     ALIGN_BOTH_ENDS |
-					     NEED_LIFETIME_FIXED |
 					     ALLOW_SHARING,
 					     TILE_XMAJOR);
     }
@@ -1500,7 +1495,6 @@ i830_allocate_backbuffer(ScrnInfoPtr pSc
 	size = ROUND_TO_PAGE(pitch * height);
 	*buffer = i830_allocate_memory(pScrn, name, size, GTT_PAGE_SIZE,
 				       ALIGN_BOTH_ENDS |
-				       NEED_LIFETIME_FIXED |
 				       ALLOW_SHARING);
     }
 
@@ -1543,7 +1537,6 @@ i830_allocate_depthbuffer(ScrnInfoPtr pS
 	    i830_allocate_memory_tiled(pScrn, "depth buffer", size, pitch,
 				       GTT_PAGE_SIZE,
 				       ALIGN_BOTH_ENDS |
-				       NEED_LIFETIME_FIXED |
 				       ALLOW_SHARING,
 				       tile_format);
     }
@@ -1555,7 +1548,7 @@ i830_allocate_depthbuffer(ScrnInfoPtr pS
 	size = ROUND_TO_PAGE(pitch * height);
 	pI830->depth_buffer =
 	    i830_allocate_memory(pScrn, "depth buffer", size, GTT_PAGE_SIZE,
-				 ALLOW_SHARING | NEED_LIFETIME_FIXED);
+				 ALLOW_SHARING);
     }
 
     if (pI830->depth_buffer == NULL) {
diff-tree 132dce7565feeea1055899f8c1627766fe84c88c (from 4ca3550fb7d488741f8dc1ba3c8722393277c3b8)
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Oct 5 12:12:06 2007 -0700

    Delay SAREA and mapping setup until EnterVT when using the memory manager.
    
    Otherwise, we would use uninitialized offsets in the early setup.

diff --git a/src/i830_dri.c b/src/i830_dri.c
index 0466410..4d3458f 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -833,12 +833,19 @@ I830DRIDoMappings(ScreenPtr pScreen)
    pScrn->pScreen->width = pScrn->virtualX;
    pScrn->pScreen->height = pScrn->virtualY;
 
-   if (!i830_update_dri_buffers(pScrn)) {
-      /* screen mappings probably failed */
-      xf86DrvMsg(pScreen->myNum, X_ERROR,
-		 "[drm] drmAddMap(screen mappings) failed. Disabling DRI\n");
-      DRICloseScreen(pScreen);
-      return FALSE;
+   /* If we are using the kernel memory manager, we have to delay SAREA and
+    * mapping setup until our buffers are pinned at EnterVT, losing the
+    * opportunity to fail cleanly early on.
+    */
+   if (pI830->memory_manager == NULL) {
+      if (!i830_update_dri_buffers(pScrn)) {
+	 /* screen mappings probably failed */
+	 xf86DrvMsg(pScreen->myNum, X_ERROR,
+		    "[drm] drmAddMap(screen mappings) failed. "
+		    "Disabling DRI\n");
+	 DRICloseScreen(pScreen);
+	 return FALSE;
+      }
    }
 
    if (pI830->allocate_classic_textures)
diff --git a/src/i830_driver.c b/src/i830_driver.c
index d24c408..abe70d7 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3070,6 +3070,11 @@ I830EnterVT(int scrnIndex, int flags)
 
 #ifdef XF86DRI
    if (pI830->directRenderingEnabled) {
+      /* Update buffer offsets in sarea and mappings, since buffer offsets
+       * may have changed.
+       */
+      if (!i830_update_dri_buffers(pScrn))
+	 FatalError("i830_update_dri_buffers() failed\n");
 
       I830DRISetVBlankInterrupt (pScrn, TRUE);
 
@@ -3088,12 +3093,6 @@ I830EnterVT(int scrnIndex, int flags)
 	 for(i = 0; i < I830_NR_TEX_REGIONS+1 ; i++)
 	    sarea->texList[i].age = sarea->texAge;
 
-	 /* Update buffer offsets in sarea and mappings, since buffer offsets
-	  * may have changed.
-	  */
-	 if (!i830_update_dri_buffers(pScrn))
-	    FatalError("i830_update_dri_buffers() failed\n");
-
 	 DPRINTF(PFX, "calling dri unlock\n");
 	 DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
       }
diff-tree 4ca3550fb7d488741f8dc1ba3c8722393277c3b8 (from f393a12d21eed668cf4771f022beded9a4c547c7)
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Oct 4 17:02:15 2007 -0700

    Rework DRI buffer mappings and sarea setup to allow for moving buffers.
    
    While this has been a desired feature for some time, to allow for reallocation
    of the front buffer, it was made more necessary by the desire to avoid
    requiring a NO_MOVE buffer type in TTM because buffer objects may not be left
    pinned over VT switch.  This is a step towards making those buffers
    movable and resizable.

diff --git a/src/i830.h b/src/i830.h
index df95fb5..a34be61 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -635,12 +635,10 @@ extern Bool I830DRIDoMappings(ScreenPtr 
 extern Bool I830DRIResume(ScreenPtr pScreen);
 extern void I830DRICloseScreen(ScreenPtr pScreen);
 extern Bool I830DRIFinishScreenInit(ScreenPtr pScreen);
-extern Bool I830UpdateDRIBuffers(ScrnInfoPtr pScrn, drmI830Sarea *sarea);
-extern void I830DRIUnmapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea);
-extern Bool I830DRIMapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea);
 extern void I830DRIUnlock(ScrnInfoPtr pScrn);
 extern Bool I830DRILock(ScrnInfoPtr pScrn);
 extern Bool I830DRISetVBlankInterrupt (ScrnInfoPtr pScrn, Bool on);
+Bool i830_update_dri_buffers(ScrnInfoPtr pScrn);
 #endif
 
 unsigned long intel_get_pixmap_offset(PixmapPtr pPix);
diff --git a/src/i830_common.h b/src/i830_common.h
index a4c3b5a..f3a7ea0 100644
--- a/src/i830_common.h
+++ b/src/i830_common.h
@@ -74,7 +74,7 @@ typedef struct {
    unsigned int depth_offset;
    unsigned int w;
    unsigned int h;
-   unsigned int pitch;
+   unsigned int pitch; /* Pitch of front buffer in units of pixels */
    unsigned int pitch_bits;
    unsigned int back_pitch;
    unsigned int depth_pitch;
diff --git a/src/i830_dri.c b/src/i830_dri.c
index 4cddf3b..0466410 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -640,7 +640,7 @@ I830DRIScreenInit(ScreenPtr pScreen)
    /* Now, nuke dri.c's dummy frontbuffer map setup if we did that. */
    if (pDRIInfo->frameBufferSize != 0) {
        int tmp;
-       unsigned int fb_handle;
+       drm_handle_t fb_handle;
        void *ptmp;
 
        /* With the compat method, it will continue to report
@@ -743,149 +743,38 @@ I830DRIScreenInit(ScreenPtr pScreen)
    return TRUE;
 }
 
-Bool
-I830DRIMapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
-{
-   ScreenPtr pScreen = pScrn->pScreen;
-   I830Ptr pI830 = I830PTR(pScrn);
-   drm_handle_t front_handle;
-
-   pI830->pDRIInfo->frameBufferPhysicalAddress = (char *) pI830->LinearAddr;
-   pI830->pDRIInfo->frameBufferStride = pScrn->displayWidth * pI830->cpp;
-   pI830->pDRIInfo->frameBufferSize =
-      ROUND_TO_PAGE(pI830->pDRIInfo->frameBufferStride * pScrn->virtualY);
-
-   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-	      "[drm] Mapping front buffer\n");
-   if (drmAddMap(pI830->drmSubFD,
-		 (drm_handle_t)(sarea->front_offset + pI830->LinearAddr),
-		 sarea->front_size,
-		 DRM_AGP,
-		 0,
-		 &front_handle) < 0) {
-       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		  "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
-       DRICloseScreen(pScreen);
-       return FALSE;
-   }
-   sarea->front_handle = front_handle;
-#if DRI_DRIVER_FRAMEBUFFER_MAP
-   pI830->pDRIInfo->hFrameBuffer = front_handle;
-#endif
-
-   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Front Buffer = 0x%08x\n",
-	      (int)sarea->front_handle);
-
-   if (drmAddMap(pI830->drmSubFD,
-                 (drm_handle_t)(sarea->back_offset + pI830->LinearAddr),
-                 sarea->back_size, DRM_AGP, 0,
-                 (drmAddress) &sarea->back_handle) < 0) {
-      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
-      DRICloseScreen(pScreen);
-      return FALSE;
-   }
-   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Back Buffer = 0x%08x\n",
-              (int)sarea->back_handle);
-
-   if (pI830->third_buffer) {
-      if (drmAddMap(pI830->drmSubFD,
-		    (drm_handle_t)(sarea->third_offset + pI830->LinearAddr),
-		    sarea->third_size, DRM_AGP, 0,
-		    (drmAddress) &sarea->third_handle) < 0) {
-	 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		    "[drm] drmAddMap(third_handle) failed. Triple buffering "
-		    "inactive\n");
-	 i830_free_memory(pScrn, pI830->third_buffer);
-	 pI830->third_buffer = NULL;
-	 sarea->third_handle = 0;
-      } else
-	 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Third Buffer = 0x%08x\n",
-		    (int)sarea->third_handle);
-   }
-
-   if (drmAddMap(pI830->drmSubFD,
-                 (drm_handle_t)sarea->depth_offset + pI830->LinearAddr,
-                 sarea->depth_size, DRM_AGP, 0,
-                 (drmAddress) &sarea->depth_handle) < 0) {
-      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
-      DRICloseScreen(pScreen);
-      return FALSE;
-   }
-   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Depth Buffer = 0x%08x\n",
-              (int)sarea->depth_handle);
-
-   if (pI830->allocate_classic_textures) {
-      if (drmAddMap(pI830->drmSubFD,
-		    (drm_handle_t)sarea->tex_offset + pI830->LinearAddr,
-		    sarea->tex_size, DRM_AGP, 0,
-		    (drmAddress) &sarea->tex_handle) < 0) {
-	 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		    "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
-	 DRICloseScreen(pScreen);
-	 return FALSE;
-      }
-
-      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] textures = 0x%08x\n",
-		 (int)sarea->tex_handle);
-   }
-   return TRUE;
-}
-
-
-void
-I830DRIUnmapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
-{
-   I830Ptr pI830 = I830PTR(pScrn);
-
-   if (sarea->front_handle) {
-      drmRmMap(pI830->drmSubFD, sarea->front_handle);
-      sarea->front_handle = 0;
-   }
-   if (sarea->back_handle) {
-      drmRmMap(pI830->drmSubFD, sarea->back_handle);
-      sarea->back_handle = 0;
-   }
-   if (sarea->third_handle) {
-      drmRmMap(pI830->drmSubFD, sarea->third_handle);
-      sarea->third_handle = 0;
-   }
-   if (sarea->depth_handle) {
-      drmRmMap(pI830->drmSubFD, sarea->depth_handle);
-      sarea->depth_handle = 0;
-   }
-   if (sarea->tex_handle) {
-      drmRmMap(pI830->drmSubFD, sarea->tex_handle);
-      sarea->tex_handle = 0;
-   }
-}
-
 static void
-I830InitTextureHeap(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
+I830InitTextureHeap(ScrnInfoPtr pScrn)
 {
    I830Ptr pI830 = I830PTR(pScrn);
 
+   if (pI830->textures == NULL)
+       return;
+
    /* Start up the simple memory manager for agp space */
    drmI830MemInitHeap drmHeap;
    drmHeap.region = I830_MEM_REGION_AGP;
    drmHeap.start  = 0;
-   drmHeap.size   = sarea->tex_size;
-      
+   drmHeap.size   = pI830->textures->size;
+
    if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT_HEAP,
 			  &drmHeap, sizeof(drmHeap))) {
       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 		    "[drm] Failed to initialized agp heap manager\n");
    } else {
       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		    "[drm] Initialized kernel agp heap manager, %d\n",
-		    sarea->tex_size);
+		    "[drm] Initialized kernel agp heap manager, %ld\n",
+		    pI830->textures->size);
 
       I830SetParam(pScrn, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY, 
-		      sarea->log_tex_granularity);
+		   pI830->TexGranularity);
    }
 }
 
+/**
+ * Sets up mappings for static, lifetime-fixed allocations, and inital SAREA
+ * setup.
+ */
 Bool
 I830DRIDoMappings(ScreenPtr pScreen)
 {
@@ -944,14 +833,17 @@ I830DRIDoMappings(ScreenPtr pScreen)
    pScrn->pScreen->width = pScrn->virtualX;
    pScrn->pScreen->height = pScrn->virtualY;
 
-   /* this will map the screen regions */
-   if (!I830UpdateDRIBuffers(pScrn, sarea)) {
+   if (!i830_update_dri_buffers(pScrn)) {
       /* screen mappings probably failed */
       xf86DrvMsg(pScreen->myNum, X_ERROR,
 		 "[drm] drmAddMap(screen mappings) failed. Disabling DRI\n");
+      DRICloseScreen(pScreen);
       return FALSE;
    }
 
+   if (pI830->allocate_classic_textures)
+      I830InitTextureHeap(pScrn);
+
    if (DEVICE_ID(pI830->PciInfo) != PCI_CHIP_845_G &&
        DEVICE_ID(pI830->PciInfo) != PCI_CHIP_I830_M) {
       I830SetParam(pScrn, I830_SETPARAM_USE_MI_BATCHBUFFER_START, 1 );
@@ -1639,17 +1531,24 @@ I830DRIClipNotify(ScreenPtr pScreen, Win
 #endif /* DRI_SUPPORTS_CLIP_NOTIFY */
 
 /**
- * Update the SAREA fields with the most recent values.
- * This gets called after the screen orientation/rotation changes.
+ * Update the SAREA fields with current buffer information.
+ *
+ * Most of the SAREA fields are already updated by i830_do_addmap().
+ *
+ * This does include other SAREA initialization which will actually be constant
+ * over the lifetime of the server.
  */
-Bool
-I830UpdateDRIBuffers(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
+static void
+i830_update_sarea(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
 {
-   I830Ptr pI830 = I830PTR(pScrn);
    ScreenPtr pScreen = pScrn->pScreen;
-   Bool success;
+   I830Ptr pI830 = I830PTR(pScrn);
 
-   I830DRIUnmapScreenRegions(pScrn, sarea);
+   sarea->width = pScreen->width;
+   sarea->height = pScreen->height;
+   sarea->pitch = pScrn->displayWidth;
+   sarea->virtualX = pScrn->virtualX;
+   sarea->virtualY = pScrn->virtualY;
 
    sarea->front_tiled = (pI830->front_buffer->tiling != TILE_NONE);
    sarea->back_tiled = (pI830->back_buffer->tiling != TILE_NONE);
@@ -1660,42 +1559,7 @@ I830UpdateDRIBuffers(ScrnInfoPtr pScrn, 
    sarea->depth_tiled = (pI830->depth_buffer->tiling != TILE_NONE);
    sarea->rotated_tiled = FALSE;
 
-   sarea->front_offset = pI830->front_buffer->offset;
-   /* Don't use front_buffer->size here as it includes the pixmap cache area
-    * Instead, calculate the entire framebuffer.
-    */
-   sarea->front_size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY *
-				     pI830->cpp);
-
-   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-              "[drm] init sarea width,height = %d x %d (pitch %d)\n",
-              pScreen->width, pScreen->height,pScrn->displayWidth);
-
-   sarea->width = pScreen->width;
-   sarea->height = pScreen->height;
-   sarea->back_offset = pI830->back_buffer->offset;
-   sarea->back_size = pI830->back_buffer->size;
-   if (pI830->third_buffer != NULL) {
-      sarea->third_offset = pI830->third_buffer->offset;
-      sarea->third_size = pI830->third_buffer->size;
-   } else {
-      sarea->third_offset = 0;
-      sarea->third_size = 0;
-   }
-
-   sarea->depth_offset = pI830->depth_buffer->offset;
-   sarea->depth_size = pI830->depth_buffer->size;
-   if (pI830->textures != NULL) {
-      sarea->tex_offset = pI830->textures->offset;
-      sarea->tex_size = pI830->textures->size;
-   } else {
-      sarea->tex_offset = 0;
-      sarea->tex_size = 0;
-   }
    sarea->log_tex_granularity = pI830->TexGranularity;
-   sarea->pitch = pScrn->displayWidth;
-   sarea->virtualX = pScrn->virtualX;
-   sarea->virtualY = pScrn->virtualY;
 
    sarea->front_bo_handle = -1;
    sarea->back_bo_handle = -1;
@@ -1719,13 +1583,149 @@ I830UpdateDRIBuffers(ScrnInfoPtr pScrn, 
    sarea->rotated_offset = -1;
    sarea->rotated_size = 0;
    sarea->rotated_pitch = pScrn->displayWidth;
+}
+
+/**
+ * Updates the DRI mapping for the given i830_memory struct, with the given
+ * flags.
+ */
+static int
+i830_do_addmap(ScrnInfoPtr pScrn, i830_memory *mem,
+	       drm_handle_t *sarea_handle, int *sarea_size, int *sarea_offset)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    int size = mem->size;
+
+    if (mem == pI830->front_buffer) {
+	/* Workaround for XAA pixmap cache: Don't use front_buffer->size
+	 * and instead, calculate the visible frontbuffer size and round to
+	 * avoid irritating the assertions of older DRI drivers.
+	 */
+	size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY *
+			     pI830->cpp);
+    }
+
+    if (*sarea_handle != 0 &&
+	(*sarea_size != size || *sarea_offset != mem->offset))
+    {
+	drmRmMap(pI830->drmSubFD, *sarea_handle);
+	*sarea_handle = 0;
+	*sarea_size = 0;
+	*sarea_offset = 0;
+    }
+
+    if (*sarea_handle == 0) {
+	int ret;
+
+	ret = drmAddMap(pI830->drmSubFD,
+			(drm_handle_t)(mem->offset + pI830->LinearAddr),
+			size, DRM_AGP, 0,
+			(drmAddress) sarea_handle);
+	if (ret == 0) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "[drm] mapped %s at 0x%08lx, handle = 0x%08x\n",
+		       mem->name, mem->offset + pI830->LinearAddr,
+		       (int)*sarea_handle);
+	    *sarea_size = size;
+	    *sarea_offset = mem->offset;
+	} else {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "[drm] failed to map %s at 0x%08lx\n",
+		       mem->name, mem->offset + pI830->LinearAddr);
+	    return FALSE;
+	}
+    }
 
-   success = I830DRIMapScreenRegions(pScrn, sarea);
+    return TRUE;
+}
 
-   if (success && pI830->allocate_classic_textures)
-      I830InitTextureHeap(pScrn, sarea);
+/**
+ * Updates the DRM mappings with the current buffer information.
+ *
+ * Some old DRI drivers may be unprepared for buffers actually moving at
+ * runtime, which would likely result in bus errors on software fallbacks or
+ * hangs or misrendering on hardware rendering.
+ */
+static Bool
+i830_update_dri_mappings(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
+{
+   I830Ptr pI830 = I830PTR(pScrn);
 
-   return success;
+   if (!i830_do_addmap(pScrn, pI830->front_buffer, &sarea->front_handle,
+		       &sarea->front_size, &sarea->front_offset)) {
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n");
+       return FALSE;
+   }
+
+   if (!i830_do_addmap(pScrn, pI830->back_buffer, &sarea->back_handle,
+		       &sarea->back_size, &sarea->back_offset)) {
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n");
+       return FALSE;
+   }
+
+   if (pI830->third_buffer) {
+       if (!i830_do_addmap(pScrn, pI830->third_buffer, &sarea->third_handle,
+			   &sarea->third_size, &sarea->third_offset)) {
+	   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n");
+	   return FALSE;
+       }
+   } else {
+       sarea->third_handle = 0;
+       sarea->third_offset = 0;
+       sarea->third_size = 0;
+   }
+
+   if (!i830_do_addmap(pScrn, pI830->depth_buffer, &sarea->depth_handle,
+		       &sarea->depth_size, &sarea->depth_offset)) {
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n");
+       return FALSE;
+   }
+
+   if (pI830->allocate_classic_textures) {
+       if (!i830_do_addmap(pScrn, pI830->textures, &sarea->tex_handle,
+			   &sarea->tex_size, &sarea->tex_offset)) {
+	   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n");
+	   return FALSE;
+       }
+   }
+
+   return TRUE;
+}
+
+static void
+i830_update_screen_private(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
+{
+   I830Ptr pI830 = I830PTR(pScrn);
+
+   pI830->pDRIInfo->frameBufferPhysicalAddress = (char *) pI830->LinearAddr;
+   pI830->pDRIInfo->frameBufferStride = pScrn->displayWidth * pI830->cpp;
+   pI830->pDRIInfo->frameBufferSize = sarea->front_size;
+#if DRI_DRIVER_FRAMEBUFFER_MAP
+   pI830->pDRIInfo->hFrameBuffer = sarea->front_handle;
+#endif
+}
+
+/**
+ * Update the SAREA fields, DRI mappings, and screen info passed through the
+ * protocol.
+ *
+ * This gets called both at startup and after any of the buffers might have
+ * been relocated.
+ */
+Bool
+i830_update_dri_buffers(ScrnInfoPtr pScrn)
+{
+   ScreenPtr pScreen = pScrn->pScreen;
+   drmI830Sarea *sarea = (drmI830Sarea *) DRIGetSAREAPrivate(pScreen);
+   Bool success;
+
+   success = i830_update_dri_mappings(pScrn, sarea);
+   if (!success)
+       return FALSE;
+   i830_update_sarea(pScrn, sarea);
+   i830_update_screen_private(pScrn, sarea);
+
+   return TRUE;
 }
 
 Bool
diff --git a/src/i830_driver.c b/src/i830_driver.c
index b3edb61..d24c408 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3018,6 +3018,17 @@ I830EnterVT(int scrnIndex, int flags)
 
    pI830->leaving = FALSE;
 
+#ifdef XF86DRI_MM
+   if (pI830->directRenderingEnabled) {
+      /* Unlock the memory manager first of all so that we can pin our
+       * buffer objects
+       */
+      if (pI830->memory_manager != NULL) {
+	 drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT);
+      }
+   }
+#endif /* XF86DRI_MM */
+
    if (I830IsPrimary(pScrn))
       if (!i830_bind_all_memory(pScrn))
          return FALSE;
@@ -3077,11 +3088,11 @@ I830EnterVT(int scrnIndex, int flags)
 	 for(i = 0; i < I830_NR_TEX_REGIONS+1 ; i++)
 	    sarea->texList[i].age = sarea->texAge;
 
-#ifdef XF86DRI_MM
-	 if (pI830->memory_manager != NULL) {
-	    drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT);
-	 }
-#endif /* XF86DRI_MM */
+	 /* Update buffer offsets in sarea and mappings, since buffer offsets
+	  * may have changed.
+	  */
+	 if (!i830_update_dri_buffers(pScrn))
+	    FatalError("i830_update_dri_buffers() failed\n");
 
 	 DPRINTF(PFX, "calling dri unlock\n");
 	 DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
diff-tree f393a12d21eed668cf4771f022beded9a4c547c7 (from 8fc4e3078210f726c7c375faa2f2fd8d05017c09)
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Oct 4 13:03:14 2007 -0700

    Move drmMMLock to after we have unbound our (pinned) buffers.
    
    There are still issues due to the fact that we're allocating
    NEED_LIFETIME_FIXED memory as buffer objects, which we refuse to unpin because
    we have no way of pinning it back in the same location.

diff --git a/src/i830_driver.c b/src/i830_driver.c
index ce84bce..b3edb61 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -2959,13 +2959,8 @@ I830LeaveVT(int scrnIndex, int flags)
 #ifdef XF86DRI
    if (pI830->directRenderingOpen) {
       DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
-#ifdef XF86DRI_MM
-      if (pI830->memory_manager != NULL) {
-	 drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT);
-      }
-#endif /* XF86DRI_MM */
+
       I830DRISetVBlankInterrupt (pScrn, FALSE);
-      
       drmCtlUninstHandler(pI830->drmSubFD);
    }
 #endif
@@ -2983,6 +2978,18 @@ I830LeaveVT(int scrnIndex, int flags)
 
    if (I830IsPrimary(pScrn))
       i830_unbind_all_memory(pScrn);
+
+   /* Tell the kernel to evict all buffer objects and block new buffer
+    * allocations until we relese the lock.
+    */
+#ifdef XF86DRI_MM
+   if (pI830->directRenderingOpen) {
+      if (pI830->memory_manager != NULL) {
+	 drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT);
+      }
+   }
+#endif /* XF86DRI_MM */
+
    if (pI830->AccelInfoRec)
       pI830->AccelInfoRec->NeedToSync = FALSE;
 }
diff-tree 8fc4e3078210f726c7c375faa2f2fd8d05017c09 (from 0de747f7d219a56434dad49a8a6d1d9d4c251ca7)
Author: Eric Anholt <eric at anholt.net>
Date:   Fri Oct 5 11:51:55 2007 -0700

    Refuse to allocate LIFETIME_FIXED objects in buffer objects.
    
    We can't guarantee the offset will stay the same using the current DRM
    interface, but the correct solution is fixing our code to allow these objects
    to move.  Breaks TTM mode of the DRI driver for now.

diff --git a/src/i830_memory.c b/src/i830_memory.c
index 85a78f5..2ff1a0c 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -758,7 +758,9 @@ i830_allocate_memory(ScrnInfoPtr pScrn, 
     I830Ptr pI830 = I830PTR(pScrn);
     i830_memory *mem;
 
-    if (pI830->memory_manager && !(flags & NEED_PHYSICAL_ADDR)) {
+    if (pI830->memory_manager && !(flags & NEED_PHYSICAL_ADDR) &&
+	!(flags & NEED_LIFETIME_FIXED))
+    {
 	return i830_allocate_memory_bo(pScrn, name, size, alignment, flags);
     } else {
 	mem = i830_allocate_aperture(pScrn, name, size, alignment, flags);
diff-tree 0de747f7d219a56434dad49a8a6d1d9d4c251ca7 (from 0040bb95445e800af80ca9fa1b92f5db33f1b4ac)
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Oct 11 10:36:01 2007 -0700

    In i830_allocate_memory_bo, bind if we control the VT, not on lifetime-fixed.

diff --git a/src/i830_memory.c b/src/i830_memory.c
index cdb7c47..85a78f5 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -709,14 +709,17 @@ i830_allocate_memory_bo(ScrnInfoPtr pScr
     mem->offset = -1;
     mem->end = -1;
     mem->size = size;
-    if (flags & NEED_LIFETIME_FIXED) {
+    if (flags & NEED_LIFETIME_FIXED)
+	mem->lifetime_fixed_offset = TRUE;
+
+    /* Bind it if we currently control the VT */
+    if (pScrn->vtSema) {
 	if (!i830_bind_memory(pScrn, mem)) {
 	    drmBOUnReference(pI830->drmSubFD, &mem->bo);
 	    xfree(mem->name);
 	    xfree(mem);
 	    return NULL;
 	}
-	mem->lifetime_fixed_offset = TRUE;
     }
 
     /* Insert new allocation into the list */
diff-tree 0040bb95445e800af80ca9fa1b92f5db33f1b4ac (from 56ae767180da4a8bd4b7a4c35b92e019ab67d753)
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Oct 10 16:48:12 2007 -0700

    Fix potential use-after-free in XV overlay code on video stop.

diff --git a/src/i830_video.c b/src/i830_video.c
index beec03e..8c2d804 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -1016,6 +1016,7 @@ I830StopVideo(ScrnInfoPtr pScrn, pointer
 	 */
 	I830Sync(pScrn);
 	i830_free_memory(pScrn, pPriv->buf);
+	pPriv->buf = NULL;
 	pPriv->videoStatus = 0;
     } else {
 	if (pPriv->videoStatus & CLIENT_VIDEO_ON) {


More information about the xorg-commit mailing list