/********************************************************************** * * 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. * 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 #include "proc.h" #endif #ifdef USE_BM_FREESPACE_CHECK #include #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<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; iaHeadFree[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; uIndexaHeadFree[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