blob: 76df4b9684b0fb45f80fa18f8d22025e5ab2f06b [file] [log] [blame]
/*************************************************************************/ /*!
@File ri_server.c
@Title Resource Information (RI) server implementation
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@Description Resource Information (RI) server functions
@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.
*/ /**************************************************************************/
#include <stdarg.h>
#include "img_defs.h"
#include "allocmem.h"
#include "pvr_debug.h"
#include "pvrsrv_error.h"
#include "osfunc.h"
#include "srvkm.h"
#include "lock.h"
/* services/include */
#include "pvr_ricommon.h"
/* services/server/include/ */
#include "ri_server.h"
/* services/include/shared/ */
#include "hash.h"
/* services/shared/include/ */
#include "dllist.h"
#include "pmr.h"
/* include/device.h */
#include "device.h"
#if !defined(RI_UNIT_TEST)
#include "pvrsrv.h"
#endif
#if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO)
#define USE_RI_LOCK 1
/*
* Initial size use for Hash table. (Used to index the RI list entries).
*/
#define _RI_INITIAL_HASH_TABLE_SIZE 64
/*
* Values written to the 'valid' field of RI structures when created and
* cleared prior to being destroyed. The code can then check this value
* before accessing the provided pointer contents as a valid RI structure.
*/
#define _VALID_RI_LIST_ENTRY 0x66bccb66
#define _VALID_RI_SUBLIST_ENTRY 0x77cddc77
#define _INVALID 0x00000000
/*
* If this define is set to 1, details of the linked lists (addresses,
* prev/next ptrs, etc) are also output when function RIDumpList() is called.
*/
#define _DUMP_LINKEDLIST_INFO 0
typedef IMG_UINT64 _RI_BASE_T;
/* No +1 in SIZE macros since sizeof includes \0 byte in size */
#define RI_PROC_BUF_SIZE 16
#define RI_MEMDESC_SUM_FRMT "PID %d %s MEMDESCs Alloc'd:0x%010" IMG_UINT64_FMTSPECx " (%" IMG_UINT64_FMTSPEC "K) + "\
"Imported:0x%010" IMG_UINT64_FMTSPECx " (%" IMG_UINT64_FMTSPEC "K) = "\
"Total:0x%010" IMG_UINT64_FMTSPECx " (%" IMG_UINT64_FMTSPEC "K)\n"
#define RI_MEMDESC_SUM_BUF_SIZE (sizeof(RI_MEMDESC_SUM_FRMT)+5+RI_PROC_BUF_SIZE+60)
#define RI_PMR_SUM_FRMT "PID %d %s PMRs Alloc'd:0x%010" IMG_UINT64_FMTSPECx ", %" IMG_UINT64_FMTSPEC "K "\
"[Physical: 0x%010" IMG_UINT64_FMTSPECx ", %" IMG_UINT64_FMTSPEC "K]\n"
#define RI_PMR_SUM_BUF_SIZE (sizeof(RI_PMR_SUM_FRMT)+(40))
#define RI_PMR_ENTRY_FRMT "%%sPID:%%-5d <%%p>\t%%-%ds\t0x%%010" IMG_UINT64_FMTSPECx "\t[0x%%010" IMG_UINT64_FMTSPECx "]\t%%c"
#define RI_PMR_ENTRY_BUF_SIZE (sizeof(RI_PMR_ENTRY_FRMT)+(3+5+16+PVR_ANNOTATION_MAX_LEN+10+10))
#define RI_PMR_ENTRY_FRMT_SIZE (sizeof(RI_PMR_ENTRY_FRMT))
/* Use %5d rather than %d so the output aligns in server/kernel.log, debugFS sees extra spaces */
#define RI_MEMDESC_ENTRY_PROC_FRMT "[%5d:%s]"
#define RI_MEMDESC_ENTRY_PROC_BUF_SIZE (sizeof(RI_MEMDESC_ENTRY_PROC_FRMT)+5+16)
#define RI_SYS_ALLOC_IMPORT_FRMT "{Import from PID %d}"
#define RI_SYS_ALLOC_IMPORT_FRMT_SIZE (sizeof(RI_SYS_ALLOC_IMPORT_FRMT)+5)
static IMG_CHAR g_szSysAllocImport[RI_SYS_ALLOC_IMPORT_FRMT_SIZE];
#define RI_MEMDESC_ENTRY_IMPORT_FRMT "{Import from PID %d}"
#define RI_MEMDESC_ENTRY_IMPORT_BUF_SIZE (sizeof(RI_MEMDESC_ENTRY_IMPORT_FRMT)+5)
#define RI_MEMDESC_ENTRY_UNPINNED_FRMT "{Unpinned}"
#define RI_MEMDESC_ENTRY_UNPINNED_BUF_SIZE (sizeof(RI_MEMDESC_ENTRY_UNPINNED_FRMT))
#define RI_MEMDESC_ENTRY_FRMT "%%sPID:%%-5d 0x%%010" IMG_UINT64_FMTSPECx "\t%%-%ds %%s\t0x%%010" IMG_UINT64_FMTSPECx "\t<%%p> %%s%%s%%s%%c"
#define RI_MEMDESC_ENTRY_BUF_SIZE (sizeof(RI_MEMDESC_ENTRY_FRMT)+(3+5+10+PVR_ANNOTATION_MAX_LEN+RI_MEMDESC_ENTRY_PROC_BUF_SIZE+16+\
RI_MEMDESC_ENTRY_IMPORT_BUF_SIZE+RI_SYS_ALLOC_IMPORT_FRMT_SIZE+RI_MEMDESC_ENTRY_UNPINNED_BUF_SIZE))
#define RI_MEMDESC_ENTRY_FRMT_SIZE (sizeof(RI_MEMDESC_ENTRY_FRMT))
#define RI_FRMT_SIZE_MAX (MAX(RI_MEMDESC_ENTRY_BUF_SIZE,\
MAX(RI_PMR_ENTRY_BUF_SIZE,\
MAX(RI_MEMDESC_SUM_BUF_SIZE,\
RI_PMR_SUM_BUF_SIZE))))
/* Structure used to make linked sublist of memory allocations (MEMDESC) */
struct _RI_SUBLIST_ENTRY_
{
DLLIST_NODE sListNode;
struct _RI_LIST_ENTRY_ *psRI;
IMG_UINT32 valid;
IMG_BOOL bIsImport;
IMG_BOOL bIsSuballoc;
IMG_PID pid;
IMG_CHAR ai8ProcName[RI_PROC_BUF_SIZE];
IMG_DEV_VIRTADDR sVAddr;
IMG_UINT64 ui64Offset;
IMG_UINT64 ui64Size;
IMG_CHAR ai8TextB[DEVMEM_ANNOTATION_MAX_LEN+1];
DLLIST_NODE sProcListNode;
};
/*
* Structure used to make linked list of PMRs. Sublists of allocations
* (MEMDESCs) made from these PMRs are chained off these entries.
*/
struct _RI_LIST_ENTRY_
{
DLLIST_NODE sListNode;
DLLIST_NODE sSysAllocListNode;
DLLIST_NODE sSubListFirst;
IMG_UINT32 valid;
PMR *psPMR;
IMG_PID pid;
IMG_CHAR ai8ProcName[RI_PROC_BUF_SIZE];
IMG_UINT16 ui16SubListCount;
IMG_UINT16 ui16MaxSubListCount;
IMG_UINT32 ui32RIPMRFlags; /* Flags used to indicate the type of allocation */
IMG_UINT32 ui32Flags; /* Flags used to indicate if PMR appears in ri debugfs output */
};
typedef struct _RI_LIST_ENTRY_ RI_LIST_ENTRY;
typedef struct _RI_SUBLIST_ENTRY_ RI_SUBLIST_ENTRY;
static IMG_UINT16 g_ui16RICount;
static HASH_TABLE *g_pRIHashTable;
static IMG_UINT16 g_ui16ProcCount;
static HASH_TABLE *g_pProcHashTable;
static POS_LOCK g_hRILock;
/* Linked list of PMR allocations made against the PVR_SYS_ALLOC_PID and lock
* to prevent concurrent access to it.
*/
static POS_LOCK g_hSysAllocPidListLock;
static DLLIST_NODE g_sSysAllocPidListHead;
/*
* Flag used to indicate if RILock should be destroyed when final PMR entry is
* deleted, i.e. if RIDeInitKM() has already been called before that point but
* the handle manager has deferred deletion of RI entries.
*/
static IMG_BOOL bRIDeInitDeferred = IMG_FALSE;
/*
* Used as head of linked-list of PMR RI entries - this is useful when we wish
* to iterate all PMR list entries (when we don't have a PMR ref)
*/
static DLLIST_NODE sListFirst;
/* Function used to produce string containing info for MEMDESC RI entries (used for both debugfs and kernel log output) */
static void _GenerateMEMDESCEntryString(RI_SUBLIST_ENTRY *psRISubEntry, IMG_BOOL bDebugFs, IMG_UINT16 ui16MaxStrLen, IMG_CHAR *pszEntryString);
/* Function used to produce string containing info for PMR RI entries (used for both debugfs and kernel log output) */
static void _GeneratePMREntryString(RI_LIST_ENTRY *psRIEntry, IMG_BOOL bDebugFs, IMG_UINT16 ui16MaxStrLen, IMG_CHAR *pszEntryString);
static PVRSRV_ERROR _DumpAllEntries (uintptr_t k, uintptr_t v);
static PVRSRV_ERROR _DeleteAllEntries (uintptr_t k, uintptr_t v);
static PVRSRV_ERROR _DeleteAllProcEntries (uintptr_t k, uintptr_t v);
static PVRSRV_ERROR _DumpList(PMR *psPMR, IMG_PID pid);
#define _RIOutput(x) PVR_LOG(x)
#define RI_FLAG_PARSED_BY_DEBUGFS 0x1
#define RI_FLAG_PMR_PHYS_COUNTED_BY_DEBUGFS 0x2
#define RI_FLAG_SYSALLOC_PMR 0x4
static IMG_UINT32
_ProcHashFunc(size_t uKeySize, void *pKey, IMG_UINT32 uHashTabLen);
static IMG_UINT32
_ProcHashFunc(size_t uKeySize, void *pKey, IMG_UINT32 uHashTabLen)
{
IMG_UINT32 *p = (IMG_UINT32 *)pKey;
IMG_UINT32 uKeyLen = uKeySize / sizeof(IMG_UINT32);
IMG_UINT32 ui;
IMG_UINT32 uHashKey = 0;
PVR_UNREFERENCED_PARAMETER(uHashTabLen);
for (ui = 0; ui < uKeyLen; ui++)
{
IMG_UINT32 uHashPart = *p++;
uHashPart += (uHashPart << 12);
uHashPart ^= (uHashPart >> 22);
uHashPart += (uHashPart << 4);
uHashPart ^= (uHashPart >> 9);
uHashPart += (uHashPart << 10);
uHashPart ^= (uHashPart >> 2);
uHashPart += (uHashPart << 7);
uHashPart ^= (uHashPart >> 12);
uHashKey += uHashPart;
}
return uHashKey;
}
static IMG_BOOL
_ProcHashComp(size_t uKeySize, void *pKey1, void *pKey2);
static IMG_BOOL
_ProcHashComp(size_t uKeySize, void *pKey1, void *pKey2)
{
IMG_UINT32 *p1 = (IMG_UINT32 *)pKey1;
IMG_UINT32 *p2 = (IMG_UINT32 *)pKey2;
IMG_UINT32 uKeyLen = uKeySize / sizeof(IMG_UINT32);
IMG_UINT32 ui;
for (ui = 0; ui < uKeyLen; ui++)
{
if (*p1++ != *p2++)
return IMG_FALSE;
}
return IMG_TRUE;
}
static void _RILock(void)
{
#if (USE_RI_LOCK == 1)
OSLockAcquire(g_hRILock);
#endif
}
static void _RIUnlock(void)
{
#if (USE_RI_LOCK == 1)
OSLockRelease(g_hRILock);
#endif
}
/* This value maintains a count of the number of PMRs attributed to the
* PVR_SYS_ALLOC_PID. Access to this value is protected by g_hRILock, so it
* does not need to be an ATOMIC_T.
*/
static IMG_UINT32 g_ui32SysAllocPMRCount;
PVRSRV_ERROR RIInitKM(void)
{
IMG_INT iCharsWritten;
PVRSRV_ERROR eError;
bRIDeInitDeferred = IMG_FALSE;
iCharsWritten = OSSNPrintf(g_szSysAllocImport,
RI_SYS_ALLOC_IMPORT_FRMT_SIZE,
RI_SYS_ALLOC_IMPORT_FRMT,
PVR_SYS_ALLOC_PID);
PVR_LOG_IF_FALSE((iCharsWritten>0 && iCharsWritten<(IMG_INT32)RI_SYS_ALLOC_IMPORT_FRMT_SIZE), \
"OSSNPrintf failed to initialise g_szSysAllocImport");
eError = OSLockCreate(&g_hSysAllocPidListLock);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"%s: OSLockCreate (g_hSysAllocPidListLock) failed (returned %d)",
__func__,
eError));
}
dllist_init(&(g_sSysAllocPidListHead));
#if (USE_RI_LOCK == 1)
eError = OSLockCreate(&g_hRILock);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"%s: OSLockCreate (g_hRILock) failed (returned %d)",
__func__,
eError));
}
#endif
return eError;
}
void RIDeInitKM(void)
{
#if (USE_RI_LOCK == 1)
if (g_ui16RICount > 0)
{
PVR_DPF((PVR_DBG_WARNING,
"%s: called with %d entries remaining - deferring OSLockDestroy()",
__func__,
g_ui16RICount));
bRIDeInitDeferred = IMG_TRUE;
}
else
{
OSLockDestroy(g_hRILock);
OSLockDestroy(g_hSysAllocPidListLock);
}
#endif
}
/*!
*******************************************************************************
@Function RILockAcquireKM
@Description
Acquires the RI Lock (which protects the integrity of the RI
linked lists). Caller will be suspended until lock is acquired.
@Return None
******************************************************************************/
void RILockAcquireKM(void)
{
_RILock();
}
/*!
*******************************************************************************
@Function RILockReleaseKM
@Description
Releases the RI Lock (which protects the integrity of the RI
linked lists).
@Return None
******************************************************************************/
void RILockReleaseKM(void)
{
_RIUnlock();
}
/*!
*******************************************************************************
@Function RIWritePMREntryWithOwnerKM
@Description
Writes a new Resource Information list entry.
The new entry will be inserted at the head of the list of
PMR RI entries and assigned the values provided.
@input psPMR - Reference (handle) to the PMR to which this reference relates
@input ui32Owner - PID of the process which owns the allocation. This
may not be the current process (e.g. a request to
grow a buffer may happen in the context of a kernel
thread, or we may import further resource for a
suballocation made from the FW heap which can then
also be utilized by other processes)
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIWritePMREntryWithOwnerKM(PMR *psPMR,
IMG_PID ui32Owner)
{
PMR *pPMRHashKey = psPMR;
RI_LIST_ENTRY *psRIEntry;
uintptr_t hashData;
/* if Hash table has not been created, create it now */
if (!g_pRIHashTable)
{
g_pRIHashTable = HASH_Create_Extended(_RI_INITIAL_HASH_TABLE_SIZE, sizeof(PMR*), HASH_Func_Default, HASH_Key_Comp_Default);
g_pProcHashTable = HASH_Create_Extended(_RI_INITIAL_HASH_TABLE_SIZE, sizeof(IMG_PID), _ProcHashFunc, _ProcHashComp);
}
if (!g_pRIHashTable || !g_pProcHashTable)
{
/* Error - no memory to allocate for Hash table(s) */
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
if (!psPMR)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
/* Acquire RI Lock */
_RILock();
/* Look-up psPMR in Hash Table */
hashData = HASH_Retrieve_Extended (g_pRIHashTable, (void *)&pPMRHashKey);
psRIEntry = (RI_LIST_ENTRY *)hashData;
if (!psRIEntry)
{
/*
* If failed to find a matching existing entry, create a new one
*/
psRIEntry = (RI_LIST_ENTRY *)OSAllocZMemNoStats(sizeof(RI_LIST_ENTRY));
if (!psRIEntry)
{
/* Release RI Lock */
_RIUnlock();
/* Error - no memory to allocate for new RI entry */
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
else
{
IMG_UINT32 ui32PMRFlags = PMR_Flags(psPMR);
PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)PMR_DeviceNode(psPMR);
/*
* Add new RI Entry
*/
if (g_ui16RICount == 0)
{
/* Initialise PMR entry linked-list head */
dllist_init(&sListFirst);
}
g_ui16RICount++;
dllist_init (&(psRIEntry->sSysAllocListNode));
dllist_init (&(psRIEntry->sSubListFirst));
psRIEntry->ui16SubListCount = 0;
psRIEntry->ui16MaxSubListCount = 0;
psRIEntry->valid = _VALID_RI_LIST_ENTRY;
/* Check if this PMR should be accounted for under the
* PVR_SYS_ALLOC_PID debugFS entry. This should happen if
* we are in the driver init phase, the flags indicate
* this is a FW local allocation (made from FW heap)
* or the owner PID is PVR_SYS_ALLOC_PID.
* Also record host dev node allocs on the system PID.
*/
if (psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_INIT ||
PVRSRV_CHECK_FW_LOCAL(ui32PMRFlags) ||
ui32Owner == PVR_SYS_ALLOC_PID ||
psDeviceNode == PVRSRVGetPVRSRVData()->psHostMemDeviceNode)
{
psRIEntry->ui32RIPMRFlags = RI_FLAG_SYSALLOC_PMR;
OSSNPrintf(psRIEntry->ai8ProcName,
RI_PROC_BUF_SIZE,
"SysProc");
psRIEntry->pid = PVR_SYS_ALLOC_PID;
OSLockAcquire(g_hSysAllocPidListLock);
/* Add this psRIEntry to the list of entries for PVR_SYS_ALLOC_PID */
dllist_add_to_tail(&g_sSysAllocPidListHead,(PDLLIST_NODE)&(psRIEntry->sSysAllocListNode));
OSLockRelease(g_hSysAllocPidListLock);
g_ui32SysAllocPMRCount++;
}
else
{
psRIEntry->ui32RIPMRFlags = 0;
psRIEntry->pid = ui32Owner;
}
OSSNPrintf(psRIEntry->ai8ProcName,
RI_PROC_BUF_SIZE,
"%s",
OSGetCurrentClientProcessNameKM());
/* Add PMR entry to linked-list of all PMR entries */
dllist_init (&(psRIEntry->sListNode));
dllist_add_to_tail(&sListFirst,(PDLLIST_NODE)&(psRIEntry->sListNode));
}
psRIEntry->psPMR = psPMR;
psRIEntry->ui32Flags = 0;
/* Create index entry in Hash Table */
HASH_Insert_Extended (g_pRIHashTable, (void *)&pPMRHashKey, (uintptr_t)psRIEntry);
/* Store phRIHandle in PMR structure, so it can delete the associated RI entry when it destroys the PMR */
PMRStoreRIHandle(psPMR, psRIEntry);
}
/* Release RI Lock */
_RIUnlock();
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIWritePMREntryKM
@Description
Writes a new Resource Information list entry.
The new entry will be inserted at the head of the list of
PMR RI entries and assigned the values provided.
@input psPMR - Reference (handle) to the PMR to which this reference relates
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIWritePMREntryKM(PMR *psPMR)
{
return RIWritePMREntryWithOwnerKM(psPMR,
OSGetCurrentClientProcessIDKM());
}
/*!
*******************************************************************************
@Function RIWriteMEMDESCEntryKM
@Description
Writes a new Resource Information sublist entry.
The new entry will be inserted at the head of the sublist of
the indicated PMR list entry, and assigned the values provided.
@input psPMR - Reference (handle) to the PMR to which this MEMDESC RI entry relates
@input ui32TextBSize - Length of string provided in psz8TextB parameter
@input psz8TextB - String describing this secondary reference (may be null)
@input ui64Offset - Offset from the start of the PMR at which this allocation begins
@input ui64Size - Size of this allocation
@input bIsImport - Flag indicating if this is an allocation or an import
@input bIsSuballoc - Flag indicating if this is a sub-allocation
@output phRIHandle - Handle to the created RI entry
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIWriteMEMDESCEntryKM(PMR *psPMR,
IMG_UINT32 ui32TextBSize,
const IMG_CHAR *psz8TextB,
IMG_UINT64 ui64Offset,
IMG_UINT64 ui64Size,
IMG_BOOL bIsImport,
IMG_BOOL bIsSuballoc,
RI_HANDLE *phRIHandle)
{
RI_SUBLIST_ENTRY *psRISubEntry;
RI_LIST_ENTRY *psRIEntry;
PMR *pPMRHashKey = psPMR;
uintptr_t hashData;
IMG_PID pid;
/* Check Hash tables have been created (meaning at least one PMR has been defined) */
if (!g_pRIHashTable || !g_pProcHashTable)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (!psPMR || !phRIHandle)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
/* Acquire RI Lock */
_RILock();
*phRIHandle = NULL;
/* Look-up psPMR in Hash Table */
hashData = HASH_Retrieve_Extended (g_pRIHashTable, (void *)&pPMRHashKey);
psRIEntry = (RI_LIST_ENTRY *)hashData;
if (!psRIEntry)
{
/* Release RI Lock */
_RIUnlock();
return PVRSRV_ERROR_INVALID_PARAMS;
}
psRISubEntry = (RI_SUBLIST_ENTRY *)OSAllocZMemNoStats(sizeof(RI_SUBLIST_ENTRY));
if (!psRISubEntry)
{
/* Release RI Lock */
_RIUnlock();
/* Error - no memory to allocate for new RI sublist entry */
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
else
{
/*
* Insert new entry in sublist
*/
PDLLIST_NODE currentNode = dllist_get_next_node(&(psRIEntry->sSubListFirst));
/*
* Insert new entry before currentNode
*/
if (!currentNode)
{
currentNode = &(psRIEntry->sSubListFirst);
}
dllist_add_to_tail(currentNode, (PDLLIST_NODE)&(psRISubEntry->sListNode));
psRISubEntry->psRI = psRIEntry;
/* Increment number of entries in sublist */
psRIEntry->ui16SubListCount++;
if (psRIEntry->ui16SubListCount > psRIEntry->ui16MaxSubListCount)
{
psRIEntry->ui16MaxSubListCount = psRIEntry->ui16SubListCount;
}
psRISubEntry->valid = _VALID_RI_SUBLIST_ENTRY;
}
/* If allocation is made during device or driver initialisation,
* track the MEMDESC entry under PVR_SYS_ALLOC_PID, otherwise use
* the current PID.
* Record host dev node allocations on the system PID.
*/
{
PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)PMR_DeviceNode(psRISubEntry->psRI->psPMR);
if (psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_INIT ||
psDeviceNode == PVRSRVGetPVRSRVData()->psHostMemDeviceNode)
{
psRISubEntry->pid = psRISubEntry->psRI->pid;
}
else
{
psRISubEntry->pid = OSGetCurrentClientProcessIDKM();
}
}
if (ui32TextBSize > sizeof(psRISubEntry->ai8TextB)-1)
{
PVR_DPF((PVR_DBG_WARNING,
"%s: TextBSize too long (%u). Text will be truncated "
"to %zu characters", __func__,
ui32TextBSize, sizeof(psRISubEntry->ai8TextB)-1));
}
/* copy ai8TextB field data */
OSSNPrintf((IMG_CHAR *)psRISubEntry->ai8TextB, sizeof(psRISubEntry->ai8TextB), "%s", psz8TextB);
psRISubEntry->ui64Offset = ui64Offset;
psRISubEntry->ui64Size = ui64Size;
psRISubEntry->bIsImport = bIsImport;
psRISubEntry->bIsSuballoc = bIsSuballoc;
OSSNPrintf((IMG_CHAR *)psRISubEntry->ai8ProcName, RI_PROC_BUF_SIZE, "%s", OSGetCurrentClientProcessNameKM());
dllist_init (&(psRISubEntry->sProcListNode));
/*
* Now insert this MEMDESC into the proc list
*/
/* look-up pid in Hash Table */
pid = psRISubEntry->pid;
hashData = HASH_Retrieve_Extended (g_pProcHashTable, (void *)&pid);
if (!hashData)
{
/*
* No allocations for this pid yet
*/
HASH_Insert_Extended (g_pProcHashTable, (void *)&pid, (uintptr_t)&(psRISubEntry->sProcListNode));
/* Increment number of entries in proc hash table */
g_ui16ProcCount++;
}
else
{
/*
* Insert allocation into pid allocations linked list
*/
PDLLIST_NODE currentNode = (PDLLIST_NODE)hashData;
/*
* Insert new entry
*/
dllist_add_to_tail(currentNode, (PDLLIST_NODE)&(psRISubEntry->sProcListNode));
}
*phRIHandle = (RI_HANDLE)psRISubEntry;
/* Release RI Lock */
_RIUnlock();
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIWriteProcListEntryKM
@Description
Write a new entry in the process list directly. We have to do this
because there might be no, multiple or changing PMR handles.
In the common case we have a PMR that will be added to the PMR list
and one or several MemDescs that are associated to it in a sub-list.
Additionally these MemDescs will be inserted in the per-process list.
There might be special descriptors from e.g. new user APIs that
are associated with no or multiple PMRs and not just one.
These can be now added to the per-process list (as RI_SUBLIST_ENTRY)
directly with this function and won't be listed in the PMR list (RIEntry)
because there might be no PMR.
To remove entries from the per-process list, just use
RIDeleteMEMDESCEntryKM().
@input psz8TextB - String describing this secondary reference (may be null)
@input ui64Size - Size of this allocation
@input ui64DevVAddr - Virtual address of this entry
@output phRIHandle - Handle to the created RI entry
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIWriteProcListEntryKM(IMG_UINT32 ui32TextBSize,
const IMG_CHAR *psz8TextB,
IMG_UINT64 ui64Size,
IMG_UINT64 ui64DevVAddr,
RI_HANDLE *phRIHandle)
{
uintptr_t hashData = 0;
IMG_PID pid;
RI_SUBLIST_ENTRY *psRISubEntry = NULL;
if (!g_pRIHashTable)
{
g_pRIHashTable = HASH_Create_Extended(_RI_INITIAL_HASH_TABLE_SIZE, sizeof(PMR*), HASH_Func_Default, HASH_Key_Comp_Default);
g_pProcHashTable = HASH_Create_Extended(_RI_INITIAL_HASH_TABLE_SIZE, sizeof(IMG_PID), _ProcHashFunc, _ProcHashComp);
if (!g_pRIHashTable || !g_pProcHashTable)
{
/* Error - no memory to allocate for Hash table(s) */
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
}
/* Acquire RI Lock */
_RILock();
*phRIHandle = NULL;
psRISubEntry = (RI_SUBLIST_ENTRY *)OSAllocZMemNoStats(sizeof(RI_SUBLIST_ENTRY));
if (!psRISubEntry)
{
/* Release RI Lock */
_RIUnlock();
/* Error - no memory to allocate for new RI sublist entry */
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psRISubEntry->valid = _VALID_RI_SUBLIST_ENTRY;
psRISubEntry->pid = OSGetCurrentClientProcessIDKM();
if (ui32TextBSize > sizeof(psRISubEntry->ai8TextB)-1)
{
PVR_DPF((PVR_DBG_WARNING,
"%s: TextBSize too long (%u). Text will be truncated "
"to %zu characters", __func__,
ui32TextBSize, sizeof(psRISubEntry->ai8TextB)-1));
}
/* copy ai8TextB field data */
OSSNPrintf((IMG_CHAR *)psRISubEntry->ai8TextB, sizeof(psRISubEntry->ai8TextB), "%s", psz8TextB);
psRISubEntry->ui64Offset = 0;
psRISubEntry->ui64Size = ui64Size;
psRISubEntry->sVAddr.uiAddr = ui64DevVAddr;
psRISubEntry->bIsImport = IMG_FALSE;
psRISubEntry->bIsSuballoc = IMG_FALSE;
OSSNPrintf((IMG_CHAR *)psRISubEntry->ai8ProcName, RI_PROC_BUF_SIZE, "%s", OSGetCurrentClientProcessNameKM());
dllist_init (&(psRISubEntry->sProcListNode));
/*
* Now insert this MEMDESC into the proc list
*/
/* look-up pid in Hash Table */
pid = psRISubEntry->pid;
hashData = HASH_Retrieve_Extended (g_pProcHashTable, (void *)&pid);
if (!hashData)
{
/*
* No allocations for this pid yet
*/
HASH_Insert_Extended (g_pProcHashTable, (void *)&pid, (uintptr_t)&(psRISubEntry->sProcListNode));
/* Increment number of entries in proc hash table */
g_ui16ProcCount++;
}
else
{
/*
* Insert allocation into pid allocations linked list
*/
PDLLIST_NODE currentNode = (PDLLIST_NODE)hashData;
/*
* Insert new entry
*/
dllist_add_to_tail(currentNode, (PDLLIST_NODE)&(psRISubEntry->sProcListNode));
}
*phRIHandle = (RI_HANDLE)psRISubEntry;
/* Release RI Lock */
_RIUnlock();
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIUpdateMEMDESCAddrKM
@Description
Update a Resource Information entry.
@input hRIHandle - Handle of object whose reference info is to be updated
@input sVAddr - New address for the RI entry
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIUpdateMEMDESCAddrKM(RI_HANDLE hRIHandle,
IMG_DEV_VIRTADDR sVAddr)
{
RI_SUBLIST_ENTRY *psRISubEntry;
if (!hRIHandle)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
psRISubEntry = (RI_SUBLIST_ENTRY *)hRIHandle;
if (psRISubEntry->valid != _VALID_RI_SUBLIST_ENTRY)
{
/* Pointer does not point to valid structure */
return PVRSRV_ERROR_INVALID_PARAMS;
}
/* Acquire RI lock*/
_RILock();
psRISubEntry->sVAddr.uiAddr = sVAddr.uiAddr;
/* Release RI lock */
_RIUnlock();
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIDeletePMREntryKM
@Description
Delete a Resource Information entry.
@input hRIHandle - Handle of object whose reference info is to be deleted
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDeletePMREntryKM(RI_HANDLE hRIHandle)
{
RI_LIST_ENTRY *psRIEntry;
PMR *pPMRHashKey;
PVRSRV_ERROR eResult = PVRSRV_OK;
if (!hRIHandle)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
psRIEntry = (RI_LIST_ENTRY *)hRIHandle;
if (psRIEntry->valid != _VALID_RI_LIST_ENTRY)
{
/* Pointer does not point to valid structure */
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (psRIEntry->ui16SubListCount == 0)
{
/* Acquire RI lock*/
_RILock();
/* Remove the HASH table index entry */
pPMRHashKey = psRIEntry->psPMR;
HASH_Remove_Extended(g_pRIHashTable, (void *)&pPMRHashKey);
psRIEntry->valid = _INVALID;
/* Remove PMR entry from linked-list of PMR entries */
dllist_remove_node((PDLLIST_NODE)&(psRIEntry->sListNode));
if (psRIEntry->ui32RIPMRFlags & RI_FLAG_SYSALLOC_PMR)
{
dllist_remove_node((PDLLIST_NODE)&(psRIEntry->sSysAllocListNode));
g_ui32SysAllocPMRCount--;
}
/* Now, free the memory used to store the RI entry */
OSFreeMemNoStats(psRIEntry);
psRIEntry = NULL;
/*
* Decrement number of RI entries - if this is now zero,
* we can delete the RI hash table
*/
if (--g_ui16RICount == 0)
{
HASH_Delete(g_pRIHashTable);
g_pRIHashTable = NULL;
_RIUnlock();
/* If deInit has been deferred, we can now destroy the RI Lock */
if (bRIDeInitDeferred)
{
OSLockDestroy(g_hRILock);
}
}
else
{
/* Release RI lock*/
_RIUnlock();
}
/*
* Make the handle NULL once PMR RI entry is deleted
*/
hRIHandle = NULL;
}
else
{
eResult = PVRSRV_ERROR_DEVICEMEM_ALLOCATIONS_REMAIN_IN_HEAP;
}
return eResult;
}
/*!
*******************************************************************************
@Function RIDeleteMEMDESCEntryKM
@Description
Delete a Resource Information entry.
Entry can be from RIEntry list or ProcList.
@input hRIHandle - Handle of object whose reference info is to be deleted
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDeleteMEMDESCEntryKM(RI_HANDLE hRIHandle)
{
RI_LIST_ENTRY *psRIEntry = NULL;
RI_SUBLIST_ENTRY *psRISubEntry;
uintptr_t hashData;
IMG_PID pid;
if (!hRIHandle)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
psRISubEntry = (RI_SUBLIST_ENTRY *)hRIHandle;
if (psRISubEntry->valid != _VALID_RI_SUBLIST_ENTRY)
{
/* Pointer does not point to valid structure */
return PVRSRV_ERROR_INVALID_PARAMS;
}
/* Acquire RI lock*/
_RILock();
/* For entries which do have a parent PMR remove the node from the sublist */
if (psRISubEntry->psRI)
{
psRIEntry = (RI_LIST_ENTRY *)psRISubEntry->psRI;
/* Now, remove entry from the sublist */
dllist_remove_node(&(psRISubEntry->sListNode));
}
psRISubEntry->valid = _INVALID;
/* Remove the entry from the proc allocations linked list */
pid = psRISubEntry->pid;
/* If this is the only allocation for this pid, just remove it from the hash table */
if (dllist_get_next_node(&(psRISubEntry->sProcListNode)) == NULL)
{
HASH_Remove_Extended(g_pProcHashTable, (void *)&pid);
/* Decrement number of entries in proc hash table, and delete the hash table if there are now none */
if (--g_ui16ProcCount == 0)
{
HASH_Delete(g_pProcHashTable);
g_pProcHashTable = NULL;
}
}
else
{
hashData = HASH_Retrieve_Extended (g_pProcHashTable, (void *)&pid);
if ((PDLLIST_NODE)hashData == &(psRISubEntry->sProcListNode))
{
HASH_Remove_Extended(g_pProcHashTable, (void *)&pid);
HASH_Insert_Extended (g_pProcHashTable, (void *)&pid, (uintptr_t)dllist_get_next_node(&(psRISubEntry->sProcListNode)));
}
}
dllist_remove_node(&(psRISubEntry->sProcListNode));
/* Now, free the memory used to store the sublist entry */
OSFreeMemNoStats(psRISubEntry);
psRISubEntry = NULL;
/*
* Decrement number of entries in sublist if this MemDesc had a parent entry.
*/
if (psRIEntry)
{
psRIEntry->ui16SubListCount--;
}
/* Release RI lock*/
_RIUnlock();
/*
* Make the handle NULL once MEMDESC RI entry is deleted
*/
hRIHandle = NULL;
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIDeleteListKM
@Description
Delete all Resource Information entries and free associated
memory.
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDeleteListKM(void)
{
PVRSRV_ERROR eResult = PVRSRV_OK;
_RILock();
if (g_pRIHashTable)
{
eResult = HASH_Iterate(g_pRIHashTable, (HASH_pfnCallback)_DeleteAllEntries);
if (eResult == PVRSRV_ERROR_RESOURCE_UNAVAILABLE)
{
/*
* PVRSRV_ERROR_RESOURCE_UNAVAILABLE is used to stop the Hash iterator when
* the hash table gets deleted as a result of deleting the final PMR entry,
* so this is not a real error condition...
*/
eResult = PVRSRV_OK;
}
}
/* After the run through the RIHashTable that holds the PMR entries there might be
* still entries left in the per-process hash table because they were added with
* RIWriteProcListEntryKM() and have no PMR parent associated.
*/
if (g_pProcHashTable)
{
eResult = HASH_Iterate(g_pProcHashTable, (HASH_pfnCallback) _DeleteAllProcEntries);
if (eResult == PVRSRV_ERROR_RESOURCE_UNAVAILABLE)
{
/*
* PVRSRV_ERROR_RESOURCE_UNAVAILABLE is used to stop the Hash iterator when
* the hash table gets deleted as a result of deleting the final PMR entry,
* so this is not a real error condition...
*/
eResult = PVRSRV_OK;
}
}
_RIUnlock();
return eResult;
}
/*!
*******************************************************************************
@Function RIDumpListKM
@Description
Dumps out the contents of the RI List entry for the
specified PMR, and all MEMDESC allocation entries
in the associated sub linked list.
At present, output is directed to Kernel log
via PVR_DPF.
@input psPMR - PMR for which RI entry details are to be output
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDumpListKM(PMR *psPMR)
{
PVRSRV_ERROR eError;
/* Acquire RI lock*/
_RILock();
eError = _DumpList(psPMR,0);
/* Release RI lock*/
_RIUnlock();
return eError;
}
/*!
*******************************************************************************
@Function RIGetListEntryKM
@Description
Returns pointer to a formatted string with details of the specified
list entry. If no entry exists (e.g. it may have been deleted
since the previous call), NULL is returned.
@input pid - pid for which RI entry details are to be output
@input ppHandle - handle to the entry, if NULL, the first entry will be
returned.
@output pszEntryString - string to be output for the entry
@output hEntry - hEntry will be returned pointing to the next entry
(or NULL if there is no next entry)
@Return PVRSRV_ERROR
******************************************************************************/
IMG_BOOL RIGetListEntryKM(IMG_PID pid,
IMG_HANDLE **ppHandle,
IMG_CHAR **ppszEntryString)
{
RI_SUBLIST_ENTRY *psRISubEntry = NULL;
RI_LIST_ENTRY *psRIEntry = NULL;
uintptr_t hashData = 0;
IMG_PID hashKey = pid;
static IMG_CHAR acStringBuffer[RI_FRMT_SIZE_MAX];
static IMG_UINT64 ui64TotalMemdescAlloc;
static IMG_UINT64 ui64TotalImport;
static IMG_UINT64 ui64TotalPMRAlloc;
static IMG_UINT64 ui64TotalPMRBacked;
static enum {
RI_GET_STATE_MEMDESCS_LIST_START,
RI_GET_STATE_MEMDESCS_SUMMARY,
RI_GET_STATE_PMR_LIST,
RI_GET_STATE_PMR_SUMMARY,
RI_GET_STATE_END,
RI_GET_STATE_LAST
} g_bNextGetState = RI_GET_STATE_MEMDESCS_LIST_START;
static DLLIST_NODE *psNode;
static DLLIST_NODE *psSysAllocNode;
static IMG_CHAR szProcName[RI_PROC_BUF_SIZE];
static IMG_UINT32 ui32ProcessedSysAllocPMRCount;
acStringBuffer[0] = '\0';
switch (g_bNextGetState)
{
case RI_GET_STATE_MEMDESCS_LIST_START:
/* look-up pid in Hash Table, to obtain first entry for pid */
hashData = HASH_Retrieve_Extended(g_pProcHashTable, (void *)&hashKey);
if (hashData)
{
if (*ppHandle)
{
psRISubEntry = (RI_SUBLIST_ENTRY *)*ppHandle;
if (psRISubEntry->valid != _VALID_RI_SUBLIST_ENTRY)
{
psRISubEntry = NULL;
}
}
else
{
psRISubEntry = IMG_CONTAINER_OF((PDLLIST_NODE)hashData, RI_SUBLIST_ENTRY, sProcListNode);
if (psRISubEntry->valid != _VALID_RI_SUBLIST_ENTRY)
{
psRISubEntry = NULL;
}
}
}
if (psRISubEntry)
{
PDLLIST_NODE psNextProcListNode = dllist_get_next_node(&psRISubEntry->sProcListNode);
if (psRISubEntry->bIsImport)
{
ui64TotalImport += psRISubEntry->ui64Size;
}
else
{
ui64TotalMemdescAlloc += psRISubEntry->ui64Size;
}
_GenerateMEMDESCEntryString(psRISubEntry,
IMG_TRUE,
RI_MEMDESC_ENTRY_BUF_SIZE,
acStringBuffer);
/* If this MEMDESC has a parent PMR and if not an imported PMR, flag 'parent' PMR has having been listed in MEMDESCs */
if (psRISubEntry->psRI && !psRISubEntry->bIsImport && !(psRISubEntry->psRI->ui32RIPMRFlags & RI_FLAG_SYSALLOC_PMR))
{
psRISubEntry->psRI->ui32RIPMRFlags |= RI_FLAG_PARSED_BY_DEBUGFS;
}
if (szProcName[0] == '\0')
{
OSStringCopy(szProcName, (pid == PVR_SYS_ALLOC_PID) ?
PVRSRV_MODNAME : psRISubEntry->ai8ProcName);
}
*ppszEntryString = acStringBuffer;
*ppHandle = (IMG_HANDLE)IMG_CONTAINER_OF(psNextProcListNode, RI_SUBLIST_ENTRY, sProcListNode);
if (psNextProcListNode == NULL ||
psNextProcListNode == (PDLLIST_NODE)hashData)
{
g_bNextGetState = RI_GET_STATE_MEMDESCS_SUMMARY;
}
/* else continue to list MEMDESCs */
}
else
{
if (ui64TotalMemdescAlloc == 0)
{
acStringBuffer[0] = '\0';
*ppszEntryString =acStringBuffer;
g_bNextGetState = RI_GET_STATE_MEMDESCS_SUMMARY;
}
/* else continue to list MEMDESCs */
}
break;
case RI_GET_STATE_MEMDESCS_SUMMARY:
OSSNPrintf(acStringBuffer,
RI_MEMDESC_SUM_BUF_SIZE,
RI_MEMDESC_SUM_FRMT,
pid,
szProcName,
ui64TotalMemdescAlloc,
ui64TotalMemdescAlloc >> 10,
ui64TotalImport,
ui64TotalImport >> 10,
(ui64TotalMemdescAlloc + ui64TotalImport),
(ui64TotalMemdescAlloc + ui64TotalImport) >> 10);
*ppszEntryString = acStringBuffer;
ui64TotalMemdescAlloc = 0;
ui64TotalImport = 0;
szProcName[0] = '\0';
g_bNextGetState = RI_GET_STATE_PMR_LIST;
break;
case RI_GET_STATE_PMR_LIST:
if (pid == PVR_SYS_ALLOC_PID)
{
OSLockAcquire(g_hSysAllocPidListLock);
acStringBuffer[0] = '\0';
if (!psSysAllocNode)
{
psSysAllocNode = &g_sSysAllocPidListHead;
ui32ProcessedSysAllocPMRCount = 0;
}
psSysAllocNode = dllist_get_next_node(psSysAllocNode);
if (szProcName[0] == '\0')
{
OSStringCopy(szProcName, PVRSRV_MODNAME);
}
if (psSysAllocNode != NULL && psSysAllocNode != &g_sSysAllocPidListHead)
{
IMG_DEVMEM_SIZE_T uiPMRPhysicalBacking, uiPMRLogicalSize = 0;
psRIEntry = IMG_CONTAINER_OF((PDLLIST_NODE)psSysAllocNode, RI_LIST_ENTRY, sSysAllocListNode);
_GeneratePMREntryString(psRIEntry,
IMG_TRUE,
RI_PMR_ENTRY_BUF_SIZE,
acStringBuffer);
PMR_LogicalSize(psRIEntry->psPMR,
&uiPMRLogicalSize);
ui64TotalPMRAlloc += uiPMRLogicalSize;
PMR_PhysicalSize(psRIEntry->psPMR, &uiPMRPhysicalBacking);
ui64TotalPMRBacked += uiPMRPhysicalBacking;
ui32ProcessedSysAllocPMRCount++;
if (ui32ProcessedSysAllocPMRCount > g_ui32SysAllocPMRCount+1)
{
g_bNextGetState = RI_GET_STATE_PMR_SUMMARY;
}
/* else continue to list PMRs */
}
else
{
g_bNextGetState = RI_GET_STATE_PMR_SUMMARY;
}
*ppszEntryString = (IMG_CHAR *)acStringBuffer;
OSLockRelease(g_hSysAllocPidListLock);
}
else
{
IMG_BOOL bPMRToDisplay = IMG_FALSE;
/* Iterate through the 'touched' PMRs and display details */
if (!psNode)
{
psNode = dllist_get_next_node(&sListFirst);
}
else
{
psNode = dllist_get_next_node(psNode);
}
while ((psNode != NULL && psNode != &sListFirst) &&
!bPMRToDisplay)
{
psRIEntry = IMG_CONTAINER_OF(psNode, RI_LIST_ENTRY, sListNode);
if (psRIEntry->ui32RIPMRFlags & RI_FLAG_PARSED_BY_DEBUGFS)
{
IMG_DEVMEM_SIZE_T uiPMRPhysicalBacking, uiPMRLogicalSize = 0;
/* This PMR was 'touched', so display details and unflag it*/
_GeneratePMREntryString(psRIEntry,
IMG_TRUE,
RI_PMR_ENTRY_BUF_SIZE,
acStringBuffer);
psRIEntry->ui32RIPMRFlags &= ~RI_FLAG_PARSED_BY_DEBUGFS;
PMR_LogicalSize(psRIEntry->psPMR, &uiPMRLogicalSize);
ui64TotalPMRAlloc += uiPMRLogicalSize;
PMR_PhysicalSize(psRIEntry->psPMR, &uiPMRPhysicalBacking);
ui64TotalPMRBacked += uiPMRPhysicalBacking;
/* Remember the name of the process for 1 PMR for the summary */
if (szProcName[0] == '\0')
{
OSStringCopy(szProcName, psRIEntry->ai8ProcName);
}
bPMRToDisplay = IMG_TRUE;
}
else
{
psNode = dllist_get_next_node(psNode);
}
}
if (psNode == NULL || (psNode == &sListFirst))
{
g_bNextGetState = RI_GET_STATE_PMR_SUMMARY;
}
/* else continue listing PMRs */
}
break;
case RI_GET_STATE_PMR_SUMMARY:
OSSNPrintf(acStringBuffer,
RI_PMR_SUM_BUF_SIZE,
RI_PMR_SUM_FRMT,
pid,
szProcName,
ui64TotalPMRAlloc,
ui64TotalPMRAlloc >> 10,
ui64TotalPMRBacked,
ui64TotalPMRBacked >> 10);
*ppszEntryString = acStringBuffer;
ui64TotalPMRAlloc = 0;
ui64TotalPMRBacked = 0;
szProcName[0] = '\0';
psSysAllocNode = NULL;
g_bNextGetState = RI_GET_STATE_END;
break;
default:
PVR_DPF((PVR_DBG_ERROR, "%s: Bad %d)",__func__, g_bNextGetState));
__fallthrough;
case RI_GET_STATE_END:
/* Reset state ready for the next gpu_mem_area file to display */
*ppszEntryString = NULL;
*ppHandle = NULL;
psNode = NULL;
szProcName[0] = '\0';
g_bNextGetState = RI_GET_STATE_MEMDESCS_LIST_START;
return IMG_FALSE;
break;
}
return IMG_TRUE;
}
/* Function used to produce string containing info for MEMDESC RI entries (used for both debugfs and kernel log output) */
static void _GenerateMEMDESCEntryString(RI_SUBLIST_ENTRY *psRISubEntry,
IMG_BOOL bDebugFs,
IMG_UINT16 ui16MaxStrLen,
IMG_CHAR *pszEntryString)
{
IMG_CHAR szProc[RI_MEMDESC_ENTRY_PROC_BUF_SIZE];
IMG_CHAR szImport[RI_MEMDESC_ENTRY_IMPORT_BUF_SIZE];
IMG_CHAR szEntryFormat[RI_MEMDESC_ENTRY_FRMT_SIZE];
const IMG_CHAR *pszAnnotationText;
IMG_PID uiRIPid = 0;
PMR* psRIPMR = NULL;
IMG_UINT32 ui32RIPMRFlags = 0;
if(psRISubEntry->psRI != NULL)
{
uiRIPid = psRISubEntry->psRI->pid;
psRIPMR = psRISubEntry->psRI->psPMR;
ui32RIPMRFlags = psRISubEntry->psRI->ui32RIPMRFlags;
}
OSSNPrintf(szEntryFormat,
RI_MEMDESC_ENTRY_FRMT_SIZE,
RI_MEMDESC_ENTRY_FRMT,
DEVMEM_ANNOTATION_MAX_LEN);
if (!bDebugFs)
{
/* we don't include process ID info for debugfs output */
OSSNPrintf(szProc,
RI_MEMDESC_ENTRY_PROC_BUF_SIZE,
RI_MEMDESC_ENTRY_PROC_FRMT,
psRISubEntry->pid,
psRISubEntry->ai8ProcName);
}
if (psRISubEntry->bIsImport && psRIPMR)
{
OSSNPrintf((IMG_CHAR *)&szImport,
RI_MEMDESC_ENTRY_IMPORT_BUF_SIZE,
RI_MEMDESC_ENTRY_IMPORT_FRMT,
uiRIPid);
/* Set pszAnnotationText to that of the 'parent' PMR RI entry */
pszAnnotationText = PMR_GetAnnotation(psRIPMR);
}
else if (!psRISubEntry->bIsSuballoc && psRIPMR)
{
/* Set pszAnnotationText to that of the 'parent' PMR RI entry */
pszAnnotationText = PMR_GetAnnotation(psRIPMR);
}
else
{
/* Set pszAnnotationText to that of the MEMDESC RI entry */
pszAnnotationText = psRISubEntry->ai8TextB;
}
/* Don't print memdescs if they are local imports
* (i.e. imported PMRs allocated by this process)
*/
if (bDebugFs &&
((psRISubEntry->sVAddr.uiAddr + psRISubEntry->ui64Offset) == 0) &&
(psRISubEntry->bIsImport && ((psRISubEntry->pid == uiRIPid) || (uiRIPid == PVR_SYS_ALLOC_PID))))
{
/* Don't print this entry */
pszEntryString[0] = '\0';
}
else
{
OSSNPrintf(pszEntryString,
ui16MaxStrLen,
szEntryFormat,
(bDebugFs ? "" : " "),
psRISubEntry->pid,
(psRISubEntry->sVAddr.uiAddr + psRISubEntry->ui64Offset),
pszAnnotationText,
(bDebugFs ? "" : (char *)szProc),
psRISubEntry->ui64Size,
psRIPMR,
(psRISubEntry->bIsImport ? (char *)&szImport : ""),
(!psRISubEntry->bIsImport && (ui32RIPMRFlags & RI_FLAG_SYSALLOC_PMR) && (psRISubEntry->pid != PVR_SYS_ALLOC_PID)) ? g_szSysAllocImport : "",
(psRIPMR && PMR_IsUnpinned(psRIPMR)) ? RI_MEMDESC_ENTRY_UNPINNED_FRMT : "",
(bDebugFs ? '\n' : ' '));
}
}
/* Function used to produce string containing info for PMR RI entries (used for debugfs and kernel log output) */
static void _GeneratePMREntryString(RI_LIST_ENTRY *psRIEntry,
IMG_BOOL bDebugFs,
IMG_UINT16 ui16MaxStrLen,
IMG_CHAR *pszEntryString)
{
const IMG_CHAR* pszAnnotationText;
IMG_DEVMEM_SIZE_T uiLogicalSize = 0;
IMG_DEVMEM_SIZE_T uiPhysicalSize = 0;
IMG_CHAR szEntryFormat[RI_PMR_ENTRY_FRMT_SIZE];
PMR_LogicalSize(psRIEntry->psPMR, &uiLogicalSize);
PMR_PhysicalSize(psRIEntry->psPMR, &uiPhysicalSize);
OSSNPrintf(szEntryFormat,
RI_PMR_ENTRY_FRMT_SIZE,
RI_PMR_ENTRY_FRMT,
DEVMEM_ANNOTATION_MAX_LEN);
/* Set pszAnnotationText to that PMR RI entry */
pszAnnotationText = (IMG_PCHAR) PMR_GetAnnotation(psRIEntry->psPMR);
OSSNPrintf(pszEntryString,
ui16MaxStrLen,
szEntryFormat,
(bDebugFs ? "" : " "),
psRIEntry->pid,
(void*)psRIEntry->psPMR,
pszAnnotationText,
uiLogicalSize,
uiPhysicalSize,
(bDebugFs ? '\n' : ' '));
}
/*!
*******************************************************************************
@Function _DumpList
@Description
Dumps out RI List entries according to parameters passed.
@input psPMR - If not NULL, function will output the RI entries for
the specified PMR only
@input pid - If non-zero, the function will only output MEMDESC RI
entries made by the process with ID pid.
If zero, all MEMDESC RI entries will be output.
@Return PVRSRV_ERROR
******************************************************************************/
static PVRSRV_ERROR _DumpList(PMR *psPMR, IMG_PID pid)
{
RI_LIST_ENTRY *psRIEntry = NULL;
RI_SUBLIST_ENTRY *psRISubEntry = NULL;
IMG_UINT16 ui16SubEntriesParsed = 0;
uintptr_t hashData = 0;
IMG_PID hashKey;
PMR *pPMRHashKey = psPMR;
IMG_BOOL bDisplayedThisPMR = IMG_FALSE;
IMG_UINT64 ui64LogicalSize = 0;
if (!psPMR)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (g_pRIHashTable && g_pProcHashTable)
{
if (pid != 0)
{
/* look-up pid in Hash Table */
hashKey = pid;
hashData = HASH_Retrieve_Extended (g_pProcHashTable, (void *)&hashKey);
if (hashData)
{
psRISubEntry = IMG_CONTAINER_OF((PDLLIST_NODE)hashData, RI_SUBLIST_ENTRY, sProcListNode);
if (psRISubEntry)
{
psRIEntry = psRISubEntry->psRI;
}
}
}
else
{
/* Look-up psPMR in Hash Table */
hashData = HASH_Retrieve_Extended (g_pRIHashTable, (void *)&pPMRHashKey);
psRIEntry = (RI_LIST_ENTRY *)hashData;
}
if (!psRIEntry)
{
/* No entry found in hash table */
return PVRSRV_ERROR_NOT_FOUND;
}
while (psRIEntry)
{
bDisplayedThisPMR = IMG_FALSE;
/* Output details for RI entry */
if (!pid)
{
PMR_LogicalSize(psPMR, (IMG_DEVMEM_SIZE_T*)&ui64LogicalSize);
_RIOutput (("%s <%p> suballocs:%d size:0x%010" IMG_UINT64_FMTSPECx,
PMR_GetAnnotation(psRIEntry->psPMR),
psRIEntry->psPMR,
(IMG_UINT)psRIEntry->ui16SubListCount,
ui64LogicalSize));
bDisplayedThisPMR = IMG_TRUE;
}
ui16SubEntriesParsed = 0;
if (psRIEntry->ui16SubListCount)
{
#if _DUMP_LINKEDLIST_INFO
_RIOutput (("RI LIST: {sSubListFirst.psNextNode:0x%p}\n",
psRIEntry->sSubListFirst.psNextNode));
#endif /* _DUMP_LINKEDLIST_INFO */
if (!pid)
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRIEntry->sSubListFirst)),
RI_SUBLIST_ENTRY, sListNode);
}
/* Traverse RI sublist and output details for each entry */
while (psRISubEntry)
{
if(psRIEntry)
{
if((ui16SubEntriesParsed >= psRIEntry->ui16SubListCount))
{
break;
}
if (!bDisplayedThisPMR)
{
PMR_LogicalSize(psPMR, (IMG_DEVMEM_SIZE_T*)&ui64LogicalSize);
_RIOutput (("%s <%p> suballocs:%d size:0x%010" IMG_UINT64_FMTSPECx,
PMR_GetAnnotation(psRIEntry->psPMR),
psRIEntry->psPMR,
(IMG_UINT)psRIEntry->ui16SubListCount,
ui64LogicalSize));
bDisplayedThisPMR = IMG_TRUE;
}
}
#if _DUMP_LINKEDLIST_INFO
_RIOutput (("RI LIST: [this subentry:0x%p]\n",psRISubEntry));
_RIOutput (("RI LIST: psRI:0x%p\n",psRISubEntry->psRI));
#endif /* _DUMP_LINKEDLIST_INFO */
{
IMG_CHAR szEntryString[RI_MEMDESC_ENTRY_BUF_SIZE];
_GenerateMEMDESCEntryString(psRISubEntry,
IMG_FALSE,
RI_MEMDESC_ENTRY_BUF_SIZE,
szEntryString);
_RIOutput (("%s",szEntryString));
}
if (pid)
{
if ((dllist_get_next_node(&(psRISubEntry->sProcListNode)) == NULL) ||
(dllist_get_next_node(&(psRISubEntry->sProcListNode)) == (PDLLIST_NODE)hashData))
{
psRISubEntry = NULL;
}
else
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRISubEntry->sProcListNode)),
RI_SUBLIST_ENTRY, sProcListNode);
if (psRISubEntry)
{
if (psRIEntry != psRISubEntry->psRI)
{
/*
* The next MEMDESC in the process linked list is in a different PMR
*/
psRIEntry = psRISubEntry->psRI;
bDisplayedThisPMR = IMG_FALSE;
}
}
}
}
else
{
ui16SubEntriesParsed++;
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRISubEntry->sListNode)),
RI_SUBLIST_ENTRY, sListNode);
}
}
}
if (!pid && psRIEntry)
{
if (ui16SubEntriesParsed != psRIEntry->ui16SubListCount)
{
/*
* Output error message as sublist does not contain the
* number of entries indicated by sublist count
*/
_RIOutput (("RI ERROR: RI sublist contains %d entries, not %d entries\n",
ui16SubEntriesParsed,psRIEntry->ui16SubListCount));
}
else if (psRIEntry->ui16SubListCount && !dllist_get_next_node(&(psRIEntry->sSubListFirst)))
{
/*
* Output error message as sublist is empty but sublist count
* is not zero
*/
_RIOutput (("RI ERROR: ui16SubListCount=%d for empty RI sublist\n",
psRIEntry->ui16SubListCount));
}
}
psRIEntry = NULL;
}
}
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIDumpAllKM
@Description
Dumps out the contents of all RI List entries (i.e. for all
MEMDESC allocations for each PMR).
At present, output is directed to Kernel log
via PVR_DPF.
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDumpAllKM(void)
{
if (g_pRIHashTable)
{
return HASH_Iterate(g_pRIHashTable, (HASH_pfnCallback)_DumpAllEntries);
}
return PVRSRV_OK;
}
/*!
*******************************************************************************
@Function RIDumpProcessKM
@Description
Dumps out the contents of all MEMDESC RI List entries (for every
PMR) which have been allocate by the specified process only.
At present, output is directed to Kernel log
via PVR_DPF.
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDumpProcessKM(IMG_PID pid)
{
PVRSRV_ERROR eError;
IMG_UINT32 dummyPMR;
if (!g_pProcHashTable)
{
return PVRSRV_OK;
}
/* Acquire RI lock*/
_RILock();
eError = _DumpList((PMR *)&dummyPMR,pid);
/* Release RI lock*/
_RIUnlock();
return eError;
}
/*!
*******************************************************************************
@Function _TotalAllocsForProcess
@Description
Totals all PMR physical backing for given process.
@input pid - ID of process.
@input ePhysHeapType - type of Physical Heap for which to total allocs
@Return Size of all physical backing for PID's PMRs allocated from the
specified heap type (in bytes).
******************************************************************************/
static IMG_INT32 _TotalAllocsForProcess(IMG_PID pid, PHYS_HEAP_TYPE ePhysHeapType)
{
RI_LIST_ENTRY *psRIEntry = NULL;
RI_SUBLIST_ENTRY *psInitialRISubEntry = NULL;
RI_SUBLIST_ENTRY *psRISubEntry = NULL;
uintptr_t hashData = 0;
IMG_PID hashKey;
IMG_INT32 i32TotalPhysical = 0;
if (g_pRIHashTable && g_pProcHashTable)
{
if (pid == PVR_SYS_ALLOC_PID)
{
IMG_UINT32 ui32ProcessedSysAllocPMRCount = 0;
DLLIST_NODE *psSysAllocNode = NULL;
OSLockAcquire(g_hSysAllocPidListLock);
psSysAllocNode = dllist_get_next_node(&g_sSysAllocPidListHead);
while (psSysAllocNode && psSysAllocNode != &g_sSysAllocPidListHead)
{
psRIEntry = IMG_CONTAINER_OF((PDLLIST_NODE)psSysAllocNode, RI_LIST_ENTRY, sSysAllocListNode);
ui32ProcessedSysAllocPMRCount++;
if (PhysHeapGetType(PMR_PhysHeap(psRIEntry->psPMR)) == ePhysHeapType)
{
IMG_UINT64 ui64PhysicalSize;
PMR_PhysicalSize(psRIEntry->psPMR, (IMG_DEVMEM_SIZE_T*)&ui64PhysicalSize);
if (((IMG_UINT64)i32TotalPhysical + ui64PhysicalSize > 0x7fffffff))
{
PVR_DPF((PVR_DBG_WARNING, "%s: i32TotalPhysical exceeding size for i32",__func__));
}
i32TotalPhysical += (IMG_INT32)(ui64PhysicalSize & 0x00000000ffffffff);
}
psSysAllocNode = dllist_get_next_node(psSysAllocNode);
}
OSLockRelease(g_hSysAllocPidListLock);
}
else
{
if (pid != 0)
{
/* look-up pid in Hash Table */
hashKey = pid;
hashData = HASH_Retrieve_Extended (g_pProcHashTable, (void *)&hashKey);
if (hashData)
{
psInitialRISubEntry = IMG_CONTAINER_OF((PDLLIST_NODE)hashData, RI_SUBLIST_ENTRY, sProcListNode);
psRISubEntry = psInitialRISubEntry;
if (psRISubEntry)
{
psRIEntry = psRISubEntry->psRI;
}
}
}
while (psRISubEntry && psRIEntry)
{
if (!psRISubEntry->bIsImport && !(psRIEntry->ui32RIPMRFlags & RI_FLAG_PMR_PHYS_COUNTED_BY_DEBUGFS) &&
(pid == PVR_SYS_ALLOC_PID || !(psRIEntry->ui32RIPMRFlags & RI_FLAG_SYSALLOC_PMR)) &&
(PhysHeapGetType(PMR_PhysHeap(psRIEntry->psPMR)) == ePhysHeapType))
{
IMG_UINT64 ui64PhysicalSize;
PMR_PhysicalSize(psRIEntry->psPMR, (IMG_DEVMEM_SIZE_T*)&ui64PhysicalSize);
if (((IMG_UINT64)i32TotalPhysical + ui64PhysicalSize > 0x7fffffff))
{
PVR_DPF((PVR_DBG_WARNING, "%s: i32TotalPhysical exceeding size for i32",__func__));
}
i32TotalPhysical += (IMG_INT32)(ui64PhysicalSize & 0x00000000ffffffff);
psRIEntry->ui32RIPMRFlags |= RI_FLAG_PMR_PHYS_COUNTED_BY_DEBUGFS;
}
if ((dllist_get_next_node(&(psRISubEntry->sProcListNode)) == NULL) ||
(dllist_get_next_node(&(psRISubEntry->sProcListNode)) == (PDLLIST_NODE)hashData))
{
psRISubEntry = NULL;
psRIEntry = NULL;
}
else
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRISubEntry->sProcListNode)),
RI_SUBLIST_ENTRY, sProcListNode);
if (psRISubEntry)
{
psRIEntry = psRISubEntry->psRI;
}
}
}
psRISubEntry = psInitialRISubEntry;
if (psRISubEntry)
{
psRIEntry = psRISubEntry->psRI;
}
while (psRISubEntry && psRIEntry)
{
psRIEntry->ui32RIPMRFlags &= ~RI_FLAG_PMR_PHYS_COUNTED_BY_DEBUGFS;
if ((dllist_get_next_node(&(psRISubEntry->sProcListNode)) == NULL) ||
(dllist_get_next_node(&(psRISubEntry->sProcListNode)) == (PDLLIST_NODE)hashData))
{
psRISubEntry = NULL;
psRIEntry = NULL;
}
else
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRISubEntry->sProcListNode)),
RI_SUBLIST_ENTRY, sProcListNode);
if (psRISubEntry)
{
psRIEntry = psRISubEntry->psRI;
}
}
}
}
}
return i32TotalPhysical;
}
/*!
*******************************************************************************
@Function RITotalAllocProcessKM
@Description
Returns the total of allocated GPU memory (backing for PMRs)
which has been allocated from the specific heap by the specified
process only.
@Return Amount of physical backing allocated (in bytes)
******************************************************************************/
IMG_INT32 RITotalAllocProcessKM(IMG_PID pid, PHYS_HEAP_TYPE ePhysHeapType)
{
IMG_INT32 i32BackingTotal = 0;
if (g_pProcHashTable)
{
/* Acquire RI lock*/
_RILock();
i32BackingTotal = _TotalAllocsForProcess(pid, ePhysHeapType);
/* Release RI lock*/
_RIUnlock();
}
return i32BackingTotal;
}
#if defined(DEBUG)
/*!
*******************************************************************************
@Function _DumpProcessList
@Description
Dumps out RI List entries according to parameters passed.
@input psPMR - If not NULL, function will output the RI entries for
the specified PMR only
@input pid - If non-zero, the function will only output MEMDESC RI
entries made by the process with ID pid.
If zero, all MEMDESC RI entries will be output.
@Return PVRSRV_ERROR
******************************************************************************/
static PVRSRV_ERROR _DumpProcessList(PMR *psPMR,
IMG_PID pid,
IMG_UINT64 ui64Offset,
IMG_DEV_VIRTADDR *psDevVAddr)
{
RI_LIST_ENTRY *psRIEntry = NULL;
RI_SUBLIST_ENTRY *psRISubEntry = NULL;
IMG_UINT16 ui16SubEntriesParsed = 0;
uintptr_t hashData = 0;
PMR *pPMRHashKey = psPMR;
psDevVAddr->uiAddr = 0;
if (!psPMR)
{
/* NULL handle provided */
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (g_pRIHashTable && g_pProcHashTable)
{
PVR_ASSERT(psPMR && pid);
/* Look-up psPMR in Hash Table */
hashData = HASH_Retrieve_Extended (g_pRIHashTable, (void *)&pPMRHashKey);
psRIEntry = (RI_LIST_ENTRY *)hashData;
if (!psRIEntry)
{
/* No entry found in hash table */
return PVRSRV_ERROR_NOT_FOUND;
}
if (psRIEntry->ui16SubListCount)
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRIEntry->sSubListFirst)),
RI_SUBLIST_ENTRY, sListNode);
/* Traverse RI sublist and output details for each entry */
while (psRISubEntry && (ui16SubEntriesParsed < psRIEntry->ui16SubListCount))
{
if (pid == psRISubEntry->pid)
{
IMG_UINT64 ui64StartOffset = psRISubEntry->ui64Offset;
IMG_UINT64 ui64EndOffset = psRISubEntry->ui64Offset + psRISubEntry->ui64Size;
if (ui64Offset >= ui64StartOffset && ui64Offset < ui64EndOffset)
{
psDevVAddr->uiAddr = psRISubEntry->sVAddr.uiAddr;
return PVRSRV_OK;
}
}
ui16SubEntriesParsed++;
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRISubEntry->sListNode)),
RI_SUBLIST_ENTRY, sListNode);
}
}
}
return PVRSRV_ERROR_INVALID_PARAMS;
}
/*!
*******************************************************************************
@Function RIDumpProcessListKM
@Description
Dumps out selected contents of all MEMDESC RI List entries (for a
PMR) which have been allocate by the specified process only.
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR RIDumpProcessListKM(PMR *psPMR,
IMG_PID pid,
IMG_UINT64 ui64Offset,
IMG_DEV_VIRTADDR *psDevVAddr)
{
PVRSRV_ERROR eError;
if (!g_pProcHashTable)
{
return PVRSRV_OK;
}
/* Acquire RI lock*/
_RILock();
eError = _DumpProcessList(psPMR,
pid,
ui64Offset,
psDevVAddr);
/* Release RI lock*/
_RIUnlock();
return eError;
}
#endif
static PVRSRV_ERROR _DumpAllEntries (uintptr_t k, uintptr_t v)
{
RI_LIST_ENTRY *psRIEntry = (RI_LIST_ENTRY *)v;
PVR_UNREFERENCED_PARAMETER (k);
return RIDumpListKM(psRIEntry->psPMR);
}
static PVRSRV_ERROR _DeleteAllEntries (uintptr_t k, uintptr_t v)
{
RI_LIST_ENTRY *psRIEntry = (RI_LIST_ENTRY *)v;
RI_SUBLIST_ENTRY *psRISubEntry;
PVRSRV_ERROR eResult = PVRSRV_OK;
PVR_UNREFERENCED_PARAMETER (k);
while ((eResult == PVRSRV_OK) && (psRIEntry->ui16SubListCount > 0))
{
psRISubEntry = IMG_CONTAINER_OF(dllist_get_next_node(&(psRIEntry->sSubListFirst)), RI_SUBLIST_ENTRY, sListNode);
eResult = RIDeleteMEMDESCEntryKM((RI_HANDLE)psRISubEntry);
}
if (eResult == PVRSRV_OK)
{
eResult = RIDeletePMREntryKM((RI_HANDLE)psRIEntry);
/*
* If we've deleted the Hash table, return
* an error to stop the iterator...
*/
if (!g_pRIHashTable)
{
eResult = PVRSRV_ERROR_RESOURCE_UNAVAILABLE;
}
}
return eResult;
}
static PVRSRV_ERROR _DeleteAllProcEntries (uintptr_t k, uintptr_t v)
{
RI_SUBLIST_ENTRY *psRISubEntry = (RI_SUBLIST_ENTRY *)v;
PVRSRV_ERROR eResult;
PVR_UNREFERENCED_PARAMETER (k);
eResult = RIDeleteMEMDESCEntryKM((RI_HANDLE) psRISubEntry);
if (eResult == PVRSRV_OK && !g_pProcHashTable)
{
/*
* If we've deleted the Hash table, return
* an error to stop the iterator...
*/
eResult = PVRSRV_ERROR_RESOURCE_UNAVAILABLE;
}
return eResult;
}
#endif /* if defined(PVRSRV_ENABLE_GPU_MEMORY_INFO) */