summaryrefslogtreecommitdiff
path: root/src/i830_memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i830_memory.c')
-rw-r--r--src/i830_memory.c1458
1 files changed, 1458 insertions, 0 deletions
diff --git a/src/i830_memory.c b/src/i830_memory.c
new file mode 100644
index 00000000..16693d4a
--- /dev/null
+++ b/src/i830_memory.c
@@ -0,0 +1,1458 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_memory.c,v 1.6 2003/02/08 02:26:56 dawes Exp $ */
+/**************************************************************************
+
+Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+Copyright © 2002 by David Dawes.
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Reformatted with GNU indent (2.2.8), using the following options:
+ *
+ * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78
+ * -lp -npcs -psl -sob -ss -br -ce -sc -hnl
+ *
+ * This provides a good match with the original i810 code and preferred
+ * XFree86 formatting conventions.
+ *
+ * When editing this driver, please follow the existing formatting, and edit
+ * with <TAB> characters expanded at 8-column intervals.
+ */
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * David Dawes <dawes@tungstengraphics.com>
+ *
+ */
+
+#include "xf86.h"
+#include "xf86_ansic.h"
+#include "xf86_OSproc.h"
+
+#include "i830.h"
+#include "i810_reg.h"
+
+/*
+ * Allocate memory from the given pool. Grow the pool if needed and if
+ * possible.
+ */
+static unsigned long
+AllocFromPool(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool,
+ unsigned long size, unsigned long alignment, int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long needed, start, end;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+
+ if (!result || !pool || !size)
+ return 0;
+
+ /* Calculate how much space is needed. */
+ if (alignment <= GTT_PAGE_SIZE)
+ needed = size;
+ else {
+ if (flags & ALLOCATE_AT_BOTTOM) {
+ start = ROUND_TO(pool->Free.Start, alignment);
+ if (flags & ALIGN_BOTH_ENDS)
+ end = ROUND_TO(start + size, alignment);
+ else
+ end = start + size;
+ needed = end - pool->Free.Start;
+ } else { /* allocate at top */
+ if (flags & ALIGN_BOTH_ENDS)
+ end = ROUND_DOWN_TO(pool->Free.End, alignment);
+ else
+ end = pool->Free.End;
+
+ start = ROUND_DOWN_TO(end - size, alignment);
+ needed = pool->Free.End - start;
+ }
+ }
+ if (needed > pool->Free.Size) {
+ unsigned long extra;
+ /* See if the pool can be grown. */
+ if (pI830->StolenOnly && !dryrun)
+ return 0;
+ extra = needed - pool->Free.Size;
+ extra = ROUND_TO_PAGE(extra);
+ if (extra > pI830->FreeMemory) {
+ if (dryrun)
+ pI830->FreeMemory = extra;
+ else
+ return 0;
+ }
+
+ if (!dryrun && (extra > pI830->MemoryAperture.Size))
+ return 0;
+
+ pool->Free.Size += extra;
+ pool->Free.End += extra;
+ pool->Total.Size += extra;
+ pool->Total.End += extra;
+ pI830->FreeMemory -= extra;
+ pI830->MemoryAperture.Start += extra;
+ pI830->MemoryAperture.Size -= extra;
+ }
+ if (flags & ALLOCATE_AT_BOTTOM) {
+ result->Start = ROUND_TO(pool->Free.Start, alignment);
+ pool->Free.Start += needed;
+ result->End = pool->Free.Start;
+ } else {
+ result->Start = ROUND_DOWN_TO(pool->Free.End - size, alignment) -
+ pool->Total.End;
+ result->End = pool->Free.End - pool->Total.End;
+ pool->Free.End -= needed;
+ }
+ pool->Free.Size = pool->Free.End - pool->Free.Start;
+ result->Size = result->End - result->Start;
+ result->Pool = pool;
+ result->Alignment = alignment;
+ return needed;
+}
+
+static unsigned long
+AllocFromAGP(ScrnInfoPtr pScrn, I830MemRange *result, unsigned long size,
+ unsigned long alignment, int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long start, end;
+ unsigned long newApStart, newApEnd;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+
+ if (!result || !size)
+ return 0;
+
+ if ((flags & ALLOCATE_AT_BOTTOM) && pI830->StolenMemory.Size != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "AllocFromAGP(): can't allocate from "
+ "bottom when there is stolen memory\n");
+ return 0;
+ }
+
+ if (size > pI830->FreeMemory) {
+ if (dryrun)
+ pI830->FreeMemory = size;
+ else
+ return 0;
+ }
+
+ /* Calculate offset */
+ if (flags & ALLOCATE_AT_BOTTOM) {
+ start = ROUND_TO(pI830->MemoryAperture.Start, alignment);
+ if (flags & ALIGN_BOTH_ENDS)
+ end = ROUND_TO(start + size, alignment);
+ else
+ end = start + size;
+ newApStart = end;
+ newApEnd = pI830->MemoryAperture.End;
+ } else {
+ if (flags & ALIGN_BOTH_ENDS)
+ end = ROUND_DOWN_TO(pI830->MemoryAperture.End, alignment);
+ else
+ end = pI830->MemoryAperture.End;
+ start = ROUND_DOWN_TO(end - size, alignment);
+ newApStart = pI830->MemoryAperture.Start;
+ newApEnd = start;
+ }
+
+ if (!dryrun) {
+ if (newApStart > newApEnd)
+ return 0;
+
+ if (flags & NEED_PHYSICAL_ADDR) {
+ result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2,
+ &(result->Physical));
+ } else {
+ result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL);
+ }
+ if (result->Key == -1)
+ return 0;
+ }
+
+ pI830->allocatedMemory += size;
+ pI830->MemoryAperture.Start = newApStart;
+ pI830->MemoryAperture.End = newApEnd;
+ pI830->MemoryAperture.Size = newApEnd - newApStart;
+ pI830->FreeMemory -= size;
+ result->Start = start;
+ result->End = start + size;
+ result->Size = size;
+ result->Offset = start;
+ result->Alignment = alignment;
+ result->Pool = NULL;
+
+ return size;
+}
+
+
+unsigned long
+I830AllocVidMem(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool,
+ unsigned long size, unsigned long alignment, int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+
+ if (!result)
+ return 0;
+
+ /* Make sure these are initialised. */
+ result->Size = 0;
+ result->Key = -1;
+
+ if (!size) {
+ return 0;
+ }
+
+ switch (flags & FROM_MASK) {
+ case FROM_POOL_ONLY:
+ return AllocFromPool(pScrn, result, pool, size, alignment, flags);
+ case FROM_NEW_ONLY:
+ if (!dryrun && (pI830->StolenOnly || (pI830->FreeMemory <= 0)))
+ return 0;
+ return AllocFromAGP(pScrn, result, size, alignment, flags);
+ case FROM_ANYWHERE:
+ if ((!(flags & ALLOCATE_AT_BOTTOM) && (pI830->FreeMemory >= size)) ||
+ (flags & NEED_PHYSICAL_ADDR))
+ return AllocFromAGP(pScrn, result, size, alignment, flags);
+ else
+ return AllocFromPool(pScrn, result, pool, size, alignment, flags);
+ default:
+ /* Shouldn't happen. */
+ return 0;
+ }
+}
+
+static Bool
+AllocateRingBuffer(ScrnInfoPtr pScrn, int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long size, alloced;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+ int verbosity = dryrun ? 4 : 1;
+ const char *s = dryrun ? "[dryrun] " : "";
+
+ /* Clear ring buffer info */
+ memset(&(pI830->LpRing), 0, sizeof(pI830->LpRing));
+ pI830->LpRing.mem.Key = -1;
+
+ if (pI830->noAccel)
+ return TRUE;
+
+ /* Ring buffer */
+ size = PRIMARY_RINGBUFFER_SIZE;
+ if (flags & FORCE_LOW)
+ flags |= FROM_POOL_ONLY | ALLOCATE_AT_BOTTOM;
+ else
+ flags |= FROM_ANYWHERE | ALLOCATE_AT_TOP;
+
+ alloced = I830AllocVidMem(pScrn, &(pI830->LpRing.mem),
+ &(pI830->StolenPool), size,
+ GTT_PAGE_SIZE, flags);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate Ring Buffer space\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the ring buffer at 0x%x\n", s,
+ alloced / 1024, pI830->LpRing.mem.Start);
+ pI830->LpRing.tail_mask = pI830->LpRing.mem.Size - 1;
+ return TRUE;
+}
+
+#ifdef I830_XV
+/*
+ * Note, the FORCE_LOW flag is currently not used or supported.
+ */
+static Bool
+AllocateOverlay(ScrnInfoPtr pScrn, int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long size, alloced;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+ int verbosity = dryrun ? 4 : 1;
+ const char *s = dryrun ? "[dryrun] " : "";
+
+ /* Clear overlay info */
+ memset(&(pI830->OverlayMem), 0, sizeof(pI830->OverlayMem));
+ pI830->OverlayMem.Key = -1;
+
+ if (!pI830->XvEnabled)
+ return TRUE;
+
+ /*
+ * The overlay register space needs a physical address in
+ * system memory. We get this from the agpgart module using
+ * a special memory type.
+ */
+
+ size = OVERLAY_SIZE;
+ if (flags & FORCE_LOW)
+ flags |= FROM_POOL_ONLY | ALLOCATE_AT_BOTTOM | NEED_PHYSICAL_ADDR;
+ else
+ flags |= FROM_ANYWHERE | ALLOCATE_AT_TOP | NEED_PHYSICAL_ADDR;
+
+ alloced = I830AllocVidMem(pScrn, &(pI830->OverlayMem),
+ &(pI830->StolenPool), size, GTT_PAGE_SIZE, flags);
+
+ /*
+ * XXX For testing only. Don't enable this unless you know how to set
+ * physBase.
+ */
+ if (flags & FORCE_LOW) {
+ ErrorF("AllocateOverlay() doesn't support setting FORCE_LOW\n");
+ return FALSE;
+ }
+
+ if (!dryrun && (alloced < size)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate Overlay register space.\n");
+ /* This failure isn't fatal. */
+ } else {
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for Overlay registers at 0x%x "
+ "(0x%08x).\n", s,
+ alloced / 1024, pI830->OverlayMem.Start,
+ pI830->OverlayMem.Physical);
+ }
+ return TRUE;
+}
+#endif
+
+static unsigned long
+GetFreeSpace(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long extra = 0;
+
+ /* First check for free space in StolenPool. */
+ if (pI830->StolenPool.Free.Size > 0)
+ extra = pI830->StolenPool.Free.Size;
+ /* Next check for unallocated space. */
+ if (pI830->FreeMemory > 0)
+ extra += pI830->FreeMemory;
+
+ return extra;
+}
+
+static Bool
+IsTileable(int pitch)
+{
+ /*
+ * Allow tiling for pitches that are a power of 2 multiple of 128 bytes,
+ * up to 64 * 128 (= 8192) bytes.
+ */
+ switch (pitch) {
+ case 128 * 1:
+ case 128 * 2:
+ case 128 * 4:
+ case 128 * 8:
+ case 128 * 16:
+ case 128 * 32:
+ case 128 * 64:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+ * Allocate memory for 2D operation. This includes the (front) framebuffer,
+ * ring buffer, scratch memory, HW cursor.
+ */
+
+Bool
+I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long size, alloced;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+ int verbosity = dryrun ? 4 : 1;
+ const char *s = dryrun ? "[dryrun] " : "";
+ Bool tileable;
+ int align, alignflags;
+
+ DPRINTF(PFX, "I830Allocate2DMemory: inital is %s\n",
+ BOOLTOSTRING(flags & ALLOC_INITIAL));
+
+ if (!pI830->StolenOnly &&
+ (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex))) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "AGP GART support is either not available or cannot "
+ "be used.\n"
+ "\tMake sure your kernel has agpgart support or has the\n"
+ "\tagpgart module loaded.\n");
+ }
+ return FALSE;
+ }
+
+
+ /*
+ * The I830 is slightly different from the I830/I815, it has no
+ * dcache and it has stolen memory by default in its gtt. All
+ * additional memory must go after it.
+ */
+
+ DPRINTF(PFX,
+ "size == %luk (%lu bytes == pScrn->videoRam)\n"
+ "pI830->StolenSize == %luk (%lu bytes)\n",
+ pScrn->videoRam, pScrn->videoRam * 1024,
+ pI830->StolenPool.Free.Size / 1024,
+ pI830->StolenPool.Free.Size);
+
+ if (flags & ALLOC_INITIAL) {
+ unsigned long minspace, avail, lineSize;
+ int cacheLines, maxCacheLines;
+
+ if (pI830->NeedRingBufferLow)
+ AllocateRingBuffer(pScrn, flags | FORCE_LOW);
+
+ /* Clear everything first. */
+ memset(&(pI830->FbMemBox), 0, sizeof(pI830->FbMemBox));
+ memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer));
+ pI830->FrontBuffer.Key = -1;
+
+ pI830->FbMemBox.x1 = 0;
+ pI830->FbMemBox.x2 = pScrn->displayWidth;
+ pI830->FbMemBox.y1 = 0;
+ pI830->FbMemBox.y2 = pScrn->virtualY;
+
+ /*
+ * Calculate how much framebuffer memory to allocate. For the
+ * initial allocation, calculate a reasonable minimum. This is
+ * enough for the virtual screen size, plus some pixmap cache
+ * space.
+ */
+
+ lineSize = pScrn->displayWidth * pI830->cpp;
+ minspace = lineSize * pScrn->virtualY;
+ avail = pScrn->videoRam * 1024;
+ maxCacheLines = (avail - minspace) / lineSize;
+ /* This shouldn't happen. */
+ if (maxCacheLines < 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal Error: "
+ "maxCacheLines < 0 in I830Allocate2DMemory()\n");
+ maxCacheLines = 0;
+ }
+ if (maxCacheLines > (MAX_DISPLAY_HEIGHT - pScrn->virtualY))
+ maxCacheLines = MAX_DISPLAY_HEIGHT - pScrn->virtualY;
+
+ if (pI830->CacheLines >= 0) {
+ cacheLines = pI830->CacheLines;
+ } else {
+#if 1
+ /* Make sure there is enough for two DVD sized YUV buffers */
+ cacheLines = (pScrn->depth == 24) ? 256 : 384;
+ if (pScrn->displayWidth <= 1024)
+ cacheLines *= 2;
+#else
+ /*
+ * Make sure there is enough for two DVD sized YUV buffers.
+ * Make that 1.5MB, which is around what was allocated with
+ * the old algorithm
+ */
+ cacheLines = (MB(1) + KB(512)) / pI830->cpp / pScrn->displayWidth;
+#endif
+ }
+ if (cacheLines > maxCacheLines)
+ cacheLines = maxCacheLines;
+
+ pI830->FbMemBox.y2 += cacheLines;
+
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocating at least %d scanlines for pixmap cache\n",
+ s, cacheLines);
+
+ tileable = !(flags & ALLOC_NO_TILING) && pI830->allowPageFlip &&
+ IsTileable(pScrn->displayWidth * pI830->cpp);
+ if (tileable) {
+ align = KB(512);
+ alignflags = ALIGN_BOTH_ENDS;
+ } else {
+ align = KB(64);
+ alignflags = 0;
+ }
+
+ size = lineSize * (pScrn->virtualY + cacheLines);
+ size = ROUND_TO_PAGE(size);
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sInitial framebuffer allocation size: %d kByte\n", s,
+ size / 1024);
+ alloced = I830AllocVidMem(pScrn, &(pI830->FrontBuffer),
+ &(pI830->StolenPool), size, align,
+ flags | alignflags |
+ FROM_ANYWHERE | ALLOCATE_AT_BOTTOM);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate framebuffer.\n");
+ }
+ return FALSE;
+ }
+ } else {
+ unsigned long lineSize;
+ unsigned long extra = 0;
+ unsigned long maxFb = 0;
+
+ /*
+ * XXX Need to "free" up any 3D allocations if the DRI ended up
+ * and make them available for 2D. The best way to do this would
+ * be position all of those regions contiguously at the end of the
+ * StolenPool.
+ */
+ extra = GetFreeSpace(pScrn);
+
+ if (extra == 0)
+ return TRUE;
+
+ maxFb = pI830->FrontBuffer.Size + extra;
+ lineSize = pScrn->displayWidth * pI830->cpp;
+ maxFb = ROUND_DOWN_TO(maxFb, lineSize);
+ if (maxFb > lineSize * MAX_DISPLAY_HEIGHT)
+ maxFb = lineSize * MAX_DISPLAY_HEIGHT;
+ if (maxFb > pI830->FrontBuffer.Size) {
+ unsigned long oldsize;
+ /*
+ * Sanity check -- the fb should be the last thing allocated at
+ * the bottom of the stolen pool.
+ */
+ if (pI830->StolenPool.Free.Start != pI830->FrontBuffer.End) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal error in I830Allocate2DMemory():\n\t"
+ "Framebuffer isn't the last allocation at the bottom"
+ " of StolenPool\n\t(%x != %x).\n",
+ pI830->FrontBuffer.End,
+ pI830->StolenPool.Free.Start);
+ return FALSE;
+ }
+ /*
+ * XXX Maybe should have a "Free" function. This should be
+ * the only place where a region is resized, and we know that
+ * the fb is always at the bottom of the aperture/stolen pool,
+ * and is the only region that is allocated bottom-up.
+ * Allowing for more general realloction would require a smarter
+ * allocation system.
+ */
+ oldsize = pI830->FrontBuffer.Size;
+ pI830->StolenPool.Free.Size += pI830->FrontBuffer.Size;
+ pI830->StolenPool.Free.Start -= pI830->FrontBuffer.Size;
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sUpdated framebuffer allocation size from %d "
+ "to %d kByte\n", s, oldsize / 1024, maxFb / 1024);
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sUpdated pixmap cache from %d scanlines to %d "
+ "scanlines\n", s,
+ oldsize / lineSize - pScrn->virtualY,
+ maxFb / lineSize - pScrn->virtualY);
+ pI830->FbMemBox.y2 = maxFb / lineSize;
+ tileable = !(flags & ALLOC_NO_TILING) && pI830->allowPageFlip &&
+ IsTileable(pScrn->displayWidth * pI830->cpp);
+ if (tileable) {
+ align = KB(512);
+ alignflags = ALIGN_BOTH_ENDS;
+ } else {
+ align = KB(64);
+ alignflags = 0;
+ }
+ alloced = I830AllocVidMem(pScrn, &(pI830->FrontBuffer),
+ &(pI830->StolenPool), maxFb, align,
+ flags | alignflags |
+ FROM_ANYWHERE | ALLOCATE_AT_BOTTOM);
+ if (alloced < maxFb) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to re-allocate framebuffer\n");
+ }
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+#if REMAP_RESERVED
+ /*
+ * Allocate a dummy page to pass when attempting to rebind the
+ * pre-allocated region.
+ */
+ if (!dryrun) {
+ memset(&(pI830->Dummy), 0, sizeof(pI830->Dummy));
+ pI830->Dummy.Key =
+ xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL);
+ pI830->Dummy.Offset = 0;
+ }
+#endif
+
+ /* Clear cursor info */
+ memset(&(pI830->CursorMem), 0, sizeof(pI830->CursorMem));
+ pI830->CursorMem.Key = -1;
+
+ if (!pI830->SWCursor) {
+ int cursFlags = 0;
+ /*
+ * Mouse cursor -- The i810-i830 need a physical address in system
+ * memory from which to upload the cursor. We get this from
+ * the agpgart module using a special memory type.
+ */
+
+ size = HWCURSOR_SIZE;
+ cursFlags = FROM_ANYWHERE | ALLOCATE_AT_TOP;
+ if (pI830->CursorNeedsPhysical)
+ cursFlags |= NEED_PHYSICAL_ADDR;
+
+ alloced = I830AllocVidMem(pScrn, &(pI830->CursorMem),
+ &(pI830->StolenPool), size,
+ GTT_PAGE_SIZE, flags | cursFlags);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate HW cursor space.\n");
+ }
+ } else {
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for HW cursor at 0x%x", s,
+ alloced / 1024, pI830->CursorMem.Start);
+ if (pI830->CursorNeedsPhysical)
+ xf86ErrorFVerb(verbosity, " (0x%08x)", pI830->CursorMem.Physical);
+ xf86ErrorFVerb(verbosity, "\n");
+ }
+ }
+
+#ifdef I830_XV
+ AllocateOverlay(pScrn, flags);
+#endif
+
+ if (!pI830->NeedRingBufferLow)
+ AllocateRingBuffer(pScrn, flags);
+
+ /* Clear scratch info */
+ memset(&(pI830->Scratch), 0, sizeof(pI830->Scratch));
+ pI830->Scratch.Key = -1;
+
+ if (!pI830->noAccel) {
+ size = MAX_SCRATCH_BUFFER_SIZE;
+ alloced = I830AllocVidMem(pScrn, &(pI830->Scratch), &(pI830->StolenPool),
+ size, GTT_PAGE_SIZE,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ if (alloced < size) {
+ size = MIN_SCRATCH_BUFFER_SIZE;
+ alloced = I830AllocVidMem(pScrn, &(pI830->Scratch),
+ &(pI830->StolenPool), size,
+ GTT_PAGE_SIZE,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ }
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate scratch buffer space\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the scratch buffer at 0x%x\n", s,
+ alloced / 1024, pI830->Scratch.Start);
+ }
+ return TRUE;
+}
+
+#ifndef ALLOCATE_ALL_BIOSMEM
+#define ALLOCATE_ALL_BIOSMEM 1
+#endif
+
+void
+I830ResetAllocations(ScrnInfoPtr pScrn, const int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ pI830->MemoryAperture.Start = pI830->StolenMemory.End;
+ pI830->MemoryAperture.End = pI830->FbMapSize;
+ pI830->MemoryAperture.Size = pI830->FbMapSize - pI830->StolenMemory.Size;
+ pI830->StolenPool.Fixed = pI830->StolenMemory;
+ pI830->StolenPool.Total = pI830->StolenMemory;
+#if ALLOCATE_ALL_BIOSMEM
+ if (pI830->overrideBIOSMemSize &&
+ pI830->BIOSMemorySize > pI830->StolenMemory.Size) {
+ pI830->StolenPool.Total.End = pI830->BIOSMemorySize;
+ pI830->StolenPool.Total.Size = pI830->BIOSMemorySize;
+ }
+#endif
+ pI830->StolenPool.Free = pI830->StolenPool.Total;
+ pI830->FreeMemory = pI830->TotalVideoRam - pI830->StolenPool.Total.Size;
+ pI830->allocatedMemory = 0;
+}
+
+long
+I830GetExcessMemoryAllocations(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long allocated;
+
+ allocated = pI830->StolenPool.Total.Size + pI830->allocatedMemory;
+ if (allocated > pI830->TotalVideoRam)
+ return allocated - pI830->TotalVideoRam;
+ else
+ return 0;
+}
+
+#ifdef XF86DRI
+static unsigned long
+GetBestTileAlignment(unsigned long size)
+{
+ unsigned long i;
+
+ for (i = KB(512); i < size; i <<= 1)
+ ;
+
+ if (i > MB(64))
+ i = MB(64);
+
+ return i;
+}
+
+static unsigned int
+myLog2(unsigned int n)
+{
+ unsigned int log2 = 1;
+
+ while (n > 1) {
+ n >>= 1;
+ log2++;
+ }
+ return log2;
+}
+
+Bool
+I830Allocate3DMemory(ScrnInfoPtr pScrn, const int flags)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ unsigned long size, alloced, align = 0;
+ int i;
+ Bool tileable;
+ Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0);
+ int verbosity = dryrun ? 4 : 1;
+ const char *s = dryrun ? "[dryrun] " : "";
+ int lines;
+
+ DPRINTF(PFX, "I830Allocate3DMemory\n");
+
+ /* Back Buffer */
+ memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer));
+ pI830->BackBuffer.Key = -1;
+ tileable = !(flags & ALLOC_NO_TILING) &&
+ IsTileable(pScrn->displayWidth * pI830->cpp);
+ if (tileable) {
+ /* Make the height a multiple of the tile height (16) */
+ lines = (pScrn->virtualY + 15) / 16 * 16;
+ } else {
+ lines = pScrn->virtualY;
+ }
+
+ size = ROUND_TO_PAGE(pScrn->displayWidth * lines * pI830->cpp);
+ /*
+ * Try to allocate on the best tile-friendly boundaries.
+ */
+ alloced = 0;
+ if (tileable) {
+ align = GetBestTileAlignment(size);
+ for (align = GetBestTileAlignment(size); align >= KB(512); align >>= 1) {
+ alloced = I830AllocVidMem(pScrn, &(pI830->BackBuffer),
+ &(pI830->StolenPool), size, align,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP |
+ ALIGN_BOTH_ENDS);
+ if (alloced >= size)
+ break;
+ }
+ }
+ if (alloced < size) {
+ /* Give up on trying to tile */
+ tileable = FALSE;
+ size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY * pI830->cpp);
+ align = GTT_PAGE_SIZE;
+ alloced = I830AllocVidMem(pScrn, &(pI830->BackBuffer),
+ &(pI830->StolenPool), size, align,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ }
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate back buffer space.\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the back buffer at 0x%x.\n", s,
+ alloced / 1024, pI830->BackBuffer.Start);
+
+ /* Depth Buffer -- same size as the back buffer */
+ memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer));
+ pI830->DepthBuffer.Key = -1;
+ /*
+ * Try to allocate on the best tile-friendly boundaries.
+ */
+ alloced = 0;
+ if (tileable) {
+ /* Start with the previous align value. */
+ for (; align >= KB(512); align >>= 1) {
+ alloced = I830AllocVidMem(pScrn, &(pI830->DepthBuffer),
+ &(pI830->StolenPool), size, align,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP |
+ ALIGN_BOTH_ENDS);
+ if (alloced >= size)
+ break;
+ }
+ }
+ if (alloced < size) {
+ /* Give up on trying to tile */
+ tileable = FALSE;
+ size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY * pI830->cpp);
+ align = GTT_PAGE_SIZE;
+ alloced = I830AllocVidMem(pScrn, &(pI830->DepthBuffer),
+ &(pI830->StolenPool), size, align,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ }
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate depth buffer space.\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the depth buffer at 0x%x.\n", s,
+ alloced / 1024, pI830->DepthBuffer.Start);
+
+ /* Space for logical context. 32k is fine for right now. */
+ memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem));
+ pI830->ContextMem.Key = -1;
+ size = KB(32);
+ alloced = I830AllocVidMem(pScrn, &(pI830->ContextMem),
+ &(pI830->StolenPool), size, GTT_PAGE_SIZE,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate logical context space.\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the logical context at 0x%x.\n", s,
+ alloced / 1024, pI830->ContextMem.Start);
+
+ /*
+ * Space for DMA buffers, only if there's enough free for at least 1MB
+ * of texture space.
+ */
+ memset(&(pI830->BufferMem), 0, sizeof(pI830->BufferMem));
+ pI830->BufferMem.Key = -1;
+ /* This should already be a page multiple */
+ size = I830_DMA_BUF_NR * I830_DMA_BUF_SZ;
+ if (dryrun || (GetFreeSpace(pScrn) >= size + MB(1))) {
+ alloced = I830AllocVidMem(pScrn, &(pI830->BufferMem),
+ &(pI830->StolenPool), size,
+ GTT_PAGE_SIZE,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate DMA buffer space.\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for the DMA buffers at 0x%x.\n", s,
+ alloced / 1024, pI830->BufferMem.Start);
+ } else {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Not enough free space for DMA buffers.\n");
+ }
+ return FALSE;
+ }
+
+ /* Allocate the remaining space for textures. */
+ memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem));
+ pI830->TexMem.Key = -1;
+ size = GetFreeSpace(pScrn);
+ if (dryrun && (size < MB(1)))
+ size = MB(1);
+ i = myLog2(size / I830_NR_TEX_REGIONS);
+ if (i < I830_LOG_MIN_TEX_REGION_SIZE)
+ i = I830_LOG_MIN_TEX_REGION_SIZE;
+ pI830->TexGranularity = i;
+ /* Truncate size */
+ size >>= i;
+ size <<= i;
+ if (size < KB(512)) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Less than %d kBytes for texture space.\n", size / 1024);
+ }
+ return FALSE;
+ }
+ alloced = I830AllocVidMem(pScrn, &(pI830->TexMem),
+ &(pI830->StolenPool), size, GTT_PAGE_SIZE,
+ flags | FROM_ANYWHERE | ALLOCATE_AT_TOP);
+ if (alloced < size) {
+ if (!dryrun) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to allocate texture space.\n");
+ }
+ return FALSE;
+ }
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity,
+ "%sAllocated %d kB for textures at 0x%x\n", s,
+ alloced / 1024, pI830->TexMem.Start);
+
+ return TRUE;
+}
+#endif
+
+/* Allocate pool space that isn't pre-allocated */
+Bool
+I830DoPoolAllocation(ScrnInfoPtr pScrn, I830MemPool *pool)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ DPRINTF(PFX, "I830DoPoolAllocation\n");
+
+ if (!pool)
+ return FALSE;
+
+ /*
+ * Sanity check: there shouldn't be an allocation required when
+ * there is only stolen memory.
+ */
+ if (pI830->StolenOnly && (pool->Total.Size > pool->Fixed.Size)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "I830DoPoolAllocation(): pool size is greater than the "
+ "preallocated size,\n\t"
+ "and there is no allocatable memory.\n");
+ return FALSE;
+ }
+
+ if (pool->Total.Size > pool->Fixed.Size) {
+ pool->Allocated.Size = pool->Total.Size - pool->Fixed.Size;
+ pool->Allocated.Key =
+ xf86AllocateGARTMemory(pScrn->scrnIndex, pool->Allocated.Size,
+ 0, NULL);
+ if (pool->Allocated.Key == -1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Pool allocation failed\n");
+ return FALSE;
+ }
+ pool->Allocated.Start = pool->Fixed.End;
+ pool->Allocated.End = pool->Total.Size;
+ pool->Allocated.Offset = pool->Allocated.Start;
+ } else
+ pool->Allocated.Key = -1;
+ return TRUE;
+}
+
+static unsigned long topOfMem = 0;
+
+/*
+ * These modify the way memory is positioned within the aperture.
+ *
+ * By default, memory allocated from the bottom or specifically within
+ * the pool at the bottom gets allocated from the "stolen pool", which is
+ * actually the stolen memory plus any extra allocated to make it a larger
+ * contiguous region. Memory allocated from the AGP is allocated top-down
+ * from the end of the aperture space. Memory allocated "from top" defaults
+ * to AGP if there is enough "free space". The total allocation (stolen +
+ * extra) doesn't exceed the orignal pScrn->videoRam amount (this isn't true
+ * when memory allocated from AGP gets moved into the pool by one of the
+ * following options.
+ *
+ * XXX Write a better description.
+ *
+ */
+#define PACK_RANGES 0
+#define POOL_RANGES 0
+
+static Bool
+FixOffset(ScrnInfoPtr pScrn, I830MemRange *mem)
+{
+#if POOL_RANGES
+ I830Ptr pI830 = I830PTR(pScrn);
+#endif
+
+ if (!mem)
+ return FALSE;
+
+ if (mem->Pool && mem->Key == -1 && mem->Start < 0) {
+ mem->Start = mem->Pool->Total.End + mem->Start;
+ mem->End = mem->Start + mem->Size;
+ }
+#if PACK_RANGES
+ /*
+ * Map AGP-allocated areas at the top of the stolen area, resulting in
+ * a contiguous region in the aperture. Normally most AGP-allocated areas
+ * will be at the top of the aperture, making alignment requirements
+ * easier to achieve. This optin is primarily for debugging purposes,
+ * and using this option can break any special alignment requirements.
+ */
+ if (!mem->Pool && mem->Start != 0 && mem->Key != -1 && mem->Physical == 0 &&
+ mem->Offset != 0) {
+ long diff;
+ if (mem->Offset != mem->Start)
+ ErrorF("mem %p, Offset != Start\n", mem);
+ diff = mem->Offset - topOfMem;
+ mem->Start -= diff;
+ mem->End -= diff;
+ mem->Offset -= diff;
+ topOfMem += mem->Size;
+ }
+#elif POOL_RANGES
+ /*
+ * Move AGP-allocated regions (that don't need a physical address) into
+ * the pre-allocated pool when there's enough space to do so. Note: the
+ * AGP-allocated areas aren't freed. This option is primarily for
+ * debugging purposes, and using it can break any special alignment
+ * requirements.
+ */
+ if (!mem->Pool && mem->Start >= pI830->StolenPool.Free.End &&
+ mem->Key != -1 && mem->Physical == 0 && mem->Offset != 0 &&
+ pI830->StolenPool.Free.Size >= mem->Size) {
+ long diff;
+ if (mem->Offset != mem->Start)
+ ErrorF("mem %p, Offset != Start\n", mem);
+ diff = mem->Offset - pI830->StolenPool.Free.Start;
+ mem->Start -= diff;
+ mem->End -= diff;
+ mem->Offset -= diff;
+ mem->Key = -1;
+ pI830->StolenPool.Free.Start += mem->Size;
+ pI830->StolenPool.Free.Size -= mem->Size;
+ }
+#endif
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "%p: Memory at offset 0x%08x, size %d kBytes\n", mem,
+ mem->Start, mem->Size / 1024);
+ return TRUE;
+}
+
+Bool
+I830FixupOffsets(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ DPRINTF(PFX, "I830FixupOffsets\n");
+
+ topOfMem = pI830->StolenPool.Total.End;
+ FixOffset(pScrn, &(pI830->FrontBuffer));
+ FixOffset(pScrn, &(pI830->CursorMem));
+ FixOffset(pScrn, &(pI830->LpRing.mem));
+ FixOffset(pScrn, &(pI830->Scratch));
+#ifdef I830_XV
+ if (pI830->XvEnabled) {
+ FixOffset(pScrn, &(pI830->OverlayMem));
+ }
+#endif
+#ifdef XF86DRI
+ if (pI830->directRenderingEnabled) {
+ FixOffset(pScrn, &(pI830->BackBuffer));
+ FixOffset(pScrn, &(pI830->DepthBuffer));
+ FixOffset(pScrn, &(pI830->ContextMem));
+ FixOffset(pScrn, &(pI830->BufferMem));
+ FixOffset(pScrn, &(pI830->TexMem));
+ }
+#endif
+ return TRUE;
+}
+
+#ifdef XF86DRI
+/* Tiled memory is good... really, really good...
+ *
+ * Need to make it less likely that we miss out on this - probably
+ * need to move the frontbuffer away from the 'guarenteed' alignment
+ * of the first memory segment, or perhaps allocate a discontigous
+ * framebuffer to get more alignment 'sweet spots'.
+ */
+static void
+SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch,
+ unsigned int size)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830RegPtr i830Reg = &pI830->ModeReg;
+ CARD32 val;
+ CARD32 fence_mask = 0;
+
+ DPRINTF(PFX, "SetFence: %d, 0x%08x, %d, %d kByte\n",
+ nr, start, pitch, size / 1024);
+
+ if (nr < 0 || nr > 7) {
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: fence %d out of range\n");
+ return;
+ }
+
+ i830Reg->Fence[nr] = 0;
+
+ fence_mask = ~I830_FENCE_START_MASK;
+
+ if (start & fence_mask) {
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: start (0x%08x) is not 512k aligned\n",
+ nr, start);
+ return;
+ }
+
+ if (start % size) {
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n",
+ nr, start, size / 1024);
+ return;
+ }
+
+ if (pitch & 127) {
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n",
+ nr, pitch);
+ return;
+ }
+
+ val = (start | FENCE_X_MAJOR | FENCE_VALID);
+
+ 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:
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024);
+ return;
+ }
+
+ switch (pitch / 128) {
+ 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(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: illegal pitch (%d)\n", nr, pitch);
+ return;
+ }
+
+ i830Reg->Fence[nr] = val;
+}
+
+static Bool
+MakeTiles(ScrnInfoPtr pScrn, I830MemRange *pMem)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ int pitch, ntiles, i;
+ static int nextTile = 0;
+ static int tileGeneration = -1;
+
+#if 0
+ /* Hack to "improve" the alignment of the front buffer.
+ */
+ while (!(pMem->Start & ~pMem->Alignment) && pMem->Alignment < 0x00400000 )
+ pMem->Alignment <<= 1;
+#endif
+
+ if (tileGeneration != serverGeneration) {
+ tileGeneration = serverGeneration;
+ nextTile = 0;
+ }
+
+ pitch = pScrn->displayWidth * pI830->cpp;
+ /*
+ * Simply try to break the region up into at most four pieces of size
+ * equal to the alignment.
+ */
+ ntiles = ROUND_TO(pMem->Size, pMem->Alignment) / pMem->Alignment;
+ if (ntiles >= 4) {
+ return FALSE;
+ }
+
+ for (i = 0; i < ntiles; i++, nextTile++) {
+ SetFence(pScrn, nextTile, pMem->Start + i * pMem->Alignment,
+ pitch, pMem->Alignment);
+ }
+ return TRUE;
+}
+
+void
+I830SetupMemoryTiling(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ /* We currently only attempt to tile the back and depth buffers. */
+ if (!pI830->directRenderingEnabled)
+ return;
+
+ if (!IsTileable(pScrn->displayWidth * pI830->cpp)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "I830SetupMemoryTiling: Not tileable 0x%x\n",
+ pScrn->displayWidth * pI830->cpp);
+ pI830->allowPageFlip = FALSE;
+ return;
+ }
+
+ if (pI830->allowPageFlip) {
+ if (pI830->allowPageFlip && pI830->FrontBuffer.Alignment >= KB(512)) {
+ if (MakeTiles(pScrn, &(pI830->FrontBuffer))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Activating tiled memory for the FRONT buffer\n");
+ } else {
+ pI830->allowPageFlip = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "MakeTiles failed for the FRONT buffer\n");
+ }
+ } else {
+ pI830->allowPageFlip = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Alignment bad for the FRONT buffer\n");
+ }
+ }
+
+ /*
+ * We tried to get the best alignment during the allocation. Check
+ * the alignment values to tell. If well-aligned allocations were
+ * successful, the address range reserved is a multiple of the align
+ * value.
+ */
+ if (pI830->BackBuffer.Alignment >= KB(512)) {
+ if (MakeTiles(pScrn, &(pI830->BackBuffer))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Activating tiled memory for the back buffer.\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "MakeTiles failed for the back buffer.\n");
+ pI830->allowPageFlip = FALSE;
+ }
+ }
+
+ if (pI830->DepthBuffer.Alignment >= KB(512)) {
+ if (MakeTiles(pScrn, &(pI830->DepthBuffer))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Activating tiled memory for the depth buffer.\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "MakeTiles failed for the back buffer.\n");
+ }
+ }
+
+}
+#endif /* XF86DRI */
+
+static Bool
+BindMemRange(ScrnInfoPtr pScrn, I830MemRange *mem)
+{
+ if (!mem)
+ return FALSE;
+
+ if (mem->Key == -1)
+ return TRUE;
+
+ return xf86BindGARTMemory(pScrn->scrnIndex, mem->Key, mem->Offset);
+}
+
+Bool
+I830BindGARTMemory(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ DPRINTF(PFX,
+ "I830BindGARTMemory: StolenOnly is %s, pI830->GttBound is %s\n",
+ BOOLTOSTRING(pI830->StolenOnly), BOOLTOSTRING(pI830->GttBound));
+
+ if (pI830->StolenOnly == TRUE)
+ return TRUE;
+
+ if (xf86AgpGARTSupported() && !pI830->GttBound) {
+ if (!xf86AcquireGART(pScrn->scrnIndex))
+ return FALSE;
+
+#if REMAP_RESERVED
+ /* Rebind the pre-allocated region. */
+ BindMemRange(pScrn, &(pI830->Dummy));
+#endif
+
+ if (!BindMemRange(pScrn, &(pI830->StolenPool.Allocated)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->FrontBuffer)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->CursorMem)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->LpRing.mem)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->Scratch)))
+ return FALSE;
+#ifdef I830_XV
+ if (!BindMemRange(pScrn, &(pI830->OverlayMem)))
+ return FALSE;
+#endif
+#ifdef XF86DRI
+ if (pI830->directRenderingEnabled) {
+ if (!BindMemRange(pScrn, &(pI830->BackBuffer)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->DepthBuffer)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->ContextMem)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->BufferMem)))
+ return FALSE;
+ if (!BindMemRange(pScrn, &(pI830->TexMem)))
+ return FALSE;
+ }
+#endif
+ pI830->GttBound = 1;
+ }
+
+ return TRUE;
+}
+
+static Bool
+UnbindMemRange(ScrnInfoPtr pScrn, I830MemRange *mem)
+{
+ if (!mem)
+ return FALSE;
+
+ if (mem->Key == -1)
+ return TRUE;
+
+ return xf86UnbindGARTMemory(pScrn->scrnIndex, mem->Key);
+}
+
+
+Bool
+I830UnbindGARTMemory(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ DPRINTF(PFX,
+ "I830UnbindGARTMemory: StolenOnly is %s, pI830->GttBound is %s\n",
+ BOOLTOSTRING(pI830->StolenOnly), BOOLTOSTRING(pI830->GttBound));
+
+ if (pI830->StolenOnly == TRUE)
+ return TRUE;
+
+ if (xf86AgpGARTSupported() && pI830->GttBound) {
+
+#if REMAP_RESERVED
+ /* "unbind" the pre-allocated region. */
+ UnbindMemRange(pScrn, &(pI830->Dummy));
+#endif
+
+ if (!UnbindMemRange(pScrn, &(pI830->StolenPool.Allocated)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->FrontBuffer)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->CursorMem)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->LpRing.mem)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->Scratch)))
+ return FALSE;
+#ifdef I830_XV
+ if (!UnbindMemRange(pScrn, &(pI830->OverlayMem)))
+ return FALSE;
+#endif
+#ifdef XF86DRI
+ if (pI830->directRenderingEnabled) {
+ if (!UnbindMemRange(pScrn, &(pI830->BackBuffer)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->DepthBuffer)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->ContextMem)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->BufferMem)))
+ return FALSE;
+ if (!UnbindMemRange(pScrn, &(pI830->TexMem)))
+ return FALSE;
+ }
+#endif
+ if (!xf86ReleaseGART(pScrn->scrnIndex))
+ return FALSE;
+
+ pI830->GttBound = 0;
+ }
+
+ return TRUE;
+}
+
+long
+I830CheckAvailableMemory(ScrnInfoPtr pScrn)
+{
+ AgpInfoPtr agpinf;
+ int maxPages;
+
+ if (!xf86AgpGARTSupported() ||
+ !xf86AcquireGART(pScrn->scrnIndex) ||
+ (agpinf = xf86GetAGPInfo(pScrn->scrnIndex)) == NULL ||
+ !xf86ReleaseGART(pScrn->scrnIndex))
+ return -1;
+
+ maxPages = agpinf->totalPages - agpinf->usedPages;
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "%s: %d kB available\n",
+ "I830CheckAvailableMemory", maxPages * 4);
+
+ return maxPages * 4;
+}