Maemo patchset 20101501+0m5
[h-e-n] / drivers / gpu / pvr / ra.c
diff --git a/drivers/gpu/pvr/ra.c b/drivers/gpu/pvr/ra.c
new file mode 100644 (file)
index 0000000..d2dd2a0
--- /dev/null
@@ -0,0 +1,1041 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful but, except
+ * as otherwise stated in writing, without any warranty; without even the
+ * implied warranty of merchantability or fitness for a particular purpose.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+ *
+ ******************************************************************************/
+
+#include "services_headers.h"
+#include "hash.h"
+#include "ra.h"
+#include "buffer_manager.h"
+#include "osfunc.h"
+
+#include <linux/kernel.h>
+#include "proc.h"
+
+
+#define MINIMUM_HASH_SIZE (64)
+
+struct BT {
+       enum bt_type {
+               btt_span,
+               btt_free,
+               btt_live
+       } type;
+
+       u32 base;
+       size_t uSize;
+
+       struct BT *pNextSegment;
+       struct BT *pPrevSegment;
+
+       struct BT *pNextFree;
+       struct BT *pPrevFree;
+
+       struct BM_MAPPING *psMapping;
+};
+
+struct RA_ARENA {
+       char *name;
+       u32 uQuantum;
+       IMG_BOOL(*pImportAlloc)(void *, size_t uSize, size_t *pActualSize,
+                       struct BM_MAPPING **ppsMapping, u32 uFlags, u32 *pBase);
+       void (*pImportFree)(void *, u32, struct BM_MAPPING *psMapping);
+       void (*pBackingStoreFree)(void *, u32, u32, void *);
+       void *pImportHandle;
+#define FREE_TABLE_LIMIT 32
+       struct BT *aHeadFree[FREE_TABLE_LIMIT];
+       struct BT *pHeadSegment;
+       struct BT *pTailSegment;
+       struct HASH_TABLE *pSegmentHash;
+#ifdef RA_STATS
+       struct RA_STATISTICS sStatistics;
+#endif
+#if defined(CONFIG_PROC_FS) && defined(DEBUG)
+#define PROC_NAME_SIZE         32
+       char szProcInfoName[PROC_NAME_SIZE];
+       char szProcSegsName[PROC_NAME_SIZE];
+#endif
+};
+
+#if defined(CONFIG_PROC_FS) && defined(DEBUG)
+static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof,
+                      void *data);
+static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof,
+                      void *data);
+#endif
+
+static IMG_BOOL _RequestAllocFail(void *_h, size_t _uSize, size_t *_pActualSize,
+                 struct BM_MAPPING **_ppsMapping, u32 _uFlags, u32 *_pBase)
+{
+       PVR_UNREFERENCED_PARAMETER(_h);
+       PVR_UNREFERENCED_PARAMETER(_uSize);
+       PVR_UNREFERENCED_PARAMETER(_pActualSize);
+       PVR_UNREFERENCED_PARAMETER(_ppsMapping);
+       PVR_UNREFERENCED_PARAMETER(_uFlags);
+       PVR_UNREFERENCED_PARAMETER(_pBase);
+
+       return IMG_FALSE;
+}
+
+static u32 pvr_log2(size_t n)
+{
+       u32 l = 0;
+       n >>= 1;
+       while (n > 0) {
+               n >>= 1;
+               l++;
+       }
+       return l;
+}
+
+static void _SegmentListInsertAfter(struct RA_ARENA *pArena,
+                                   struct BT *pInsertionPoint, struct BT *pBT)
+{
+       PVR_ASSERT(pArena != NULL);
+       PVR_ASSERT(pInsertionPoint != NULL);
+
+       pBT->pNextSegment = pInsertionPoint->pNextSegment;
+       pBT->pPrevSegment = pInsertionPoint;
+       if (pInsertionPoint->pNextSegment == NULL)
+               pArena->pTailSegment = pBT;
+       else
+               pInsertionPoint->pNextSegment->pPrevSegment = pBT;
+       pInsertionPoint->pNextSegment = pBT;
+}
+
+static void _SegmentListInsert(struct RA_ARENA *pArena, struct BT *pBT)
+{
+
+       if (pArena->pHeadSegment == NULL) {
+               pArena->pHeadSegment = pArena->pTailSegment = pBT;
+               pBT->pNextSegment = pBT->pPrevSegment = NULL;
+       } else {
+               struct BT *pBTScan;
+               pBTScan = pArena->pHeadSegment;
+               while (pBTScan->pNextSegment != NULL
+                      && pBT->base >= pBTScan->pNextSegment->base)
+                       pBTScan = pBTScan->pNextSegment;
+               _SegmentListInsertAfter(pArena, pBTScan, pBT);
+       }
+}
+
+static void _SegmentListRemove(struct RA_ARENA *pArena, struct BT *pBT)
+{
+       if (pBT->pPrevSegment == NULL)
+               pArena->pHeadSegment = pBT->pNextSegment;
+       else
+               pBT->pPrevSegment->pNextSegment = pBT->pNextSegment;
+
+       if (pBT->pNextSegment == NULL)
+               pArena->pTailSegment = pBT->pPrevSegment;
+       else
+               pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment;
+}
+
+static struct BT *_SegmentSplit(struct RA_ARENA *pArena, struct BT *pBT,
+                               size_t uSize)
+{
+       struct BT *pNeighbour;
+
+       PVR_ASSERT(pArena != NULL);
+
+       if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                      sizeof(struct BT),
+                      (void **) &pNeighbour, NULL) != PVRSRV_OK)
+               return NULL;
+
+       pNeighbour->pPrevSegment = pBT;
+       pNeighbour->pNextSegment = pBT->pNextSegment;
+       if (pBT->pNextSegment == NULL)
+               pArena->pTailSegment = pNeighbour;
+       else
+               pBT->pNextSegment->pPrevSegment = pNeighbour;
+       pBT->pNextSegment = pNeighbour;
+
+       pNeighbour->type = btt_free;
+       pNeighbour->uSize = pBT->uSize - uSize;
+       pNeighbour->base = pBT->base + uSize;
+       pNeighbour->psMapping = pBT->psMapping;
+       pBT->uSize = uSize;
+       return pNeighbour;
+}
+
+static void _FreeListInsert(struct RA_ARENA *pArena, struct BT *pBT)
+{
+       u32 uIndex;
+       uIndex = pvr_log2(pBT->uSize);
+       pBT->type = btt_free;
+       pBT->pNextFree = pArena->aHeadFree[uIndex];
+       pBT->pPrevFree = NULL;
+       if (pArena->aHeadFree[uIndex] != NULL)
+               pArena->aHeadFree[uIndex]->pPrevFree = pBT;
+       pArena->aHeadFree[uIndex] = pBT;
+}
+
+static void _FreeListRemove(struct RA_ARENA *pArena, struct BT *pBT)
+{
+       u32 uIndex;
+       uIndex = pvr_log2(pBT->uSize);
+       if (pBT->pNextFree != NULL)
+               pBT->pNextFree->pPrevFree = pBT->pPrevFree;
+       if (pBT->pPrevFree == NULL)
+               pArena->aHeadFree[uIndex] = pBT->pNextFree;
+       else
+               pBT->pPrevFree->pNextFree = pBT->pNextFree;
+}
+
+static struct BT *_BuildSpanMarker(u32 base, size_t uSize)
+{
+       struct BT *pBT;
+
+       if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                      sizeof(struct BT),
+                      (void **) &pBT, NULL) != PVRSRV_OK)
+               return NULL;
+
+       pBT->type = btt_span;
+       pBT->base = base;
+       pBT->uSize = uSize;
+       pBT->psMapping = NULL;
+
+       return pBT;
+}
+
+static struct BT *_BuildBT(u32 base, size_t uSize)
+{
+       struct BT *pBT;
+
+       if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                      sizeof(struct BT),
+                      (void **) &pBT, NULL) != PVRSRV_OK)
+               return NULL;
+
+       pBT->type = btt_free;
+       pBT->base = base;
+       pBT->uSize = uSize;
+
+       return pBT;
+}
+
+static struct BT *_InsertResource(struct RA_ARENA *pArena, u32 base,
+                          size_t uSize)
+{
+       struct BT *pBT;
+       PVR_ASSERT(pArena != NULL);
+       pBT = _BuildBT(base, uSize);
+       if (pBT != NULL) {
+               _SegmentListInsert(pArena, pBT);
+               _FreeListInsert(pArena, pBT);
+#ifdef RA_STATS
+               pArena->sStatistics.uTotalResourceCount += uSize;
+               pArena->sStatistics.uFreeResourceCount += uSize;
+               pArena->sStatistics.uSpanCount++;
+#endif
+       }
+       return pBT;
+}
+
+static struct BT *_InsertResourceSpan(struct RA_ARENA *pArena, u32 base,
+                              size_t uSize)
+{
+       struct BT *pSpanStart;
+       struct BT *pSpanEnd;
+       struct BT *pBT;
+
+       PVR_ASSERT(pArena != NULL);
+
+       PVR_DPF(PVR_DBG_MESSAGE,
+                "RA_InsertResourceSpan: arena='%s', base=0x%x, size=0x%x",
+                pArena->name, base, uSize);
+
+       pSpanStart = _BuildSpanMarker(base, uSize);
+       if (pSpanStart == NULL)
+               goto fail_start;
+       pSpanEnd = _BuildSpanMarker(base + uSize, 0);
+       if (pSpanEnd == NULL)
+               goto fail_end;
+
+       pBT = _BuildBT(base, uSize);
+       if (pBT == NULL)
+               goto fail_bt;
+
+       _SegmentListInsert(pArena, pSpanStart);
+       _SegmentListInsertAfter(pArena, pSpanStart, pBT);
+       _FreeListInsert(pArena, pBT);
+       _SegmentListInsertAfter(pArena, pBT, pSpanEnd);
+#ifdef RA_STATS
+       pArena->sStatistics.uTotalResourceCount += uSize;
+#endif
+       return pBT;
+
+fail_bt:
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanEnd, NULL);
+fail_end:
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pSpanStart, NULL);
+fail_start:
+       return NULL;
+}
+
+static void _FreeBT(struct RA_ARENA *pArena, struct BT *pBT,
+                   IMG_BOOL bFreeBackingStore)
+{
+       struct BT *pNeighbour;
+       u32 uOrigBase;
+       size_t uOrigSize;
+
+       PVR_ASSERT(pArena != NULL);
+       PVR_ASSERT(pBT != NULL);
+
+#ifdef RA_STATS
+       pArena->sStatistics.uLiveSegmentCount--;
+       pArena->sStatistics.uFreeSegmentCount++;
+       pArena->sStatistics.uFreeResourceCount += pBT->uSize;
+#endif
+
+       uOrigBase = pBT->base;
+       uOrigSize = pBT->uSize;
+
+       pNeighbour = pBT->pPrevSegment;
+       if (pNeighbour != NULL
+           && pNeighbour->type == btt_free
+           && pNeighbour->base + pNeighbour->uSize == pBT->base) {
+               _FreeListRemove(pArena, pNeighbour);
+               _SegmentListRemove(pArena, pNeighbour);
+               pBT->base = pNeighbour->base;
+               pBT->uSize += pNeighbour->uSize;
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT),
+                         pNeighbour, NULL);
+#ifdef RA_STATS
+               pArena->sStatistics.uFreeSegmentCount--;
+#endif
+       }
+
+       pNeighbour = pBT->pNextSegment;
+       if (pNeighbour != NULL
+           && pNeighbour->type == btt_free
+           && pBT->base + pBT->uSize == pNeighbour->base) {
+               _FreeListRemove(pArena, pNeighbour);
+               _SegmentListRemove(pArena, pNeighbour);
+               pBT->uSize += pNeighbour->uSize;
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT),
+                         pNeighbour, NULL);
+#ifdef RA_STATS
+               pArena->sStatistics.uFreeSegmentCount--;
+#endif
+       }
+
+       if (pArena->pBackingStoreFree != NULL && bFreeBackingStore) {
+               u32 uRoundedStart, uRoundedEnd;
+
+               uRoundedStart = (uOrigBase / pArena->uQuantum) *
+                                                       pArena->uQuantum;
+
+               if (uRoundedStart < pBT->base)
+                       uRoundedStart += pArena->uQuantum;
+
+               uRoundedEnd =
+                   ((uOrigBase + uOrigSize + pArena->uQuantum -
+                     1) / pArena->uQuantum) * pArena->uQuantum;
+
+               if (uRoundedEnd > (pBT->base + pBT->uSize))
+                       uRoundedEnd -= pArena->uQuantum;
+
+               if (uRoundedStart < uRoundedEnd)
+                       pArena->pBackingStoreFree(pArena->pImportHandle,
+                                                 uRoundedStart, uRoundedEnd,
+                                                 (void *) 0);
+       }
+
+       if (pBT->pNextSegment != NULL && pBT->pNextSegment->type == btt_span
+           && pBT->pPrevSegment != NULL
+           && pBT->pPrevSegment->type == btt_span) {
+               struct BT *next = pBT->pNextSegment;
+               struct BT *prev = pBT->pPrevSegment;
+               _SegmentListRemove(pArena, next);
+               _SegmentListRemove(pArena, prev);
+               _SegmentListRemove(pArena, pBT);
+               pArena->pImportFree(pArena->pImportHandle, pBT->base,
+                                   pBT->psMapping);
+#ifdef RA_STATS
+               pArena->sStatistics.uSpanCount--;
+               pArena->sStatistics.uExportCount++;
+               pArena->sStatistics.uFreeSegmentCount--;
+               pArena->sStatistics.uFreeResourceCount -= pBT->uSize;
+               pArena->sStatistics.uTotalResourceCount -= pBT->uSize;
+#endif
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), next,
+                         NULL);
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), prev,
+                         NULL);
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT,
+                         NULL);
+       } else
+               _FreeListInsert(pArena, pBT);
+}
+
+static IMG_BOOL _AttemptAllocAligned(struct RA_ARENA *pArena, size_t uSize,
+                    struct BM_MAPPING **ppsMapping, u32 uFlags, u32 uAlignment,
+                    u32 uAlignmentOffset, u32 *base)
+{
+       u32 uIndex;
+       PVR_ASSERT(pArena != NULL);
+
+       PVR_UNREFERENCED_PARAMETER(uFlags);
+
+       if (uAlignment > 1)
+               uAlignmentOffset %= uAlignment;
+
+       uIndex = pvr_log2(uSize);
+
+       while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex] == NULL)
+               uIndex++;
+
+       while (uIndex < FREE_TABLE_LIMIT) {
+               if (pArena->aHeadFree[uIndex] != NULL) {
+                       struct BT *pBT;
+
+                       pBT = pArena->aHeadFree[uIndex];
+                       while (pBT != NULL) {
+                               u32 aligned_base;
+
+                               if (uAlignment > 1)
+                                       aligned_base =
+                                         (pBT->base + uAlignmentOffset +
+                                           uAlignment - 1) / uAlignment *
+                                           uAlignment - uAlignmentOffset;
+                               else
+                                       aligned_base = pBT->base;
+                               PVR_DPF(PVR_DBG_MESSAGE,
+                                  "RA_AttemptAllocAligned: pBT-base=0x%x "
+                                  "pBT-size=0x%x alignedbase=0x%x size=0x%x",
+                                  pBT->base, pBT->uSize, aligned_base, uSize);
+
+                               if (pBT->base + pBT->uSize >=
+                                               aligned_base + uSize) {
+                                       if (!pBT->psMapping ||
+                                           pBT->psMapping->ui32Flags ==
+                                                                   uFlags) {
+                                               _FreeListRemove(pArena, pBT);
+                                               PVR_ASSERT(pBT->type ==
+                                                               btt_free);
+#ifdef RA_STATS
+                                               pArena->sStatistics.
+                                                       uLiveSegmentCount++;
+                                               pArena->sStatistics.
+                                                       uFreeSegmentCount--;
+                                               pArena->sStatistics.
+                                                       uFreeResourceCount -=
+                                                       pBT->uSize;
+#endif
+                                               if (aligned_base > pBT->base) {
+                                                       struct BT *pNeighbour;
+
+                                                       pNeighbour =
+                                                               _SegmentSplit
+                                                               (pArena, pBT,
+                                                                aligned_base -
+                                                                pBT->base);
+
+                                                       if (pNeighbour ==
+                                                                       NULL) {
+                                                               PVR_DPF(
+                                                               PVR_DBG_ERROR,
+                                                               "_AttemptAlloc"
+                                                               "Aligned: "
+                                                               "Front split "
+                                                               "failed");
+
+                                                               _FreeListInsert
+                                                                       (pArena,
+                                                                        pBT);
+                                                               return
+                                                                    IMG_FALSE;
+                                                       }
+
+                                                       _FreeListInsert(pArena,
+                                                                       pBT);
+#ifdef RA_STATS
+                                                       pArena->sStatistics.
+                                                           uFreeSegmentCount++;
+                                                       pArena->sStatistics.
+                                                          uFreeResourceCount +=
+                                                                   pBT->uSize;
+#endif
+                                                       pBT = pNeighbour;
+                                               }
+
+                                               if (pBT->uSize > uSize) {
+                                                       struct BT *pNeighbour;
+                                                       pNeighbour =
+                                                               _SegmentSplit
+                                                               (pArena, pBT,
+                                                                uSize);
+
+                                                       if (pNeighbour ==
+                                                                       NULL) {
+                                                               PVR_DPF(
+                                                               PVR_DBG_ERROR,
+                                                               "_AttemptAlloc"
+                                                               "Aligned:"
+                                                               " Back split "
+                                                               "failed");
+
+                                                               _FreeListInsert
+                                                                       (pArena,
+                                                                        pBT);
+                                                               return
+                                                                    IMG_FALSE;
+                                                       }
+
+                                                       _FreeListInsert(pArena,
+                                                               pNeighbour);
+#ifdef RA_STATS
+                                                       pArena->sStatistics.
+                                                           uFreeSegmentCount++;
+                                                       pArena->sStatistics.
+                                                          uFreeResourceCount +=
+                                                             pNeighbour->uSize;
+#endif
+                                               }
+
+                                               pBT->type = btt_live;
+
+                                               if (!HASH_Insert(
+                                                        pArena->pSegmentHash,
+                                                        pBT->base, (u32)pBT)) {
+                                                       _FreeBT(pArena, pBT,
+                                                               IMG_FALSE);
+                                                       return IMG_FALSE;
+                                               }
+
+                                               if (ppsMapping != NULL)
+                                                       *ppsMapping =
+                                                               pBT->psMapping;
+
+                                               *base = pBT->base;
+
+                                               return IMG_TRUE;
+                                       } else {
+                                               PVR_DPF(PVR_DBG_MESSAGE,
+                                               "AttemptAllocAligned: "
+                                               "mismatch in flags. "
+                                               "Import has %x, request "
+                                               "was %x",
+                                               pBT->psMapping->ui32Flags,
+                                               uFlags);
+
+                                       }
+                               }
+                               pBT = pBT->pNextFree;
+                       }
+
+               }
+               uIndex++;
+       }
+
+       return IMG_FALSE;
+}
+
+struct RA_ARENA *RA_Create(char *name, u32 base, size_t uSize,
+                   struct BM_MAPPING *psMapping, size_t uQuantum,
+                   IMG_BOOL(*alloc) (void *, size_t uSize,
+                                     size_t *pActualSize,
+                                     struct BM_MAPPING **ppsMapping,
+                                     u32 _flags, u32 *pBase),
+                   void(*free) (void *, u32, struct BM_MAPPING *psMapping),
+                   void(*backingstore_free) (void *, u32, u32, void *),
+                   void *pImportHandle)
+{
+       struct RA_ARENA *pArena;
+       struct BT *pBT;
+       int i;
+
+       PVR_DPF(PVR_DBG_MESSAGE, "RA_Create: "
+               "name='%s', base=0x%x, uSize=0x%x, alloc=0x%x, free=0x%x",
+               name, base, uSize, alloc, free);
+
+       if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                      sizeof(*pArena),
+                      (void **) &pArena, NULL) != PVRSRV_OK)
+               goto arena_fail;
+
+       pArena->name = name;
+       pArena->pImportAlloc = alloc != NULL ? alloc : _RequestAllocFail;
+       pArena->pImportFree = free;
+       pArena->pBackingStoreFree = backingstore_free;
+       pArena->pImportHandle = pImportHandle;
+       for (i = 0; i < FREE_TABLE_LIMIT; i++)
+               pArena->aHeadFree[i] = NULL;
+       pArena->pHeadSegment = NULL;
+       pArena->pTailSegment = NULL;
+       pArena->uQuantum = uQuantum;
+
+#ifdef RA_STATS
+       pArena->sStatistics.uSpanCount = 0;
+       pArena->sStatistics.uLiveSegmentCount = 0;
+       pArena->sStatistics.uFreeSegmentCount = 0;
+       pArena->sStatistics.uFreeResourceCount = 0;
+       pArena->sStatistics.uTotalResourceCount = 0;
+       pArena->sStatistics.uCumulativeAllocs = 0;
+       pArena->sStatistics.uCumulativeFrees = 0;
+       pArena->sStatistics.uImportCount = 0;
+       pArena->sStatistics.uExportCount = 0;
+#endif
+
+#if defined(CONFIG_PROC_FS) && defined(DEBUG)
+       if (strcmp(pArena->name, "") != 0) {
+               sprintf(pArena->szProcInfoName, "ra_info_%s", pArena->name);
+               CreateProcEntry(pArena->szProcInfoName, RA_DumpInfo, NULL,
+                               pArena);
+               sprintf(pArena->szProcSegsName, "ra_segs_%s", pArena->name);
+               CreateProcEntry(pArena->szProcSegsName, RA_DumpSegs, NULL,
+                               pArena);
+       }
+#endif
+
+       pArena->pSegmentHash = HASH_Create(MINIMUM_HASH_SIZE);
+       if (pArena->pSegmentHash == NULL)
+               goto hash_fail;
+       if (uSize > 0) {
+               uSize = (uSize + uQuantum - 1) / uQuantum * uQuantum;
+               pBT = _InsertResource(pArena, base, uSize);
+               if (pBT == NULL)
+                       goto insert_fail;
+               pBT->psMapping = psMapping;
+
+       }
+       return pArena;
+
+insert_fail:
+       HASH_Delete(pArena->pSegmentHash);
+hash_fail:
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
+                 NULL);
+arena_fail:
+       return NULL;
+}
+
+void RA_Delete(struct RA_ARENA *pArena)
+{
+       u32 uIndex;
+
+       PVR_ASSERT(pArena != NULL);
+       PVR_DPF(PVR_DBG_MESSAGE, "RA_Delete: name='%s'", pArena->name);
+
+       for (uIndex = 0; uIndex < FREE_TABLE_LIMIT; uIndex++)
+               pArena->aHeadFree[uIndex] = NULL;
+
+       while (pArena->pHeadSegment != NULL) {
+               struct BT *pBT = pArena->pHeadSegment;
+               PVR_ASSERT(pBT->type == btt_free);
+               _SegmentListRemove(pArena, pBT);
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BT), pBT,
+                         NULL);
+#ifdef RA_STATS
+               pArena->sStatistics.uSpanCount--;
+#endif
+       }
+#if defined(CONFIG_PROC_FS) && defined(DEBUG)
+       RemoveProcEntry(pArena->szProcInfoName);
+       RemoveProcEntry(pArena->szProcSegsName);
+#endif
+       HASH_Delete(pArena->pSegmentHash);
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct RA_ARENA), pArena,
+                 NULL);
+}
+
+IMG_BOOL RA_Add(struct RA_ARENA *pArena, u32 base, size_t uSize)
+{
+       PVR_ASSERT(pArena != NULL);
+
+       PVR_DPF(PVR_DBG_MESSAGE,
+                "RA_Add: name='%s', base=0x%x, size=0x%x", pArena->name, base,
+                uSize);
+
+       uSize =
+           (uSize + pArena->uQuantum -
+            1) / pArena->uQuantum * pArena->uQuantum;
+       return (IMG_BOOL)(_InsertResource(pArena, base, uSize) != NULL);
+}
+
+IMG_BOOL RA_Alloc(struct RA_ARENA *pArena, size_t uRequestSize,
+                 size_t *pActualSize, struct BM_MAPPING **ppsMapping,
+                 u32 uFlags, u32 uAlignment, u32 uAlignmentOffset, u32 *base)
+{
+       IMG_BOOL bResult = IMG_FALSE;
+       size_t uSize = uRequestSize;
+
+       PVR_ASSERT(pArena != NULL);
+
+
+       if (pActualSize != NULL)
+               *pActualSize = uSize;
+
+       PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
+                "arena='%s', size=0x%x(0x%x), alignment=0x%x, offset=0x%x",
+                pArena->name, uSize, uRequestSize, uAlignment,
+                uAlignmentOffset);
+
+       bResult = _AttemptAllocAligned(pArena, uSize, ppsMapping, uFlags,
+                                      uAlignment, uAlignmentOffset, base);
+       if (!bResult) {
+               struct BM_MAPPING *psImportMapping;
+               u32 import_base;
+               size_t uImportSize = uSize;
+
+               if (uAlignment > pArena->uQuantum)
+                       uImportSize += (uAlignment - 1);
+
+               uImportSize =
+                   ((uImportSize + pArena->uQuantum -
+                     1) / pArena->uQuantum) * pArena->uQuantum;
+
+               bResult =
+                   pArena->pImportAlloc(pArena->pImportHandle, uImportSize,
+                                        &uImportSize, &psImportMapping, uFlags,
+                                        &import_base);
+               if (bResult) {
+                       struct BT *pBT;
+                       pBT =
+                           _InsertResourceSpan(pArena, import_base,
+                                               uImportSize);
+
+                       if (pBT == NULL) {
+
+                               pArena->pImportFree(pArena->pImportHandle,
+                                                   import_base,
+                                                   psImportMapping);
+                               PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
+                                       "name='%s', size=0x%x failed!",
+                                        pArena->name, uSize);
+
+                               return IMG_FALSE;
+                       }
+                       pBT->psMapping = psImportMapping;
+#ifdef RA_STATS
+                       pArena->sStatistics.uFreeSegmentCount++;
+                       pArena->sStatistics.uFreeResourceCount += uImportSize;
+                       pArena->sStatistics.uImportCount++;
+                       pArena->sStatistics.uSpanCount++;
+#endif
+                       bResult =
+                           _AttemptAllocAligned(pArena, uSize, ppsMapping,
+                                                uFlags, uAlignment,
+                                                uAlignmentOffset, base);
+                       if (!bResult)
+                               PVR_DPF(PVR_DBG_MESSAGE, "RA_Alloc: "
+                                       "name='%s' uAlignment failed!",
+                                        pArena->name);
+               }
+       }
+#ifdef RA_STATS
+       if (bResult)
+               pArena->sStatistics.uCumulativeAllocs++;
+#endif
+
+       PVR_DPF(PVR_DBG_MESSAGE,
+                "RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d",
+                pArena->name, uSize, *base, bResult);
+
+       return bResult;
+}
+
+void RA_Free(struct RA_ARENA *pArena, u32 base, IMG_BOOL bFreeBackingStore)
+{
+       struct BT *pBT;
+
+       PVR_ASSERT(pArena != NULL);
+
+
+       PVR_DPF(PVR_DBG_MESSAGE,
+                "RA_Free: name='%s', base=0x%x", pArena->name, base);
+
+       pBT = (struct BT *)HASH_Remove(pArena->pSegmentHash, base);
+       PVR_ASSERT(pBT != NULL);
+
+       if (pBT) {
+               PVR_ASSERT(pBT->base == base);
+
+#ifdef RA_STATS
+               pArena->sStatistics.uCumulativeFrees++;
+#endif
+
+               _FreeBT(pArena, pBT, bFreeBackingStore);
+       }
+}
+
+IMG_BOOL RA_GetNextLiveSegment(void *hArena,
+                              struct RA_SEGMENT_DETAILS *psSegDetails)
+{
+       struct BT *pBT;
+
+       if (psSegDetails->hSegment) {
+               pBT = (struct BT *)psSegDetails->hSegment;
+       } else {
+               struct RA_ARENA *pArena = (struct RA_ARENA *)hArena;
+
+               pBT = pArena->pHeadSegment;
+       }
+
+       while (pBT != NULL) {
+               if (pBT->type == btt_live) {
+                       psSegDetails->uiSize = pBT->uSize;
+                       psSegDetails->sCpuPhyAddr.uiAddr = pBT->base;
+                       psSegDetails->hSegment = (void *) pBT->pNextSegment;
+
+                       return IMG_TRUE;
+               }
+
+               pBT = pBT->pNextSegment;
+       }
+
+       psSegDetails->uiSize = 0;
+       psSegDetails->sCpuPhyAddr.uiAddr = 0;
+       psSegDetails->hSegment = (void *) -1;
+
+       return IMG_FALSE;
+}
+
+#if (defined(CONFIG_PROC_FS) && defined(DEBUG)) || defined(RA_STATS)
+static char *_BTType(int eType)
+{
+       switch (eType) {
+       case btt_span:
+               return "span";
+       case btt_free:
+               return "free";
+       case btt_live:
+               return "live";
+       }
+       return "junk";
+}
+#endif
+
+#if defined(CONFIG_PROC_FS) && defined(DEBUG)
+static int RA_DumpSegs(char *page, char **start, off_t off, int count, int *eof,
+                      void *data)
+{
+       struct BT *pBT = NULL;
+       int len = 0;
+       struct RA_ARENA *pArena = (struct RA_ARENA *)data;
+
+       if (count < 80) {
+               *start = (char *)0;
+               return 0;
+       }
+       *eof = 0;
+       *start = (char *)1;
+       if (off == 0)
+               return printAppend(page, count, 0,
+                       "Arena \"%s\"\nBase         Size Type Ref\n",
+                       pArena->name);
+       for (pBT = pArena->pHeadSegment; --off && pBT;
+            pBT = pBT->pNextSegment)
+               ;
+       if (pBT)
+               len = printAppend(page, count, 0, "%08x %8x %4s %08x\n",
+                                 (unsigned int)pBT->base,
+                                 (unsigned int)pBT->uSize, _BTType(pBT->type),
+                                 (unsigned int)pBT->psMapping);
+       else
+               *eof = 1;
+       return len;
+}
+
+static int RA_DumpInfo(char *page, char **start, off_t off, int count, int *eof,
+           void *data)
+{
+       int len = 0;
+       struct RA_ARENA *pArena = (struct RA_ARENA *)data;
+
+       if (count < 80) {
+               *start = (char *)0;
+               return 0;
+       }
+       *eof = 0;
+       switch (off) {
+       case 0:
+               len = printAppend(page, count, 0, "quantum\t\t\t%u\n",
+                                 pArena->uQuantum);
+               break;
+       case 1:
+               len =
+                   printAppend(page, count, 0, "import_handle\t\t%08X\n",
+                               (unsigned int)pArena->pImportHandle);
+               break;
+#ifdef RA_STATS
+       case 2:
+               len = printAppend(page, count, 0, "span count\t\t%u\n",
+                               pArena->sStatistics.uSpanCount);
+               break;
+       case 3:
+               len = printAppend(page, count, 0, "live segment count\t%u\n",
+                               pArena->sStatistics.uLiveSegmentCount);
+               break;
+       case 4:
+               len = printAppend(page, count, 0, "free segment count\t%u\n",
+                               pArena->sStatistics.uFreeSegmentCount);
+               break;
+       case 5:
+               len = printAppend(page, count, 0,
+                               "free resource count\t%u (0x%x)\n",
+                               pArena->sStatistics.uFreeResourceCount,
+                               (unsigned int)pArena->sStatistics.
+                               uFreeResourceCount);
+               break;
+       case 6:
+               len = printAppend(page, count, 0, "total allocs\t\t%u\n",
+                               pArena->sStatistics.uCumulativeAllocs);
+               break;
+       case 7:
+               len = printAppend(page, count, 0, "total frees\t\t%u\n",
+                               pArena->sStatistics.uCumulativeFrees);
+               break;
+       case 8:
+               len = printAppend(page, count, 0, "import count\t\t%u\n",
+                               pArena->sStatistics.uImportCount);
+               break;
+       case 9:
+               len = printAppend(page, count, 0, "export count\t\t%u\n",
+                               pArena->sStatistics.uExportCount);
+               break;
+#endif
+
+       default:
+               *eof = 1;
+       }
+       *start = (char *)1;
+       return len;
+}
+#endif
+
+#ifdef RA_STATS
+enum PVRSRV_ERROR RA_GetStats(struct RA_ARENA *pArena,
+                        char **ppszStr, u32 *pui32StrLen)
+{
+       char *pszStr = *ppszStr;
+       u32 ui32StrLen = *pui32StrLen;
+       s32 i32Count;
+       struct BT *pBT;
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count = OSSNPrintf(pszStr, 100, "\nArena '%s':\n", pArena->name);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100,
+                      "  allocCB=%08X freeCB=%08X handle=%08X quantum=%d\n",
+                      pArena->pImportAlloc, pArena->pImportFree,
+                      pArena->pImportHandle, pArena->uQuantum);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "span count\t\t%lu\n",
+                      pArena->sStatistics.uSpanCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "live segment count\t%lu\n",
+                      pArena->sStatistics.uLiveSegmentCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "free segment count\t%lu\n",
+                      pArena->sStatistics.uFreeSegmentCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%lu (0x%x)\n",
+                             pArena->sStatistics.uFreeResourceCount,
+                             (unsigned int)pArena->sStatistics.
+                             uFreeResourceCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "total allocs\t\t%lu\n",
+                      pArena->sStatistics.uCumulativeAllocs);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "total frees\t\t%lu\n",
+                      pArena->sStatistics.uCumulativeFrees);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "import count\t\t%lu\n",
+                      pArena->sStatistics.uImportCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count =
+           OSSNPrintf(pszStr, 100, "export count\t\t%lu\n",
+                      pArena->sStatistics.uExportCount);
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       CHECK_SPACE(ui32StrLen);
+       i32Count = OSSNPrintf(pszStr, 100, "  segment Chain:\n");
+       UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+
+       if (pArena->pHeadSegment != NULL &&
+           pArena->pHeadSegment->pPrevSegment != NULL) {
+               CHECK_SPACE(ui32StrLen);
+               i32Count =
+                   OSSNPrintf(pszStr, 100,
+                      "  error: head boundary tag has invalid pPrevSegment\n");
+               UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+       }
+
+       if (pArena->pTailSegment != NULL &&
+           pArena->pTailSegment->pNextSegment != NULL) {
+               CHECK_SPACE(ui32StrLen);
+               i32Count =
+                   OSSNPrintf(pszStr, 100,
+                      "  error: tail boundary tag has invalid pNextSegment\n");
+               UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+       }
+
+       for (pBT = pArena->pHeadSegment; pBT != NULL;
+            pBT = pBT->pNextSegment) {
+               CHECK_SPACE(ui32StrLen);
+               i32Count =
+                   OSSNPrintf(pszStr, 100,
+                              "\tbase=0x%x size=0x%x type=%s ref=%08X\n",
+                              (unsigned long)pBT->base, pBT->uSize,
+                              _BTType(pBT->type), pBT->psMapping);
+               UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
+       }
+
+       *ppszStr = pszStr;
+       *pui32StrLen = ui32StrLen;
+
+       return PVRSRV_OK;
+}
+#endif