diff options
author | Eric Anholt <eric@anholt.net> | 2007-02-22 10:41:09 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2007-02-23 12:50:49 -0800 |
commit | d3ac440e127c8a7716062852cd3b5e7943e289e4 (patch) | |
tree | 10b80c3905e06ecd885957ea2f333d9d8d705c56 /src/i830_memory.c | |
parent | a61a6b1db610a07060d0dcca54b66a4b2b3686cc (diff) |
Rework the video memory allocation.
The previous allocator worked in multiple passes, with (at least) one of
setting up allocations, another to attempt to adjust those for tiling, and
then a pass to set up the offsets and fix them in memory.
The new allocator is simpler, allocating memory immediately if possible,
setting up tiling up front, and choosing offsets immediately. AGP memory
is only allocated to back actual memory used, saving some memory that would
have been allocated for padding previous. It will also allow dynamic freeing
and reallocation of memory, which will be useful for framebuffer resizing.
Diffstat (limited to 'src/i830_memory.c')
-rw-r--r-- | src/i830_memory.c | 2160 |
1 files changed, 842 insertions, 1318 deletions
diff --git a/src/i830_memory.c b/src/i830_memory.c index 1b2af120..93429fba 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -50,6 +50,51 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * Alan Hourihane <alanh@tungstengraphics.com> */ +/** + * @file i830_memory.c + * + * This is the video memory allocator. Our memory allocation is different from + * other graphics chips, where you have a fixed amount of graphics memory + * available that you want to put to the best use. Instead, we have almost no + * memory pre-allocated, and we have to choose an appropriate amount of sytem + * memory to use. + * + * The allocations we might do: + * + * - Ring buffer + * - HW cursor 1 + * - HW cursor 2 + * - HW ARGB cursor 1 + * - HW ARGB cursor 2 + * - Overlay registers + * - XAA linear allocator (optional) + * - EXA 965 state buffer + * - XAA scratch (screen 1) + * - XAA scratch (screen 2, only in zaphod mode) + * - Front buffer (screen 1, more is better for XAA) + * - Front buffer (screen 2, only in zaphod mode, more is better for XAA) + * - Back/depth buffer (3D only) + * - Compatibility texture pool (optional, more is always better) + * - New texture pool (optional, more is always better. aperture allocation + * only) + * - EXA offscreen pool (more is always better) + * + * We also want to be able to resize the front/back/depth buffers, and then + * resize the EXA and texture memory pools appropriately. + * + * The user may request a specific amount of memory to be used + * (pI830->pEnt->videoRam != 0), in which case allocations have to fit within + * that much aperture. If not, the individual allocations will be + * automatically sized, and will be fit within the maximum aperture size. + * Only the actual memory used (not alignment padding) will get actual AGP + * memory allocated. + * + * Given that the allocations listed are generally a page or more than a page, + * our allocator will only return page-aligned offsets, simplifying the memory + * binding process. For smaller allocations, the acceleration architecture's + * linear allocator is preferred. + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -62,383 +107,541 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i830.h" #include "i810_reg.h" -static int nextTile = 0; -static unsigned int tileGeneration = -1; +#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) + +enum tile_format { + TILING_NONE, + TILING_XMAJOR, + TILING_YMAJOR +}; + +static void i830_set_fence(ScrnInfoPtr pScrn, int nr, unsigned int offset, + unsigned int pitch, unsigned int size, + enum tile_format tile_format); +/** + * Returns the fence size for a tiled area of the given size. + */ static unsigned long -GetBestTileAlignment(unsigned long size) +i830_get_fence_size(ScrnInfoPtr pScrn, unsigned long size) { + I830Ptr pI830 = I830PTR(pScrn); unsigned long i; + unsigned long start; - for (i = KB(512); i < size; i <<= 1) - ; + if (IS_I965G(pI830)) { + /* The 965 can have fences at any page boundary. */ + return ALIGN(size, GTT_PAGE_SIZE); + } else { + /* Align the size to a power of two greater than the smallest fence + * size. + */ + if (IS_I9XX(pI830)) + start = MB(1); + else + start = KB(512); - if (i > MB(64)) - i = MB(64); + for (i = start; i < size; i <<= 1) + ; - return i; + 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) +static Bool +i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) { 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 (mem == NULL || mem->key == -1 || mem->bound || !pI830->gtt_acquired) + return TRUE; + + if (xf86BindGARTMemory(pScrn->scrnIndex, mem->key, mem->agp_offset)) { + mem->bound = TRUE; + return TRUE; + } else { + return FALSE; } - 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; + return TRUE; +} - 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; +static Bool +i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem) +{ + if (mem == NULL || mem->key == -1 || !mem->bound) + return TRUE; + + if (xf86UnbindGARTMemory(pScrn->scrnIndex, mem->key)) { + mem->bound = FALSE; + return TRUE; } else { - result->Start = ROUND_DOWN_TO(pool->Free.End - size, alignment); - pool->Free.End -= needed; - result->End = result->Start + needed; + return FALSE; } - 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) +static void +i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) +{ + i830_unbind_memory(pScrn, mem); + + /* Disconnect from the list of allocations */ + if (mem->prev != NULL) + mem->prev->next = mem->next; + if (mem->next != NULL) + mem->next->prev = mem->prev; + + /* Free any AGP memory. */ + i830_unbind_memory(pScrn, mem); + + if (mem->key != -1) { + xf86DeallocateGARTMemory(pScrn->scrnIndex, mem->key); + mem->key = -1; + } + + xfree(mem->name); + xfree(mem); +} + +/* Resets the state of the aperture allocator, freeing all memory that had + * been allocated. + */ +void +i830_reset_allocations(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - unsigned long start, end; - unsigned long newApStart, newApEnd; - Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; - if (!result || !size) - return 0; + /* While there is any memory between the start and end markers, free it. */ + while (pI830->memory_list->next->next != NULL) + i830_free_memory(pScrn, pI830->memory_list->next); - 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; + /* Null out the pointers for all the allocations we just freed. This is + * kind of gross, but at least it's just one place now. + */ + for (i = 0; i < xf86_config->num_crtc; i++) { + I830CrtcPrivatePtr intel_crtc = xf86_config->crtc[i]->driver_private; + + intel_crtc->cursor_mem = NULL; + intel_crtc->cursor_mem_argb = NULL; } - if (size > pI830->FreeMemory) { - if (dryrun) - pI830->FreeMemory = size; - else - return 0; + pI830->front_buffer = NULL; + pI830->front_buffer_2 = NULL; + pI830->xaa_scratch = NULL; + pI830->xaa_scratch_2 = NULL; + pI830->exa_offscreen = NULL; + pI830->exa_965_state = NULL; + pI830->overlay_regs = NULL; + pI830->xaa_linear = NULL; + pI830->logical_context = NULL; + pI830->back_buffer = NULL; + pI830->depth_buffer = NULL; + pI830->textures = NULL; + pI830->memory_manager = NULL; + pI830->LpRing->mem = NULL; +} + +/** + * Initialize's the driver's video memory allocator to allocate in the + * given range. + */ +Bool +i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, + unsigned long size) +{ + I830Ptr pI830 = I830PTR(pScrn); + i830_memory *start, *end; + + start = xcalloc(1, sizeof(*start)); + if (start == NULL) + return FALSE; + start->name = xstrdup("start marker"); + if (start->name == NULL) { + xfree(start); + return FALSE; + } + end = xcalloc(1, sizeof(*end)); + if (end == NULL) { + xfree(start->name); + xfree(start); + return FALSE; + } + end->name = xstrdup("end marker"); + if (end->name == NULL) { + xfree(start->name); + xfree(start); + xfree(end); + return FALSE; } - /* 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 { + start->key = -1; + start->offset = offset; + start->end = start->offset; + start->size = 0; + start->next = end; + end->key = -1; + end->offset = offset + size; + end->end = end->offset; + end->size = 0; + end->prev = start; + + pI830->memory_list = start; + + return TRUE; +} + +/* Allocate aperture space for the given size and alignment, and returns the + * memory allocation. + * + * Allocations are a minimum of a page, and will be at least page-aligned. + */ +static i830_memory * +i830_allocate_aperture(ScrnInfoPtr pScrn, const char *name, + long size, unsigned long alignment, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + i830_memory *mem, *scan; + + mem = xcalloc(1, sizeof(*mem)); + if (mem == NULL) + return NULL; + + /* No memory allocated to back the region */ + mem->key = -1; + + mem->name = xstrdup(name); + if (mem->name == NULL) { + xfree(mem); + return NULL; + } + mem->size = size; + + if (alignment < GTT_PAGE_SIZE) + alignment = GTT_PAGE_SIZE; + + for (scan = pI830->memory_list; scan->next != NULL; scan = scan->next) { + mem->offset = ROUND_TO(scan->end, alignment); + mem->end = mem->offset + size; 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; + mem->end = ROUND_TO(mem->end, alignment); + if (mem->end <= scan->next->offset) + break; + } + if (scan->next == NULL) { + /* Reached the end of the list, and didn't find space */ + xfree(mem->name); + xfree(mem); + return NULL; } + /* Insert new allocation into the list */ + mem->prev = scan; + mem->next = scan->next; + scan->next = mem; + mem->next->prev = scan; - if (!dryrun) { - if (newApStart > newApEnd) - return 0; + return mem; +} - if (flags & NEED_PHYSICAL_ADDR) { - result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, - &(result->Physical)); - } else { - result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, - NULL); - } +/** + * Allocates the AGP memory necessary for the part of a memory allocation not + * already covered by the stolen memory. + * + * The memory is automatically bound if we have the VT. + */ +static Bool +i830_allocate_agp_memory(ScrnInfoPtr pScrn, i830_memory *mem, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long size; + + if (mem->key != -1) + return TRUE; + + if (mem->offset + mem->size <= pI830->stolen_size) + return TRUE; + + if (mem->offset < pI830->stolen_size) + mem->agp_offset = pI830->stolen_size; + else + mem->agp_offset = mem->offset; + + size = mem->size - (mem->agp_offset - mem->offset); - if (result->Key == -1) - return 0; + if (flags & NEED_PHYSICAL_ADDR) + mem->key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, + &mem->bus_addr); + else + mem->key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL); + if (mem->key == -1 || ((flags & NEED_PHYSICAL_ADDR) && mem->bus_addr == 0)) + { + return FALSE; + } + + if (!i830_bind_memory(pScrn, mem)) { + return FALSE; } - 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; + return TRUE; } -void -I830FreeVidMem(ScrnInfoPtr pScrn, I830MemRange *range) + +/* Allocates video memory at the given size and alignment. + * + * The memory will be bound automatically when the driver is in control of the + * VT. + */ +static i830_memory * +i830_allocate_memory(ScrnInfoPtr pScrn, const char *name, + unsigned long size, unsigned long alignment, int flags) { - I830Ptr pI830 = I830PTR(pScrn); + i830_memory *mem; - if (!range || range->Size == 0) - return; + mem = i830_allocate_aperture(pScrn, name, size, alignment, flags); + if (mem == NULL) + return NULL; - if (range->Key != -1) - xf86DeallocateGARTMemory(pScrn->scrnIndex, range->Key); + if (!i830_allocate_agp_memory(pScrn, mem, flags)) { + i830_free_memory(pScrn, mem); + return NULL; + } - 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; - Pool->Total.End = pI830->StolenMemory.End; + return mem; +} - if (pI830->StolenOnly) - Pool->Free.End += range->Size; - else - Pool->Free.End = Pool->Total.End; +/* Allocate a tiled region with the given size and pitch. + * + * As is, we might miss out on tiling some allocations on older hardware with + * large framebuffer size and a small aperture size, where the first + * allocations use a large alignment even though we've got fences to spare, and + * the later allocations can't find enough aperture space left. We could do + * some search across all allocation options to fix this, probably, but that + * would be another rewrite. + */ +static i830_memory * +i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name, + unsigned long size, unsigned long pitch, + unsigned long alignment, int flags, + enum tile_format tile_format) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long aper_size; + unsigned long aper_align; + i830_memory *mem; + int fence_divide, i; - if (Pool->Free.End < Pool->Free.Start) { - Pool->Free.End = Pool->Free.Start; - } + if (tile_format == TILING_NONE) + return i830_allocate_memory(pScrn, name, size, alignment, flags); - Pool->Free.Size = Pool->Free.End - Pool->Free.Start; - Pool->Total.Size = Pool->Total.End - Pool->Total.Start; + /* Check for maximum tiled region size */ + if (IS_I9XX(pI830)) { + if (size > MB(128)) + return NULL; + } else { + if (size > MB(64)) + return NULL; + } - if (!pI830->StolenOnly) { - pI830->FreeMemory -= Pool->Free.Size; - pI830->MemoryAperture.Start -= (range->Size - Pool->Free.Size); - pI830->MemoryAperture.Size += (range->Size - Pool->Free.Size); - } + aper_size = i830_get_fence_size(pScrn, size); + if (IS_I965G(pI830)) { + aper_align = GTT_PAGE_SIZE; } else { - if (range->Alignment == GTT_PAGE_SIZE) - pI830->MemoryAperture.End = range->End; - else { - pI830->MemoryAperture.End = range->End - range->Size + - range->Alignment; + /* The offset has to be aligned to at least the size of the fence + * region. + */ + aper_align = aper_size; + } + if (aper_align < alignment) + aper_align = alignment; + + fence_divide = 1; + mem = i830_allocate_aperture(pScrn, name, aper_size, aper_align, flags); + if (mem == NULL && !IS_I965G(pI830)) { + /* For the older hardware with stricter fencing limits, if we + * couldn't allocate with the large alignment, try relaxing the + * alignment requirements and using more fences to cover the area. + */ + for (fence_divide = 2; fence_divide <= 4 && mem == NULL; + fence_divide *= 2) + { + /* Check that it's not too small for fencing. */ + if (i830_get_fence_size(pScrn, aper_align / fence_divide) != + aper_align / fence_divide) + { + break; + } + + mem = i830_allocate_aperture(pScrn, name, aper_size, + aper_align / fence_divide, flags); } - pI830->MemoryAperture.Size = pI830->MemoryAperture.End - - pI830->MemoryAperture.Start; } - if (!pI830->StolenOnly) - pI830->FreeMemory += range->Size; - pI830->allocatedMemory -= range->Size; + if (mem == NULL) + return NULL; + + /* Make sure we've got enough free fence regs. It's pretty hard to run + * out, luckily, with 8 even on older hardware and us only tiling + * front/back/depth buffers. + */ + if (pI830->next_fence + fence_divide > + (IS_I965G(pI830) ? FENCE_NEW_NR : FENCE_NR)) + { + i830_free_memory(pScrn, mem); + return NULL; + } + + /* Allocate any necessary AGP memory to back this allocation */ + if (!i830_allocate_agp_memory(pScrn, mem, flags)) { + i830_free_memory(pScrn, mem); + return NULL; + } + + /* Set up the fence registers. */ + for (i = 0; i < fence_divide; i++) { + i830_set_fence(pScrn, pI830->next_fence++, + mem->offset + mem->size * i / fence_divide, pitch, + mem->size / fence_divide, tile_format); + } + + mem->size = size; + + return mem; +} + +static void +i830_describe_tiling(ScrnInfoPtr pScrn, int verbosity, const char *prefix, + i830_memory *mem, unsigned int tiling_mode) +{ + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%s%s is %stiled\n", prefix, mem->name, + (tiling_mode == FENCE_LINEAR) ? "not " : ""); } -unsigned long -I830AllocVidMem(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool, - long size, unsigned long alignment, int flags) +void +i830_describe_allocations(ScrnInfoPtr pScrn, int verbosity, const char *prefix) { I830Ptr pI830 = I830PTR(pScrn); - Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + i830_memory *mem; - if (!result) - return 0; + if (pI830->memory_list == NULL) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sMemory allocator not initialized\n", prefix); + return; + } - /* Make sure these are initialised. */ - result->Size = 0; - result->Key = -1; + if (pI830->memory_list->next->next == NULL) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sNo memory allocations\n", prefix); + return; + } - if (!size) { - return 0; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sMemory allocation layout:\n", prefix); + + for (mem = pI830->memory_list->next; mem->next != NULL; mem = mem->next) { + + if (mem->offset >= pI830->stolen_size && + mem->prev->offset <= pI830->stolen_size) + { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%s0x%08lx: end of stolen memory\n", + prefix, pI830->stolen_size); + } + + if (mem->bus_addr == 0) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%s0x%08lx-0x%08lx: %s (%ld kB)\n", prefix, + mem->offset, mem->end - 1, mem->name, + mem->size / 1024); + } else { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%s0x%08lx-0x%08lx: %s (%ld kB, %08lx physical)\n", + prefix, + mem->offset, mem->end - 1, mem->name, + mem->size / 1024, mem->bus_addr); + } } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%s0x%08lx: end of aperture\n", + prefix, pI830->FbMapSize); - 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; + if (pI830->front_buffer != NULL) { + i830_describe_tiling(pScrn, verbosity, prefix, pI830->front_buffer, + pI830->front_tiled); + } + if (pI830->back_buffer != NULL) { + i830_describe_tiling(pScrn, verbosity, prefix, pI830->back_buffer, + pI830->back_tiled); + } + if (pI830->depth_buffer != NULL) { + i830_describe_tiling(pScrn, verbosity, prefix, pI830->depth_buffer, + pI830->depth_tiled); } } static Bool -AllocateRingBuffer(ScrnInfoPtr pScrn, int flags) +i830_allocate_ringbuffer(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) + if (pI830->noAccel || pI830->LpRing->mem != NULL) 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) { + pI830->LpRing->mem = i830_allocate_memory(pScrn, "ring buffer", + PRIMARY_RINGBUFFER_SIZE, + GTT_PAGE_SIZE, 0); + if (pI830->LpRing->mem == NULL) { 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; + + 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. +/** + * Allocate space for overlay registers and XAA linear allocator (if + * requested) */ static Bool -AllocateOverlay(ScrnInfoPtr pScrn, int flags) +i830_allocate_overlay(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) + /* Only allocate if overlay is going to be enabled. */ + if (!pI830->XvEnabled || IS_I965G(pI830)) 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); + if (!IS_I965G(pI830)) { + pI830->overlay_regs = i830_allocate_memory(pScrn, "overlay registers", + OVERLAY_SIZE, GTT_PAGE_SIZE, + NEED_PHYSICAL_ADDR); + if (pI830->overlay_regs == NULL) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate Overlay register space.\n"); + /* This failure isn't fatal. */ + } + } } - /* 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 (!pI830->useEXA && pI830->LinearAlloc) { + pI830->xaa_linear = i830_allocate_memory(pScrn, "XAA linear memory", + KB(pI830->LinearAlloc), + GTT_PAGE_SIZE, 0); + if (pI830->xaa_linear == NULL) { 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; @@ -479,22 +682,6 @@ IsTileable(ScrnInfoPtr pScrn, int pitch) } } -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; -} - /* This is the 2D rendering vertical coordinate limit. We can ignore * the 3D rendering limits in our 2d pixmap cache allocation, because XAA * doesn't do any 3D rendering to/from the cache lines when using an offset @@ -512,24 +699,23 @@ GetFreeSpace(ScrnInfoPtr pScrn) * \param pI830 I830Ptr for the screen being allocated. * \param FbMemBox */ -static Bool -I830AllocateFramebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, - I830MemRange *FrontBuffer, I830MemPool *StolenPool, - Bool secondary, const int flags) +static i830_memory * +i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, + Bool secondary, int flags) { Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); - unsigned long minspace, avail, lineSize; + unsigned int pitch = pScrn->displayWidth * pI830->cpp; + unsigned long minspace, avail; int cacheLines, maxCacheLines; int verbosity = dryrun ? 4 : 1; const char *s = dryrun ? "[dryrun] " : ""; - Bool tileable; - int align, alignflags; - long size, alloced, fb_height; + int align; + long size, fb_height; + char *name; + i830_memory *front_buffer = NULL; /* Clear everything first. */ memset(FbMemBox, 0, sizeof(*FbMemBox)); - memset(FrontBuffer, 0, sizeof(*FrontBuffer)); - FrontBuffer->Key = -1; /* We'll allocate the fb such that the root window will fit regardless of * rotation. @@ -549,18 +735,16 @@ I830AllocateFramebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, * enough for the virtual screen size, plus some pixmap cache * space if we're using XAA. */ - - lineSize = pScrn->displayWidth * pI830->cpp; - minspace = lineSize * pScrn->virtualY; + minspace = pitch * pScrn->virtualY; avail = pScrn->videoRam * 1024; if (!pI830->useEXA) { - maxCacheLines = (avail - minspace) / lineSize; + maxCacheLines = (avail - minspace) / pitch; /* This shouldn't happen. */ if (maxCacheLines < 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal Error: " - "maxCacheLines < 0 in I830Allocate2DMemory()\n"); + "maxCacheLines < 0 in i830_allocate_2d_memory()\n"); maxCacheLines = 0; } if (maxCacheLines > (MAX_2D_HEIGHT - pScrn->virtualY)) @@ -571,11 +755,11 @@ I830AllocateFramebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, } else { int size; - size = 3 * lineSize * pScrn->virtualY; + size = 3 * pitch * pScrn->virtualY; size += 1920 * 1088 * 2 * 2; size = ROUND_TO_PAGE(size); - cacheLines = (size + lineSize - 1) / lineSize; + cacheLines = (size + pitch - 1) / pitch; } if (cacheLines > maxCacheLines) cacheLines = maxCacheLines; @@ -592,125 +776,96 @@ I830AllocateFramebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, cacheLines = 0; } - tileable = !(flags & ALLOC_NO_TILING) && pI830->allowPageFlip && - IsTileable(pScrn, pScrn->displayWidth * pI830->cpp); - if (tileable) { + size = pitch * (fb_height + cacheLines); + size = ROUND_TO_PAGE(size); + + name = secondary ? "secondary front buffer" : "front buffer"; + + /* Attempt to allocate it tiled first if we have page flipping on. */ + if (!flags & ALLOC_NO_TILING && pI830->allowPageFlip && + IsTileable(pScrn, pitch)) + { + /* XXX: probably not the case on 965 */ if (IS_I9XX(pI830)) align = MB(1); else align = KB(512); - alignflags = ALIGN_BOTH_ENDS; - } else { - align = KB(64); - alignflags = 0; + front_buffer = i830_allocate_memory_tiled(pScrn, name, size, + pitch, align, + flags, TILING_XMAJOR); + pI830->front_tiled = FENCE_XMAJOR; } - size = lineSize * (fb_height + cacheLines); - size = ROUND_TO_PAGE(size); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, - "%sInitial %sframebuffer allocation size: %ld kByte\n", - s, secondary ? "secondary " : "", - size / 1024); - alloced = I830AllocVidMem(pScrn, FrontBuffer, - StolenPool, size, align, - flags | alignflags | - FROM_ANYWHERE | ALLOCATE_AT_BOTTOM); - if (alloced < size) { + /* If not, attempt it linear */ + if (front_buffer == NULL) { + front_buffer = i830_allocate_memory(pScrn, name, size, KB(64), flags); + pI830->front_tiled = FENCE_LINEAR; + } + + if (front_buffer == NULL) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate " "%sframebuffer. Is your VideoRAM set too low?\n", secondary ? "secondary " : ""); } - return FALSE; + return NULL; } - return TRUE; + return front_buffer; } static Bool -I830AllocateCursorBuffers(xf86CrtcPtr crtc, const int flags) +i830_allocate_cursor_buffers(xf86CrtcPtr crtc, int flags) { ScrnInfoPtr pScrn = crtc->scrn; I830CrtcPrivatePtr intel_crtc = crtc->driver_private; I830Ptr pI830 = I830PTR(pScrn); Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); - int verbosity = dryrun ? 4 : 1; - const char *s = dryrun ? "[dryrun] " : ""; - long size, alloced; - int cursFlags = 0; - - /* Clear cursor info */ - memset(&intel_crtc->cursor_mem, 0, sizeof(I830MemRange)); - intel_crtc->cursor_mem.Key = -1; - memset(&intel_crtc->cursor_mem_argb, 0, sizeof(I830MemRange)); - intel_crtc->cursor_mem_argb.Key = -1; + long size; if (pI830->SWCursor) return FALSE; - /* - * Mouse cursor -- The i810-i830 need a physical address in system + /* 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; + flags |= NEED_PHYSICAL_ADDR; - alloced = I830AllocVidMem(pScrn, &intel_crtc->cursor_mem, - &pI830->StolenPool, size, - GTT_PAGE_SIZE, flags | cursFlags); - if (alloced < size || - (pI830->CursorNeedsPhysical && !intel_crtc->cursor_mem.Physical)) - { - if (!dryrun) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to allocate HW cursor space.\n"); + if (intel_crtc->cursor_mem == NULL) { + intel_crtc->cursor_mem = i830_allocate_memory(pScrn, "HW cursor", + size, GTT_PAGE_SIZE, + flags); + if (intel_crtc->cursor_mem == NULL) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate HW cursor space.\n"); + } return FALSE; } - } else { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, - "%sAllocated %ld kB for HW cursor at 0x%lx", s, - alloced / 1024, intel_crtc->cursor_mem.Start); - if (pI830->CursorNeedsPhysical) { - xf86ErrorFVerb(verbosity, " (0x%08lx)", - intel_crtc->cursor_mem.Physical); - } - xf86ErrorFVerb(verbosity, "\n"); } - /* Allocate the ARGB cursor space. Its success is optional -- we won't set - * SWCursor if it fails. - */ - size = HWCURSOR_SIZE_ARGB; - cursFlags = FROM_ANYWHERE | ALLOCATE_AT_TOP; - if (pI830->CursorNeedsPhysical) - cursFlags |= NEED_PHYSICAL_ADDR; - - alloced = I830AllocVidMem(pScrn, &intel_crtc->cursor_mem_argb, - &pI830->StolenPool, size, - GTT_PAGE_SIZE, flags | cursFlags); - if (alloced < size || - (pI830->CursorNeedsPhysical && !intel_crtc->cursor_mem_argb.Physical)) - { - 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, intel_crtc->cursor_mem_argb.Start); - if (pI830->CursorNeedsPhysical) { - xf86ErrorFVerb(verbosity, " (0x%08lx)", - intel_crtc->cursor_mem_argb.Physical); + if (intel_crtc->cursor_mem_argb == NULL) { + /* Allocate the ARGB cursor space. Its success is optional -- we won't + * set SWCursor if it fails. + */ + intel_crtc->cursor_mem_argb = i830_allocate_memory(pScrn, + "HW ARGB cursor", + HWCURSOR_SIZE_ARGB, + GTT_PAGE_SIZE, + flags); + if (intel_crtc->cursor_mem_argb == NULL) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate HW (ARGB) cursor space.\n"); + } } - xf86ErrorFVerb(verbosity, "\n"); } - return FALSE; + return TRUE; } /* @@ -718,18 +873,16 @@ I830AllocateCursorBuffers(xf86CrtcPtr crtc, const int flags) * ring buffer, scratch memory, HW cursor. */ Bool -I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags) +i830_allocate_2d_memory(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - long size, alloced; + unsigned int pitch = pScrn->displayWidth * pI830->cpp; + long size; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); - int verbosity = dryrun ? 4 : 1; - const char *s = dryrun ? "[dryrun] " : ""; - Bool tileable; - int align, alignflags, i; + int i; - DPRINTF(PFX, "I830Allocate2DMemory: inital is %s\n", + DPRINTF(PFX, "i830_allocate_2d_memory: inital is %s\n", BOOLTOSTRING(flags & ALLOC_INITIAL)); if (!pI830->StolenOnly && @@ -738,88 +891,70 @@ I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags) 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"); + "\tMake sure your kernel has agpgart support or has\n" + "\tthe agpgart module loaded.\n"); } return FALSE; } + /* Allocate the ring buffer first, so it ends up in stolen mem. */ + i830_allocate_ringbuffer(pScrn, flags); - /* - * 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) { - 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); - - if (!I830AllocateFramebuffer(pI830Ent->pScrn_2, pI8302, - &pI830->FbMemBox2, - &pI830->FrontBuffer2, - &pI830->StolenPool, - TRUE, flags)) - { - return FALSE; - } - } - if (!I830AllocateFramebuffer(pScrn, pI830, &pI830->FbMemBox, - &pI830->FrontBuffer, &pI830->StolenPool, - FALSE, flags)) - { - return FALSE; + /* Next, allocate other fixed-size allocations we have. */ + if (!pI830->SWCursor) { + /* Allocate cursor memory */ + for (i = 0; i < xf86_config->num_crtc; i++) { + if (!i830_allocate_cursor_buffers(xf86_config->crtc[i], flags) && + !pI830->SWCursor) + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling HW cursor because the cursor memory " + "allocation failed.\n"); + pI830->SWCursor = TRUE; + break; + } } + } + +#ifdef I830_XV + /* Allocate overlay register space and optional XAA linear allocator + * space. The second head in zaphod mode will share the space. + */ + if (I830IsPrimary(pScrn)) + i830_allocate_overlay(pScrn, flags); +#endif #ifdef I830_USE_EXA - if (pI830->useEXA) { + if (pI830->useEXA) { + if (pI830->exa_offscreen == NULL) { /* Default EXA to having 3 screens worth of offscreen memory space * (for pixmaps), plus a double-buffered, 1920x1088 video's worth. + * + * XXX: It would be nice to auto-size it larger if the user + * specified a larger size, or to fit along with texture and FB + * memory if a low videoRam is specified. */ - size = 3 * pScrn->displayWidth * pI830->cpp * pScrn->virtualY; + size = 3 * pitch * pScrn->virtualY; size += 1920 * 1088 * 2 * 2; size = ROUND_TO_PAGE(size); - alloced = I830AllocVidMem(pScrn, &(pI830->Offscreen), - &(pI830->StolenPool), size, 1, - flags | - FROM_ANYWHERE | ALLOCATE_AT_BOTTOM); - if (alloced < size) { + pI830->exa_offscreen = i830_allocate_memory(pScrn, "exa offscreen", + size, 1, flags); + if (pI830->exa_offscreen == NULL) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate " "offscreen memory. Not enough VRAM?\n"); } return FALSE; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Successful allocation of " - "EXA offscreen memory at 0x%lx, size %ld KB\n", - pI830->Offscreen.Start, pI830->Offscreen.Size/1024); } } - if (pI830->useEXA && IS_I965G(pI830)) { - memset(&(pI830->EXAStateMem), 0, sizeof(I830MemRange)); - pI830->EXAStateMem.Key = -1; - size = ROUND_TO_PAGE(EXA_LINEAR_EXTRA); - align = GTT_PAGE_SIZE; - alloced = I830AllocVidMem(pScrn, &(pI830->EXAStateMem), - &(pI830->StolenPool), size, align, - flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); - if (alloced < size) { + + if (IS_I965G(pI830) && pI830->exa_965_state == NULL) { + pI830->exa_965_state = + i830_allocate_memory(pScrn, "exa G965 state buffer", + EXA_LINEAR_EXTRA, GTT_PAGE_SIZE, + flags); + if (pI830->exa_965_state == NULL) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "G965: Failed to allocate exa state buffer " @@ -827,228 +962,85 @@ I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags) } return FALSE; } - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, - "%sAllocated %ld kB for the G965 exa state buffer " - "at 0x%lx - 0x%lx.\n", s, - alloced / 1024, pI830->EXAStateMem.Start, - pI830->EXAStateMem.End); - } -#endif - } 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_2D_HEIGHT) - maxFb = lineSize * MAX_2D_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, pScrn->displayWidth * pI830->cpp); - if (tileable) { - if (IS_I9XX(pI830)) - align = MB(1); - else - 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; } +#endif /* I830_USE_EXA */ -#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 + if (flags & ALLOC_INITIAL) { - if (!pI830->SWCursor && !dryrun) { - for (i = 0; i < xf86_config->num_crtc; i++) { - if (!I830AllocateCursorBuffers(xf86_config->crtc[i], flags) && - pI830->SWCursor) - { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Disabling HW cursor because the cursor memory " - "allocation failed.\n"); - pI830->SWCursor = TRUE; - break; - } + /* 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); + + pI830->front_buffer_2 = + i830_allocate_framebuffer(pI830Ent->pScrn_2, pI8302, + &pI830->FbMemBox2, + TRUE, flags); + if (pI830->front_buffer_2 == NULL) + return FALSE; } + pI830->front_buffer = + i830_allocate_framebuffer(pScrn, pI830, &pI830->FbMemBox, + FALSE, flags); + if (pI830->front_buffer == NULL) + return FALSE; } -#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"); + if (!pI830->noAccel && !pI830->useEXA) { + if (pI830->xaa_scratch == NULL) { + pI830->xaa_scratch = + i830_allocate_memory(pScrn, "xaa scratch", + MAX_SCRATCH_BUFFER_SIZE, GTT_PAGE_SIZE, + flags); + if (pI830->xaa_scratch == NULL) { + pI830->xaa_scratch = + i830_allocate_memory(pScrn, "xaa scratch", + MIN_SCRATCH_BUFFER_SIZE, + GTT_PAGE_SIZE, + flags); + if (pI830->xaa_scratch == NULL) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate scratch buffer " + "space\n"); + } + return FALSE; + } } - 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"); + if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2 && + pI830->xaa_scratch_2 == NULL) + { + pI830->xaa_scratch_2 = + i830_allocate_memory(pScrn, "xaa scratch 2", + MAX_SCRATCH_BUFFER_SIZE, GTT_PAGE_SIZE, + flags); + if (pI830->xaa_scratch_2 == NULL) { + pI830->xaa_scratch_2 = + i830_allocate_memory(pScrn, "xaa scratch 2", + MIN_SCRATCH_BUFFER_SIZE, + GTT_PAGE_SIZE, + flags); + if (pI830->xaa_scratch_2 == NULL) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate secondary scratch " + "buffer space\n"); + } + return FALSE; } - 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; -#ifdef XF86DRI - if (!pI830->directRenderingDisabled) { - pI830->MemoryAperture.End -= KB(pI830->mmSize); - pI830->MemoryAperture.Size -= KB(pI830->mmSize); - } -#endif - pI830->StolenPool.Fixed = pI830->StolenMemory; - pI830->StolenPool.Total = pI830->StolenMemory; - 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) @@ -1062,16 +1054,13 @@ myLog2(unsigned int n) return log2; } -Bool -I830AllocateBackBuffer(ScrnInfoPtr pScrn, const int flags) +static Bool +i830_allocate_backbuffer(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); - unsigned long size, alloced, align = 0; - Bool tileable; + unsigned int pitch = pScrn->displayWidth * pI830->cpp; + unsigned long size; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); - int verbosity = dryrun ? 4 : 1; - const char *s = dryrun ? "[dryrun] " : ""; - int lines; int height; if (pI830->rotation & (RR_Rotate_0 | RR_Rotate_180)) @@ -1079,152 +1068,106 @@ I830AllocateBackBuffer(ScrnInfoPtr pScrn, const int flags) else height = pScrn->virtualX; - /* Back Buffer */ - memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer)); - pI830->BackBuffer.Key = -1; - tileable = !(flags & ALLOC_NO_TILING) && - IsTileable(pScrn, pScrn->displayWidth * pI830->cpp); - if (tileable) { - /* Make the height a multiple of the tile height (16) */ - lines = (height + 15) / 16 * 16; - } else { - lines = height; + /* Try to allocate on the best tile-friendly boundaries. */ + if (!(flags & ALLOC_NO_TILING) && IsTileable(pScrn, pitch)) + { + size = ROUND_TO_PAGE(pitch * ALIGN(height, 16)); + pI830->back_buffer = + i830_allocate_memory_tiled(pScrn, "back buffer", + size, pitch, GTT_PAGE_SIZE, + flags | ALIGN_BOTH_ENDS, + TILING_XMAJOR); + pI830->back_tiled = FENCE_XMAJOR; } - 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 >= (IS_I9XX(pI830) ? MB(1) : 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; - } + /* Otherwise, just allocate it linear */ + if (pI830->back_buffer == NULL) { + size = ROUND_TO_PAGE(pitch * height); + pI830->back_buffer = i830_allocate_memory(pScrn, "back buffer", + size, GTT_PAGE_SIZE, + flags | ALIGN_BOTH_ENDS); + pI830->back_tiled = FENCE_LINEAR; } - 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 (pI830->back_buffer == NULL) { 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) +static Bool +i830_allocate_depthbuffer(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); - unsigned long size, alloced, align = 0; - Bool tileable; + unsigned long size; Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); - int verbosity = dryrun ? 4 : 1; - const char *s = dryrun ? "[dryrun] " : ""; - int lines; + unsigned int pitch = pScrn->displayWidth * pI830->cpp; int height; + /* XXX: this rotation stuff is bogus */ if (pI830->rotation & (RR_Rotate_0 | RR_Rotate_180)) height = pScrn->virtualY; else height = 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, pScrn->displayWidth * pI830->cpp); - if (tileable) { - /* Make the height a multiple of the tile height (16) */ - lines = (height + 15) / 16 * 16; - } else { - lines = height; - } + /* First try allocating it tiled */ + if (!(flags & ALLOC_NO_TILING) && IsTileable(pScrn, pitch)) + { + size = ROUND_TO_PAGE(pitch * ALIGN(height, 16)); - 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 >= (IS_I9XX(pI830) ? MB(1) : 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; - } + pI830->depth_buffer = + i830_allocate_memory_tiled(pScrn, "depth buffer", size, pitch, + GTT_PAGE_SIZE, flags | ALIGN_BOTH_ENDS, + TILING_YMAJOR); + pI830->depth_tiled = FENCE_YMAJOR; } - 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); + + /* Otherwise, allocate it linear. */ + if (pI830->depth_buffer == NULL) { + size = ROUND_TO_PAGE(pitch * height); + pI830->depth_buffer = + i830_allocate_memory(pScrn, "depth buffer", size, GTT_PAGE_SIZE, + flags); + pI830->depth_tiled = FENCE_LINEAR; } - if (alloced < size) { + + if (pI830->depth_buffer == NULL) { 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) +static Bool +i830_allocate_texture_memory(ScrnInfoPtr pScrn, const int flags) { I830Ptr pI830 = I830PTR(pScrn); - unsigned long size, alloced; + unsigned long size; 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; + if (pI830->mmModeFlags & I830_KERNEL_MM) { + pI830->memory_manager = + i830_allocate_aperture(pScrn, "DRI memory manager", + pI830->mmSize, GTT_PAGE_SIZE, + flags | ALIGN_BOTH_ENDS); + /* XXX: try memory manager size backoff here? */ + if (pI830->memory_manager == NULL) + return FALSE; + } if (pI830->mmModeFlags & I830_KERNEL_TEX) { - if (dryrun && pI830->pEnt->device->videoRam == 0) { - /* If we're laying out a default-sized allocation, then don't be - * too greedy and just ask for 32MB. - */ - size = MB(32); - } else { - size = GetFreeSpace(pScrn); - } + /* XXX: auto-sizing */ + size = MB(32); if (dryrun && (size < MB(1))) size = MB(1); i = myLog2(size / I830_NR_TEX_REGIONS); @@ -1237,306 +1180,157 @@ I830AllocateTextureMemory(ScrnInfoPtr pScrn, const int flags) if (size < KB(512)) { if (!dryrun) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Less than 512 kBytes for texture space (real %ld " + "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) { + pI830->textures = i830_allocate_memory(pScrn, "textures", size, + GTT_PAGE_SIZE, flags); + if (pI830->textures == NULL) { 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) +i830_allocate_3d_memory(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) { + pI830->logical_context = i830_allocate_memory(pScrn, "logical 3D context", + KB(32), GTT_PAGE_SIZE, + flags); + if (pI830->logical_context == NULL) { 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)) + if (!i830_allocate_backbuffer(pScrn, flags)) return FALSE; - if (!I830AllocateDepthBuffer(pScrn, flags)) + if (!i830_allocate_depthbuffer(pScrn, flags)) return FALSE; - if (!I830AllocateTextureMemory(pScrn, flags)) + if (!i830_allocate_texture_memory(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); - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int i; - - DPRINTF(PFX, "I830FixupOffsets\n"); - - topOfMem = pI830->StolenPool.Total.End; - if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) - I830FixOffset(pScrn, &(pI830->FrontBuffer2)); - I830FixOffset(pScrn, &(pI830->FrontBuffer)); - - for (i = 0; i < xf86_config->num_crtc; i++) { - I830CrtcPrivatePtr intel_crtc = xf86_config->crtc[i]->driver_private; - - I830FixOffset(pScrn, &intel_crtc->cursor_mem); - I830FixOffset(pScrn, &intel_crtc->cursor_mem_argb); - } - - 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)); - if (pI830->mmModeFlags & I830_KERNEL_TEX) { - I830FixOffset(pScrn, &(pI830->TexMem)); - } - } -#endif -#ifdef I830_USE_EXA - if (pI830->useEXA) { - I830FixOffset(pScrn, &(pI830->Offscreen)); - if (IS_I965G(pI830)) - I830FixOffset(pScrn, &(pI830->EXAStateMem)); - } -#endif - return TRUE; -} - #ifdef XF86DRI -/* Tiled memory is good... really, really good... +/** + * Sets up a fence area for the hardware. * - * 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'. + * The fences control automatic tiled address swizzling for CPU access of the + * framebuffer. */ static void -SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, - unsigned int size) +i830_set_fence(ScrnInfoPtr pScrn, int nr, unsigned int offset, + unsigned int pitch, unsigned int size, + enum tile_format tile_format) { 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); + DPRINTF(PFX, "i830_set_fence(): %d, 0x%08x, %d, %d kByte\n", + nr, offset, pitch, size / 1024); + + assert(tile_format != TILING_NONE); - if (nr < 0 || nr > 7) { + if (IS_I965G(pI830)) { + if (nr < 0 || nr >= FENCE_NEW_NR) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "i830_set_fence(): fence %d out of range\n",nr); + return; + } + + switch (tile_format) { + case TILING_XMAJOR: + pI830->fence[nr] = (((pitch / 128) - 1) << 2) | offset | 1; + pI830->fence[nr] |= I965_FENCE_X_MAJOR; + break; + case TILING_YMAJOR: + /* YMajor can be 128B aligned but the current code dictates + * otherwise. This isn't a problem apart from memory waste. + * FIXME */ + pI830->fence[nr] = (((pitch / 128) - 1) << 2) | offset | 1; + pI830->fence[nr] |= I965_FENCE_Y_MAJOR; + break; + case TILING_NONE: + break; + } + + /* XXX Is it the next page, or the last page of the fenced region? */ + pI830->fence[FENCE_NEW_NR + nr] = offset + size; + return; + } + + if (nr < 0 || nr >= FENCE_NR) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: fence %d out of range\n",nr); + "i830_set_fence(): fence %d out of range\n",nr); return; } - i830Reg->Fence[nr] = 0; + pI830->fence[nr] = 0; if (IS_I9XX(pI830)) fence_mask = ~I915G_FENCE_START_MASK; else fence_mask = ~I830_FENCE_START_MASK; - if (start & fence_mask) { + if (offset & fence_mask) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: start (0x%08x) is not %s aligned\n", - nr, start, (IS_I9XX(pI830)) ? "1MB" : "512k"); + "i830_set_fence(): %d: offset (0x%08x) is not %s aligned\n", + nr, offset, (IS_I9XX(pI830)) ? "1MB" : "512k"); return; } - if (start % size) { + if (offset % size) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n", - nr, start, size / 1024); + "i830_set_fence(): %d: offset (0x%08x) is not size (%dk) " + "aligned\n", + nr, offset, size / 1024); return; } if (pitch & 127) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n", + "i830_set_fence(): %d: pitch (%d) not a multiple of 128 " + "bytes\n", nr, pitch); return; } - val = (start | FENCE_X_MAJOR | FENCE_VALID); + val = offset | FENCE_VALID; + + switch (tile_format) { + case TILING_XMAJOR: + val |= FENCE_X_MAJOR; + break; + case TILING_YMAJOR: + val |= FENCE_Y_MAJOR; + break; + case TILING_NONE: + break; + } if (IS_I9XX(pI830)) { switch (size) { @@ -1552,9 +1346,9 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, case MB(8): val |= I915G_FENCE_SIZE_8M; break; - case MB(16): - val |= I915G_FENCE_SIZE_16M; - break; + case MB(16): + val |= I915G_FENCE_SIZE_16M; + break; case MB(32): val |= I915G_FENCE_SIZE_32M; break; @@ -1562,8 +1356,8 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, val |= I915G_FENCE_SIZE_64M; break; default: - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: illegal size (%d kByte)\n", + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "i830_set_fence(): %d: illegal size (%d kByte)\n", nr, size / 1024); return; } @@ -1594,8 +1388,8 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, val |= FENCE_SIZE_64M; break; default: - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: illegal size (%d kByte)\n", + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "i830_set_fence(): %d: illegal size (%d kByte)\n", nr, size / 1024); return; } @@ -1620,8 +1414,8 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, val |= FENCE_PITCH_8; break; case 16: - val |= FENCE_PITCH_16; - break; + val |= FENCE_PITCH_16; + break; case 32: val |= FENCE_PITCH_32; break; @@ -1629,352 +1423,82 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, val |= FENCE_PITCH_64; break; default: - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "SetFence: %d: illegal pitch (%d)\n", nr, pitch); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "i830_set_fence(): %d: illegal pitch (%d)\n", nr, pitch); return; } - i830Reg->Fence[nr] = val; + pI830->fence[nr] = val; } - -static Bool -MakeTiles(ScrnInfoPtr pScrn, I830MemRange *pMem, unsigned int fence) -{ - 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; - - if (IS_I965G(pI830)) { - I830RegPtr i830Reg = &pI830->ModeReg; - - switch (fence) { - case FENCE_XMAJOR: - i830Reg->Fence[nextTile] = (((pitch / 128) - 1) << 2) | - pMem->Start | 1; - break; - case FENCE_YMAJOR: - /* YMajor can be 128B aligned but the current code dictates - * otherwise. This isn't a problem apart from memory waste. - * FIXME */ - i830Reg->Fence[nextTile] = (((pitch / 128) - 1) << 2) | - pMem->Start | 1; - i830Reg->Fence[nextTile] |= (1<<1); - break; - default: - case FENCE_LINEAR: - break; - } - - i830Reg->Fence[nextTile+FENCE_NEW_NR] = pMem->End; - nextTile++; - return TRUE; - } - - /* - * 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 */ - if (IS_I965G(pI830)) { - for (i = 0; i < FENCE_NEW_NR*2; i++) - pI830->ModeReg.Fence[i] = 0; - } else { - 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, pScrn->displayWidth * pI830->cpp)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "I830SetupMemoryTiling: Not tileable 0x%x\n", - pScrn->displayWidth * pI830->cpp); - pI830->allowPageFlip = FALSE; - return; - } - - pI830->front_tiled = FENCE_LINEAR; - pI830->back_tiled = FENCE_LINEAR; - pI830->depth_tiled = FENCE_LINEAR; - - if (pI830->allowPageFlip) { - if (pI830->allowPageFlip && pI830->FrontBuffer.Alignment >= KB(512)) { - if (MakeTiles(pScrn, &(pI830->FrontBuffer), FENCE_XMAJOR)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Activating tiled memory for the front buffer\n"); - pI830->front_tiled = FENCE_XMAJOR; - } 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), FENCE_XMAJOR)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Activating tiled memory for the back buffer.\n"); - pI830->back_tiled = FENCE_XMAJOR; - } 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), FENCE_YMAJOR)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Activating tiled memory for the depth buffer.\n"); - pI830->depth_tiled = FENCE_YMAJOR; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "MakeTiles failed for the depth 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); -} - +/** + * Called at EnterVT to grab the AGP GART and bind our allocations. + * + * In zaphod mode, this will walk the list trying to bind twice, since each + * pI830 points to the same allocation list, but the bind_memory will just + * no-op then. + */ Bool -I830BindAGPMemory(ScrnInfoPtr pScrn) +i830_bind_all_memory(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) + if (pI830->StolenOnly == TRUE || pI830->memory_list == NULL) return TRUE; - if (xf86AgpGARTSupported() && !pI830->GttBound) { - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int i; + if (xf86AgpGARTSupported() && !pI830->gtt_acquired) { + i830_memory *mem; 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; + pI830->gtt_acquired = TRUE; - for (i = 0; i < xf86_config->num_crtc; i++) { - I830CrtcPrivatePtr intel_crtc = xf86_config->crtc[i]->driver_private; - - if (!BindMemRange(pScrn, &intel_crtc->cursor_mem)) - return FALSE; - if (!BindMemRange(pScrn, &intel_crtc->cursor_mem_argb)) - 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 -#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 ((pI830->mmModeFlags & I830_KERNEL_TEX) && - !BindMemRange(pScrn, &(pI830->TexMem))) - return FALSE; - } -#endif -#ifdef I830_USE_EXA - if (pI830->useEXA) { - if (!BindMemRange(pScrn, &(pI830->Offscreen))) - return FALSE; - if (IS_I965G(pI830) && !BindMemRange(pScrn, &(pI830->EXAStateMem))) - return FALSE; + for (mem = pI830->memory_list->next; mem->next != NULL; + mem = mem->next) + { + if (!i830_bind_memory(pScrn, mem)) { + /* This shouldn't happen */ + FatalError("Couldn't bind memory for %s\n", mem->name); + } } -#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); -} - - +/** Called at LeaveVT, to unbind all of our AGP allocations. */ Bool -I830UnbindAGPMemory(ScrnInfoPtr pScrn) +i830_unbind_all_memory(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) { - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int i; + if (xf86AgpGARTSupported() && pI830->gtt_acquired) { + i830_memory *mem; -#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; - - for (i = 0; i < xf86_config->num_crtc; i++) { - I830CrtcPrivatePtr intel_crtc = - xf86_config->crtc[i]->driver_private; - - if (!UnbindMemRange(pScrn, &intel_crtc->cursor_mem)) - return FALSE; - if (!UnbindMemRange(pScrn, &intel_crtc->cursor_mem_argb)) - return FALSE; + for (mem = pI830->memory_list->next; mem->next != NULL; + mem = mem->next) + { + i830_unbind_memory(pScrn, mem); } - 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 -#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 ((pI830->mmModeFlags & I830_KERNEL_TEX) && - !UnbindMemRange(pScrn, &(pI830->TexMem))) - return FALSE; - } -#endif -#ifdef I830_USE_EXA - if (pI830->useEXA) { - if (!UnbindMemRange(pScrn, &(pI830->Offscreen))) - return FALSE; - if (IS_I965G(pI830) && !UnbindMemRange(pScrn, - &(pI830->EXAStateMem))) - return FALSE; - } -#endif + pI830->gtt_acquired = FALSE; + if (!xf86ReleaseGART(pScrn->scrnIndex)) return FALSE; - - pI830->GttBound = 0; } return TRUE; } +/** + * Returns the amount of system memory that could potentially be allocated + * from AGP, in kB. + */ long I830CheckAvailableMemory(ScrnInfoPtr pScrn) { |