From 3ad0d9a73bc0a4f3edb858d5f3a7c36827b7a429 Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Fri, 14 Nov 2003 16:48:55 +0000 Subject: Initial revision --- src/i830_memory.c | 1458 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1458 insertions(+) create mode 100644 src/i830_memory.c (limited to 'src/i830_memory.c') 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 characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell + * David Dawes + * + */ + +#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; +} -- cgit v1.2.3