/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_memory.c,v 1.9 2003/09/24 03:16:54 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 * * Updated for Dual Head capabilities: * Alan Hourihane */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xf86.h" #include "xf86_ansic.h" #include "xf86_OSproc.h" #include "i830.h" #include "i810_reg.h" static int nextTile = 0; static unsigned int tileGeneration = -1; #ifndef ALLOCATE_ALL_BIOSMEM #define ALLOCATE_ALL_BIOSMEM 1 #endif 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; } /* * Allocate memory from the given pool. Grow the pool if needed and if * possible. */ static unsigned long AllocFromPool(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool, long size, unsigned long alignment, int flags) { I830Ptr pI830 = I830PTR(pScrn); 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 = end - start; } } if (needed > pool->Free.Size) { 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 && ((long)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->Free.End -= needed; result->End = result->Start + 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, 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; } void I830FreeVidMem(ScrnInfoPtr pScrn, I830MemRange *range) { I830Ptr pI830 = I830PTR(pScrn); if (!range || range->Size == 0) return; if (range->Key != -1) xf86DeallocateGARTMemory(pScrn->scrnIndex, range->Key); if (range->Pool) { /* * This code essentially resets what I830DoPoolAllocation() did. * And if things are freed in the wrong order this can break wildly! * USE CAUTION when changing anything here... */ I830MemPool *Pool = range->Pool; if (pI830->overrideBIOSMemSize && pI830->BIOSMemorySize > pI830->StolenMemory.Size) Pool->Total.End = pI830->BIOSMemorySize; else Pool->Total.End = pI830->StolenMemory.End; if (pI830->StolenOnly) Pool->Free.End += range->Size; else Pool->Free.End = Pool->Total.End; if (Pool->Free.End < Pool->Free.Start) { Pool->Free.End = Pool->Free.Start; } Pool->Free.Size = Pool->Free.End - Pool->Free.Start; Pool->Total.Size = Pool->Total.End - Pool->Total.Start; if (!pI830->StolenOnly) { pI830->FreeMemory -= Pool->Free.Size; pI830->MemoryAperture.Start -= (range->Size - Pool->Free.Size); pI830->MemoryAperture.Size += (range->Size - Pool->Free.Size); } } else { if (range->Alignment == GTT_PAGE_SIZE) pI830->MemoryAperture.End = range->End; else pI830->MemoryAperture.End = range->End - range->Size + range->Alignment; pI830->MemoryAperture.Size = pI830->MemoryAperture.End - pI830->MemoryAperture.Start; } if (!pI830->StolenOnly) pI830->FreeMemory += range->Size; pI830->allocatedMemory -= range->Size; } unsigned long I830AllocVidMem(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool, 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(I830RingBuffer)); 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 %ld kB for the ring buffer at 0x%lx\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(I830MemRange)); 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 %ld kB for Overlay registers at 0x%lx " "(0x%08lx).\n", s, alloced / 1024, pI830->OverlayMem->Start, pI830->OverlayMem->Physical); } /* Clear linearmem info */ if (pI830->LinearAlloc) { memset(&(pI830->LinearMem), 0, sizeof(I830MemRange)); pI830->LinearMem.Key = -1; size = KB(pI830->LinearAlloc); alloced = I830AllocVidMem(pScrn, &(pI830->LinearMem), &(pI830->StolenPool), size, GTT_PAGE_SIZE, FROM_ANYWHERE | ALLOCATE_AT_TOP); if (alloced < size) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate linear buffer space\n"); } } else xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocated %ld kB for the linear buffer at 0x%lx\n", s, alloced / 1024, pI830->LinearMem.Start); } return TRUE; } #endif 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; } } Bool I830AllocateRotatedBuffer(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] " : ""; int align; Bool tileable; int lines; int height = (pI830->rotation & (RR_Rotate_0 | RR_Rotate_180)) ? pScrn->virtualY : pScrn->virtualX; /* Rotated Buffer */ memset(&(pI830->RotatedMem), 0, sizeof(I830MemRange)); pI830->RotatedMem.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 = (height + 15) / 16 * 16; } else { lines = height; } 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->RotatedMem), &(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 * height * pI830->cpp); align = GTT_PAGE_SIZE; alloced = I830AllocVidMem(pScrn, &(pI830->RotatedMem), &(pI830->StolenPool), size, align, flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); } if (alloced < size) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate rotated buffer space.\n"); } return FALSE; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocated %ld kB for the rotated buffer at 0x%lx.\n", s, alloced / 1024, pI830->RotatedMem.Start); return TRUE; } Bool I830AllocateRotated2Buffer(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] " : ""; int align; Bool tileable; int lines; I830EntPtr pI830Ent = pI830->entityPrivate; I830Ptr pI8302 = I830PTR(pI830Ent->pScrn_2); int height = (pI8302->rotation & (RR_Rotate_0 | RR_Rotate_180)) ? pI830Ent->pScrn_2->virtualY : pI830Ent->pScrn_2->virtualX; /* Rotated Buffer */ memset(&(pI830->RotatedMem2), 0, sizeof(I830MemRange)); pI830->RotatedMem2.Key = -1; tileable = !(flags & ALLOC_NO_TILING) && IsTileable(pI830Ent->pScrn_2->displayWidth * pI8302->cpp); if (tileable) { /* Make the height a multiple of the tile height (16) */ lines = (height + 15) / 16 * 16; } else { lines = height; } size = ROUND_TO_PAGE(pI830Ent->pScrn_2->displayWidth * lines * pI8302->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->RotatedMem2), &(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(pI830Ent->pScrn_2->displayWidth * height * pI8302->cpp); align = GTT_PAGE_SIZE; alloced = I830AllocVidMem(pScrn, &(pI830->RotatedMem2), &(pI830->StolenPool), size, align, flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); } if (alloced < size) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate rotated2 buffer space.\n"); } return FALSE; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocated %ld kB for the rotated2 buffer at 0x%lx.\n", s, alloced / 1024, pI830->RotatedMem2.Start); return TRUE; } 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; } /* * 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); 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); /* Unfortunately this doesn't run on the DRY_RUN pass because our * second head hasn't been created yet..... */ if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) { I830EntPtr pI830Ent = pI830->entityPrivate; I830Ptr pI8302 = I830PTR(pI830Ent->pScrn_2); /* Clear everything first. */ memset(&(pI830->FbMemBox2), 0, sizeof(pI830->FbMemBox2)); memset(&(pI830->FrontBuffer2), 0, sizeof(pI830->FrontBuffer2)); pI830->FrontBuffer2.Key = -1; pI830->FbMemBox2.x1 = 0; pI830->FbMemBox2.x2 = pI830Ent->pScrn_2->displayWidth; pI830->FbMemBox2.y1 = 0; if (pI830Ent->pScrn_2->virtualX > pI830Ent->pScrn_2->virtualY) pI830->FbMemBox2.y2 = pI830Ent->pScrn_2->virtualX; else pI830->FbMemBox2.y2 = pI830Ent->pScrn_2->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 = pI830Ent->pScrn_2->displayWidth * pI8302->cpp; minspace = lineSize * pI830Ent->pScrn_2->virtualY; avail = pI830Ent->pScrn_2->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 - pI830Ent->pScrn_2->virtualY)) maxCacheLines = MAX_DISPLAY_HEIGHT - pI830Ent->pScrn_2->virtualY; if (pI8302->CacheLines >= 0) { cacheLines = pI8302->CacheLines; } else { #if 1 /* Make sure there is enough for two DVD sized YUV buffers */ cacheLines = (pI830Ent->pScrn_2->depth == 24) ? 256 : 384; if (pI830Ent->pScrn_2->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)) / pI8302->cpp / pI830Ent->pScrn_2->displayWidth; #endif } if (cacheLines > maxCacheLines) cacheLines = maxCacheLines; pI830->FbMemBox2.y2 += cacheLines; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocating at least %d scanlines for pixmap cache\n", s, cacheLines); tileable = !(flags & ALLOC_NO_TILING) && pI8302->allowPageFlip && IsTileable(pI830Ent->pScrn_2->displayWidth * pI8302->cpp); if (tileable) { align = KB(512); alignflags = ALIGN_BOTH_ENDS; } else { align = KB(64); alignflags = 0; } if (pI830Ent->pScrn_2->virtualX > pI830Ent->pScrn_2->virtualY) size = lineSize * (pI830Ent->pScrn_2->virtualX + cacheLines); else size = lineSize * (pI830Ent->pScrn_2->virtualY + cacheLines); size = ROUND_TO_PAGE(size); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sSecondary framebuffer allocation size: %ld kByte\n", s, size / 1024); alloced = I830AllocVidMem(pScrn, &(pI830->FrontBuffer2), &(pI830->StolenPool), size, align, flags | alignflags | FROM_ANYWHERE | ALLOCATE_AT_BOTTOM); if (alloced < size) { if (!dryrun) { xf86DrvMsg(pI830Ent->pScrn_2->scrnIndex, X_ERROR, "Failed to allocate secondary framebuffer.\n"); } return FALSE; } } /* 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; if (pScrn->virtualX > pScrn->virtualY) pI830->FbMemBox.y2 = pScrn->virtualX; else 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; } if (pScrn->virtualX > pScrn->virtualY) size = lineSize * (pScrn->virtualX + cacheLines); else size = lineSize * (pScrn->virtualY + cacheLines); size = ROUND_TO_PAGE(size); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sInitial framebuffer allocation size: %ld 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. Is your VideoRAM set too low ??\n"); } return FALSE; } } else { long lineSize; long extra = 0; 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 (0/*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(%lx != %lx).\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 %ld " "to %ld kByte\n", s, oldsize / 1024, maxFb / 1024); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sUpdated pixmap cache from %ld scanlines to %ld " "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(I830MemRange)); pI830->CursorMem->Key = -1; memset(pI830->CursorMemARGB, 0, sizeof(I830MemRange)); pI830->CursorMemARGB->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 %ld kB for HW cursor at 0x%lx", s, alloced / 1024, pI830->CursorMem->Start); if (pI830->CursorNeedsPhysical) xf86ErrorFVerb(verbosity, " (0x%08lx)", pI830->CursorMem->Physical); xf86ErrorFVerb(verbosity, "\n"); } size = HWCURSOR_SIZE_ARGB; cursFlags = FROM_ANYWHERE | ALLOCATE_AT_TOP; if (pI830->CursorNeedsPhysical) cursFlags |= NEED_PHYSICAL_ADDR; alloced = I830AllocVidMem(pScrn, pI830->CursorMemARGB, &(pI830->StolenPool), size, GTT_PAGE_SIZE, flags | cursFlags); if (alloced < size) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate HW (ARGB) cursor space.\n"); } } else { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocated %ld kB for HW (ARGB) cursor at 0x%lx", s, alloced / 1024, pI830->CursorMemARGB->Start); if (pI830->CursorNeedsPhysical) xf86ErrorFVerb(verbosity, " (0x%08lx)", pI830->CursorMemARGB->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(I830MemRange)); pI830->Scratch.Key = -1; memset(&(pI830->Scratch2), 0, sizeof(I830MemRange)); pI830->Scratch2.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 %ld kB for the scratch buffer at 0x%lx\n", s, alloced / 1024, pI830->Scratch.Start); /* Let's allocate another scratch buffer for the second head */ /* Again, this code won't execute on the dry run pass */ if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) { size = MAX_SCRATCH_BUFFER_SIZE; alloced = I830AllocVidMem(pScrn, &(pI830->Scratch2), &(pI830->StolenPool), size, GTT_PAGE_SIZE, flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); if (alloced < size) { size = MIN_SCRATCH_BUFFER_SIZE; alloced = I830AllocVidMem(pScrn, &(pI830->Scratch2), &(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 second scratch buffer space\n"); } return FALSE; } xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sAllocated %ld kB for the second scratch buffer at 0x%lx\n", s, alloced / 1024, pI830->Scratch2.Start); } } return TRUE; } 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); long allocated; allocated = pI830->StolenPool.Total.Size + pI830->allocatedMemory; if (allocated > pI830->TotalVideoRam) return allocated - pI830->TotalVideoRam; else return 0; } #ifdef XF86DRI static unsigned int myLog2(unsigned int n) { unsigned int log2 = 1; while (n > 1) { n >>= 1; log2++; } return log2; } Bool I830AllocateBackBuffer(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); unsigned long size, alloced, align = 0; Bool tileable; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); int verbosity = dryrun ? 4 : 1; const char *s = dryrun ? "[dryrun] " : ""; int lines; int height = (pI830->rotation & (RR_Rotate_0 | RR_Rotate_180)) ? pScrn->virtualY : pScrn->virtualX; /* 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 = (height + 15) / 16 * 16; } else { lines = height; } 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 * height * 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 %ld kB for the back buffer at 0x%lx.\n", s, alloced / 1024, pI830->BackBuffer.Start); return TRUE; } Bool I830AllocateDepthBuffer(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); unsigned long size, alloced, align = 0; Bool tileable; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); int verbosity = dryrun ? 4 : 1; const char *s = dryrun ? "[dryrun] " : ""; int lines; int height = (pI830->rotation & (RR_Rotate_0 | RR_Rotate_180)) ? pScrn->virtualY : pScrn->virtualX; /* Depth Buffer -- same size as the back buffer */ memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer)); pI830->DepthBuffer.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 = (height + 15) / 16 * 16; } else { lines = height; } 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->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 * height * 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 %ld kB for the depth buffer at 0x%lx.\n", s, alloced / 1024, pI830->DepthBuffer.Start); return TRUE; } Bool I830AllocateTextureMemory(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); unsigned long size, alloced; int i; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); int verbosity = dryrun ? 4 : 1; const char *s = dryrun ? "[dryrun] " : ""; /* 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 512 kBytes for texture space (real %ld kBytes).\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 %ld kB for textures at 0x%lx\n", s, alloced / 1024, pI830->TexMem.Start); return TRUE; } Bool I830Allocate3DMemory(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] " : ""; DPRINTF(PFX, "I830Allocate3DMemory\n"); /* 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 %ld kB for the logical context at 0x%lx.\n", s, alloced / 1024, pI830->ContextMem.Start); if (!I830AllocateBackBuffer(pScrn, flags)) return FALSE; if (!I830AllocateDepthBuffer(pScrn, flags)) return FALSE; if (!I830AllocateTextureMemory(pScrn, flags)) return FALSE; 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 Bool I830FixOffset(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%08lx, size %ld kBytes\n", (void *)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; if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) I830FixOffset(pScrn, &(pI830->FrontBuffer2)); I830FixOffset(pScrn, &(pI830->FrontBuffer)); I830FixOffset(pScrn, pI830->CursorMem); I830FixOffset(pScrn, pI830->CursorMemARGB); I830FixOffset(pScrn, &(pI830->LpRing->mem)); I830FixOffset(pScrn, &(pI830->Scratch)); if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) I830FixOffset(pScrn, &(pI830->Scratch2)); #ifdef I830_XV if (pI830->XvEnabled) { I830FixOffset(pScrn, pI830->OverlayMem); if (pI830->LinearAlloc) I830FixOffset(pScrn, &(pI830->LinearMem)); } #endif #ifdef XF86DRI if (pI830->directRenderingEnabled) { I830FixOffset(pScrn, &(pI830->ContextMem)); I830FixOffset(pScrn, &(pI830->BackBuffer)); I830FixOffset(pScrn, &(pI830->DepthBuffer)); I830FixOffset(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; unsigned int fence_pitch; 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",nr); return; } i830Reg->Fence[nr] = 0; if (IS_I9XX(pI830)) fence_mask = ~I915G_FENCE_START_MASK; else fence_mask = ~I830_FENCE_START_MASK; if (start & fence_mask) { xf86DrvMsg(X_WARNING, pScrn->scrnIndex, "SetFence: %d: start (0x%08x) is not %s aligned\n", nr, start, (IS_I9XX(pI830)) ? "1MB" : "512k"); 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); 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: xf86DrvMsg(X_WARNING, pScrn->scrnIndex, "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024); return; } } 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: xf86DrvMsg(X_WARNING, pScrn->scrnIndex, "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024); return; } } if (IS_I9XX(pI830)) fence_pitch = pitch / 512; else fence_pitch = pitch / 128; 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(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; #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); int i; /* Clear out */ for (i = 0; i < 8; i++) pI830->ModeReg.Fence[i] = 0; nextTile = 0; tileGeneration = -1; /* 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 depth buffer.\n"); } } if (pI830->RotatedMem.Alignment >= KB(512)) { if (MakeTiles(pScrn, &(pI830->RotatedMem))) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Activating tiled memory for the rotated buffer.\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MakeTiles failed for the rotated buffer.\n"); } } #if 0 if (pI830->RotatedMem2.Alignment >= KB(512)) { if (MakeTiles(pScrn, &(pI830->RotatedMem2))) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Activating tiled memory for the rotated2 buffer.\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MakeTiles failed for the rotated buffer.\n"); } } #endif } #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 I830BindAGPMemory(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); DPRINTF(PFX, "I830BindAGPMemory: 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 (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) if (!BindMemRange(pScrn, &(pI830->FrontBuffer2))) return FALSE; if (!BindMemRange(pScrn, &(pI830->FrontBuffer))) return FALSE; if (!BindMemRange(pScrn, pI830->CursorMem)) return FALSE; if (!BindMemRange(pScrn, pI830->CursorMemARGB)) return FALSE; if (!BindMemRange(pScrn, &(pI830->LpRing->mem))) return FALSE; if (!BindMemRange(pScrn, &(pI830->Scratch))) return FALSE; if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) if (!BindMemRange(pScrn, &(pI830->Scratch2))) return FALSE; #ifdef I830_XV if (pI830->XvEnabled) { if (!BindMemRange(pScrn, pI830->OverlayMem)) return FALSE; if (pI830->LinearAlloc) if (!BindMemRange(pScrn, &(pI830->LinearMem))) return FALSE; } #endif if (pI830->RotatedMem.Start) if (!BindMemRange(pScrn, &(pI830->RotatedMem))) return FALSE; if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2 && pI830->RotatedMem2.Start) if (!BindMemRange(pScrn, &(pI830->RotatedMem2))) return FALSE; #ifdef XF86DRI if (pI830->directRenderingEnabled) { if (!BindMemRange(pScrn, &(pI830->ContextMem))) return FALSE; if (!BindMemRange(pScrn, &(pI830->BackBuffer))) return FALSE; if (!BindMemRange(pScrn, &(pI830->DepthBuffer))) 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 I830UnbindAGPMemory(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); DPRINTF(PFX, "I830UnbindAGPMemory: 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 (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) if (!UnbindMemRange(pScrn, &(pI830->FrontBuffer2))) return FALSE; if (!UnbindMemRange(pScrn, &(pI830->FrontBuffer))) return FALSE; if (!UnbindMemRange(pScrn, pI830->CursorMem)) return FALSE; if (!UnbindMemRange(pScrn, pI830->CursorMemARGB)) return FALSE; if (!UnbindMemRange(pScrn, &(pI830->LpRing->mem))) return FALSE; if (!UnbindMemRange(pScrn, &(pI830->Scratch))) return FALSE; if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) if (!UnbindMemRange(pScrn, &(pI830->Scratch2))) return FALSE; #ifdef I830_XV if (pI830->XvEnabled) { if (!UnbindMemRange(pScrn, pI830->OverlayMem)) return FALSE; if (pI830->LinearAlloc) if (!UnbindMemRange(pScrn, &(pI830->LinearMem))) return FALSE; } #endif if (pI830->RotatedMem.Start) if (!UnbindMemRange(pScrn, &(pI830->RotatedMem))) return FALSE; if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2 && pI830->RotatedMem2.Start) if (!UnbindMemRange(pScrn, &(pI830->RotatedMem2))) return FALSE; #ifdef XF86DRI if (pI830->directRenderingEnabled) { if (!UnbindMemRange(pScrn, &(pI830->ContextMem))) return FALSE; if (!UnbindMemRange(pScrn, &(pI830->BackBuffer))) return FALSE; if (!UnbindMemRange(pScrn, &(pI830->DepthBuffer))) 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; }