blob: 84a2162dca56efb2135e3aa4e33f25288b4e8f11 [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) 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"
#ifdef __linux__
#include <linux/kernel.h>
#include "proc.h"
#endif
#ifdef USE_BM_FREESPACE_CHECK
#include <stdio.h>
#endif
#define MINIMUM_HASH_SIZE (64)
#if defined(VALIDATE_ARENA_TEST)
typedef enum RESOURCE_DESCRIPTOR_TAG {
RESOURCE_SPAN_LIVE = 10,
RESOURCE_SPAN_FREE,
IMPORTED_RESOURCE_SPAN_START,
IMPORTED_RESOURCE_SPAN_LIVE,
IMPORTED_RESOURCE_SPAN_FREE,
IMPORTED_RESOURCE_SPAN_END,
} RESOURCE_DESCRIPTOR;
typedef enum RESOURCE_TYPE_TAG {
IMPORTED_RESOURCE_TYPE = 20,
NON_IMPORTED_RESOURCE_TYPE
} RESOURCE_TYPE;
static IMG_UINT32 ui32BoundaryTagID = 0;
IMG_UINT32 ValidateArena(RA_ARENA *pArena);
#endif
struct _BT_
{
enum bt_type
{
btt_span,
btt_free,
btt_live
} type;
IMG_UINTPTR_T base;
IMG_SIZE_T uSize;
struct _BT_ *pNextSegment;
struct _BT_ *pPrevSegment;
struct _BT_ *pNextFree;
struct _BT_ *pPrevFree;
BM_MAPPING *psMapping;
#if defined(VALIDATE_ARENA_TEST)
RESOURCE_DESCRIPTOR eResourceSpan;
RESOURCE_TYPE eResourceType;
IMG_UINT32 ui32BoundaryTagID;
#endif
};
typedef struct _BT_ BT;
struct _RA_ARENA_
{
IMG_CHAR *name;
IMG_SIZE_T uQuantum;
IMG_BOOL (*pImportAlloc)(IMG_VOID *,
IMG_SIZE_T uSize,
IMG_SIZE_T *pActualSize,
BM_MAPPING **ppsMapping,
IMG_UINT32 uFlags,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength,
IMG_UINTPTR_T *pBase);
IMG_VOID (*pImportFree) (IMG_VOID *,
IMG_UINTPTR_T,
BM_MAPPING *psMapping);
IMG_VOID (*pBackingStoreFree) (IMG_VOID *, IMG_SIZE_T, IMG_SIZE_T, IMG_HANDLE);
IMG_VOID *pImportHandle;
#define FREE_TABLE_LIMIT 32
BT *aHeadFree [FREE_TABLE_LIMIT];
BT *pHeadSegment;
BT *pTailSegment;
HASH_TABLE *pSegmentHash;
#ifdef RA_STATS
RA_STATISTICS sStatistics;
#endif
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
#define PROC_NAME_SIZE 64
struct proc_dir_entry* pProcInfo;
struct proc_dir_entry* pProcSegs;
IMG_BOOL bInitProcEntry;
#endif
};
#if defined(ENABLE_RA_DUMP)
IMG_VOID RA_Dump (RA_ARENA *pArena);
#endif
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
static void RA_ProcSeqShowInfo(struct seq_file *sfile, void* el);
static void* RA_ProcSeqOff2ElementInfo(struct seq_file * sfile, loff_t off);
static void RA_ProcSeqShowRegs(struct seq_file *sfile, void* el);
static void* RA_ProcSeqOff2ElementRegs(struct seq_file * sfile, loff_t off);
#endif
#ifdef USE_BM_FREESPACE_CHECK
IMG_VOID CheckBMFreespace(IMG_VOID);
#endif
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
static IMG_CHAR *ReplaceSpaces(IMG_CHAR * const pS)
{
IMG_CHAR *pT;
for(pT = pS; *pT != 0; pT++)
{
if (*pT == ' ' || *pT == '\t')
{
*pT = '_';
}
}
return pS;
}
#endif
static IMG_BOOL
_RequestAllocFail (IMG_VOID *_h,
IMG_SIZE_T _uSize,
IMG_SIZE_T *_pActualSize,
BM_MAPPING **_ppsMapping,
IMG_UINT32 _uFlags,
IMG_PVOID _pvPrivData,
IMG_UINT32 _ui32PrivDataLength,
IMG_UINTPTR_T *_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);
PVR_UNREFERENCED_PARAMETER (_pvPrivData);
PVR_UNREFERENCED_PARAMETER (_ui32PrivDataLength);
return IMG_FALSE;
}
static IMG_UINT32
pvr_log2 (IMG_SIZE_T n)
{
IMG_UINT32 l = 0;
n>>=1;
while (n>0)
{
n>>=1;
l++;
}
return l;
}
static PVRSRV_ERROR
_SegmentListInsertAfter (RA_ARENA *pArena,
BT *pInsertionPoint,
BT *pBT)
{
PVR_ASSERT (pArena != IMG_NULL);
PVR_ASSERT (pInsertionPoint != IMG_NULL);
if ((pInsertionPoint == IMG_NULL) || (pArena == IMG_NULL))
{
PVR_DPF ((PVR_DBG_ERROR,"_SegmentListInsertAfter: invalid parameters"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
pBT->pNextSegment = pInsertionPoint->pNextSegment;
pBT->pPrevSegment = pInsertionPoint;
if (pInsertionPoint->pNextSegment == IMG_NULL)
pArena->pTailSegment = pBT;
else
pInsertionPoint->pNextSegment->pPrevSegment = pBT;
pInsertionPoint->pNextSegment = pBT;
return PVRSRV_OK;
}
static PVRSRV_ERROR
_SegmentListInsert (RA_ARENA *pArena, BT *pBT)
{
PVRSRV_ERROR eError = PVRSRV_OK;
if (pArena->pHeadSegment == IMG_NULL)
{
pArena->pHeadSegment = pArena->pTailSegment = pBT;
pBT->pNextSegment = pBT->pPrevSegment = IMG_NULL;
}
else
{
BT *pBTScan;
if (pBT->base < pArena->pHeadSegment->base)
{
pBT->pNextSegment = pArena->pHeadSegment;
pArena->pHeadSegment->pPrevSegment = pBT;
pArena->pHeadSegment = pBT;
pBT->pPrevSegment = IMG_NULL;
}
else
{
pBTScan = pArena->pHeadSegment;
while ((pBTScan->pNextSegment != IMG_NULL) && (pBT->base >= pBTScan->pNextSegment->base))
{
pBTScan = pBTScan->pNextSegment;
}
eError = _SegmentListInsertAfter (pArena, pBTScan, pBT);
if (eError != PVRSRV_OK)
{
return eError;
}
}
}
return eError;
}
static IMG_VOID
_SegmentListRemove (RA_ARENA *pArena, BT *pBT)
{
if (pBT->pPrevSegment == IMG_NULL)
pArena->pHeadSegment = pBT->pNextSegment;
else
pBT->pPrevSegment->pNextSegment = pBT->pNextSegment;
if (pBT->pNextSegment == IMG_NULL)
pArena->pTailSegment = pBT->pPrevSegment;
else
pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment;
}
static BT *
_SegmentSplit (RA_ARENA *pArena, BT *pBT, IMG_SIZE_T uSize)
{
BT *pNeighbour;
PVR_ASSERT (pArena != IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_SegmentSplit: invalid parameter - pArena"));
return IMG_NULL;
}
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(BT),
(IMG_VOID **)&pNeighbour, IMG_NULL,
"Boundary Tag") != PVRSRV_OK)
{
return IMG_NULL;
}
OSMemSet(pNeighbour, 0, sizeof(BT));
#if defined(VALIDATE_ARENA_TEST)
pNeighbour->ui32BoundaryTagID = ++ui32BoundaryTagID;
#endif
pNeighbour->pPrevSegment = pBT;
pNeighbour->pNextSegment = pBT->pNextSegment;
if (pBT->pNextSegment == IMG_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;
#if defined(VALIDATE_ARENA_TEST)
if (pNeighbour->pPrevSegment->eResourceType == IMPORTED_RESOURCE_TYPE)
{
pNeighbour->eResourceType = IMPORTED_RESOURCE_TYPE;
pNeighbour->eResourceSpan = IMPORTED_RESOURCE_SPAN_FREE;
}
else if (pNeighbour->pPrevSegment->eResourceType == NON_IMPORTED_RESOURCE_TYPE)
{
pNeighbour->eResourceType = NON_IMPORTED_RESOURCE_TYPE;
pNeighbour->eResourceSpan = RESOURCE_SPAN_FREE;
}
else
{
PVR_DPF ((PVR_DBG_ERROR,"_SegmentSplit: pNeighbour->pPrevSegment->eResourceType unrecognized"));
PVR_DBG_BREAK;
}
#endif
return pNeighbour;
}
static IMG_VOID
_FreeListInsert (RA_ARENA *pArena, BT *pBT)
{
IMG_UINT32 uIndex;
uIndex = pvr_log2 (pBT->uSize);
pBT->type = btt_free;
pBT->pNextFree = pArena->aHeadFree [uIndex];
pBT->pPrevFree = IMG_NULL;
if (pArena->aHeadFree[uIndex] != IMG_NULL)
pArena->aHeadFree[uIndex]->pPrevFree = pBT;
pArena->aHeadFree [uIndex] = pBT;
}
static IMG_VOID
_FreeListRemove (RA_ARENA *pArena, BT *pBT)
{
IMG_UINT32 uIndex;
uIndex = pvr_log2 (pBT->uSize);
if (pBT->pNextFree != IMG_NULL)
pBT->pNextFree->pPrevFree = pBT->pPrevFree;
if (pBT->pPrevFree == IMG_NULL)
pArena->aHeadFree[uIndex] = pBT->pNextFree;
else
pBT->pPrevFree->pNextFree = pBT->pNextFree;
}
static BT *
_BuildSpanMarker (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pBT;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(BT),
(IMG_VOID **)&pBT, IMG_NULL,
"Boundary Tag") != PVRSRV_OK)
{
return IMG_NULL;
}
OSMemSet(pBT, 0, sizeof(BT));
#if defined(VALIDATE_ARENA_TEST)
pBT->ui32BoundaryTagID = ++ui32BoundaryTagID;
#endif
pBT->type = btt_span;
pBT->base = base;
pBT->uSize = uSize;
pBT->psMapping = IMG_NULL;
return pBT;
}
static BT *
_BuildBT (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pBT;
if(OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof(BT),
(IMG_VOID **)&pBT, IMG_NULL,
"Boundary Tag") != PVRSRV_OK)
{
return IMG_NULL;
}
OSMemSet(pBT, 0, sizeof(BT));
#if defined(VALIDATE_ARENA_TEST)
pBT->ui32BoundaryTagID = ++ui32BoundaryTagID;
#endif
pBT->type = btt_free;
pBT->base = base;
pBT->uSize = uSize;
return pBT;
}
static BT *
_InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
BT *pBT;
PVR_ASSERT (pArena!=IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_InsertResource: invalid parameter - pArena"));
return IMG_NULL;
}
pBT = _BuildBT (base, uSize);
if (pBT != IMG_NULL)
{
#if defined(VALIDATE_ARENA_TEST)
pBT->eResourceSpan = RESOURCE_SPAN_FREE;
pBT->eResourceType = NON_IMPORTED_RESOURCE_TYPE;
#endif
if (_SegmentListInsert (pArena, pBT) != PVRSRV_OK)
{
PVR_DPF ((PVR_DBG_ERROR,"_InsertResource: call to _SegmentListInsert failed"));
return IMG_NULL;
}
_FreeListInsert (pArena, pBT);
#ifdef RA_STATS
pArena->sStatistics.uTotalResourceCount+=uSize;
pArena->sStatistics.uFreeResourceCount+=uSize;
pArena->sStatistics.uSpanCount++;
#endif
}
return pBT;
}
static BT *
_InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
PVRSRV_ERROR eError;
BT *pSpanStart;
BT *pSpanEnd;
BT *pBT;
PVR_ASSERT (pArena != IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_InsertResourceSpan: invalid parameter - pArena"));
return IMG_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 == IMG_NULL)
{
goto fail_start;
}
#if defined(VALIDATE_ARENA_TEST)
pSpanStart->eResourceSpan = IMPORTED_RESOURCE_SPAN_START;
pSpanStart->eResourceType = IMPORTED_RESOURCE_TYPE;
#endif
pSpanEnd = _BuildSpanMarker (base + uSize, 0);
if (pSpanEnd == IMG_NULL)
{
goto fail_end;
}
#if defined(VALIDATE_ARENA_TEST)
pSpanEnd->eResourceSpan = IMPORTED_RESOURCE_SPAN_END;
pSpanEnd->eResourceType = IMPORTED_RESOURCE_TYPE;
#endif
pBT = _BuildBT (base, uSize);
if (pBT == IMG_NULL)
{
goto fail_bt;
}
#if defined(VALIDATE_ARENA_TEST)
pBT->eResourceSpan = IMPORTED_RESOURCE_SPAN_FREE;
pBT->eResourceType = IMPORTED_RESOURCE_TYPE;
#endif
eError = _SegmentListInsert (pArena, pSpanStart);
if (eError != PVRSRV_OK)
{
goto fail_SegListInsert;
}
eError = _SegmentListInsertAfter (pArena, pSpanStart, pBT);
if (eError != PVRSRV_OK)
{
goto fail_SegListInsert;
}
_FreeListInsert (pArena, pBT);
eError = _SegmentListInsertAfter (pArena, pBT, pSpanEnd);
if (eError != PVRSRV_OK)
{
goto fail_SegListInsert;
}
#ifdef RA_STATS
pArena->sStatistics.uTotalResourceCount+=uSize;
#endif
return pBT;
fail_SegListInsert:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
fail_bt:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanEnd, IMG_NULL);
fail_end:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanStart, IMG_NULL);
fail_start:
return IMG_NULL;
}
static IMG_VOID
_FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
{
BT *pNeighbour;
IMG_UINTPTR_T uOrigBase;
IMG_SIZE_T uOrigSize;
PVR_ASSERT (pArena!=IMG_NULL);
PVR_ASSERT (pBT!=IMG_NULL);
if ((pArena == IMG_NULL) || (pBT == IMG_NULL))
{
PVR_DPF ((PVR_DBG_ERROR,"_FreeBT: invalid parameter"));
return;
}
#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!=IMG_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(BT), pNeighbour, IMG_NULL);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
pNeighbour = pBT->pNextSegment;
if (pNeighbour!=IMG_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(BT), pNeighbour, IMG_NULL);
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
if (pArena->pBackingStoreFree != IMG_NULL && bFreeBackingStore)
{
IMG_UINTPTR_T 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, (IMG_SIZE_T)uRoundedStart, (IMG_SIZE_T)uRoundedEnd, (IMG_HANDLE)0);
}
}
if (pBT->pNextSegment!=IMG_NULL && pBT->pNextSegment->type == btt_span
&& pBT->pPrevSegment!=IMG_NULL && pBT->pPrevSegment->type == btt_span)
{
BT *next = pBT->pNextSegment;
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(BT), next, IMG_NULL);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), prev, IMG_NULL);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
}
else
_FreeListInsert (pArena, pBT);
}
static IMG_BOOL
_AttemptAllocAligned (RA_ARENA *pArena,
IMG_SIZE_T uSize,
BM_MAPPING **ppsMapping,
IMG_UINT32 uFlags,
IMG_UINT32 uAlignment,
IMG_UINT32 uAlignmentOffset,
IMG_UINTPTR_T *base)
{
IMG_UINT32 uIndex;
PVR_ASSERT (pArena!=IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: invalid parameter - pArena"));
return IMG_FALSE;
}
if (uAlignment>1)
uAlignmentOffset %= uAlignment;
uIndex = pvr_log2 (uSize);
#if 0
if (1u<<uIndex < uSize)
uIndex++;
#endif
while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex]==IMG_NULL)
uIndex++;
while (uIndex < FREE_TABLE_LIMIT)
{
if (pArena->aHeadFree[uIndex]!=IMG_NULL)
{
BT *pBT;
pBT = pArena->aHeadFree [uIndex];
while (pBT!=IMG_NULL)
{
IMG_UINTPTR_T 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)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, (IMG_SIZE_T)(aligned_base - pBT->base));
if (pNeighbour==IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: 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)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, uSize);
if (pNeighbour==IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: 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 defined(VALIDATE_ARENA_TEST)
if (pBT->eResourceType == IMPORTED_RESOURCE_TYPE)
{
pBT->eResourceSpan = IMPORTED_RESOURCE_SPAN_LIVE;
}
else if (pBT->eResourceType == NON_IMPORTED_RESOURCE_TYPE)
{
pBT->eResourceSpan = RESOURCE_SPAN_LIVE;
}
else
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned ERROR: pBT->eResourceType unrecognized"));
PVR_DBG_BREAK;
}
#endif
if (!HASH_Insert (pArena->pSegmentHash, pBT->base, (IMG_UINTPTR_T) pBT))
{
_FreeBT (pArena, pBT, IMG_FALSE);
return IMG_FALSE;
}
if (ppsMapping!=IMG_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;
}
RA_ARENA *
RA_Create (IMG_CHAR *name,
IMG_UINTPTR_T base,
IMG_SIZE_T uSize,
BM_MAPPING *psMapping,
IMG_SIZE_T uQuantum,
IMG_BOOL (*imp_alloc)(IMG_VOID *, IMG_SIZE_T uSize, IMG_SIZE_T *pActualSize,
BM_MAPPING **ppsMapping, IMG_UINT32 _flags,
IMG_PVOID pvPrivData, IMG_UINT32 ui32PrivDataLength,
IMG_UINTPTR_T *pBase),
IMG_VOID (*imp_free) (IMG_VOID *, IMG_UINTPTR_T, BM_MAPPING *),
IMG_VOID (*backingstore_free) (IMG_VOID*, IMG_SIZE_T, IMG_SIZE_T, IMG_HANDLE),
IMG_VOID *pImportHandle)
{
RA_ARENA *pArena;
BT *pBT;
IMG_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, (IMG_UINTPTR_T)imp_alloc, (IMG_UINTPTR_T)imp_free));
if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
sizeof (*pArena),
(IMG_VOID **)&pArena, IMG_NULL,
"Resource Arena") != PVRSRV_OK)
{
goto arena_fail;
}
pArena->name = name;
pArena->pImportAlloc = (imp_alloc!=IMG_NULL) ? imp_alloc : &_RequestAllocFail;
pArena->pImportFree = imp_free;
pArena->pBackingStoreFree = backingstore_free;
pArena->pImportHandle = pImportHandle;
for (i=0; i<FREE_TABLE_LIMIT; i++)
pArena->aHeadFree[i] = IMG_NULL;
pArena->pHeadSegment = IMG_NULL;
pArena->pTailSegment = IMG_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)
{
IMG_INT ret;
IMG_CHAR szProcInfoName[PROC_NAME_SIZE];
IMG_CHAR szProcSegsName[PROC_NAME_SIZE];
struct proc_dir_entry* (*pfnCreateProcEntrySeq)(const IMG_CHAR *,
IMG_VOID*,
pvr_next_proc_seq_t,
pvr_show_proc_seq_t,
pvr_off2element_proc_seq_t,
pvr_startstop_proc_seq_t,
write_proc_t);
pArena->bInitProcEntry = !PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL);
pfnCreateProcEntrySeq = pArena->bInitProcEntry ? CreateProcEntrySeq : CreatePerProcessProcEntrySeq;
ret = snprintf(szProcInfoName, sizeof(szProcInfoName), "ra_info_%s", pArena->name);
if (ret > 0 && ret < sizeof(szProcInfoName))
{
pArena->pProcInfo = pfnCreateProcEntrySeq(ReplaceSpaces(szProcInfoName), pArena, NULL,
RA_ProcSeqShowInfo, RA_ProcSeqOff2ElementInfo, NULL, NULL);
}
else
{
pArena->pProcInfo = 0;
PVR_DPF((PVR_DBG_ERROR, "RA_Create: couldn't create ra_info proc entry for arena %s", pArena->name));
}
ret = snprintf(szProcSegsName, sizeof(szProcSegsName), "ra_segs_%s", pArena->name);
if (ret > 0 && ret < sizeof(szProcInfoName))
{
pArena->pProcSegs = pfnCreateProcEntrySeq(ReplaceSpaces(szProcSegsName), pArena, NULL,
RA_ProcSeqShowRegs, RA_ProcSeqOff2ElementRegs, NULL, NULL);
}
else
{
pArena->pProcSegs = 0;
PVR_DPF((PVR_DBG_ERROR, "RA_Create: couldn't create ra_segs proc entry for arena %s", pArena->name));
}
}
#endif
pArena->pSegmentHash = HASH_Create (MINIMUM_HASH_SIZE);
if (pArena->pSegmentHash==IMG_NULL)
{
goto hash_fail;
}
if (uSize>0)
{
uSize = (uSize + uQuantum - 1) / uQuantum * uQuantum;
pBT = _InsertResource (pArena, base, uSize);
if (pBT == IMG_NULL)
{
goto insert_fail;
}
pBT->psMapping = psMapping;
}
return pArena;
insert_fail:
HASH_Delete (pArena->pSegmentHash);
hash_fail:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL);
arena_fail:
return IMG_NULL;
}
IMG_VOID
RA_Delete (RA_ARENA *pArena)
{
IMG_UINT32 uIndex;
PVR_ASSERT(pArena != IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_Delete: invalid parameter - pArena"));
return;
}
PVR_DPF ((PVR_DBG_MESSAGE,
"RA_Delete: name='%s'", pArena->name));
for (uIndex=0; uIndex<FREE_TABLE_LIMIT; uIndex++)
pArena->aHeadFree[uIndex] = IMG_NULL;
while (pArena->pHeadSegment != IMG_NULL)
{
BT *pBT = pArena->pHeadSegment;
if (pBT->type != btt_free)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_Delete: allocations still exist in the arena that is being destroyed"));
PVR_DPF ((PVR_DBG_ERROR,"Likely Cause: client drivers not freeing alocations before destroying devmemcontext"));
PVR_DPF ((PVR_DBG_ERROR,"RA_Delete: base = 0x%x size=0x%x", pBT->base, pBT->uSize));
}
_SegmentListRemove (pArena, pBT);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
#ifdef RA_STATS
pArena->sStatistics.uSpanCount--;
#endif
}
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
{
IMG_VOID (*pfnRemoveProcEntrySeq)(struct proc_dir_entry*);
pfnRemoveProcEntrySeq = pArena->bInitProcEntry ? RemoveProcEntrySeq : RemovePerProcessProcEntrySeq;
if (pArena->pProcInfo != 0)
{
pfnRemoveProcEntrySeq( pArena->pProcInfo );
}
if (pArena->pProcSegs != 0)
{
pfnRemoveProcEntrySeq( pArena->pProcSegs );
}
}
#endif
HASH_Delete (pArena->pSegmentHash);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL);
}
IMG_BOOL
RA_TestDelete (RA_ARENA *pArena)
{
PVR_ASSERT(pArena != IMG_NULL);
if (pArena != IMG_NULL)
{
while (pArena->pHeadSegment != IMG_NULL)
{
BT *pBT = pArena->pHeadSegment;
if (pBT->type != btt_free)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_TestDelete: detected resource leak!"));
PVR_DPF ((PVR_DBG_ERROR,"RA_TestDelete: base = 0x%x size=0x%x", pBT->base, pBT->uSize));
return IMG_FALSE;
}
}
}
return IMG_TRUE;
}
IMG_BOOL
RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
PVR_ASSERT (pArena != IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_Add: invalid parameter - pArena"));
return IMG_FALSE;
}
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) != IMG_NULL));
}
IMG_BOOL
RA_Alloc (RA_ARENA *pArena,
IMG_SIZE_T uRequestSize,
IMG_SIZE_T *pActualSize,
BM_MAPPING **ppsMapping,
IMG_UINT32 uFlags,
IMG_UINT32 uAlignment,
IMG_UINT32 uAlignmentOffset,
IMG_PVOID pvPrivData,
IMG_UINT32 ui32PrivDataLength,
IMG_UINTPTR_T *base)
{
IMG_BOOL bResult;
IMG_SIZE_T uSize = uRequestSize;
PVR_ASSERT (pArena!=IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_Alloc: invalid parameter - pArena"));
return IMG_FALSE;
}
#if defined(VALIDATE_ARENA_TEST)
ValidateArena(pArena);
#endif
#ifdef USE_BM_FREESPACE_CHECK
CheckBMFreespace();
#endif
if (pActualSize != IMG_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)
{
BM_MAPPING *psImportMapping;
IMG_UINTPTR_T import_base;
IMG_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,
pvPrivData, ui32PrivDataLength, &import_base);
if (bResult)
{
BT *pBT;
pBT = _InsertResourceSpan (pArena, import_base, uImportSize);
if (pBT == IMG_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));
#if defined(VALIDATE_ARENA_TEST)
ValidateArena(pArena);
#endif
return bResult;
}
#if defined(VALIDATE_ARENA_TEST)
IMG_UINT32 ValidateArena(RA_ARENA *pArena)
{
BT* pSegment;
RESOURCE_DESCRIPTOR eNextSpan;
pSegment = pArena->pHeadSegment;
if (pSegment == IMG_NULL)
{
return 0;
}
if (pSegment->eResourceType == IMPORTED_RESOURCE_TYPE)
{
PVR_ASSERT(pSegment->eResourceSpan == IMPORTED_RESOURCE_SPAN_START);
while (pSegment->pNextSegment)
{
eNextSpan = pSegment->pNextSegment->eResourceSpan;
switch (pSegment->eResourceSpan)
{
case IMPORTED_RESOURCE_SPAN_LIVE:
if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END)))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
case IMPORTED_RESOURCE_SPAN_FREE:
if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END)))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
case IMPORTED_RESOURCE_SPAN_END:
if ((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
case IMPORTED_RESOURCE_SPAN_START:
if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE)))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
default:
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
break;
}
pSegment = pSegment->pNextSegment;
}
}
else if (pSegment->eResourceType == NON_IMPORTED_RESOURCE_TYPE)
{
PVR_ASSERT((pSegment->eResourceSpan == RESOURCE_SPAN_FREE) || (pSegment->eResourceSpan == RESOURCE_SPAN_LIVE));
while (pSegment->pNextSegment)
{
eNextSpan = pSegment->pNextSegment->eResourceSpan;
switch (pSegment->eResourceSpan)
{
case RESOURCE_SPAN_LIVE:
if (!((eNextSpan == RESOURCE_SPAN_FREE) ||
(eNextSpan == RESOURCE_SPAN_LIVE)))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
case RESOURCE_SPAN_FREE:
if (!((eNextSpan == RESOURCE_SPAN_FREE) ||
(eNextSpan == RESOURCE_SPAN_LIVE)))
{
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
}
break;
default:
PVR_DPF((PVR_DBG_ERROR, "ValidateArena ERROR: adjacent boundary tags %d (base=0x%x) and %d (base=0x%x) are incompatible (arena: %s)",
pSegment->ui32BoundaryTagID, pSegment->base, pSegment->pNextSegment->ui32BoundaryTagID, pSegment->pNextSegment->base, pArena->name));
PVR_DBG_BREAK;
break;
}
pSegment = pSegment->pNextSegment;
}
}
else
{
PVR_DPF ((PVR_DBG_ERROR,"ValidateArena ERROR: pSegment->eResourceType unrecognized"));
PVR_DBG_BREAK;
}
return 0;
}
#endif
IMG_VOID
RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore)
{
BT *pBT;
PVR_ASSERT (pArena != IMG_NULL);
if (pArena == IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"RA_Free: invalid parameter - pArena"));
return;
}
#ifdef USE_BM_FREESPACE_CHECK
CheckBMFreespace();
#endif
PVR_DPF ((PVR_DBG_MESSAGE,
"RA_Free: name='%s', base=0x%x", pArena->name, base));
pBT = (BT *) HASH_Remove (pArena->pSegmentHash, base);
PVR_ASSERT (pBT != IMG_NULL);
if (pBT)
{
PVR_ASSERT (pBT->base == base);
#ifdef RA_STATS
pArena->sStatistics.uCumulativeFrees++;
#endif
#ifdef USE_BM_FREESPACE_CHECK
{
IMG_BYTE* p;
IMG_BYTE* endp;
p = (IMG_BYTE*)pBT->base + SysGetDevicePhysOffset();
endp = (IMG_BYTE*)((IMG_UINT32)(p + pBT->uSize));
while ((IMG_UINT32)p & 3)
{
*p++ = 0xAA;
}
while (p < (IMG_BYTE*)((IMG_UINT32)endp & 0xfffffffc))
{
*(IMG_UINT32*)p = 0xAAAAAAAA;
p += sizeof(IMG_UINT32);
}
while (p < endp)
{
*p++ = 0xAA;
}
PVR_DPF((PVR_DBG_MESSAGE,"BM_FREESPACE_CHECK: RA_Free Cleared %08X to %08X (size=0x%x)",(IMG_BYTE*)pBT->base + SysGetDevicePhysOffset(),endp-1,pBT->uSize));
}
#endif
_FreeBT (pArena, pBT, bFreeBackingStore);
}
}
IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetails)
{
BT *pBT;
if (psSegDetails->hSegment)
{
pBT = (BT *)psSegDetails->hSegment;
}
else
{
RA_ARENA *pArena = (RA_ARENA *)hArena;
pBT = pArena->pHeadSegment;
}
while (pBT != IMG_NULL)
{
if (pBT->type == btt_live)
{
psSegDetails->uiSize = pBT->uSize;
psSegDetails->sCpuPhyAddr.uiAddr = pBT->base;
psSegDetails->hSegment = (IMG_HANDLE)pBT->pNextSegment;
return IMG_TRUE;
}
pBT = pBT->pNextSegment;
}
psSegDetails->uiSize = 0;
psSegDetails->sCpuPhyAddr.uiAddr = 0;
psSegDetails->hSegment = (IMG_HANDLE)IMG_UNDEF;
return IMG_FALSE;
}
#ifdef USE_BM_FREESPACE_CHECK
RA_ARENA* pJFSavedArena = IMG_NULL;
IMG_VOID CheckBMFreespace(IMG_VOID)
{
BT *pBT;
IMG_BYTE* p;
IMG_BYTE* endp;
if (pJFSavedArena != IMG_NULL)
{
for (pBT=pJFSavedArena->pHeadSegment; pBT!=IMG_NULL; pBT=pBT->pNextSegment)
{
if (pBT->type == btt_free)
{
p = (IMG_BYTE*)pBT->base + SysGetDevicePhysOffset();
endp = (IMG_BYTE*)((IMG_UINT32)(p + pBT->uSize) & 0xfffffffc);
while ((IMG_UINT32)p & 3)
{
if (*p++ != 0xAA)
{
fprintf(stderr,"BM_FREESPACE_CHECK: Blank space at %08X has changed to 0x%x\n",p,*(IMG_UINT32*)p);
for (;;);
break;
}
}
while (p < endp)
{
if (*(IMG_UINT32*)p != 0xAAAAAAAA)
{
fprintf(stderr,"BM_FREESPACE_CHECK: Blank space at %08X has changed to 0x%x\n",p,*(IMG_UINT32*)p);
for (;;);
break;
}
p += 4;
}
}
}
}
}
#endif
#if (defined(CONFIG_PROC_FS) && defined(DEBUG)) || defined (RA_STATS)
static IMG_CHAR *
_BTType (IMG_INT eType)
{
switch (eType)
{
case btt_span: return "span";
case btt_free: return "free";
case btt_live: return "live";
}
return "junk";
}
#endif
#if defined(ENABLE_RA_DUMP)
IMG_VOID
RA_Dump (RA_ARENA *pArena)
{
BT *pBT;
PVR_ASSERT (pArena != IMG_NULL);
PVR_DPF ((PVR_DBG_MESSAGE,"Arena '%s':", pArena->name));
PVR_DPF ((PVR_DBG_MESSAGE," alloc=%08X free=%08X handle=%08X quantum=%d",
pArena->pImportAlloc, pArena->pImportFree, pArena->pImportHandle,
pArena->uQuantum));
PVR_DPF ((PVR_DBG_MESSAGE," segment Chain:"));
if (pArena->pHeadSegment != IMG_NULL &&
pArena->pHeadSegment->pPrevSegment != IMG_NULL)
PVR_DPF ((PVR_DBG_MESSAGE," error: head boundary tag has invalid pPrevSegment"));
if (pArena->pTailSegment != IMG_NULL &&
pArena->pTailSegment->pNextSegment != IMG_NULL)
PVR_DPF ((PVR_DBG_MESSAGE," error: tail boundary tag has invalid pNextSegment"));
for (pBT=pArena->pHeadSegment; pBT!=IMG_NULL; pBT=pBT->pNextSegment)
{
PVR_DPF ((PVR_DBG_MESSAGE,"\tbase=0x%x size=0x%x type=%s ref=%08X",
(IMG_UINT32) pBT->base, pBT->uSize, _BTType (pBT->type),
pBT->pRef));
}
#ifdef HASH_TRACE
HASH_Dump (pArena->pSegmentHash);
#endif
}
#endif
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
static void RA_ProcSeqShowInfo(struct seq_file *sfile, void* el)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)sfile->private;
RA_ARENA *pArena = (RA_ARENA *)handlers->data;
IMG_INT off = (IMG_INT)el;
switch (off)
{
case 1:
seq_printf(sfile, "quantum\t\t\t%u\n", pArena->uQuantum);
break;
case 2:
seq_printf(sfile, "import_handle\t\t%08X\n", (IMG_UINT)pArena->pImportHandle);
break;
#ifdef RA_STATS
case 3:
seq_printf(sfile,"span count\t\t%u\n", pArena->sStatistics.uSpanCount);
break;
case 4:
seq_printf(sfile, "live segment count\t%u\n", pArena->sStatistics.uLiveSegmentCount);
break;
case 5:
seq_printf(sfile, "free segment count\t%u\n", pArena->sStatistics.uFreeSegmentCount);
break;
case 6:
seq_printf(sfile, "free resource count\t%u (0x%x)\n",
pArena->sStatistics.uFreeResourceCount,
(IMG_UINT)pArena->sStatistics.uFreeResourceCount);
break;
case 7:
seq_printf(sfile, "total allocs\t\t%u\n", pArena->sStatistics.uCumulativeAllocs);
break;
case 8:
seq_printf(sfile, "total frees\t\t%u\n", pArena->sStatistics.uCumulativeFrees);
break;
case 9:
seq_printf(sfile, "import count\t\t%u\n", pArena->sStatistics.uImportCount);
break;
case 10:
seq_printf(sfile, "export count\t\t%u\n", pArena->sStatistics.uExportCount);
break;
#endif
}
}
static void* RA_ProcSeqOff2ElementInfo(struct seq_file * sfile, loff_t off)
{
#ifdef RA_STATS
if(off <= 9)
#else
if(off <= 1)
#endif
return (void*)(IMG_INT)(off+1);
return 0;
}
static void RA_ProcSeqShowRegs(struct seq_file *sfile, void* el)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)sfile->private;
RA_ARENA *pArena = (RA_ARENA *)handlers->data;
BT *pBT = (BT*)el;
if (el == PVR_PROC_SEQ_START_TOKEN)
{
seq_printf(sfile, "Arena \"%s\"\nBase Size Type Ref\n", pArena->name);
return;
}
if (pBT)
{
seq_printf(sfile, "%08x %8x %4s %08x\n",
(IMG_UINT)pBT->base, (IMG_UINT)pBT->uSize, _BTType (pBT->type),
(IMG_UINT)pBT->psMapping);
}
}
static void* RA_ProcSeqOff2ElementRegs(struct seq_file * sfile, loff_t off)
{
PVR_PROC_SEQ_HANDLERS *handlers = (PVR_PROC_SEQ_HANDLERS*)sfile->private;
RA_ARENA *pArena = (RA_ARENA *)handlers->data;
BT *pBT = 0;
if(off == 0)
return PVR_PROC_SEQ_START_TOKEN;
for (pBT=pArena->pHeadSegment; --off && pBT; pBT=pBT->pNextSegment);
return (void*)pBT;
}
#endif
#ifdef RA_STATS
PVRSRV_ERROR RA_GetStats(RA_ARENA *pArena,
IMG_CHAR **ppszStr,
IMG_UINT32 *pui32StrLen)
{
IMG_CHAR *pszStr = *ppszStr;
IMG_UINT32 ui32StrLen = *pui32StrLen;
IMG_INT32 i32Count;
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=%p freeCB=%p handle=%p 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%u\n", pArena->sStatistics.uSpanCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "live segment count\t%u\n", pArena->sStatistics.uLiveSegmentCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "free segment count\t%u\n", pArena->sStatistics.uFreeSegmentCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "free resource count\t%u (0x%x)\n",
pArena->sStatistics.uFreeResourceCount,
(IMG_UINT)pArena->sStatistics.uFreeResourceCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "total allocs\t\t%u\n", pArena->sStatistics.uCumulativeAllocs);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "total frees\t\t%u\n", pArena->sStatistics.uCumulativeFrees);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "import count\t\t%u\n", pArena->sStatistics.uImportCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "export count\t\t%u\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 != IMG_NULL &&
pArena->pHeadSegment->pPrevSegment != IMG_NULL)
{
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, " error: head boundary tag has invalid pPrevSegment\n");
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
}
if (pArena->pTailSegment != IMG_NULL &&
pArena->pTailSegment->pNextSegment != IMG_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!=IMG_NULL; pBT=pBT->pNextSegment)
{
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "\tbase=0x%x size=0x%x type=%s ref=%p\n",
(IMG_UINT32) pBT->base,
pBT->uSize,
_BTType(pBT->type),
pBT->psMapping);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
}
*ppszStr = pszStr;
*pui32StrLen = ui32StrLen;
return PVRSRV_OK;
}
PVRSRV_ERROR RA_GetStatsFreeMem(RA_ARENA *pArena,
IMG_CHAR **ppszStr,
IMG_UINT32 *pui32StrLen)
{
IMG_CHAR *pszStr = *ppszStr;
IMG_UINT32 ui32StrLen = *pui32StrLen;
IMG_INT32 i32Count;
CHECK_SPACE(ui32StrLen);
i32Count = OSSNPrintf(pszStr, 100, "Bytes free: Arena %-30s: %u (0x%x)\n", pArena->name,
pArena->sStatistics.uFreeResourceCount,
pArena->sStatistics.uFreeResourceCount);
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
*ppszStr = pszStr;
*pui32StrLen = ui32StrLen;
return PVRSRV_OK;
}
#endif