/*************************************************************************/ /*!
|
@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
|