blob: dc88f95e2d68e03a7059a65738a4ca554e8503ce [file] [log] [blame]
/*************************************************************************/ /*!
@File
@Title Services synchronisation checkpoint interface
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@Description Implements server side code for services synchronisation
interface
@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 "img_types.h"
#include "allocmem.h"
#include "devicemem.h"
#include "devicemem_pdump.h"
#include "pvr_debug.h"
#include "pvr_notifier.h"
#include "osfunc.h"
#include "dllist.h"
#include "sync.h"
#include "sync_checkpoint_external.h"
#include "sync_checkpoint.h"
#include "sync_checkpoint_internal.h"
#include "lock.h"
#include "log2.h"
#include "pvrsrv.h"
#include "pdump_km.h"
#include "pvrsrv_sync_km.h"
#define SYNC_CHECKPOINT_BLOCK_LIST_CHUNK_SIZE 10
#define LOCAL_SYNC_CHECKPOINT_RESET_VALUE PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED
/*
This defines the maximum amount of synchronisation memory
that can be allocated per sync checkpoint context.
In reality this number is meaningless as we would run out
of synchronisation memory before we reach this limit, but
we need to provide a size to the span RA.
*/
#define MAX_SYNC_CHECKPOINT_MEM (4 * 1024 * 1024)
/* definitions for functions to be implemented by OS-specific sync - the OS-specific sync code
will call x when initialised, in order to register functions we can then call */
typedef PVRSRV_ERROR (*PFN_SYNC_CHECKPOINT_FENCE_RESOLVE_FN)(PVRSRV_FENCE_KM fence, IMG_UINT32 *nr_checkpoints, PSYNC_CHECKPOINT *checkpoint_handles);
typedef PVRSRV_ERROR (*PFN_SYNC_CHECKPOINT_FENCE_CREATE_FN)(const IMG_CHAR *fence_name, PVRSRV_TIMELINE_KM timeline, PVRSRV_FENCE_KM *new_fence, PSYNC_CHECKPOINT *new_checkpoint_handle);
typedef struct _SYNC_CHECKPOINT_BLOCK_LIST_
{
IMG_UINT32 ui32BlockCount; /*!< Number of contexts in the list */
IMG_UINT32 ui32BlockListSize; /*!< Size of the array contexts */
SYNC_CHECKPOINT_BLOCK **papsSyncCheckpointBlock; /*!< Array of sync checkpoint blocks */
} SYNC_CHECKPOINT_BLOCK_LIST;
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
#define DECREMENT_WITH_WRAP(value, sz) ((value) ? ((value) - 1) : ((sz) - 1))
struct SYNC_CHECKPOINT_RECORD
{
SYNC_CHECKPOINT_BLOCK *psSyncCheckpointBlock; /*!< handle to SYNC_CHECKPOINT_BLOCK */
IMG_UINT32 ui32SyncOffset; /*!< offset to sync in block */
IMG_UINT32 ui32FwBlockAddr;
IMG_PID uiPID;
IMG_UINT64 ui64OSTime;
DLLIST_NODE sNode;
IMG_CHAR szClassName[SYNC_MAX_CLASS_NAME_LEN];
};
#endif /* defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) */
static PFN_SYNC_CHECKPOINT_FENCE_RESOLVE_FN g_pfnFenceResolve = NULL;
static PFN_SYNC_CHECKPOINT_FENCE_CREATE_FN g_pfnFenceCreate = NULL;
PVRSRV_ERROR
SyncCheckpointRecordAdd(PSYNC_CHECKPOINT_RECORD_HANDLE *phRecord,
SYNC_CHECKPOINT_BLOCK *hSyncCheckpointBlock,
IMG_UINT32 ui32FwBlockAddr,
IMG_UINT32 ui32SyncOffset,
IMG_UINT32 ui32ClassNameSize,
const IMG_CHAR *pszClassName);
PVRSRV_ERROR
SyncCheckpointRecordRemove(PSYNC_CHECKPOINT_RECORD_HANDLE hRecord);
static void _SyncCheckpointState(PDLLIST_NODE psNode,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile);
static void _SyncCheckpointDebugRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle,
IMG_UINT32 ui32VerbLevel,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile);
static PVRSRV_ERROR _SyncCheckpointRecordListInit(_SYNC_CHECKPOINT_CONTEXT *psContext);
static void _SyncCheckpointRecordListDeinit(_SYNC_CHECKPOINT_CONTEXT *psContext);
PVRSRV_ERROR SyncCheckpointSignalPDump(_SYNC_CHECKPOINT *psSyncCheckpoint);
PVRSRV_ERROR SyncCheckpointErrorPDump(_SYNC_CHECKPOINT *psSyncCheckpoint);
PVRSRV_ERROR SyncCheckpointRegisterFunctions(PFN_SYNC_CHECKPOINT_FENCE_RESOLVE_FN pfnFenceResolve,
PFN_SYNC_CHECKPOINT_FENCE_CREATE_FN pfnFenceCreate);
/* Unique incremental ID assigned to sync checkpoints when allocated */
static IMG_UINT32 g_SyncCheckpointUID = 0;
/*
Internal interfaces for management of _SYNC_CHECKPOINT_CONTEXT
*/
static void
_SyncCheckpointContextUnref(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
if (!OSAtomicRead(&psContext->hRefCount))
{
PVR_LOG_ERROR(PVRSRV_ERROR_INVALID_CONTEXT, "_SyncCheckpointContextUnref context already freed");
}
else if (0 == OSAtomicDecrement(&psContext->hRefCount))
{
/* SyncCheckpointContextDestroy only when no longer referenced */
_SyncCheckpointRecordListDeinit(psContext);
PVRSRVUnregisterDbgRequestNotify(psContext->hCheckpointNotify);
OSLockDestroy(psContext->hCheckpointListLock);
RA_Delete(psContext->psSpanRA);
RA_Delete(psContext->psSubAllocRA);
OSFreeMem(psContext);
}
}
static void
_SyncCheckpointContextRef(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
if (!OSAtomicRead(&psContext->hRefCount))
{
PVR_LOG_ERROR(PVRSRV_ERROR_INVALID_CONTEXT, "_SyncCheckpointContextRef context use after free");
}
else
{
OSAtomicIncrement(&psContext->hRefCount);
}
}
/*
Internal interfaces for management of synchronisation block memory
*/
static PVRSRV_ERROR
_AllocSyncCheckpointBlock(_SYNC_CHECKPOINT_CONTEXT *psContext,
SYNC_CHECKPOINT_BLOCK **ppsSyncBlock)
{
PVRSRV_DEVICE_NODE *psDevNode;
SYNC_CHECKPOINT_BLOCK *psSyncBlk;
PVRSRV_ERROR eError;
psSyncBlk = OSAllocMem(sizeof(SYNC_CHECKPOINT_BLOCK));
if (psSyncBlk == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
PVR_LOG_ERROR(eError, "OSAllocMem");
goto fail_alloc;
}
psSyncBlk->psContext = psContext;
/* Allocate sync checkpoint block */
psDevNode = psContext->psDevNode;
if (!psDevNode)
{
eError = PVRSRV_ERROR_INVALID_PARAMS;
PVR_LOG_ERROR(eError, "context device node invalid");
goto fail_alloc_ufo_block;
}
psSyncBlk->psDevNode = psDevNode;
eError = psDevNode->pfnAllocUFOBlock(psDevNode,
&psSyncBlk->hMemDesc,
&psSyncBlk->ui32FirmwareAddr,
&psSyncBlk->ui32SyncBlockSize);
if (eError != PVRSRV_OK)
{
PVR_LOG_ERROR(eError, "failed to allocate ufo block");
goto fail_alloc_ufo_block;
}
eError = DevmemAcquireCpuVirtAddr(psSyncBlk->hMemDesc,
(void **) &psSyncBlk->pui32LinAddr);
if (eError != PVRSRV_OK)
{
PVR_LOG_ERROR(eError, "DevmemAcquireCpuVirtAddr");
goto fail_devmem_acquire;
}
OSAtomicWrite(&psSyncBlk->hRefCount, 1);
PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
"Allocated Sync Checkpoint UFO block (FirmwareVAddr = 0x%08x)",
psSyncBlk->ui32FirmwareAddr);
*ppsSyncBlock = psSyncBlk;
return PVRSRV_OK;
fail_devmem_acquire:
psDevNode->pfnFreeUFOBlock(psDevNode, psSyncBlk->hMemDesc);
fail_alloc_ufo_block:
OSFreeMem(psSyncBlk);
fail_alloc:
return eError;
}
static void
_FreeSyncCheckpointBlock(SYNC_CHECKPOINT_BLOCK *psSyncBlk)
{
if (0 == OSAtomicDecrement(&psSyncBlk->hRefCount))
{
PVRSRV_DEVICE_NODE *psDevNode = psSyncBlk->psDevNode;
DevmemReleaseCpuVirtAddr(psSyncBlk->hMemDesc);
psDevNode->pfnFreeUFOBlock(psDevNode, psSyncBlk->hMemDesc);
OSFreeMem(psSyncBlk);
}
}
static PVRSRV_ERROR
_SyncCheckpointBlockImport(RA_PERARENA_HANDLE hArena,
RA_LENGTH_T uSize,
RA_FLAGS_T uFlags,
const IMG_CHAR *pszAnnotation,
RA_BASE_T *puiBase,
RA_LENGTH_T *puiActualSize,
RA_PERISPAN_HANDLE *phImport)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = hArena;
SYNC_CHECKPOINT_BLOCK *psSyncBlock = NULL;
RA_LENGTH_T uiSpanSize;
PVRSRV_ERROR eError;
PVR_UNREFERENCED_PARAMETER(uFlags);
PVR_LOG_IF_FALSE((hArena != NULL), "hArena is NULL");
/* Check we've not be called with an unexpected size */
PVR_LOG_IF_FALSE((uSize == sizeof(_SYNC_CHECKPOINT_FW_OBJ)), "uiSize is not the size of _SYNC_CHECKPOINT_FW_OBJ");
/*
Ensure the sync checkpoint context doesn't go away while we have sync blocks
attached to it
*/
_SyncCheckpointContextRef(psContext);
/* Allocate the block of memory */
eError = _AllocSyncCheckpointBlock(psContext, &psSyncBlock);
if (eError != PVRSRV_OK)
{
goto fail_syncblockalloc;
}
/* Allocate a span for it */
eError = RA_Alloc(psContext->psSpanRA,
psSyncBlock->ui32SyncBlockSize,
RA_NO_IMPORT_MULTIPLIER,
0,
psSyncBlock->ui32SyncBlockSize,
pszAnnotation,
&psSyncBlock->uiSpanBase,
&uiSpanSize,
NULL);
if (eError != PVRSRV_OK)
{
goto fail_spanalloc;
}
/*
There is no reason the span RA should return an allocation larger
then we request
*/
PVR_LOG_IF_FALSE((uiSpanSize == psSyncBlock->ui32SyncBlockSize), "uiSpanSize invalid");
*puiBase = psSyncBlock->uiSpanBase;
*puiActualSize = psSyncBlock->ui32SyncBlockSize;
*phImport = psSyncBlock;
return PVRSRV_OK;
fail_spanalloc:
_FreeSyncCheckpointBlock(psSyncBlock);
fail_syncblockalloc:
_SyncCheckpointContextUnref(psContext);
return eError;
}
static void
_SyncCheckpointBlockUnimport(RA_PERARENA_HANDLE hArena,
RA_BASE_T uiBase,
RA_PERISPAN_HANDLE hImport)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = hArena;
SYNC_CHECKPOINT_BLOCK *psSyncBlock = hImport;
PVR_LOG_IF_FALSE((psContext != NULL), "hArena invalid");
PVR_LOG_IF_FALSE((psSyncBlock != NULL), "hImport invalid");
PVR_LOG_IF_FALSE((uiBase == psSyncBlock->uiSpanBase), "uiBase invalid");
/* Free the span this import is using */
RA_Free(psContext->psSpanRA, uiBase);
/* Free the sync checkpoint block */
_FreeSyncCheckpointBlock(psSyncBlock);
/* Drop our reference to the sync checkpoint context */
_SyncCheckpointContextUnref(psContext);
}
static INLINE IMG_UINT32 _SyncCheckpointGetOffset(_SYNC_CHECKPOINT *psSyncInt)
{
IMG_UINT64 ui64Temp;
ui64Temp = psSyncInt->uiSpanAddr - psSyncInt->psSyncCheckpointBlock->uiSpanBase;
PVR_ASSERT(ui64Temp<IMG_UINT32_MAX);
return (IMG_UINT32)ui64Temp;
}
/* Used by SyncCheckpointContextCreate() below */
static INLINE IMG_UINT32 _Log2(IMG_UINT32 ui32Align)
{
PVR_ASSERT(IsPower2(ui32Align));
return ExactLog2(ui32Align);
}
/*
External interfaces
*/
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointRegisterFunctions(PFN_SYNC_CHECKPOINT_FENCE_RESOLVE_FN pfnFenceResolve, PFN_SYNC_CHECKPOINT_FENCE_CREATE_FN pfnFenceCreate)
{
PVRSRV_ERROR eError = PVRSRV_OK;
g_pfnFenceResolve = pfnFenceResolve;
g_pfnFenceCreate = pfnFenceCreate;
return eError;
}
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointResolveFence(PVRSRV_FENCE_KM hFence, IMG_UINT32 *pui32NumSyncCheckpoints, PSYNC_CHECKPOINT *psSyncCheckpoints)
{
PVRSRV_ERROR eError = PVRSRV_OK;
if (!g_pfnFenceResolve)
{
PVR_DPF((PVR_DBG_ERROR, "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", __FUNCTION__));
PVR_LOG_ERROR(eError, "g_pfnFenceResolve is NULL");
eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED;
}
else
{
eError = g_pfnFenceResolve(hFence, pui32NumSyncCheckpoints, psSyncCheckpoints);
}
return eError;
}
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointCreateFence(const IMG_CHAR *pszFenceName, PVRSRV_TIMELINE_KM hTimeline, PVRSRV_FENCE_KM *phNewFence, PSYNC_CHECKPOINT *psNewSyncCheckpoint)
{
PVRSRV_ERROR eError = PVRSRV_OK;
if (!g_pfnFenceCreate)
{
PVR_DPF((PVR_DBG_ERROR, "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", __FUNCTION__));
PVR_LOG_ERROR(eError, "g_pfnFenceCreate is NULL");
eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED;
}
else
{
eError = g_pfnFenceCreate(pszFenceName, hTimeline, phNewFence, psNewSyncCheckpoint);
}
return eError;
}
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointContextCreate(PVRSRV_DEVICE_NODE *psDevNode,
PSYNC_CHECKPOINT_CONTEXT *ppsSyncCheckpointContext)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = NULL;
PVRSRV_ERROR eError;
PVR_LOGR_IF_FALSE((ppsSyncCheckpointContext != NULL), "ppsSyncCheckpointContext invalid", PVRSRV_ERROR_INVALID_PARAMS);
psContext = OSAllocZMem(sizeof(_SYNC_CHECKPOINT_CONTEXT));
if (psContext == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_alloc;
}
psContext->psDevNode = psDevNode;
OSSNPrintf(psContext->azName, SYNC_CHECKPOINT_NAME_SIZE, "Sync Prim RA-%p", psContext);
OSSNPrintf(psContext->azSpanName, SYNC_CHECKPOINT_NAME_SIZE, "Sync Prim span RA-%p", psContext);
/*
Create the RA for sub-allocations of the sync checkpoints
Note:
The import size doesn't matter here as the server will pass
back the blocksize when it does the import which overrides
what we specify here.
*/
psContext->psSubAllocRA = RA_Create(psContext->azName,
/* Params for imports */
_Log2(sizeof(IMG_UINT32)),
RA_LOCKCLASS_2,
_SyncCheckpointBlockImport,
_SyncCheckpointBlockUnimport,
psContext,
IMG_FALSE);
if (psContext->psSubAllocRA == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_suballoc;
}
/*
Create the span-management RA
The RA requires that we work with linear spans. For our use
here we don't require this behaviour as we're always working
within offsets of blocks (imports). However, we need to keep
the RA happy so we create the "span" management RA which
ensures that all are imports are added to the RA in a linear
fashion
*/
psContext->psSpanRA = RA_Create(psContext->azSpanName,
/* Params for imports */
0,
RA_LOCKCLASS_1,
NULL,
NULL,
NULL,
IMG_FALSE);
if (psContext->psSpanRA == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_span;
}
if (!RA_Add(psContext->psSpanRA, 0, MAX_SYNC_CHECKPOINT_MEM, 0, NULL))
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_span_add;
}
OSAtomicWrite(&psContext->hRefCount, 1);
OSAtomicWrite(&psContext->hCheckpointCount, 0);
eError = OSLockCreate(&psContext->hCheckpointListLock, LOCK_TYPE_NONE);
if (eError != PVRSRV_OK)
{
goto fail_span;
}
dllist_init(&psContext->sCheckpointList);
eError = PVRSRVRegisterDbgRequestNotify(&psContext->hCheckpointNotify,
psDevNode,
_SyncCheckpointDebugRequest,
DEBUG_REQUEST_SYNCCHECKPOINT,
psContext);
if (eError != PVRSRV_OK)
{
goto fail_register_dbg_request;
}
eError = _SyncCheckpointRecordListInit(psContext);
if (eError != PVRSRV_OK)
{
goto fail_record_list_init;
}
*ppsSyncCheckpointContext = (PSYNC_CHECKPOINT_CONTEXT)psContext;
return PVRSRV_OK;
fail_record_list_init:
PVRSRVUnregisterDbgRequestNotify(psContext->hCheckpointNotify);
fail_register_dbg_request:
OSLockDestroy(psContext->hCheckpointListLock);
fail_span_add:
RA_Delete(psContext->psSpanRA);
fail_span:
RA_Delete(psContext->psSubAllocRA);
fail_suballoc:
OSFreeMem(psContext);
fail_alloc:
return eError;
}
IMG_INTERNAL PVRSRV_ERROR SyncCheckpointContextDestroy(PSYNC_CHECKPOINT_CONTEXT psSyncCheckpointContext)
{
PVRSRV_ERROR eError = PVRSRV_OK;
_SYNC_CHECKPOINT_CONTEXT *psContext = (_SYNC_CHECKPOINT_CONTEXT*)psSyncCheckpointContext;
IMG_INT iRf = 0;
PVR_LOG_IF_FALSE((psSyncCheckpointContext != NULL), "psSyncCheckpointContext invalid");
iRf = OSAtomicRead(&psContext->hCheckpointCount);
if (iRf != 0)
{
PVR_DPF((PVR_DBG_ERROR, "%s <%p> attempted with active references (iRf=%d), may be the result of a race", __FUNCTION__, (void*)psContext, iRf));
eError = PVRSRV_ERROR_UNABLE_TO_DESTROY_CONTEXT;
}
else
{
IMG_INT iRf2 = 0;
iRf2 = OSAtomicRead(&psContext->hRefCount);
_SyncCheckpointContextUnref(psContext);
}
return eError;
}
IMG_INTERNAL
PVRSRV_ERROR
SyncCheckpointAlloc(PSYNC_CHECKPOINT_CONTEXT psSyncContext,
const IMG_CHAR *pszCheckpointName,
PSYNC_CHECKPOINT *ppsSyncCheckpoint)
{
_SYNC_CHECKPOINT *psNewSyncCheckpoint = NULL;
_SYNC_CHECKPOINT_CONTEXT *psSyncContextInt = (_SYNC_CHECKPOINT_CONTEXT*)psSyncContext;
PVRSRV_ERROR eError;
PVR_LOGR_IF_FALSE((psSyncContext != NULL), "psSyncContext invalid", PVRSRV_ERROR_INVALID_PARAMS);
PVR_LOGR_IF_FALSE((ppsSyncCheckpoint != NULL), "ppsSyncCheckpoint invalid", PVRSRV_ERROR_INVALID_PARAMS);
psNewSyncCheckpoint = OSAllocMem(sizeof(*psNewSyncCheckpoint));
if (psNewSyncCheckpoint == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
PVR_LOG_ERROR(eError, "OSAllocMem");
goto fail_alloc;
}
eError = RA_Alloc(psSyncContextInt->psSubAllocRA,
sizeof(_SYNC_CHECKPOINT_FW_OBJ),
RA_NO_IMPORT_MULTIPLIER,
0,
sizeof(IMG_UINT32),
(IMG_CHAR*)pszCheckpointName,
&psNewSyncCheckpoint->uiSpanAddr,
NULL,
(RA_PERISPAN_HANDLE *) &psNewSyncCheckpoint->psSyncCheckpointBlock);
if (PVRSRV_OK != eError)
{
PVR_LOG_ERROR(eError, "RA_Alloc");
goto fail_raalloc;
}
psNewSyncCheckpoint->psSyncCheckpointFwObj = (volatile _SYNC_CHECKPOINT_FW_OBJ*)(psNewSyncCheckpoint->psSyncCheckpointBlock->pui32LinAddr +
(_SyncCheckpointGetOffset(psNewSyncCheckpoint)/sizeof(IMG_UINT32)));
/* the allocation of the backing memory for the sync prim block
* is done with ZERO_ON_ALLOC so the memory is initially all zero.
* States are also reset to unsignalled on free, so no need to set here
*/
OSAtomicWrite(&psNewSyncCheckpoint->hRefCount, 1);
OSAtomicWrite(&psNewSyncCheckpoint->hEnqueuedCCBCount, 0);
if(pszCheckpointName)
{
/* Copy over the checkpoint name annotation */
OSStringNCopy(psNewSyncCheckpoint->azName, pszCheckpointName, SYNC_CHECKPOINT_NAME_SIZE);
psNewSyncCheckpoint->azName[SYNC_CHECKPOINT_NAME_SIZE-1] = 0;
}
else
{
/* No sync checkpoint name annotation */
psNewSyncCheckpoint->azName[0] = '\0';
}
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
{
IMG_CHAR szChkptName[SYNC_CHECKPOINT_MAX_CLASS_NAME_LEN];
if(pszCheckpointName)
{
/* Copy the checkpoint name annotation into a fixed-size array */
OSStringNCopy(szChkptName, pszCheckpointName, SYNC_CHECKPOINT_MAX_CLASS_NAME_LEN - 1);
szChkptName[SYNC_MAX_CLASS_NAME_LEN - 1] = 0;
}
else
{
/* No checkpoint name annotation */
szChkptName[0] = 0;
}
/* record this sync */
eError = SyncCheckpointRecordAdd(&psNewSyncCheckpoint->hRecord,
psNewSyncCheckpoint->psSyncCheckpointBlock,
psNewSyncCheckpoint->psSyncCheckpointBlock->ui32FirmwareAddr,
_SyncCheckpointGetOffset(psNewSyncCheckpoint),
OSStringNLength(szChkptName, SYNC_CHECKPOINT_MAX_CLASS_NAME_LEN),
szChkptName);
if (eError != PVRSRV_OK)
{
PVR_LOG_ERROR(eError, "SyncCheckpointRecordAdd");
}
}
#else
PVR_UNREFERENCED_PARAMETER(pszCheckpointName);
#endif /* if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) */
OSAtomicIncrement(&psNewSyncCheckpoint->psSyncCheckpointBlock->psContext->hCheckpointCount);
/* Assign unique ID to this sync checkpoint */
psNewSyncCheckpoint->ui32UID = g_SyncCheckpointUID++;
/* Add the sync checkpoint to the context list */
OSLockAcquire(psSyncContextInt->hCheckpointListLock);
dllist_add_to_head(&psSyncContextInt->sCheckpointList,
&psNewSyncCheckpoint->sListNode);
OSLockRelease(psSyncContextInt->hCheckpointListLock);
*ppsSyncCheckpoint = (PSYNC_CHECKPOINT)psNewSyncCheckpoint;
return PVRSRV_OK;
fail_raalloc:
OSFreeMem(psNewSyncCheckpoint);
fail_alloc:
return eError;
}
IMG_INTERNAL void SyncCheckpointFree(PSYNC_CHECKPOINT psSyncCheckpoint)
{
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
_SYNC_CHECKPOINT_CONTEXT *psContext = psSyncCheckpointInt->psSyncCheckpointBlock->psContext;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if (!OSAtomicRead(&psSyncCheckpointInt->hRefCount))
{
PVR_DPF((PVR_DBG_ERROR, "SyncCheckpointUnref sync checkpoint already freed"));
}
else if (0 == OSAtomicDecrement(&psSyncCheckpointInt->hRefCount))
{
/* If the firmware has serviced all enqueued references to the sync checkpoint, free it */
if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount == (IMG_UINT32)(OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount)))
{
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
{
PVRSRV_ERROR eError;
/* remove this sync record */
eError = SyncCheckpointRecordRemove(psSyncCheckpointInt->hRecord);
PVR_LOG_IF_ERROR(eError, "SyncCheckpointRecordRemove");
}
#endif
/* Remove the sync checkpoint from the global list */
OSLockAcquire(psContext->hCheckpointListLock);
dllist_remove_node(&psSyncCheckpointInt->sListNode);
OSLockRelease(psContext->hCheckpointListLock);
OSAtomicDecrement(&psSyncCheckpointInt->psSyncCheckpointBlock->psContext->hCheckpointCount);
RA_Free(psSyncCheckpointInt->psSyncCheckpointBlock->psContext->psSubAllocRA, psSyncCheckpointInt->uiSpanAddr);
}
}
}
IMG_INTERNAL void
SyncCheckpointSignal(PSYNC_CHECKPOINT psSyncCheckpoint)
{
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if(psSyncCheckpointInt)
{
PVR_LOG_IF_FALSE((psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED), "psSyncCheckpoint already signalled");
if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED)
{
psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_SIGNALLED;
#if defined(PDUMP)
PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
"Signalled Sync Checkpoint (FirmwareVAddr = 0x%08x)",
(psSyncCheckpointInt->psSyncCheckpointBlock->ui32FirmwareAddr + _SyncCheckpointGetOffset(psSyncCheckpointInt)));
SyncCheckpointSignalPDump(psSyncCheckpointInt);
#endif
}
}
}
IMG_INTERNAL void
SyncCheckpointError(PSYNC_CHECKPOINT psSyncCheckpoint)
{
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if(psSyncCheckpointInt)
{
PVR_LOG_IF_FALSE((psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED), "psSyncCheckpoint already signalled");
if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED)
{
psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_ERRORED;
#if defined(PDUMP)
PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
"Errored Sync Checkpoint (FirmwareVAddr = 0x%08x)",
(psSyncCheckpointInt->psSyncCheckpointBlock->ui32FirmwareAddr + _SyncCheckpointGetOffset(psSyncCheckpointInt)));
SyncCheckpointErrorPDump(psSyncCheckpointInt);
#endif
}
}
}
IMG_BOOL SyncCheckpointIsSignalled(PSYNC_CHECKPOINT psSyncCheckpoint)
{
IMG_BOOL bRet = IMG_FALSE;
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if (psSyncCheckpointInt)
{
bRet = ((psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) ||
(psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ERRORED));
}
return bRet;
}
IMG_INTERNAL IMG_BOOL
SyncCheckpointIsErrored(PSYNC_CHECKPOINT psSyncCheckpoint)
{
IMG_BOOL bRet = IMG_FALSE;
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if (psSyncCheckpointInt)
{
bRet = (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ERRORED);
}
return bRet;
}
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointTakeRef(PSYNC_CHECKPOINT psSyncCheckpoint)
{
PVRSRV_ERROR eRet = PVRSRV_OK;
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOGR_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", PVRSRV_ERROR_INVALID_PARAMS);
OSAtomicIncrement(&psSyncCheckpointInt->hRefCount);
return eRet;
}
IMG_INTERNAL PVRSRV_ERROR
SyncCheckpointDropRef(PSYNC_CHECKPOINT psSyncCheckpoint)
{
PVRSRV_ERROR eRet = PVRSRV_OK;
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOGR_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", PVRSRV_ERROR_INVALID_PARAMS);
OSAtomicDecrement(&psSyncCheckpointInt->hRefCount);
return eRet;
}
IMG_INTERNAL void
SyncCheckpointCCBEnqueued(PSYNC_CHECKPOINT psSyncCheckpoint)
{
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid");
if (psSyncCheckpointInt)
{
OSAtomicIncrement(&psSyncCheckpointInt->hEnqueuedCCBCount);
}
}
IMG_INTERNAL IMG_UINT32
SyncCheckpointGetFirmwareAddr(PSYNC_CHECKPOINT psSyncCheckpoint)
{
_SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint;
SYNC_CHECKPOINT_BLOCK *psSyncBlock;
PVR_LOGG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", invalid_chkpt);
psSyncBlock = psSyncCheckpointInt->psSyncCheckpointBlock;
/* add 1 to addr to indicate this FW addr is a sync checkpoint (not a sync prim) */
return psSyncBlock->ui32FirmwareAddr + _SyncCheckpointGetOffset(psSyncCheckpointInt) + 1;
invalid_chkpt:
return 0;
}
void SyncCheckpointErrorFromUFO(PSYNC_CHECKPOINT_CONTEXT psSyncContext,
IMG_UINT32 ui32FwAddr)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = (_SYNC_CHECKPOINT_CONTEXT *)psSyncContext;
_SYNC_CHECKPOINT *psSyncCheckpointInt;
IMG_BOOL bFound = IMG_FALSE;
PDLLIST_NODE psNode;
PVR_DPF((PVR_DBG_ERROR, "%s: Entry (ui32FWAddr=%d) >",__FUNCTION__, ui32FwAddr));
OSLockAcquire(psContext->hCheckpointListLock);
psNode = dllist_get_next_node(&psContext->sCheckpointList);
while ((psNode != NULL) && !bFound)
{
psSyncCheckpointInt = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode);
if (ui32FwAddr == SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt))
{
bFound = IMG_TRUE;
/* Mark as errored */
SyncCheckpointError((PSYNC_CHECKPOINT)psSyncCheckpointInt);
}
psNode = dllist_get_next_node(psNode);
}
OSLockRelease(psContext->hCheckpointListLock);
PVR_DPF((PVR_DBG_ERROR, "%s: Exit <",__FUNCTION__));
}
static void _SyncCheckpointState(PDLLIST_NODE psNode,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile)
{
_SYNC_CHECKPOINT *psSyncCheckpoint = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode);
if (psSyncCheckpoint->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_NOT_SIGNALLED)
{
PVR_DUMPDEBUG_LOG("\tPending sync checkpoint(ID = %d, FWAddr = 0x%08x): (%s)",
psSyncCheckpoint->ui32UID,
psSyncCheckpoint->psSyncCheckpointBlock->ui32FirmwareAddr + _SyncCheckpointGetOffset(psSyncCheckpoint),
psSyncCheckpoint->azName);
}
}
static void _SyncCheckpointDebugRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle,
IMG_UINT32 ui32VerbLevel,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = (_SYNC_CHECKPOINT_CONTEXT *)hDebugRequestHandle;
DLLIST_NODE *psNode, *psNext;
if (ui32VerbLevel == DEBUG_REQUEST_VERBOSITY_HIGH)
{
PVR_DUMPDEBUG_LOG("Dumping all pending sync checkpoints");
OSLockAcquire(psContext->hCheckpointListLock);
dllist_foreach_node(&psContext->sCheckpointList, psNode, psNext)
{
_SyncCheckpointState(psNode, pfnDumpDebugPrintf, pvDumpDebugFile);
}
OSLockRelease(psContext->hCheckpointListLock);
}
}
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
PVRSRV_ERROR
SyncCheckpointRecordAdd(
PSYNC_CHECKPOINT_RECORD_HANDLE * phRecord,
SYNC_CHECKPOINT_BLOCK * hSyncCheckpointBlock,
IMG_UINT32 ui32FwBlockAddr,
IMG_UINT32 ui32SyncOffset,
IMG_UINT32 ui32ClassNameSize,
const IMG_CHAR *pszClassName)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = hSyncCheckpointBlock->psContext;
struct SYNC_CHECKPOINT_RECORD * psSyncRec;
PVRSRV_ERROR eError = PVRSRV_OK;
if (!phRecord)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
*phRecord = NULL;
psSyncRec = OSAllocMem(sizeof(*psSyncRec));
if (!psSyncRec)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_alloc;
}
psSyncRec->psSyncCheckpointBlock = hSyncCheckpointBlock;
psSyncRec->ui32SyncOffset = ui32SyncOffset;
psSyncRec->ui32FwBlockAddr = ui32FwBlockAddr;
psSyncRec->ui64OSTime = OSClockns64();
psSyncRec->uiPID = OSGetCurrentProcessID();
if(pszClassName)
{
if (ui32ClassNameSize >= SYNC_MAX_CLASS_NAME_LEN)
ui32ClassNameSize = SYNC_MAX_CLASS_NAME_LEN - 1;
/* Copy over the class name annotation */
OSStringNCopy(psSyncRec->szClassName, pszClassName, ui32ClassNameSize);
psSyncRec->szClassName[ui32ClassNameSize] = 0;
}
else
{
/* No class name annotation */
psSyncRec->szClassName[0] = 0;
}
OSLockAcquire(psContext->hCheckpointRecordLock);
dllist_add_to_head(&psContext->sCheckpointRecordList, &psSyncRec->sNode);
OSLockRelease(psContext->hCheckpointRecordLock);
*phRecord = (PSYNC_CHECKPOINT_RECORD_HANDLE)psSyncRec;
fail_alloc:
return eError;
}
PVRSRV_ERROR
SyncCheckpointRecordRemove(PSYNC_CHECKPOINT_RECORD_HANDLE hRecord)
{
struct SYNC_CHECKPOINT_RECORD **ppFreedSync;
struct SYNC_CHECKPOINT_RECORD *pSync = (struct SYNC_CHECKPOINT_RECORD*)hRecord;
_SYNC_CHECKPOINT_CONTEXT *psContext;
if (!hRecord)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
psContext = pSync->psSyncCheckpointBlock->psContext;
OSLockAcquire(psContext->hCheckpointRecordLock);
dllist_remove_node(&pSync->sNode);
if (psContext->uiCheckpointRecordFreeIdx >= PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN)
{
PVR_DPF((PVR_DBG_ERROR, "%s: freed sync record index out of range", __FUNCTION__));
psContext->uiCheckpointRecordFreeIdx = 0;
}
ppFreedSync = &psContext->apsCheckpointRecordsFreed[psContext->uiCheckpointRecordFreeIdx];
psContext->uiCheckpointRecordFreeIdx =
(psContext->uiCheckpointRecordFreeIdx + 1) % PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN;
if (*ppFreedSync)
{
OSFreeMem(*ppFreedSync);
}
pSync->psSyncCheckpointBlock = NULL;
pSync->ui64OSTime = OSClockns64();
*ppFreedSync = pSync;
OSLockRelease(psContext->hCheckpointRecordLock);
return PVRSRV_OK;
}
#define NS_IN_S (1000000000UL)
static void _SyncCheckpointRecordPrint(struct SYNC_CHECKPOINT_RECORD *psSyncCheckpointRec,
IMG_UINT64 ui64TimeNow,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile)
{
SYNC_CHECKPOINT_BLOCK *psSyncCheckpointBlock = psSyncCheckpointRec->psSyncCheckpointBlock;
IMG_UINT64 ui64DeltaS;
IMG_UINT32 ui32DeltaF;
IMG_UINT64 ui64Delta = ui64TimeNow - psSyncCheckpointRec->ui64OSTime;
ui64DeltaS = OSDivide64(ui64Delta, NS_IN_S, &ui32DeltaF);
if (psSyncCheckpointBlock && psSyncCheckpointBlock->pui32LinAddr)
{
void *pSyncCheckpointAddr;
pSyncCheckpointAddr = (void*)(psSyncCheckpointBlock->pui32LinAddr + psSyncCheckpointRec->ui32SyncOffset);
PVR_DUMPDEBUG_LOG("\t%05u %05llu.%09u FWAddr=0x%08x State=%s (%s)",
psSyncCheckpointRec->uiPID,
ui64DeltaS, ui32DeltaF,
(psSyncCheckpointRec->ui32FwBlockAddr+psSyncCheckpointRec->ui32SyncOffset),
(*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) ? "SIGNALLED" : ((*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_ERRORED) ? "ERRORED" : "NOT_SIGNALLED"),
psSyncCheckpointRec->szClassName
);
}
else
{
PVR_DUMPDEBUG_LOG("\t%05u %05llu.%09u FWAddr=0x%08x State=<null_ptr> (%s)",
psSyncCheckpointRec->uiPID,
ui64DeltaS, ui32DeltaF,
(psSyncCheckpointRec->ui32FwBlockAddr+psSyncCheckpointRec->ui32SyncOffset),
psSyncCheckpointRec->szClassName
);
}
}
static void _SyncCheckpointRecordRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle,
IMG_UINT32 ui32VerbLevel,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile)
{
_SYNC_CHECKPOINT_CONTEXT *psContext = (_SYNC_CHECKPOINT_CONTEXT *)hDebugRequestHandle;
IMG_UINT64 ui64TimeNowS;
IMG_UINT32 ui32TimeNowF;
IMG_UINT64 ui64TimeNow = OSClockns64();
DLLIST_NODE *psNode, *psNext;
ui64TimeNowS = OSDivide64(ui64TimeNow, NS_IN_S, &ui32TimeNowF);
if (ui32VerbLevel == DEBUG_REQUEST_VERBOSITY_HIGH)
{
IMG_UINT32 i;
OSLockAcquire(psContext->hCheckpointRecordLock);
PVR_DUMPDEBUG_LOG("Dumping all allocated sync checkpoints @ %05llu.%09u", ui64TimeNowS, ui32TimeNowF);
PVR_DUMPDEBUG_LOG("\t%-5s %-15s %-17s %-14s (%s)",
"PID", "Time Delta (s)", "Address", "State", "Annotation");
dllist_foreach_node(&psContext->sCheckpointRecordList, psNode, psNext)
{
struct SYNC_CHECKPOINT_RECORD *psSyncCheckpointRec =
IMG_CONTAINER_OF(psNode, struct SYNC_CHECKPOINT_RECORD, sNode);
_SyncCheckpointRecordPrint(psSyncCheckpointRec, ui64TimeNow,
pfnDumpDebugPrintf, pvDumpDebugFile);
}
PVR_DUMPDEBUG_LOG("Dumping all recently freed sync checkpoints @ %05llu.%09u", ui64TimeNowS, ui32TimeNowF);
PVR_DUMPDEBUG_LOG("\t%-5s %-15s %-17s %-14s (%s)",
"PID", "Time Delta (s)", "Address", "State", "Annotation");
for (i = DECREMENT_WITH_WRAP(psContext->uiCheckpointRecordFreeIdx, PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN);
i != psContext->uiCheckpointRecordFreeIdx;
i = DECREMENT_WITH_WRAP(i, PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN))
{
if (psContext->apsCheckpointRecordsFreed[i])
{
_SyncCheckpointRecordPrint(psContext->apsCheckpointRecordsFreed[i],
ui64TimeNow, pfnDumpDebugPrintf, pvDumpDebugFile);
}
else
{
break;
}
}
OSLockRelease(psContext->hCheckpointRecordLock);
}
}
#undef NS_IN_S
static PVRSRV_ERROR _SyncCheckpointRecordListInit(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
PVRSRV_ERROR eError;
eError = OSLockCreate(&psContext->hCheckpointRecordLock, LOCK_TYPE_NONE);
if (eError != PVRSRV_OK)
{
goto fail_lock_create;
}
dllist_init(&psContext->sCheckpointRecordList);
eError = PVRSRVRegisterDbgRequestNotify(&psContext->hCheckpointRecordNotify,
psContext->psDevNode,
_SyncCheckpointRecordRequest,
DEBUG_REQUEST_SYNCCHECKPOINT,
psContext);
if (eError != PVRSRV_OK)
{
goto fail_dbg_register;
}
return PVRSRV_OK;
fail_dbg_register:
OSLockDestroy(psContext->hCheckpointRecordLock);
fail_lock_create:
return eError;
}
static void _SyncCheckpointRecordListDeinit(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
int i;
DLLIST_NODE *psNode, *psNext;
OSLockAcquire(psContext->hCheckpointRecordLock);
dllist_foreach_node(&psContext->sCheckpointRecordList, psNode, psNext)
{
struct SYNC_CHECKPOINT_RECORD *pSyncCheckpointRec =
IMG_CONTAINER_OF(psNode, struct SYNC_CHECKPOINT_RECORD, sNode);
dllist_remove_node(psNode);
OSFreeMem(pSyncCheckpointRec);
}
for (i = 0; i < PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN; i++)
{
if (psContext->apsCheckpointRecordsFreed[i])
{
OSFreeMem(psContext->apsCheckpointRecordsFreed[i]);
psContext->apsCheckpointRecordsFreed[i] = NULL;
}
}
OSLockRelease(psContext->hCheckpointRecordLock);
PVRSRVUnregisterDbgRequestNotify(psContext->hCheckpointRecordNotify);
psContext->hCheckpointRecordNotify = NULL;
OSLockDestroy(psContext->hCheckpointRecordLock);
psContext->hCheckpointRecordLock = NULL;
}
#else /* defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) */
PVRSRV_ERROR
SyncCheckpointRecordAdd(
PSYNC_CHECKPOINT_RECORD_HANDLE * phRecord,
SYNC_CHECKPOINT_BLOCK * hSyncCheckpointBlock,
IMG_UINT32 ui32FwBlockAddr,
IMG_UINT32 ui32SyncOffset,
IMG_UINT32 ui32ClassNameSize,
const IMG_CHAR *pszClassName)
{
PVR_UNREFERENCED_PARAMETER(phRecord);
PVR_UNREFERENCED_PARAMETER(hSyncCheckpointBlock);
PVR_UNREFERENCED_PARAMETER(ui32FwBlockAddr);
PVR_UNREFERENCED_PARAMETER(ui32SyncOffset);
PVR_UNREFERENCED_PARAMETER(ui32ClassNameSize);
PVR_UNREFERENCED_PARAMETER(pszClassName);
return PVRSRV_OK;
}
PVRSRV_ERROR
SyncCheckpointRecordRemove(PSYNC_CHECKPOINT_RECORD_HANDLE hRecord)
{
PVR_UNREFERENCED_PARAMETER(hRecord);
return PVRSRV_OK;
}
static PVRSRV_ERROR _SyncCheckpointRecordListInit(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
PVR_UNREFERENCED_PARAMETER(psContext);
return PVRSRV_OK;
}
static void _SyncCheckpointRecordListDeinit(_SYNC_CHECKPOINT_CONTEXT *psContext)
{
PVR_UNREFERENCED_PARAMETER(psContext);
}
#endif /* defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) */
#if defined(PDUMP)
PVRSRV_ERROR
SyncCheckpointSignalPDump(_SYNC_CHECKPOINT *psSyncCheckpoint)
{
/*
We might be ask to PDump sync state outside of capture range
(e.g. texture uploads) so make this continuous.
*/
DevmemPDumpLoadMemValue32(psSyncCheckpoint->psSyncCheckpointBlock->hMemDesc,
_SyncCheckpointGetOffset(psSyncCheckpoint),
PVRSRV_SYNC_CHECKPOINT_SIGNALLED,
PDUMP_FLAGS_CONTINUOUS);
return PVRSRV_OK;
}
PVRSRV_ERROR
SyncCheckpointErrorPDump(_SYNC_CHECKPOINT *psSyncCheckpoint)
{
/*
We might be ask to PDump sync state outside of capture range
(e.g. texture uploads) so make this continuous.
*/
DevmemPDumpLoadMemValue32(psSyncCheckpoint->psSyncCheckpointBlock->hMemDesc,
_SyncCheckpointGetOffset(psSyncCheckpoint),
PVRSRV_SYNC_CHECKPOINT_ERRORED,
PDUMP_FLAGS_CONTINUOUS);
return PVRSRV_OK;
}
#endif