i830_memory.c

来自「是由intel提供的针对intel显卡915以上系列的linux驱动」· C语言 代码 · 共 1,966 行 · 第 1/4 页

C
1,966
字号
/* $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 acopy of this software and associated documentation files (the"Software"), to deal in the Software without restriction, includingwithout limitation the rights to use, copy, modify, merge, publish,distribute, sub license, and/or sell copies of the Software, and topermit persons to whom the Software is furnished to do so, subject tothe following conditions:The above copyright notice and this permission notice (including thenext paragraph) shall be included in all copies or substantial portionsof the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESSOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OFMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FORANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**************************************************************************//* * Reformatted with GNU indent (2.2.8), using the following options: * *    -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 *    -lp -npcs -psl -sob -ss -br -ce -sc -hnl * * This provides a good match with the original i810 code and preferred * XFree86 formatting conventions. * * When editing this driver, please follow the existing formatting, and edit * with <TAB> characters expanded at 8-column intervals. *//* * Authors: *   Keith Whitwell <keith@tungstengraphics.com> *   David Dawes <dawes@xfree86.org> * * Updated for Dual Head capabilities: *   Alan Hourihane <alanh@tungstengraphics.com> */#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#endifstatic unsigned longGetBestTileAlignment(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 longAllocFromPool(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 longAllocFromAGP(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 = I830AllocateGARTMemory(pScrn->scrnIndex, size, 2,					      &(result->Physical));      } else {         /* Due to a bug in agpgart in 2.6 kernels resulting in very poor	  * allocation performance we need to workaround it here...	  */	 result->Key = I830AllocateGARTMemory(pScrn->scrnIndex, size, 3, NULL);         if (result->Key == -1)	    result->Key = I830AllocateGARTMemory(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;}voidI830FreeVidMem(ScrnInfoPtr pScrn, I830MemRange *range){   I830Ptr pI830 = I830PTR(pScrn);   if (!range || range->Size == 0)      return;   if (range->Key != -1)      I830DeallocateGARTMemory(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 longI830AllocVidMem(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 BoolAllocateRingBuffer(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 BoolAllocateOverlay(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);   }   return TRUE;}#endifstatic BoolIsTileable(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;   }}BoolI830AllocateRotatedBuffer(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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?