summaryrefslogtreecommitdiff
path: root/sgx/services4/srvkm/common/ra.c
diff options
context:
space:
mode:
Diffstat (limited to 'sgx/services4/srvkm/common/ra.c')
-rw-r--r--sgx/services4/srvkm/common/ra.c641
1 files changed, 533 insertions, 108 deletions
diff --git a/sgx/services4/srvkm/common/ra.c b/sgx/services4/srvkm/common/ra.c
index e93f05f..819c36a 100644
--- a/sgx/services4/srvkm/common/ra.c
+++ b/sgx/services4/srvkm/common/ra.c
@@ -1,28 +1,90 @@
-/**********************************************************************
- *
- * 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
- *
- ******************************************************************************/
+/*************************************************************************/ /*!
+@Title Resource Allocator
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+@Description
+ Implements generic resource allocation. The resource
+ allocator was originally intended to manage address spaces in
+ practice the resource allocator is generic and can manages arbitrary
+ sets of integers.
+
+ Resources are allocated from arenas. Arena's can be created with an
+ initial span of resources. Further resources spans can be added to
+ arenas. A call back mechanism allows an arena to request further
+ resource spans on demand.
+
+ Each arena maintains an ordered list of resource segments each
+ described by a boundary tag. Each boundary tag describes a segment
+ of resources which are either 'free', available for allocation, or
+ 'busy' currently allocated. Adjacent 'free' segments are always
+ coallesced to avoid fragmentation.
+
+ For allocation, all 'free' segments are kept on lists of 'free'
+ segments in a table index by pvr_log2(segment size). ie Each table index
+ n holds 'free' segments in the size range 2**(n-1) -> 2**n.
+
+ Allocation policy is based on an *almost* best fit
+ stratedy. Choosing any segment from the appropriate table entry
+ guarantees that we choose a segment which is with a power of 2 of
+ the size we are allocating.
+
+ Allocated segments are inserted into a self scaling hash table which
+ maps the base resource of the span to the relevant boundary
+ tag. This allows the code to get back to the bounary tag without
+ exporting explicit boundary tag references through the API.
+
+ Each arena has an associated quantum size, all allocations from the
+ arena are made in multiples of the basic quantum.
+
+ On resource exhaustion in an arena, a callback if provided will be
+ used to request further resources. Resouces spans allocated by the
+ callback mechanism are delimited by special boundary tag markers of
+ zero span, 'span' markers. Span markers are never coallesced. Span
+ markers are used to detect when an imported span is completely free
+ and can be deallocated by the callback mechanism.
+*/ /**************************************************************************/
+
+/* Issues:
+ * - flags, flags are passed into the resource allocator but are not currently used.
+ * - determination, of import size, is currently braindead.
+ * - debug code should be moved out to own module and #ifdef'd
+ */
#include "services_headers.h"
#include "hash.h"
@@ -30,7 +92,7 @@
#include "buffer_manager.h"
#include "osfunc.h"
-#ifdef __linux__
+#if defined(__linux__) && defined(__KERNEL__)
#include <linux/kernel.h>
#include "proc.h"
#endif
@@ -39,10 +101,18 @@
#include <stdio.h>
#endif
+/* The initial, and minimum size of the live address -> boundary tag
+ structure hash table. The value 64 is a fairly arbitrary
+ choice. The hash table resizes on demand so the value choosen is
+ not critical. */
#define MINIMUM_HASH_SIZE (64)
#if defined(VALIDATE_ARENA_TEST)
+/* This test validates the doubly linked ordered list of boundary tags, by
+checking that adjacent members of the list have compatible eResourceSpan
+and eResourceType values. */
+
typedef enum RESOURCE_DESCRIPTOR_TAG {
RESOURCE_SPAN_LIVE = 10,
@@ -67,33 +137,36 @@ static IMG_UINT32 ui32BoundaryTagID = 0;
IMG_UINT32 ValidateArena(RA_ARENA *pArena);
#endif
+/* boundary tags, used to describe a resource segment */
struct _BT_
{
enum bt_type
{
- btt_span,
- btt_free,
- btt_live
+ btt_span, /* span markers */
+ btt_free, /* free resource segment */
+ btt_live /* allocated resource segment */
} type;
-
+ /* The base resource and extent of this segment */
IMG_UINTPTR_T base;
IMG_SIZE_T uSize;
-
+ /* doubly linked ordered list of all segments within the arena */
struct _BT_ *pNextSegment;
struct _BT_ *pPrevSegment;
-
+ /* doubly linked un-ordered list of free segments. */
struct _BT_ *pNextFree;
struct _BT_ *pPrevFree;
-
+ /* a user reference associated with this span, user references are
+ * currently only provided in the callback mechanism */
BM_MAPPING *psMapping;
#if defined(VALIDATE_ARENA_TEST)
RESOURCE_DESCRIPTOR eResourceSpan;
RESOURCE_TYPE eResourceType;
-
+ /* This variable provides a reference (used in debug messages) to incompatible
+ boundary tags within the doubly linked ordered list. */
IMG_UINT32 ui32BoundaryTagID;
#endif
@@ -101,40 +174,45 @@ struct _BT_
typedef struct _BT_ BT;
+/* resource allocation arena */
struct _RA_ARENA_
{
-
+ /* arena name for diagnostics output */
IMG_CHAR *name;
-
+ /* allocations within this arena are quantum sized */
IMG_SIZE_T uQuantum;
-
+ /* import interface, if provided */
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);
-
+ /* arbitrary handle provided by arena owner to be passed into the
+ * import alloc and free hooks */
IMG_VOID *pImportHandle;
-
+ /* head of list of free boundary tags for indexed by pvr_log2 of the
+ boundary tag size */
#define FREE_TABLE_LIMIT 32
-
+ /* power-of-two table of free lists */
BT *aHeadFree [FREE_TABLE_LIMIT];
-
+ /* resource ordered segment list */
BT *pHeadSegment;
BT *pTailSegment;
-
+ /* segment address to boundary tag hash table */
HASH_TABLE *pSegmentHash;
#ifdef RA_STATS
@@ -150,6 +228,7 @@ struct _RA_ARENA_
IMG_BOOL bInitProcEntry;
#endif
};
+/* #define ENABLE_RA_DUMP 1 */
#if defined(ENABLE_RA_DUMP)
IMG_VOID RA_Dump (RA_ARENA *pArena);
#endif
@@ -162,7 +241,7 @@ 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
+#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */
#ifdef USE_BM_FREESPACE_CHECK
IMG_VOID CheckBMFreespace(IMG_VOID);
@@ -185,12 +264,33 @@ static IMG_CHAR *ReplaceSpaces(IMG_CHAR * const pS)
}
#endif
+/*!
+******************************************************************************
+ @Function _RequestAllocFail
+
+ @Description Default callback allocator used if no callback is
+ specified, always fails to allocate further resources to the
+ arena.
+
+ @Input _h - callback handle
+ @Input _uSize - requested allocation size
+ @Output _pActualSize - actual allocation size
+ @Input _pRef - user reference
+ @Input _uflags - allocation flags
+ @Input _pvPrivData - private data
+ @Input _ui32PrivDataLength - private data length
+ @Input _pBase - receives allocated base
+
+ @Return IMG_FALSE, this function always fails to allocate.
+******************************************************************************/
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);
@@ -199,10 +299,22 @@ _RequestAllocFail (IMG_VOID *_h,
PVR_UNREFERENCED_PARAMETER (_ppsMapping);
PVR_UNREFERENCED_PARAMETER (_uFlags);
PVR_UNREFERENCED_PARAMETER (_pBase);
+ PVR_UNREFERENCED_PARAMETER (_pvPrivData);
+ PVR_UNREFERENCED_PARAMETER (_ui32PrivDataLength);
return IMG_FALSE;
}
+/*!
+******************************************************************************
+ @Function pvr_log2
+
+ @Description Computes the floor of the log base 2 of a unsigned integer
+
+ @Input n - unsigned integer
+
+ @Return Floor(Log2(n))
+******************************************************************************/
static IMG_UINT32
pvr_log2 (IMG_SIZE_T n)
{
@@ -216,6 +328,19 @@ pvr_log2 (IMG_SIZE_T n)
return l;
}
+/*!
+******************************************************************************
+ @Function _SegmentListInsertAfter
+
+ @Description Insert a boundary tag into an arena segment list after a
+ specified boundary tag.
+
+ @Input pArena - the arena.
+ @Input pInsertionPoint - the insertion point.
+ @Input pBT - the boundary tag to insert.
+
+ @Return PVRSRV_ERROR
+******************************************************************************/
static PVRSRV_ERROR
_SegmentListInsertAfter (RA_ARENA *pArena,
BT *pInsertionPoint,
@@ -241,12 +366,24 @@ _SegmentListInsertAfter (RA_ARENA *pArena,
return PVRSRV_OK;
}
+/*!
+******************************************************************************
+ @Function _SegmentListInsert
+
+ @Description Insert a boundary tag into an arena segment list at the
+ appropriate point.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag to insert.
+
+ @Return None
+******************************************************************************/
static PVRSRV_ERROR
_SegmentListInsert (RA_ARENA *pArena, BT *pBT)
{
PVRSRV_ERROR eError = PVRSRV_OK;
-
+ /* insert into the segment chain */
if (pArena->pHeadSegment == IMG_NULL)
{
pArena->pHeadSegment = pArena->pTailSegment = pBT;
@@ -258,7 +395,8 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT)
if (pBT->base < pArena->pHeadSegment->base)
{
-
+ /* The base address of pBT is less than the base address of the boundary tag
+ at the head of the list - so insert this boundary tag at the head. */
pBT->pNextSegment = pArena->pHeadSegment;
pArena->pHeadSegment->pPrevSegment = pBT;
pArena->pHeadSegment = pBT;
@@ -267,9 +405,10 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT)
else
{
-
-
-
+ /* The base address of pBT is greater than or equal to that of the boundary tag
+ at the head of the list. Search for the insertion point: pBT must be inserted
+ before the first boundary tag with a greater base value - or at the end of the list.
+ */
pBTScan = pArena->pHeadSegment;
while ((pBTScan->pNextSegment != IMG_NULL) && (pBT->base >= pBTScan->pNextSegment->base))
@@ -287,6 +426,17 @@ _SegmentListInsert (RA_ARENA *pArena, BT *pBT)
return eError;
}
+/*!
+******************************************************************************
+ @Function _SegmentListRemove
+
+ @Description Remove a boundary tag from an arena segment list.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag to remove.
+
+ @Return None
+******************************************************************************/
static IMG_VOID
_SegmentListRemove (RA_ARENA *pArena, BT *pBT)
{
@@ -301,6 +451,23 @@ _SegmentListRemove (RA_ARENA *pArena, BT *pBT)
pBT->pNextSegment->pPrevSegment = pBT->pPrevSegment;
}
+/*!
+******************************************************************************
+ @Function _SegmentSplit
+
+ @Description Split a segment into two, maintain the arena segment list. The
+ boundary tag should not be in the free table. Neither the
+ original or the new neighbour bounary tag will be in the free
+ table.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag to split.
+ @Input uSize - the required segment size of boundary tag after
+ splitting.
+
+ @Return New neighbour boundary tag.
+
+******************************************************************************/
static BT *
_SegmentSplit (RA_ARENA *pArena, BT *pBT, IMG_SIZE_T uSize)
{
@@ -363,6 +530,18 @@ _SegmentSplit (RA_ARENA *pArena, BT *pBT, IMG_SIZE_T uSize)
return pNeighbour;
}
+/*!
+******************************************************************************
+ @Function _FreeListInsert
+
+ @Description Insert a boundary tag into an arena free table.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag.
+
+ @Return None
+
+******************************************************************************/
static IMG_VOID
_FreeListInsert (RA_ARENA *pArena, BT *pBT)
{
@@ -376,6 +555,18 @@ _FreeListInsert (RA_ARENA *pArena, BT *pBT)
pArena->aHeadFree [uIndex] = pBT;
}
+/*!
+******************************************************************************
+ @Function _FreeListRemove
+
+ @Description Remove a boundary tag from an arena free table.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag.
+
+ @Return None
+
+******************************************************************************/
static IMG_VOID
_FreeListRemove (RA_ARENA *pArena, BT *pBT)
{
@@ -389,6 +580,18 @@ _FreeListRemove (RA_ARENA *pArena, BT *pBT)
pBT->pPrevFree->pNextFree = pBT->pNextFree;
}
+/*!
+******************************************************************************
+ @Function _BuildSpanMarker
+
+ @Description Construct a span marker boundary tag.
+
+ @Input pArena - arena to contain span marker
+ @Input base - the base of the bounary tag.
+
+ @Return span marker boundary tag
+
+******************************************************************************/
static BT *
_BuildSpanMarker (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
@@ -416,6 +619,18 @@ _BuildSpanMarker (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
return pBT;
}
+/*!
+******************************************************************************
+ @Function _BuildBT
+
+ @Description Construct a boundary tag for a free segment.
+
+ @Input base - the base of the resource segment.
+ @Input uSize - the extent of the resouce segment.
+
+ @Return boundary tag
+
+******************************************************************************/
static BT *
_BuildBT (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
@@ -442,6 +657,20 @@ _BuildBT (IMG_UINTPTR_T base, IMG_SIZE_T uSize)
return pBT;
}
+/*!
+******************************************************************************
+ @Function _InsertResource
+
+ @Description Add a free resource segment to an arena.
+
+ @Input pArena - the arena.
+ @Input base - the base of the resource segment.
+ @Input uSize - the extent of the resource segment.
+
+ @Return New bucket pointer
+ IMG_NULL failure
+
+******************************************************************************/
static BT *
_InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
@@ -477,6 +706,19 @@ _InsertResource (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
return pBT;
}
+/*!
+******************************************************************************
+ @Function _InsertResourceSpan
+
+ @Description Add a free resource span to an arena, complete with span markers.
+
+ @Input pArena - the arena.
+ @Input base - the base of the resource segment.
+ @Input uSize - the extent of the resource segment.
+
+ @Return the boundary tag representing the free resource segment,
+ or IMG_NULL on failure.
+******************************************************************************/
static BT *
_InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
@@ -551,22 +793,40 @@ _InsertResourceSpan (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
#ifdef RA_STATS
pArena->sStatistics.uTotalResourceCount+=uSize;
+/* pArena->sStatistics.uFreeResourceCount+=uSize;
+ This has got to be wrong as uFreeResourceCount ends
+ up larger than uTotalResourceCount by uTotalResourceCount
+ - allocated memory
+*/
#endif
return pBT;
fail_SegListInsert:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
-
+ /*not nulling pointer, out of scope*/
fail_bt:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanEnd, IMG_NULL);
-
+ /*not nulling pointer, out of scope*/
fail_end:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pSpanStart, IMG_NULL);
-
+ /*not nulling pointer, out of scope*/
fail_start:
return IMG_NULL;
}
+/*!
+******************************************************************************
+ @Function _FreeBT
+
+ @Description Free a boundary tag taking care of the segment list and the
+ boundary tag free table.
+
+ @Input pArena - the arena.
+ @Input pBT - the boundary tag to free.
+ @Input bFreeBackingStore - Should backing for the memory be freed
+ as well.
+ @Return None
+******************************************************************************/
static IMG_VOID
_FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
{
@@ -592,7 +852,7 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
uOrigBase = pBT->base;
uOrigSize = pBT->uSize;
-
+ /* try and coalesce with left neighbour */
pNeighbour = pBT->pPrevSegment;
if (pNeighbour!=IMG_NULL
&& pNeighbour->type == btt_free
@@ -603,13 +863,13 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
pBT->base = pNeighbour->base;
pBT->uSize += pNeighbour->uSize;
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pNeighbour, IMG_NULL);
-
+ /*not nulling original pointer, already overwritten*/
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
-
+ /* try to coalesce with right neighbour */
pNeighbour = pBT->pNextSegment;
if (pNeighbour!=IMG_NULL
&& pNeighbour->type == btt_free
@@ -619,28 +879,28 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
_SegmentListRemove (pArena, pNeighbour);
pBT->uSize += pNeighbour->uSize;
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pNeighbour, IMG_NULL);
-
+ /*not nulling original pointer, already overwritten*/
#ifdef RA_STATS
pArena->sStatistics.uFreeSegmentCount--;
#endif
}
-
+ /* try to free backing store memory. */
if (pArena->pBackingStoreFree != IMG_NULL && bFreeBackingStore)
{
IMG_UINTPTR_T uRoundedStart, uRoundedEnd;
-
+ /* Work out the first address we might be able to free. */
uRoundedStart = (uOrigBase / pArena->uQuantum) * pArena->uQuantum;
-
+ /* If a span is still using that address then leave it. */
if (uRoundedStart < pBT->base)
{
uRoundedStart += pArena->uQuantum;
}
-
+ /* Work out the last address we might be able to free. */
uRoundedEnd = ((uOrigBase + uOrigSize + pArena->uQuantum - 1) / pArena->uQuantum) * pArena->uQuantum;
-
+ /* If a span is still using that addres then leave it. */
if (uRoundedEnd > (pBT->base + pBT->uSize))
{
uRoundedEnd -= pArena->uQuantum;
@@ -669,17 +929,35 @@ _FreeBT (RA_ARENA *pArena, BT *pBT, IMG_BOOL bFreeBackingStore)
pArena->sStatistics.uTotalResourceCount-=pBT->uSize;
#endif
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), next, IMG_NULL);
-
+ /*not nulling original pointer, already overwritten*/
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), prev, IMG_NULL);
-
+ /*not nulling original pointer, already overwritten*/
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
}
else
_FreeListInsert (pArena, pBT);
}
+/*!
+******************************************************************************
+ @Function _AttemptAllocAligned
+
+ @Description Attempt an allocation from an arena.
+
+ @Input pArena - the arena.
+ @Input uSize - the requested allocation size.
+ @Output ppsMapping - the user references associated with
+ the allocated segment.
+ @Input flags - allocation flags
+ @Input uAlignment - required uAlignment, or 0
+ @Input uAlignmentOffset
+ @Output base - allocated resource base
+
+ @Return IMG_FALSE failure
+ IMG_TRUE success
+******************************************************************************/
static IMG_BOOL
_AttemptAllocAligned (RA_ARENA *pArena,
IMG_SIZE_T uSize,
@@ -700,16 +978,11 @@ _AttemptAllocAligned (RA_ARENA *pArena,
if (uAlignment>1)
uAlignmentOffset %= uAlignment;
-
-
+ /* search for a near fit free boundary tag, start looking at the
+ pvr_log2 free table for our required size and work on up the
+ table. */
uIndex = pvr_log2 (uSize);
-#if 0
-
- if (1u<<uIndex < uSize)
- uIndex++;
-#endif
-
while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex]==IMG_NULL)
uIndex++;
@@ -717,7 +990,7 @@ _AttemptAllocAligned (RA_ARENA *pArena,
{
if (pArena->aHeadFree[uIndex]!=IMG_NULL)
{
-
+ /* we have a cached free boundary tag */
BT *pBT;
pBT = pArena->aHeadFree [uIndex];
@@ -748,16 +1021,16 @@ _AttemptAllocAligned (RA_ARENA *pArena,
pArena->sStatistics.uFreeResourceCount-=pBT->uSize;
#endif
-
+ /* with uAlignment we might need to discard the front of this segment */
if (aligned_base > pBT->base)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, (IMG_SIZE_T)(aligned_base - pBT->base));
-
+ /* partition the buffer, create a new boundary tag */
if (pNeighbour==IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Front split failed"));
-
+ /* Put pBT back in the list */
_FreeListInsert (pArena, pBT);
return IMG_FALSE;
}
@@ -770,16 +1043,16 @@ _AttemptAllocAligned (RA_ARENA *pArena,
pBT = pNeighbour;
}
-
+ /* the segment might be too big, if so, discard the back of the segment */
if (pBT->uSize > uSize)
{
BT *pNeighbour;
pNeighbour = _SegmentSplit (pArena, pBT, uSize);
-
+ /* partition the buffer, create a new boundary tag */
if (pNeighbour==IMG_NULL)
{
PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Back split failed"));
-
+ /* Put pBT back in the list */
_FreeListInsert (pArena, pBT);
return IMG_FALSE;
}
@@ -840,6 +1113,23 @@ _AttemptAllocAligned (RA_ARENA *pArena,
+/*!
+******************************************************************************
+ @Function RA_Create
+
+ @Description To create a resource arena.
+
+ @Input name - the name of the arena for diagnostic purposes.
+ @Input base - the base of an initial resource span or 0.
+ @Input uSize - the size of an initial resource span or 0.
+ @Input uQuantum - the arena allocation quantum.
+ @Input alloc - a resource allocation callback or 0.
+ @Input free - a resource de-allocation callback or 0.
+ @Input backingstore_free - a callback to free resources for spans or 0.
+ @Input pImportHandle - handle passed to alloc and free or 0.
+
+ @Return arena handle, or IMG_NULL.
+******************************************************************************/
RA_ARENA *
RA_Create (IMG_CHAR *name,
IMG_UINTPTR_T base,
@@ -847,7 +1137,9 @@ RA_Create (IMG_CHAR *name,
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_UINTPTR_T *pBase),
+ 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)
@@ -908,7 +1200,7 @@ RA_Create (IMG_CHAR *name,
pArena->bInitProcEntry = !PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL);
-
+ /* Don't put shared heap info into a per process /proc subdirectory */
pfnCreateProcEntrySeq = pArena->bInitProcEntry ? CreateProcEntrySeq : CreatePerProcessProcEntrySeq;
ret = snprintf(szProcInfoName, sizeof(szProcInfoName), "ra_info_%s", pArena->name);
@@ -935,7 +1227,7 @@ RA_Create (IMG_CHAR *name,
PVR_DPF((PVR_DBG_ERROR, "RA_Create: couldn't create ra_segs proc entry for arena %s", pArena->name));
}
}
-#endif
+#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */
pArena->pSegmentHash = HASH_Create (MINIMUM_HASH_SIZE);
if (pArena->pSegmentHash==IMG_NULL)
@@ -959,11 +1251,22 @@ insert_fail:
HASH_Delete (pArena->pSegmentHash);
hash_fail:
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL);
-
+ /*not nulling pointer, out of scope*/
arena_fail:
return IMG_NULL;
}
+/*!
+******************************************************************************
+ @Function RA_Delete
+
+ @Description To delete a resource arena. All resources allocated from
+ the arena must be freed before deleting the arena.
+
+ @Input pArena - the arena to delete.
+
+ @Return None
+******************************************************************************/
IMG_VOID
RA_Delete (RA_ARENA *pArena)
{
@@ -996,7 +1299,7 @@ RA_Delete (RA_ARENA *pArena)
_SegmentListRemove (pArena, pBT);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(BT), pBT, IMG_NULL);
-
+ /*not nulling original pointer, it has changed*/
#ifdef RA_STATS
pArena->sStatistics.uSpanCount--;
#endif
@@ -1020,9 +1323,20 @@ RA_Delete (RA_ARENA *pArena)
#endif
HASH_Delete (pArena->pSegmentHash);
OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(RA_ARENA), pArena, IMG_NULL);
-
+ /*not nulling pointer, copy on stack*/
}
+/*!
+******************************************************************************
+ @Function RA_TestDelete
+
+ @Description To test whether it is safe to delete a resource arena. If any
+ allocations have not been freed, the RA must not be deleted.
+
+ @Input pArena - the arena to test.
+
+ @Return IMG_BOOL - IMG_TRUE if is safe to go on and call RA_Delete.
+******************************************************************************/
IMG_BOOL
RA_TestDelete (RA_ARENA *pArena)
{
@@ -1045,6 +1359,20 @@ RA_TestDelete (RA_ARENA *pArena)
return IMG_TRUE;
}
+/*!
+******************************************************************************
+ @Function RA_Add
+
+ @Description To add a resource span to an arena. The span must not
+ overlapp with any span previously added to the arena.
+
+ @Input pArena - the arena to add a span into.
+ @Input base - the base of the span.
+ @Input uSize - the extent of the span.
+
+ @Return IMG_TRUE - Success
+ IMG_FALSE - failure
+******************************************************************************/
IMG_BOOL
RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
{
@@ -1063,6 +1391,29 @@ RA_Add (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_SIZE_T uSize)
return ((IMG_BOOL)(_InsertResource (pArena, base, uSize) != IMG_NULL));
}
+/*!
+******************************************************************************
+ @Function RA_Alloc
+
+ @Description To allocate resource from an arena.
+
+ @Input pArena - the arena
+ @Input uRequestSize - the size of resource segment requested.
+ @Output pActualSize - the actual size of resource segment
+ allocated, typcially rounded up by quantum.
+ @Output ppsMapping - the user reference associated with allocated resource span.
+ @Input uFlags - flags influencing allocation policy.
+ @Input uAlignment - the uAlignment constraint required for the
+ allocated segment, use 0 if uAlignment not required.
+ @Input uAlignmentOffset
+ @Input pvPrivData - opaque private data passed through to allocator
+ @Input ui32PrivDataLength - length of opaque private data
+
+ @Output base - allocated base resource
+
+ @Return IMG_TRUE - success
+ IMG_FALSE - failure
+******************************************************************************/
IMG_BOOL
RA_Alloc (RA_ARENA *pArena,
IMG_SIZE_T uRequestSize,
@@ -1071,6 +1422,8 @@ RA_Alloc (RA_ARENA *pArena,
IMG_UINT32 uFlags,
IMG_UINT32 uAlignment,
IMG_UINT32 uAlignmentOffset,
+ IMG_PVOID pvPrivData,
+ IMG_UINT32 ui32PrivDataLength,
IMG_UINTPTR_T *base)
{
IMG_BOOL bResult;
@@ -1101,8 +1454,9 @@ RA_Alloc (RA_ARENA *pArena,
"RA_Alloc: arena='%s', size=0x%x(0x%x), alignment=0x%x, offset=0x%x",
pArena->name, uSize, uRequestSize, uAlignment, uAlignmentOffset));
-
-
+ /* if allocation failed then we might have an import source which
+ can provide more resource, else we will have to fail the
+ allocation to the caller. */
bResult = _AttemptAllocAligned (pArena, uSize, ppsMapping, uFlags,
uAlignment, uAlignmentOffset, base);
if (!bResult)
@@ -1111,34 +1465,38 @@ RA_Alloc (RA_ARENA *pArena,
IMG_UINTPTR_T import_base;
IMG_SIZE_T uImportSize = uSize;
-
-
-
+ /*
+ Ensure that we allocate sufficient space to meet the uAlignment
+ constraint
+ */
if (uAlignment > pArena->uQuantum)
{
uImportSize += (uAlignment - 1);
}
-
+ /* ensure that we import according to the quanta of this arena */
uImportSize = ((uImportSize + pArena->uQuantum - 1)/pArena->uQuantum)*pArena->uQuantum;
bResult =
pArena->pImportAlloc (pArena->pImportHandle, uImportSize, &uImportSize,
- &psImportMapping, uFlags, &import_base);
+ &psImportMapping, uFlags,
+ pvPrivData, ui32PrivDataLength, &import_base);
if (bResult)
{
BT *pBT;
pBT = _InsertResourceSpan (pArena, import_base, uImportSize);
-
+ /* successfully import more resource, create a span to
+ represent it and retry the allocation attempt */
if (pBT == IMG_NULL)
{
-
+ /* insufficient resources to insert the newly acquired span,
+ so free it back again */
pArena->pImportFree(pArena->pImportHandle, import_base,
psImportMapping);
PVR_DPF ((PVR_DBG_MESSAGE,
"RA_Alloc: name='%s', size=0x%x failed!",
pArena->name, uSize));
-
+ /* RA_Dump (arena); */
return IMG_FALSE;
}
pBT->psMapping = psImportMapping;
@@ -1168,7 +1526,9 @@ RA_Alloc (RA_ARENA *pArena,
"RA_Alloc: name='%s', size=0x%x, *base=0x%x = %d",
pArena->name, uSize, *base, bResult));
-
+ /* RA_Dump (pArena);
+ ra_stats (pArena);
+ */
#if defined(VALIDATE_ARENA_TEST)
ValidateArena(pArena);
@@ -1180,6 +1540,20 @@ RA_Alloc (RA_ARENA *pArena,
#if defined(VALIDATE_ARENA_TEST)
+/*!
+******************************************************************************
+ @Function ValidateArena
+
+ @Description Validate an arena by checking that adjacent members of the
+ double linked ordered list are compatible. PVR_DBG_BREAK and
+ PVR_DPF messages are used when an error is detected.
+ NOTE: A DEBUG build is required for PVR_DBG_BREAK and PVR_DPF
+ to operate.
+
+ @Input pArena - the arena
+
+ @Return 0
+******************************************************************************/
IMG_UINT32 ValidateArena(RA_ARENA *pArena)
{
BT* pSegment;
@@ -1208,7 +1582,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END)))
{
-
+ /* error - next span must be live, free or 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));
@@ -1221,7 +1595,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END)))
{
-
+ /* error - next span must be live or 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));
@@ -1235,7 +1609,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_END))
{
-
+ /* error - next span cannot be live, free or 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));
@@ -1249,7 +1623,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
if (!((eNextSpan == IMPORTED_RESOURCE_SPAN_LIVE) ||
(eNextSpan == IMPORTED_RESOURCE_SPAN_FREE)))
{
-
+ /* error - next span must be live or 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));
@@ -1282,7 +1656,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
if (!((eNextSpan == RESOURCE_SPAN_FREE) ||
(eNextSpan == RESOURCE_SPAN_LIVE)))
{
-
+ /* error - next span must be free or 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));
@@ -1295,7 +1669,7 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
if (!((eNextSpan == RESOURCE_SPAN_FREE) ||
(eNextSpan == RESOURCE_SPAN_LIVE)))
{
-
+ /* error - next span must be free or 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));
@@ -1327,6 +1701,18 @@ IMG_UINT32 ValidateArena(RA_ARENA *pArena)
#endif
+/*!
+******************************************************************************
+ @Function RA_Free
+
+ @Description To free a resource segment.
+
+ @Input pArena - the arena the segment was originally allocated from.
+ @Input base - the base of the resource span to free.
+ @Input bFreeBackingStore - Should backing store memory be freed.
+
+ @Return None
+******************************************************************************/
IMG_VOID
RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore)
{
@@ -1386,6 +1772,17 @@ RA_Free (RA_ARENA *pArena, IMG_UINTPTR_T base, IMG_BOOL bFreeBackingStore)
}
+/*!
+******************************************************************************
+ @Function RA_GetNextLiveSegment
+
+ @Description Returns details of the next live resource segments
+
+ @Input pArena - the arena the segment was originally allocated from.
+ @InOut psSegDetails - rtn details of segments
+
+ @Return IMG_TRUE if operation succeeded
+******************************************************************************/
IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetails)
{
BT *pBT;
@@ -1400,7 +1797,7 @@ IMG_BOOL RA_GetNextLiveSegment(IMG_HANDLE hArena, RA_SEGMENT_DETAILS *psSegDetai
pBT = pArena->pHeadSegment;
}
-
+ /* walk the arena segments and write live one to the buffer */
while (pBT != IMG_NULL)
{
if (pBT->type == btt_live)
@@ -1479,9 +1876,19 @@ _BTType (IMG_INT eType)
}
return "junk";
}
-#endif
+#endif /*defined(CONFIG_PROC_FS) && defined(DEBUG)*/
#if defined(ENABLE_RA_DUMP)
+/*!
+******************************************************************************
+ @Function RA_Dump
+
+ @Description To dump a readable description of an arena. Diagnostic only.
+
+ @Input pArena - the arena to dump.
+
+ @Return None
+******************************************************************************/
IMG_VOID
RA_Dump (RA_ARENA *pArena)
{
@@ -1501,16 +1908,15 @@ RA_Dump (RA_ARENA *pArena)
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));
+ PVR_DPF ((PVR_DBG_MESSAGE,"\tbase=0x%x size=0x%x type=%s",
+ (IMG_UINT32) pBT->base, pBT->uSize, _BTType (pBT->type)));
}
#ifdef HASH_TRACE
HASH_Dump (pArena->pSegmentHash);
#endif
}
-#endif
+#endif /* #if defined(ENABLE_RA_DUMP) */
#if defined(CONFIG_PROC_FS) && defined(DEBUG)
@@ -1607,10 +2013,22 @@ static void* RA_ProcSeqOff2ElementRegs(struct seq_file * sfile, loff_t off)
return (void*)pBT;
}
-#endif
+#endif /* defined(CONFIG_PROC_FS) && defined(DEBUG) */
#ifdef RA_STATS
+/*!
+******************************************************************************
+ @Function RA_GetStats
+
+ @Description Gets the arena stats and places in client buffer
+
+ @Input pArena - the arena to print statistics for.
+ @Input ppszStr - caller string to fill
+ @Input pui32StrLen - length of caller string
+
+ @Return PVRSRV_ERROR
+******************************************************************************/
PVRSRV_ERROR RA_GetStats(RA_ARENA *pArena,
IMG_CHAR **ppszStr,
IMG_UINT32 *pui32StrLen)
@@ -1723,3 +2141,10 @@ PVRSRV_ERROR RA_GetStatsFreeMem(RA_ARENA *pArena,
}
#endif
+/******************************************************************************
+ End of file (ra.c)
+******************************************************************************/
+
+
+
+