| /*************************************************************************/ /*! |
| @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_defs.h" |
| #include "img_types.h" |
| #include "img_defs.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 "sync_checkpoint_internal_fw.h" |
| #include "sync_checkpoint_init.h" |
| #include "lock.h" |
| #include "log2.h" |
| #include "pvrsrv.h" |
| #include "pdump_km.h" |
| #include "info_page.h" |
| |
| #include "pvrsrv_sync_km.h" |
| #include "rgxhwperf.h" |
| |
| #if defined(PVRSRV_NEED_PVR_DPF) |
| |
| /* Enable this to turn on debug relating to the creation and |
| resolution of contexts */ |
| #define ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG 0 |
| |
| /* Enable this to turn on debug relating to the creation and |
| resolution of fences */ |
| #define ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG 0 |
| |
| /* Enable this to turn on debug relating to the sync checkpoint |
| allocation and freeing */ |
| #define ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG 0 |
| |
| /* Enable this to turn on debug relating to the sync checkpoint |
| enqueuing and signalling */ |
| #define ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG 0 |
| |
| /* Enable this to turn on debug relating to the sync checkpoint pool */ |
| #define ENABLE_SYNC_CHECKPOINT_POOL_DEBUG 0 |
| |
| /* Enable this to turn on debug relating to sync checkpoint UFO |
| lookup */ |
| #define ENABLE_SYNC_CHECKPOINT_UFO_DEBUG 0 |
| |
| /* Enable this to turn on sync checkpoint deferred cleanup debug |
| * (for syncs we have been told to free but which have some |
| * outstanding FW operations remaining (enqueued in CCBs) |
| */ |
| #define ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG 0 |
| |
| #else |
| |
| #define ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_POOL_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_UFO_DEBUG 0 |
| #define ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG 0 |
| |
| #endif |
| |
| /* Set the size of the sync checkpoint pool (not used if 0). |
| * A pool will be maintained for each sync checkpoint context. |
| */ |
| #define SYNC_CHECKPOINT_POOL_SIZE 128 |
| /* The 'sediment' value represents the minimum number of |
| * sync checkpoints which must be in the pool before one |
| * will be allocated from the pool rather than from memory. |
| * This effectively helps avoid re-use of a sync checkpoint |
| * just after it has been returned to the pool, making |
| * debugging somewhat easier to understand. |
| */ |
| #define SYNC_CHECKPOINT_POOL_SEDIMENT 20 |
| |
| #define SYNC_CHECKPOINT_BLOCK_LIST_CHUNK_SIZE 10 |
| |
| /* |
| 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) |
| |
| |
| 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; |
| |
| typedef struct _SYNC_CHECKPOINT_CONTEXT_CTL_ |
| { |
| SHARED_DEV_CONNECTION psDeviceNode; |
| PFN_SYNC_CHECKPOINT_FENCE_RESOLVE_FN pfnFenceResolve; |
| PFN_SYNC_CHECKPOINT_FENCE_CREATE_FN pfnFenceCreate; |
| /* |
| * Used as head of linked-list of sync checkpoints for which |
| * SyncCheckpointFree() has been called, but have outstanding |
| * FW operations (enqueued in CCBs) |
| * This list will be check whenever a SyncCheckpointFree() is |
| * called, and when SyncCheckpointContextDestroy() is called. |
| */ |
| DLLIST_NODE sDeferredCleanupListHead; |
| /* Lock to protect the deferred cleanup list */ |
| POS_LOCK hDeferredCleanupListLock; |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| _SYNC_CHECKPOINT *psSyncCheckpointPool[SYNC_CHECKPOINT_POOL_SIZE]; |
| IMG_BOOL bSyncCheckpointPoolFull; |
| IMG_BOOL bSyncCheckpointPoolValid; |
| IMG_UINT32 ui32SyncCheckpointPoolCount; |
| IMG_UINT32 ui32SyncCheckpointPoolWp; |
| IMG_UINT32 ui32SyncCheckpointPoolRp; |
| POS_LOCK hSyncCheckpointPoolLock; |
| #endif |
| } _SYNC_CHECKPOINT_CONTEXT_CTL; |
| |
| /* this is the max number of sync checkpoint records we will search or dump |
| * at any time. |
| */ |
| #define SYNC_CHECKPOINT_RECORD_LIMIT 20000 |
| |
| #define DECREMENT_WITH_WRAP(value, sz) ((value) ? ((value) - 1) : ((sz) - 1)) |
| |
| struct SYNC_CHECKPOINT_RECORD |
| { |
| PVRSRV_DEVICE_NODE *psDevNode; |
| SYNC_CHECKPOINT_BLOCK *psSyncCheckpointBlock; /*!< handle to SYNC_CHECKPOINT_BLOCK */ |
| IMG_UINT32 ui32SyncOffset; /*!< offset to sync in block */ |
| IMG_UINT32 ui32FwBlockAddr; |
| IMG_PID uiPID; |
| IMG_UINT32 ui32UID; |
| IMG_UINT64 ui64OSTime; |
| DLLIST_NODE sNode; |
| IMG_CHAR szClassName[PVRSRV_SYNC_NAME_LENGTH]; |
| PSYNC_CHECKPOINT pSyncCheckpt; |
| }; |
| |
| static IMG_BOOL gbSyncCheckpointInit = IMG_FALSE; |
| static PFN_SYNC_CHECKPOINT_STRUCT *g_psSyncCheckpointPfnStruct; |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| static _SYNC_CHECKPOINT *_GetCheckpointFromPool(_SYNC_CHECKPOINT_CONTEXT *psContext); |
| static IMG_BOOL _PutCheckpointInPool(_SYNC_CHECKPOINT *psSyncCheckpoint); |
| static IMG_UINT32 _CleanCheckpointPool(_SYNC_CHECKPOINT_CONTEXT *psContext); |
| #endif |
| |
| #if (ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG == 1) |
| static IMG_UINT32 gui32NumSyncCheckpointContexts = 0; |
| #endif |
| |
| /* Defined values to indicate status of sync checkpoint, which is |
| * stored in the memory of the structure */ |
| #define SYNC_CHECKPOINT_PATTERN_IN_USE 0x1a1aa |
| #define SYNC_CHECKPOINT_PATTERN_IN_POOL 0x2b2bb |
| #define SYNC_CHECKPOINT_PATTERN_FREED 0x3c3cc |
| |
| #if defined(SUPPORT_RGX) |
| static inline void RGXSRVHWPerfSyncCheckpointUFOIsSignalled(PVRSRV_RGXDEV_INFO *psDevInfo, |
| _SYNC_CHECKPOINT *psSyncCheckpointInt, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| if (RGXHWPerfHostIsEventEnabled(psDevInfo, RGX_HWPERF_HOST_UFO) |
| && !(ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_SUPPRESS_HWP_PKT)) |
| { |
| RGX_HWPERF_UFO_EV eEv; |
| RGX_HWPERF_UFO_DATA_ELEMENT sSyncData; |
| |
| if (psSyncCheckpointInt) |
| { |
| if ((psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) || |
| (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ERRORED)) |
| { |
| sSyncData.sCheckSuccess.ui32FWAddr = SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt); |
| sSyncData.sCheckSuccess.ui32Value = psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State; |
| eEv = RGX_HWPERF_UFO_EV_CHECK_SUCCESS; |
| } |
| else |
| { |
| sSyncData.sCheckFail.ui32FWAddr = SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt); |
| sSyncData.sCheckFail.ui32Value = psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State; |
| sSyncData.sCheckFail.ui32Required = PVRSRV_SYNC_CHECKPOINT_SIGNALLED; |
| eEv = RGX_HWPERF_UFO_EV_CHECK_FAIL; |
| } |
| RGXHWPerfHostPostUfoEvent(psDevInfo, eEv, &sSyncData, |
| (ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_CTX_ATOMIC) ? IMG_FALSE : IMG_TRUE); |
| } |
| } |
| } |
| |
| static inline void RGXSRVHWPerfSyncCheckpointUFOUpdate(PVRSRV_RGXDEV_INFO *psDevInfo, |
| _SYNC_CHECKPOINT *psSyncCheckpointInt, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| if (RGXHWPerfHostIsEventEnabled(psDevInfo, RGX_HWPERF_HOST_UFO) |
| && !(ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_SUPPRESS_HWP_PKT)) |
| { |
| RGX_HWPERF_UFO_DATA_ELEMENT sSyncData; |
| |
| if (psSyncCheckpointInt) |
| { |
| sSyncData.sUpdate.ui32FWAddr = SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt); |
| sSyncData.sUpdate.ui32OldValue = psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State; |
| sSyncData.sUpdate.ui32NewValue = PVRSRV_SYNC_CHECKPOINT_SIGNALLED; |
| RGXHWPerfHostPostUfoEvent(psDevInfo, RGX_HWPERF_UFO_EV_UPDATE, &sSyncData, |
| (ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_CTX_ATOMIC) ? IMG_FALSE : IMG_TRUE); |
| } |
| } |
| } |
| #endif |
| |
| static PVRSRV_ERROR |
| _SyncCheckpointRecordAdd(PSYNC_CHECKPOINT_RECORD_HANDLE *phRecord, |
| SYNC_CHECKPOINT_BLOCK *hSyncCheckpointBlock, |
| IMG_UINT32 ui32FwBlockAddr, |
| IMG_UINT32 ui32SyncOffset, |
| IMG_UINT32 ui32UID, |
| IMG_UINT32 ui32ClassNameSize, |
| const IMG_CHAR *pszClassName, PSYNC_CHECKPOINT pSyncCheckpt); |
| static 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(PVRSRV_DEVICE_NODE *psDevNode); |
| static void _SyncCheckpointRecordListDeinit(PVRSRV_DEVICE_NODE *psDevNode); |
| |
| #if defined(PDUMP) |
| static PVRSRV_ERROR _SyncCheckpointSignalPDump(_SYNC_CHECKPOINT *psSyncCheckpoint); |
| static PVRSRV_ERROR _SyncCheckpointErrorPDump(_SYNC_CHECKPOINT *psSyncCheckpoint); |
| #endif |
| |
| /* Unique incremental ID assigned to sync checkpoints when allocated */ |
| static IMG_UINT32 g_SyncCheckpointUID; |
| |
| static void _CheckDeferredCleanupList(_SYNC_CHECKPOINT_CONTEXT *psContext); |
| |
| void SyncCheckpointContextUnref(PSYNC_CHECKPOINT_CONTEXT psContext) |
| { |
| _SYNC_CHECKPOINT_CONTEXT *psContextInt = (_SYNC_CHECKPOINT_CONTEXT *)psContext; |
| IMG_UINT32 ui32RefCt = OSAtomicRead(&psContextInt->hRefCount); |
| |
| if (ui32RefCt == 0) |
| { |
| PVR_LOG_ERROR(PVRSRV_ERROR_INVALID_CONTEXT, |
| "SyncCheckpointContextUnref context already freed"); |
| } |
| else if (0 == OSAtomicDecrement(&psContextInt->hRefCount)) |
| { |
| /* SyncCheckpointContextDestroy only when no longer referenced */ |
| OSLockDestroy(psContextInt->psContextCtl->hDeferredCleanupListLock); |
| psContextInt->psContextCtl->hDeferredCleanupListLock = NULL; |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| if (psContextInt->psContextCtl->ui32SyncCheckpointPoolCount) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called for context<%p> with %d sync checkpoints still in the pool", |
| __func__, |
| (void*)psContext, |
| psContextInt->psContextCtl->ui32SyncCheckpointPoolCount)); |
| } |
| psContextInt->psContextCtl->bSyncCheckpointPoolValid = IMG_FALSE; |
| OSLockDestroy(psContextInt->psContextCtl->hSyncCheckpointPoolLock); |
| psContextInt->psContextCtl->hSyncCheckpointPoolLock = NULL; |
| #endif |
| OSFreeMem(psContextInt->psContextCtl); |
| RA_Delete(psContextInt->psSpanRA); |
| RA_Delete(psContextInt->psSubAllocRA); |
| OSLockDestroy(psContextInt->hLock); |
| psContextInt->hLock = NULL; |
| OSFreeMem(psContext); |
| } |
| } |
| |
| void SyncCheckpointContextRef(PSYNC_CHECKPOINT_CONTEXT psContext) |
| { |
| _SYNC_CHECKPOINT_CONTEXT *psContextInt = (_SYNC_CHECKPOINT_CONTEXT *)psContext; |
| IMG_UINT32 ui32RefCt = OSAtomicRead(&psContextInt->hRefCount); |
| |
| if (ui32RefCt == 0) |
| { |
| PVR_LOG_ERROR(PVRSRV_ERROR_INVALID_CONTEXT, |
| "SyncCheckpointContextRef context use after free"); |
| } |
| else |
| { |
| OSAtomicIncrement(&psContextInt->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(*psSyncBlk)); |
| PVR_LOGG_IF_NOMEM(psSyncBlk, "OSAllocMem", eError, 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); |
| |
| OSLockCreate(&psSyncBlk->hLock); |
| |
| 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) |
| { |
| OSLockAcquire(psSyncBlk->hLock); |
| if (0 == OSAtomicDecrement(&psSyncBlk->hRefCount)) |
| { |
| PVRSRV_DEVICE_NODE *psDevNode = psSyncBlk->psDevNode; |
| |
| DevmemReleaseCpuVirtAddr(psSyncBlk->hMemDesc); |
| psDevNode->pfnFreeUFOBlock(psDevNode, psSyncBlk->hMemDesc); |
| OSLockRelease(psSyncBlk->hLock); |
| OSLockDestroy(psSyncBlk->hLock); |
| psSyncBlk->hLock = NULL; |
| OSFreeMem(psSyncBlk); |
| } |
| else |
| { |
| OSLockRelease(psSyncBlk->hLock); |
| } |
| } |
| |
| 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((PSYNC_CHECKPOINT_CONTEXT)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((PSYNC_CHECKPOINT_CONTEXT)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((PSYNC_CHECKPOINT_CONTEXT)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 |
| */ |
| |
| PVRSRV_ERROR |
| SyncCheckpointRegisterFunctions(PFN_SYNC_CHECKPOINT_STRUCT *psSyncCheckpointPfns) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| g_psSyncCheckpointPfnStruct = psSyncCheckpointPfns; |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointResolveFence(PSYNC_CHECKPOINT_CONTEXT psSyncCheckpointContext, |
| PVRSRV_FENCE hFence, IMG_UINT32 *pui32NumSyncCheckpoints, |
| PSYNC_CHECKPOINT **papsSyncCheckpoints, |
| IMG_UINT64 *pui64FenceUID) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnFenceResolve) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| PVR_LOG_ERROR(eError, "g_pfnFenceResolve is NULL"); |
| return eError; |
| } |
| |
| if (papsSyncCheckpoints) |
| { |
| eError = g_psSyncCheckpointPfnStruct->pfnFenceResolve( |
| psSyncCheckpointContext, |
| hFence, |
| pui32NumSyncCheckpoints, |
| papsSyncCheckpoints, |
| pui64FenceUID); |
| } |
| else |
| { |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| } |
| |
| PVR_LOGR_IF_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnFenceResolve"); |
| |
| if (*pui32NumSyncCheckpoints > MAX_SYNC_CHECKPOINTS_PER_FENCE) |
| { |
| IMG_UINT32 i; |
| PVR_DPF((PVR_DBG_ERROR, "%s: g_psSyncCheckpointPfnStruct->pfnFenceResolve() returned too many checkpoints (%u > MAX_SYNC_CHECKPOINTS_PER_FENCE=%u)", |
| __func__, *pui32NumSyncCheckpoints, MAX_SYNC_CHECKPOINTS_PER_FENCE)); |
| |
| /* Free resources after error */ |
| if (*papsSyncCheckpoints) |
| { |
| for (i = 0; i < *pui32NumSyncCheckpoints; i++) |
| { |
| SyncCheckpointDropRef((*papsSyncCheckpoints)[i]); |
| } |
| |
| SyncCheckpointFreeCheckpointListMem(*papsSyncCheckpoints); |
| } |
| |
| return PVRSRV_ERROR_INVALID_PARAMS; |
| } |
| |
| #if (ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG == 1) |
| { |
| IMG_UINT32 ii; |
| |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: g_psSyncCheckpointPfnStruct->pfnFenceResolve() for fence %d returned the following %d checkpoints:", |
| __func__, |
| hFence, |
| *pui32NumSyncCheckpoints)); |
| |
| for (ii=0; ii<*pui32NumSyncCheckpoints; ii++) |
| { |
| PSYNC_CHECKPOINT psNextCheckpoint = *(*papsSyncCheckpoints + ii); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: *papsSyncCheckpoints[%d]:<%p>", |
| __func__, |
| ii, |
| (void*)psNextCheckpoint)); |
| } |
| } |
| #endif |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointCreateFence(PVRSRV_DEVICE_NODE *psDevNode, |
| const IMG_CHAR *pszFenceName, |
| PVRSRV_TIMELINE hTimeline, |
| PSYNC_CHECKPOINT_CONTEXT psSyncCheckpointContext, |
| PVRSRV_FENCE *phNewFence, |
| IMG_UINT64 *puiUpdateFenceUID, |
| void **ppvFenceFinaliseData, |
| PSYNC_CHECKPOINT *psNewSyncCheckpoint, |
| void **ppvTimelineUpdateSyncPrim, |
| IMG_UINT32 *pui32TimelineUpdateValue) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| PVR_UNREFERENCED_PARAMETER(psDevNode); |
| |
| if (unlikely(!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnFenceCreate)) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| PVR_LOG_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnFenceCreate is NULL"); |
| } |
| else |
| { |
| eError = g_psSyncCheckpointPfnStruct->pfnFenceCreate( |
| pszFenceName, |
| hTimeline, |
| psSyncCheckpointContext, |
| phNewFence, |
| puiUpdateFenceUID, |
| ppvFenceFinaliseData, |
| psNewSyncCheckpoint, |
| ppvTimelineUpdateSyncPrim, |
| pui32TimelineUpdateValue); |
| if (unlikely(eError != PVRSRV_OK)) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s failed to create new fence<%p> for timeline<%d> using " |
| "sync checkpoint context<%p>, psNewSyncCheckpoint=<%p>, eError=%s", |
| __func__, |
| (void*)phNewFence, |
| hTimeline, |
| (void*)psSyncCheckpointContext, |
| (void*)psNewSyncCheckpoint, |
| PVRSRVGetErrorString(eError))); |
| } |
| #if (ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG == 1) |
| else |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s created new fence<%d> for timeline<%d> using " |
| "sync checkpoint context<%p>, new sync_checkpoint=<%p>", |
| __func__, |
| *phNewFence, |
| hTimeline, |
| (void*)psSyncCheckpointContext, |
| (void*)*psNewSyncCheckpoint)); |
| } |
| #endif |
| } |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointRollbackFenceData(PVRSRV_FENCE hFence, void *pvFinaliseData) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnFenceDataRollback) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| PVR_LOG_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnFenceDataRollback is NULL"); |
| } |
| else |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: called to rollback fence data <%p>", |
| __func__, |
| pvFinaliseData)); |
| #endif |
| eError = g_psSyncCheckpointPfnStruct->pfnFenceDataRollback( |
| hFence, pvFinaliseData); |
| PVR_LOG_IF_ERROR(eError, |
| "g_psSyncCheckpointPfnStruct->pfnFenceDataRollback returned error"); |
| } |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointFinaliseFence(PPVRSRV_DEVICE_NODE psDevNode, |
| PVRSRV_FENCE hFence, |
| void *pvFinaliseData, |
| PSYNC_CHECKPOINT psSyncCheckpoint, |
| const IMG_CHAR *pszName) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnFenceFinalise) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: Warning (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED) (this is permitted)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| } |
| else |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_FENCE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: called to finalise fence <%d>", |
| __func__, |
| hFence)); |
| #endif |
| eError = g_psSyncCheckpointPfnStruct->pfnFenceFinalise(hFence, pvFinaliseData); |
| PVR_LOG_IF_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnFenceFinalise returned error"); |
| |
| RGXSRV_HWPERF_ALLOC_FENCE(psDevNode, OSGetCurrentClientProcessIDKM(), hFence, |
| SyncCheckpointGetFirmwareAddr(psSyncCheckpoint), |
| pszName, OSStringLength(pszName)); |
| } |
| return eError; |
| } |
| |
| void |
| SyncCheckpointFreeCheckpointListMem(void *pvCheckpointListMem) |
| { |
| if (g_psSyncCheckpointPfnStruct->pfnFreeCheckpointListMem) |
| { |
| g_psSyncCheckpointPfnStruct->pfnFreeCheckpointListMem(pvCheckpointListMem); |
| } |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointNoHWUpdateTimelines(void *pvPrivateData) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnNoHWUpdateTimelines) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| PVR_LOG_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnNoHWUpdateTimelines is NULL"); |
| } |
| else |
| { |
| g_psSyncCheckpointPfnStruct->pfnNoHWUpdateTimelines(pvPrivateData); |
| } |
| return eError; |
| |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointDumpInfoOnStalledUFOs(IMG_UINT32 ui32NumUFOs, IMG_UINT32 *pui32Vaddrs, IMG_UINT32 *pui32NumSyncOwnedUFOs) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| PVR_LOGR_IF_FALSE((pui32NumSyncOwnedUFOs != NULL), "pui32NumSyncOwnedUFOs invalid", PVRSRV_ERROR_INVALID_PARAMS); |
| |
| if (!g_psSyncCheckpointPfnStruct || !g_psSyncCheckpointPfnStruct->pfnDumpInfoOnStalledUFOs) |
| { |
| *pui32NumSyncOwnedUFOs = 0; |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: ERROR (eError=PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED)", |
| __func__)); |
| eError = PVRSRV_ERROR_SYNC_NATIVESYNC_NOT_REGISTERED; |
| PVR_LOG_ERROR(eError, "g_psSyncCheckpointPfnStruct->pfnDumpInfoOnStalledUFOs is NULL"); |
| } |
| else |
| { |
| *pui32NumSyncOwnedUFOs = g_psSyncCheckpointPfnStruct->pfnDumpInfoOnStalledUFOs(ui32NumUFOs, pui32Vaddrs); |
| PVR_LOG(("%d sync checkpoint%s owned by %s in stalled context", |
| *pui32NumSyncOwnedUFOs, *pui32NumSyncOwnedUFOs==1 ? "" : "s", |
| g_psSyncCheckpointPfnStruct->pszImplName)); |
| } |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointContextCreate(PPVRSRV_DEVICE_NODE psDevNode, |
| PSYNC_CHECKPOINT_CONTEXT *ppsSyncCheckpointContext) |
| { |
| _SYNC_CHECKPOINT_CONTEXT *psContext = NULL; |
| _SYNC_CHECKPOINT_CONTEXT_CTL *psContextCtl = NULL; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| PVR_LOGR_IF_FALSE((ppsSyncCheckpointContext != NULL), |
| "ppsSyncCheckpointContext invalid", |
| PVRSRV_ERROR_INVALID_PARAMS); |
| |
| psContext = OSAllocMem(sizeof(*psContext)); |
| PVR_LOGG_IF_NOMEM(psContext, "OSAllocMem", eError, fail_alloc); /* Sets OOM error code */ |
| |
| psContextCtl = OSAllocMem(sizeof(*psContextCtl)); |
| PVR_LOGG_IF_NOMEM(psContextCtl, "OSAllocMem", eError, fail_alloc2); /* Sets OOM error code */ |
| |
| eError = OSLockCreate(&psContext->hLock); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call " |
| "to OSLockCreate(context lock) failed"); |
| goto fail_create_context_lock; |
| } |
| |
| eError = OSLockCreate(&psContextCtl->hDeferredCleanupListLock); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call " |
| "to OSLockCreate(deferred cleanup list lock) failed"); |
| goto fail_create_deferred_cleanup_lock; |
| } |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| eError = OSLockCreate(&psContextCtl->hSyncCheckpointPoolLock); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call " |
| "to OSLockCreate(sync checkpoint pool lock) failed"); |
| goto fail_create_pool_lock; |
| } |
| #endif |
| |
| dllist_init(&psContextCtl->sDeferredCleanupListHead); |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| psContextCtl->ui32SyncCheckpointPoolCount = 0; |
| psContextCtl->ui32SyncCheckpointPoolWp = 0; |
| psContextCtl->ui32SyncCheckpointPoolRp = 0; |
| psContextCtl->bSyncCheckpointPoolFull = IMG_FALSE; |
| psContextCtl->bSyncCheckpointPoolValid = IMG_TRUE; |
| #endif |
| psContext->psDevNode = psDevNode; |
| |
| OSSNPrintf(psContext->azName, PVRSRV_SYNC_NAME_LENGTH, "Sync Prim RA-%p", psContext); |
| OSSNPrintf(psContext->azSpanName, PVRSRV_SYNC_NAME_LENGTH, "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; |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call to RA_Create(subAlloc) failed"); |
| 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; |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call to RA_Create(span) failed"); |
| goto fail_span; |
| } |
| |
| if (!RA_Add(psContext->psSpanRA, 0, MAX_SYNC_CHECKPOINT_MEM, 0, NULL)) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| PVR_LOG_ERROR(eError, "SyncCheckpointContextCreate call to RA_Add(span) failed"); |
| goto fail_span_add; |
| } |
| |
| OSAtomicWrite(&psContext->hRefCount, 1); |
| OSAtomicWrite(&psContext->hCheckpointCount, 0); |
| |
| psContext->psContextCtl = psContextCtl; |
| |
| *ppsSyncCheckpointContext = (PSYNC_CHECKPOINT_CONTEXT)psContext; |
| #if (ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: created psSyncCheckpointContext=<%p> (%d contexts exist)", |
| __func__, |
| (void*)*ppsSyncCheckpointContext, |
| ++gui32NumSyncCheckpointContexts)); |
| #endif |
| return PVRSRV_OK; |
| |
| fail_span_add: |
| RA_Delete(psContext->psSpanRA); |
| fail_span: |
| RA_Delete(psContext->psSubAllocRA); |
| fail_suballoc: |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| OSLockDestroy(psContextCtl->hSyncCheckpointPoolLock); |
| psContextCtl->hSyncCheckpointPoolLock = NULL; |
| fail_create_pool_lock: |
| #endif |
| OSLockDestroy(psContextCtl->hDeferredCleanupListLock); |
| psContextCtl->hDeferredCleanupListLock = NULL; |
| fail_create_deferred_cleanup_lock: |
| OSLockDestroy(psContext->hLock); |
| psContext->hLock = NULL; |
| fail_create_context_lock: |
| OSFreeMem(psContextCtl); |
| fail_alloc2: |
| OSFreeMem(psContext); |
| fail_alloc: |
| return eError; |
| } |
| |
| /* Poisons and frees the checkpoint and lock. |
| * Decrements context refcount. */ |
| static void _FreeSyncCheckpoint(_SYNC_CHECKPOINT *psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT_CONTEXT *psContext = psSyncCheckpoint->psSyncCheckpointBlock->psContext; |
| |
| psSyncCheckpoint->sCheckpointUFOAddr.ui32Addr = 0; |
| psSyncCheckpoint->psSyncCheckpointFwObj = NULL; |
| psSyncCheckpoint->ui32ValidationCheck = SYNC_CHECKPOINT_PATTERN_FREED; |
| |
| RA_Free(psSyncCheckpoint->psSyncCheckpointBlock->psContext->psSubAllocRA, |
| psSyncCheckpoint->uiSpanAddr); |
| psSyncCheckpoint->psSyncCheckpointBlock = NULL; |
| |
| OSLockDestroy(psSyncCheckpoint->hLock); |
| OSFreeMem(psSyncCheckpoint); |
| |
| OSAtomicDecrement(&psContext->hCheckpointCount); |
| } |
| |
| PVRSRV_ERROR SyncCheckpointContextDestroy(PSYNC_CHECKPOINT_CONTEXT psSyncCheckpointContext) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| _SYNC_CHECKPOINT_CONTEXT *psContext = (_SYNC_CHECKPOINT_CONTEXT*)psSyncCheckpointContext; |
| PVRSRV_DEVICE_NODE *psDevNode; |
| IMG_INT iRf = 0; |
| |
| PVR_LOGR_IF_FALSE((psSyncCheckpointContext != NULL), |
| "psSyncCheckpointContext invalid", |
| PVRSRV_ERROR_INVALID_PARAMS); |
| |
| psDevNode = (PVRSRV_DEVICE_NODE *)psContext->psDevNode; |
| |
| #if (ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s: destroying psSyncCheckpointContext=<%p> (now have %d contexts)", |
| __func__, |
| (void*)psSyncCheckpointContext, |
| --gui32NumSyncCheckpointContexts)); |
| #endif |
| |
| _CheckDeferredCleanupList(psContext); |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| if (psContext->psContextCtl->ui32SyncCheckpointPoolCount > 0) |
| { |
| IMG_UINT32 ui32NumFreedFromPool = _CleanCheckpointPool(psContext); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s freed %d sync checkpoints that were still in the pool for context<%p>", |
| __func__, |
| ui32NumFreedFromPool, |
| (void*)psContext)); |
| #else |
| PVR_UNREFERENCED_PARAMETER(ui32NumFreedFromPool); |
| #endif |
| } |
| #endif |
| |
| iRf = OSAtomicRead(&psContext->hCheckpointCount); |
| |
| if (iRf != 0) |
| { |
| /* Note, this is not a permanent error as the caller may retry later */ |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s <%p> attempted with active references (iRf=%d), " |
| "may be the result of a race", |
| __func__, |
| (void*)psContext, |
| iRf)); |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| { |
| DLLIST_NODE *psNode, *psNext; |
| |
| dllist_foreach_node(&psDevNode->sSyncCheckpointSyncsList, psNode, psNext) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpoint = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode); |
| IMG_BOOL bDeferredFree = dllist_node_is_in_list(&psSyncCheckpoint->sDeferredFreeListNode); |
| |
| /* Line below avoids build error in release builds (where PVR_DPF is not defined) */ |
| PVR_UNREFERENCED_PARAMETER(bDeferredFree); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s syncCheckpoint<%p> ID=%d, %s, refs=%d, state=%s, fwaddr=%#08x, enqCount:%d, FWCount:%d %s", |
| __func__, |
| (void*)psSyncCheckpoint, |
| psSyncCheckpoint->ui32UID, |
| psSyncCheckpoint->azName, |
| OSAtomicRead(&psSyncCheckpoint->hRefCount), |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_SIGNALLED ? |
| "PVRSRV_SYNC_CHECKPOINT_SIGNALLED" : |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ACTIVE ? |
| "PVRSRV_SYNC_CHECKPOINT_ACTIVE" : "PVRSRV_SYNC_CHECKPOINT_ERRORED", |
| psSyncCheckpoint->ui32FWAddr, |
| OSAtomicRead(&psSyncCheckpoint->hEnqueuedCCBCount), |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32FwRefCount, |
| bDeferredFree ? "(deferred free)" : "")); |
| |
| eError = PVRSRV_ERROR_UNABLE_TO_DESTROY_CONTEXT; |
| #if (ENABLE_SYNC_CHECKPOINT_CONTEXT_DEBUG == 1) |
| gui32NumSyncCheckpointContexts++; |
| #endif |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| } |
| else |
| { |
| IMG_INT iRf2 = 0; |
| |
| iRf2 = OSAtomicRead(&psContext->hRefCount); |
| SyncCheckpointContextUnref(psSyncCheckpointContext); |
| } |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointAlloc(PSYNC_CHECKPOINT_CONTEXT psSyncContext, |
| PVRSRV_TIMELINE hTimeline, |
| PVRSRV_FENCE hFence, |
| const IMG_CHAR *pszCheckpointName, |
| PSYNC_CHECKPOINT *ppsSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psNewSyncCheckpoint = NULL; |
| _SYNC_CHECKPOINT_CONTEXT *psSyncContextInt = (_SYNC_CHECKPOINT_CONTEXT*)psSyncContext; |
| PVRSRV_DEVICE_NODE *psDevNode; |
| 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); |
| |
| psDevNode = (PVRSRV_DEVICE_NODE *)psSyncContextInt->psDevNode; |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| #if ((ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) || (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1)) |
| PVR_DPF((PVR_DBG_WARNING, "%s Entry, Getting checkpoint from pool", |
| __func__)); |
| #endif |
| psNewSyncCheckpoint = _GetCheckpointFromPool(psSyncContextInt); |
| if (!psNewSyncCheckpoint) |
| { |
| #if ((ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) || (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1)) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s checkpoint pool empty - will have to allocate", |
| __func__)); |
| #endif |
| } |
| #endif |
| /* If pool is empty (or not defined) alloc the new sync checkpoint */ |
| if (!psNewSyncCheckpoint) |
| { |
| psNewSyncCheckpoint = OSAllocMem(sizeof(*psNewSyncCheckpoint)); |
| PVR_LOGG_IF_NOMEM(psNewSyncCheckpoint, "OSAllocMem", eError, fail_alloc); /* Sets OOM error code */ |
| |
| eError = OSLockCreate(&psNewSyncCheckpoint->hLock); |
| |
| PVR_LOGG_IF_ERROR(eError, "OSLockCreate", fail_create_checkpoint_lock); |
| |
| eError = RA_Alloc(psSyncContextInt->psSubAllocRA, |
| sizeof(*psNewSyncCheckpoint->psSyncCheckpointFwObj), |
| RA_NO_IMPORT_MULTIPLIER, |
| 0, |
| sizeof(IMG_UINT32), |
| (IMG_CHAR*)pszCheckpointName, |
| &psNewSyncCheckpoint->uiSpanAddr, |
| NULL, |
| (RA_PERISPAN_HANDLE *) &psNewSyncCheckpoint->psSyncCheckpointBlock); |
| PVR_LOGG_IF_ERROR(eError, "RA_Alloc", fail_raalloc); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s CALLED RA_Alloc(), psSubAllocRA=<%p>, ui32SpanAddr=0x%llx", |
| __func__, |
| (void*)psSyncContextInt->psSubAllocRA, |
| psNewSyncCheckpoint->uiSpanAddr)); |
| #endif |
| psNewSyncCheckpoint->psSyncCheckpointFwObj = |
| (volatile SYNC_CHECKPOINT_FW_OBJ*)(psNewSyncCheckpoint->psSyncCheckpointBlock->pui32LinAddr + |
| (_SyncCheckpointGetOffset(psNewSyncCheckpoint)/sizeof(IMG_UINT32))); |
| psNewSyncCheckpoint->ui32FWAddr = psNewSyncCheckpoint->psSyncCheckpointBlock->ui32FirmwareAddr + |
| _SyncCheckpointGetOffset(psNewSyncCheckpoint) + 1; |
| OSAtomicIncrement(&psNewSyncCheckpoint->psSyncCheckpointBlock->psContext->hCheckpointCount); |
| psNewSyncCheckpoint->ui32ValidationCheck = SYNC_CHECKPOINT_PATTERN_IN_USE; |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called to allocate new sync checkpoint<%p> for context<%p>", |
| __func__, (void*)psNewSyncCheckpoint, (void*)psSyncContext)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpointFwObj<%p>", |
| __func__, (void*)psNewSyncCheckpoint->psSyncCheckpointFwObj)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint FwAddr=0x%x", |
| __func__, SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psNewSyncCheckpoint))); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s pszCheckpointName = %s", |
| __func__, pszCheckpointName)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint Timeline=%d", |
| __func__, hTimeline)); |
| #endif |
| } |
| |
| psNewSyncCheckpoint->hTimeline = hTimeline; |
| OSAtomicWrite(&psNewSyncCheckpoint->hRefCount, 1); |
| OSAtomicWrite(&psNewSyncCheckpoint->hEnqueuedCCBCount, 0); |
| psNewSyncCheckpoint->psSyncCheckpointFwObj->ui32FwRefCount = 0; |
| psNewSyncCheckpoint->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_ACTIVE; |
| psNewSyncCheckpoint->uiProcess = OSGetCurrentClientProcessIDKM(); |
| OSCachedMemSet(&psNewSyncCheckpoint->sDeferredFreeListNode, 0, sizeof(psNewSyncCheckpoint->sDeferredFreeListNode)); |
| |
| if (pszCheckpointName) |
| { |
| /* Copy over the checkpoint name annotation */ |
| OSStringLCopy(psNewSyncCheckpoint->azName, pszCheckpointName, PVRSRV_SYNC_NAME_LENGTH); |
| } |
| else |
| { |
| /* No sync checkpoint name annotation */ |
| psNewSyncCheckpoint->azName[0] = '\0'; |
| } |
| |
| /* Store sync checkpoint FW address in PRGXFWIF_UFO_ADDR struct */ |
| psNewSyncCheckpoint->sCheckpointUFOAddr.ui32Addr = SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psNewSyncCheckpoint); |
| |
| /* Assign unique ID to this sync checkpoint */ |
| psNewSyncCheckpoint->ui32UID = g_SyncCheckpointUID++; |
| |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, |
| "Allocated Sync Checkpoint %s (ID:%d, TL:%d, FirmwareVAddr = 0x%08x)", |
| psNewSyncCheckpoint->azName, |
| psNewSyncCheckpoint->ui32UID, psNewSyncCheckpoint->hTimeline, |
| psNewSyncCheckpoint->sCheckpointUFOAddr.ui32Addr); |
| |
| RGXSRV_HWPERF_ALLOC_SYNC_CP(psDevNode, psNewSyncCheckpoint->hTimeline, |
| OSGetCurrentClientProcessIDKM(), |
| hFence, |
| psNewSyncCheckpoint->ui32FWAddr, |
| psNewSyncCheckpoint->azName, |
| sizeof(psNewSyncCheckpoint->azName)); |
| |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_FULL_SYNC_TRACKING_ENABLED) |
| { |
| IMG_CHAR szChkptName[PVRSRV_SYNC_NAME_LENGTH]; |
| |
| if (pszCheckpointName) |
| { |
| /* Copy the checkpoint name annotation into a fixed-size array */ |
| OSStringLCopy(szChkptName, pszCheckpointName, PVRSRV_SYNC_NAME_LENGTH); |
| } |
| else |
| { |
| /* No checkpoint name annotation */ |
| szChkptName[0] = 0; |
| } |
| /* record this sync */ |
| eError = _SyncCheckpointRecordAdd(&psNewSyncCheckpoint->hRecord, |
| psNewSyncCheckpoint->psSyncCheckpointBlock, |
| psNewSyncCheckpoint->psSyncCheckpointBlock->ui32FirmwareAddr, |
| _SyncCheckpointGetOffset(psNewSyncCheckpoint), |
| psNewSyncCheckpoint->ui32UID, |
| OSStringNLength(szChkptName, PVRSRV_SYNC_NAME_LENGTH), |
| szChkptName, (PSYNC_CHECKPOINT)psNewSyncCheckpoint); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed to add sync checkpoint record \"%s\" (%s)", |
| __func__, |
| szChkptName, |
| PVRSRVGetErrorString(eError))); |
| psNewSyncCheckpoint->hRecord = NULL; |
| /* note the error but continue without affecting driver operation */ |
| } |
| } |
| |
| /* Add the sync checkpoint to the device list */ |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_add_to_head(&psDevNode->sSyncCheckpointSyncsList, |
| &psNewSyncCheckpoint->sListNode); |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| |
| *ppsSyncCheckpoint = (PSYNC_CHECKPOINT)psNewSyncCheckpoint; |
| |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s Exit(Ok), psNewSyncCheckpoint->ui32UID=%d <%p>", |
| __func__, |
| psNewSyncCheckpoint->ui32UID, |
| (void*)psNewSyncCheckpoint)); |
| #endif |
| return PVRSRV_OK; |
| |
| fail_raalloc: |
| OSLockDestroy(psNewSyncCheckpoint->hLock); |
| psNewSyncCheckpoint->hLock = NULL; |
| fail_create_checkpoint_lock: |
| OSFreeMem(psNewSyncCheckpoint); |
| fail_alloc: |
| return eError; |
| } |
| |
| static void SyncCheckpointUnref(_SYNC_CHECKPOINT *psSyncCheckpointInt) |
| { |
| _SYNC_CHECKPOINT_CONTEXT *psContext; |
| PVRSRV_DEVICE_NODE *psDevNode; |
| |
| psContext = psSyncCheckpointInt->psSyncCheckpointBlock->psContext; |
| psDevNode = (PVRSRV_DEVICE_NODE *)psContext->psDevNode; |
| |
| /* |
| * Without this reference, the context may be destroyed as soon |
| * as _FreeSyncCheckpoint is called, but the context is still |
| * needed when _CheckDeferredCleanupList is called at the end |
| * of this function. |
| */ |
| SyncCheckpointContextRef((PSYNC_CHECKPOINT_CONTEXT)psContext); |
| |
| PVR_ASSERT(psSyncCheckpointInt->ui32ValidationCheck == SYNC_CHECKPOINT_PATTERN_IN_USE); |
| 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 (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s No outstanding FW ops and hRef is zero, deleting SyncCheckpoint..", |
| __func__)); |
| #endif |
| if ((GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_FULL_SYNC_TRACKING_ENABLED) |
| && psSyncCheckpointInt->hRecord) |
| { |
| PVRSRV_ERROR eError; |
| /* remove this sync record */ |
| eError = _SyncCheckpointRecordRemove(psSyncCheckpointInt->hRecord); |
| PVR_LOG_IF_ERROR(eError, "_SyncCheckpointRecordRemove"); |
| } |
| |
| /* Remove the sync checkpoint from the global list */ |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_remove_node(&psSyncCheckpointInt->sListNode); |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| |
| RGXSRV_HWPERF_FREE(psDevNode, SYNC_CP, psSyncCheckpointInt->ui32FWAddr); |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| #if ((ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) || (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1)) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s attempting to return sync checkpoint to the pool", |
| __func__)); |
| #endif |
| if (!_PutCheckpointInPool(psSyncCheckpointInt)) |
| #endif |
| { |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| #if ((ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) || (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1)) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s pool is full, so just free it", |
| __func__)); |
| #endif |
| #endif |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s CALLING RA_Free(psSyncCheckpoint(ID:%d)<%p>), psSubAllocRA=<%p>, ui32SpanAddr=0x%llx", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt, |
| (void*)psSyncCheckpointInt->psSyncCheckpointBlock->psContext->psSubAllocRA, |
| psSyncCheckpointInt->uiSpanAddr)); |
| #endif |
| _FreeSyncCheckpoint(psSyncCheckpointInt); |
| } |
| } |
| else |
| { |
| #if ((ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) || (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1)) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s Outstanding FW ops hEnqueuedCCBCount=%d != FwObj->ui32FwRefCount=%d " |
| "- DEFERRING CLEANUP psSyncCheckpoint(ID:%d)<%p>", |
| __func__, |
| OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount), |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt)); |
| #endif |
| /* Add the sync checkpoint to the deferred free list */ |
| OSLockAcquire(psContext->psContextCtl->hDeferredCleanupListLock); |
| dllist_add_to_tail(&psContext->psContextCtl->sDeferredCleanupListHead, |
| &psSyncCheckpointInt->sDeferredFreeListNode); |
| OSLockRelease(psContext->psContextCtl->hDeferredCleanupListLock); |
| } |
| } |
| else |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint(ID:%d)<%p>, hRefCount decremented to %d", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt, |
| (IMG_UINT32)(OSAtomicRead(&psSyncCheckpointInt->hRefCount)))); |
| #endif |
| } |
| |
| /* See if any sync checkpoints in the deferred cleanup list can be freed */ |
| _CheckDeferredCleanupList(psContext); |
| |
| SyncCheckpointContextUnref((PSYNC_CHECKPOINT_CONTEXT)psContext); |
| } |
| |
| void SyncCheckpointFree(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid"); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s Entry, psSyncCheckpoint(ID:%d)<%p>, hRefCount=%d, psSyncCheckpoint->ui32ValidationCheck=0x%x", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpoint, |
| (IMG_UINT32)(OSAtomicRead(&psSyncCheckpointInt->hRefCount)), |
| psSyncCheckpointInt->ui32ValidationCheck)); |
| #endif |
| SyncCheckpointUnref(psSyncCheckpointInt); |
| } |
| |
| void |
| SyncCheckpointSignal(PSYNC_CHECKPOINT psSyncCheckpoint, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| _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_ACTIVE), |
| "psSyncCheckpoint already signalled"); |
| |
| if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ACTIVE) |
| { |
| #if defined(SUPPORT_RGX) |
| PVRSRV_RGXDEV_INFO *psDevInfo = psSyncCheckpointInt->psSyncCheckpointBlock->psDevNode->pvDevice; |
| |
| RGXSRVHWPerfSyncCheckpointUFOUpdate(psDevInfo, psSyncCheckpointInt, ui32FenceSyncFlags); |
| #endif |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_SIGNALLED; |
| |
| #if defined(PDUMP) |
| /* We may need to temporarily disable the posting of PDump events here, as the caller can be |
| * in interrupt context and PDUMPCOMMENTWITHFLAGS takes the PDUMP_LOCK mutex |
| */ |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, |
| "Signalled Sync Checkpoint %s (ID:%d, TL:%d, FirmwareVAddr = 0x%08x)", |
| psSyncCheckpointInt->azName, |
| psSyncCheckpointInt->ui32UID, psSyncCheckpointInt->hTimeline, |
| (psSyncCheckpointInt->psSyncCheckpointBlock->ui32FirmwareAddr + |
| _SyncCheckpointGetOffset(psSyncCheckpointInt))); |
| _SyncCheckpointSignalPDump(psSyncCheckpointInt); |
| #endif |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s asked to set PVRSRV_SYNC_CHECKPOINT_SIGNALLED(%d) for (psSyncCheckpointInt->ui32UID=%d), " |
| "when value is already %d", |
| __func__, |
| PVRSRV_SYNC_CHECKPOINT_SIGNALLED, |
| psSyncCheckpointInt->ui32UID, |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State)); |
| } |
| } |
| } |
| |
| void |
| SyncCheckpointSignalNoHW(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_ACTIVE), |
| "psSyncCheckpoint already signalled"); |
| |
| if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ACTIVE) |
| { |
| #if defined(SUPPORT_RGX) |
| PVRSRV_RGXDEV_INFO *psDevInfo = psSyncCheckpointInt->psSyncCheckpointBlock->psDevNode->pvDevice; |
| |
| RGXSRVHWPerfSyncCheckpointUFOUpdate(psDevInfo, psSyncCheckpointInt, PVRSRV_FENCE_FLAG_NONE); |
| #endif |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_SIGNALLED; |
| } |
| else |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s asked to set PVRSRV_SYNC_CHECKPOINT_SIGNALLED(%d) for (psSyncCheckpointInt->ui32UID=%d), " |
| "when value is already %d", |
| __func__, |
| PVRSRV_SYNC_CHECKPOINT_SIGNALLED, |
| psSyncCheckpointInt->ui32UID, |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State)); |
| #endif |
| } |
| } |
| } |
| |
| void |
| SyncCheckpointError(PSYNC_CHECKPOINT psSyncCheckpoint, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| _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_ACTIVE), |
| "psSyncCheckpoint already signalled"); |
| |
| if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ACTIVE) |
| { |
| #if defined(SUPPORT_RGX) |
| if (!(ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_SUPPRESS_HWP_PKT)) |
| { |
| RGX_HWPERF_UFO_DATA_ELEMENT sSyncData; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psSyncCheckpointInt->psSyncCheckpointBlock->psDevNode->pvDevice; |
| |
| sSyncData.sUpdate.ui32FWAddr = SyncCheckpointGetFirmwareAddr(psSyncCheckpoint); |
| sSyncData.sUpdate.ui32OldValue = psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State; |
| sSyncData.sUpdate.ui32NewValue = PVRSRV_SYNC_CHECKPOINT_ERRORED; |
| |
| RGXSRV_HWPERF_UFO(psDevInfo, RGX_HWPERF_UFO_EV_UPDATE, &sSyncData, |
| (ui32FenceSyncFlags & PVRSRV_FENCE_FLAG_CTX_ATOMIC) ? IMG_FALSE : IMG_TRUE); |
| } |
| #endif |
| |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_ERRORED; |
| |
| #if defined(PDUMP) |
| /* We may need to temporarily disable the posting of PDump events here, as the caller can be |
| * in interrupt context and PDUMPCOMMENTWITHFLAGS takes the PDUMP_LOCK mutex |
| */ |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, |
| "Errored Sync Checkpoint %s (ID:%d, TL:%d, FirmwareVAddr = 0x%08x)", |
| psSyncCheckpointInt->azName, |
| psSyncCheckpointInt->ui32UID, psSyncCheckpointInt->hTimeline, |
| (psSyncCheckpointInt->psSyncCheckpointBlock->ui32FirmwareAddr + |
| _SyncCheckpointGetOffset(psSyncCheckpointInt))); |
| _SyncCheckpointErrorPDump(psSyncCheckpointInt); |
| #endif |
| } |
| } |
| } |
| |
| IMG_BOOL SyncCheckpointIsSignalled(PSYNC_CHECKPOINT psSyncCheckpoint, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| IMG_BOOL bRet = IMG_FALSE; |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid"); |
| |
| if (psSyncCheckpointInt) |
| { |
| #if defined(SUPPORT_RGX) |
| PVRSRV_RGXDEV_INFO *psDevInfo = psSyncCheckpointInt->psSyncCheckpointBlock->psDevNode->pvDevice; |
| |
| RGXSRVHWPerfSyncCheckpointUFOIsSignalled(psDevInfo, psSyncCheckpointInt, ui32FenceSyncFlags); |
| #endif |
| bRet = ((psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) || |
| (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ERRORED)); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called for psSyncCheckpoint<%p>, returning %d", |
| __func__, |
| (void*)psSyncCheckpoint, |
| bRet)); |
| #endif |
| } |
| return bRet; |
| } |
| |
| IMG_BOOL |
| SyncCheckpointIsErrored(PSYNC_CHECKPOINT psSyncCheckpoint, IMG_UINT32 ui32FenceSyncFlags) |
| { |
| IMG_BOOL bRet = IMG_FALSE; |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid"); |
| |
| if (psSyncCheckpointInt) |
| { |
| #if defined(SUPPORT_RGX) |
| PVRSRV_RGXDEV_INFO *psDevInfo = psSyncCheckpointInt->psSyncCheckpointBlock->psDevNode->pvDevice; |
| |
| RGXSRVHWPerfSyncCheckpointUFOIsSignalled(psDevInfo, psSyncCheckpointInt, ui32FenceSyncFlags); |
| #endif |
| bRet = (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State == PVRSRV_SYNC_CHECKPOINT_ERRORED); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called for psSyncCheckpoint<%p>, returning %d", |
| __func__, |
| (void*)psSyncCheckpoint, |
| bRet)); |
| #endif |
| } |
| return bRet; |
| } |
| |
| const IMG_CHAR * |
| SyncCheckpointGetStateString(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOGR_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", "Null"); |
| |
| switch (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State) |
| { |
| case PVRSRV_SYNC_CHECKPOINT_SIGNALLED: |
| return "Signalled"; |
| case PVRSRV_SYNC_CHECKPOINT_ACTIVE: |
| return "Active"; |
| case PVRSRV_SYNC_CHECKPOINT_ERRORED: |
| return "Errored"; |
| case PVRSRV_SYNC_CHECKPOINT_UNDEF: |
| return "Undefined"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| 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); |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s called for psSyncCheckpoint<%p> %d->%d (FWRef %u)", |
| __func__, |
| psSyncCheckpointInt, |
| OSAtomicRead(&psSyncCheckpointInt->hRefCount), |
| OSAtomicRead(&psSyncCheckpointInt->hRefCount)+1, |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount)); |
| #endif |
| OSAtomicIncrement(&psSyncCheckpointInt->hRefCount); |
| |
| return eRet; |
| } |
| |
| 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); |
| #if (ENABLE_SYNC_CHECKPOINT_ALLOC_AND_FREE_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s called for psSyncCheckpoint<%p> %d->%d (FWRef %u)", |
| __func__, |
| psSyncCheckpointInt, |
| OSAtomicRead(&psSyncCheckpointInt->hRefCount), |
| OSAtomicRead(&psSyncCheckpointInt->hRefCount)-1, |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount)); |
| #endif |
| SyncCheckpointUnref(psSyncCheckpointInt); |
| |
| return eRet; |
| } |
| |
| void |
| SyncCheckpointCCBEnqueued(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid"); |
| |
| if (psSyncCheckpointInt) |
| { |
| #if !defined(NO_HARDWARE) |
| #if (ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s called for psSyncCheckpoint<%p> %d->%d (FWRef %u)", |
| __func__, |
| (void*)psSyncCheckpoint, |
| OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount), |
| OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount)+1, |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount)); |
| #endif |
| OSAtomicIncrement(&psSyncCheckpointInt->hEnqueuedCCBCount); |
| #endif |
| } |
| } |
| |
| PRGXFWIF_UFO_ADDR* |
| SyncCheckpointGetRGXFWIFUFOAddr(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| PVR_LOGG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", invalid_chkpt); |
| |
| if (psSyncCheckpointInt) |
| { |
| if (psSyncCheckpointInt->ui32ValidationCheck == SYNC_CHECKPOINT_PATTERN_IN_USE) |
| { |
| return &psSyncCheckpointInt->sCheckpointUFOAddr; |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s called for psSyncCheckpoint<%p>, but ui32ValidationCheck=0x%x", |
| __func__, |
| (void*)psSyncCheckpoint, |
| psSyncCheckpointInt->ui32ValidationCheck)); |
| } |
| } |
| |
| invalid_chkpt: |
| return NULL; |
| } |
| |
| IMG_UINT32 |
| SyncCheckpointGetFirmwareAddr(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| IMG_UINT32 ui32Ret = 0; |
| |
| PVR_LOGG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", invalid_chkpt); |
| |
| if (psSyncCheckpointInt) |
| { |
| if (psSyncCheckpointInt->ui32ValidationCheck == SYNC_CHECKPOINT_PATTERN_IN_USE) |
| { |
| ui32Ret = psSyncCheckpointInt->ui32FWAddr; |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s called for psSyncCheckpoint<%p>, but ui32ValidationCheck=0x%x", |
| __func__, |
| (void*)psSyncCheckpoint, |
| psSyncCheckpointInt->ui32ValidationCheck)); |
| } |
| } |
| |
| invalid_chkpt: |
| return ui32Ret; |
| } |
| |
| IMG_UINT32 |
| SyncCheckpointGetId(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| IMG_UINT32 ui32Ret = 0; |
| |
| PVR_LOGG_IF_FALSE((psSyncCheckpoint != NULL), "psSyncCheckpoint invalid", invalid_chkpt); |
| |
| if (psSyncCheckpointInt) |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s returning ID for sync checkpoint<%p>", |
| __func__, |
| (void*)psSyncCheckpointInt)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s (validationCheck=0x%x)", |
| __func__, |
| psSyncCheckpointInt->ui32ValidationCheck)); |
| #endif |
| ui32Ret = psSyncCheckpointInt->ui32UID; |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s (ui32UID=0x%x)", |
| __func__, |
| psSyncCheckpointInt->ui32UID)); |
| #endif |
| } |
| return ui32Ret; |
| |
| invalid_chkpt: |
| return 0; |
| } |
| |
| PVRSRV_TIMELINE |
| SyncCheckpointGetTimeline(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| PVRSRV_TIMELINE i32Ret = PVRSRV_NO_TIMELINE; |
| |
| PVR_LOGG_IF_FALSE((psSyncCheckpoint != NULL), |
| "psSyncCheckpoint invalid", |
| invalid_chkpt); |
| |
| if (psSyncCheckpointInt) |
| { |
| i32Ret = psSyncCheckpointInt->hTimeline; |
| } |
| return i32Ret; |
| |
| invalid_chkpt: |
| return 0; |
| } |
| |
| |
| IMG_UINT32 |
| SyncCheckpointGetEnqueuedCount(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| PVR_LOGR_IF_FALSE(psSyncCheckpoint != NULL, "psSyncCheckpoint invalid", 0); |
| |
| return OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount); |
| } |
| |
| IMG_UINT32 |
| SyncCheckpointGetReferenceCount(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| PVR_LOGR_IF_FALSE(psSyncCheckpoint != NULL, "psSyncCheckpoint invalid", 0); |
| |
| return OSAtomicRead(&psSyncCheckpointInt->hRefCount); |
| } |
| |
| IMG_PID |
| SyncCheckpointGetCreator(PSYNC_CHECKPOINT psSyncCheckpoint) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| PVR_LOGR_IF_FALSE(psSyncCheckpoint != NULL, "psSyncCheckpoint invalid", 0); |
| |
| return psSyncCheckpointInt->uiProcess; |
| } |
| |
| IMG_UINT32 SyncCheckpointStateFromUFO(PPVRSRV_DEVICE_NODE psDevNode, |
| IMG_UINT32 ui32FwAddr) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt; |
| PDLLIST_NODE psNode, psNext; |
| IMG_UINT32 ui32State = 0; |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointSyncsList, psNode, psNext) |
| { |
| psSyncCheckpointInt = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode); |
| if (ui32FwAddr == SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt)) |
| { |
| ui32State = psSyncCheckpointInt->psSyncCheckpointFwObj->ui32State; |
| break; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| return ui32State; |
| } |
| |
| void SyncCheckpointErrorFromUFO(PPVRSRV_DEVICE_NODE psDevNode, |
| IMG_UINT32 ui32FwAddr) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt; |
| PDLLIST_NODE psNode, psNext; |
| |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called to error UFO with ui32FWAddr=%d", |
| __func__, |
| ui32FwAddr)); |
| #endif |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointSyncsList, psNode, psNext) |
| { |
| psSyncCheckpointInt = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode); |
| if (ui32FwAddr == SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt)) |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s calling SyncCheckpointError for sync checkpoint <%p>", |
| __func__, |
| (void*)psSyncCheckpointInt)); |
| #endif |
| /* Mark as errored */ |
| SyncCheckpointError((PSYNC_CHECKPOINT)psSyncCheckpointInt, IMG_TRUE); |
| break; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| } |
| |
| void SyncCheckpointRollbackFromUFO(PPVRSRV_DEVICE_NODE psDevNode, IMG_UINT32 ui32FwAddr) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = NULL; |
| PDLLIST_NODE psNode = NULL, psNext = NULL; |
| |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called to rollback UFO with ui32FWAddr=0x%x", |
| __func__, |
| ui32FwAddr)); |
| #endif |
| #if !defined(NO_HARDWARE) |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointSyncsList, psNode, psNext) |
| { |
| psSyncCheckpointInt = IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sListNode); |
| if (ui32FwAddr == SyncCheckpointGetFirmwareAddr((PSYNC_CHECKPOINT)psSyncCheckpointInt)) |
| { |
| #if ((ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1)) || (ENABLE_SYNC_CHECKPOINT_ENQ_AND_SIGNAL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s called for psSyncCheckpointInt<%p> %d->%d", |
| __func__, |
| (void*)psSyncCheckpointInt, |
| OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount), |
| OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount)-1)); |
| #endif |
| OSAtomicDecrement(&psSyncCheckpointInt->hEnqueuedCCBCount); |
| break; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| #else |
| PVR_UNREFERENCED_PARAMETER(psNode); |
| PVR_UNREFERENCED_PARAMETER(psNext); |
| PVR_UNREFERENCED_PARAMETER(psSyncCheckpointInt); |
| #endif |
| } |
| |
| #if defined(PVRSRV_SYNC_CHECKPOINT_CCB) |
| IMG_BOOL SyncCheckpointUFOHasSignalled(PPVRSRV_DEVICE_NODE psDevNode, IMG_UINT32 ui32FwAddr, IMG_UINT32 ui32Value) |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_UFO_DEBUG == 1) |
| PVR_LOG(("%s called because UFO with ui32FWAddr=%#08x has set to %#04x", |
| __func__, |
| ui32FwAddr, |
| ui32Value)); |
| #endif |
| |
| if (g_psSyncCheckpointPfnStruct->pfnCheckpointHasSignalled) |
| { |
| return g_psSyncCheckpointPfnStruct->pfnCheckpointHasSignalled(ui32FwAddr, ui32Value); |
| } |
| else |
| { |
| return IMG_FALSE; |
| } |
| } |
| |
| void |
| SyncCheckpointCheckState(void) |
| { |
| if (g_psSyncCheckpointPfnStruct->pfnCheckState) |
| { |
| g_psSyncCheckpointPfnStruct->pfnCheckState(); |
| } |
| } |
| |
| void |
| SyncCheckpointSignalWaiters(void) |
| { |
| if (g_psSyncCheckpointPfnStruct->pfnSignalWaiters) |
| { |
| PVRSRV_ERROR eError = g_psSyncCheckpointPfnStruct->pfnSignalWaiters(); |
| PVR_LOG_IF_ERROR(eError, __func__); |
| } |
| } |
| #endif /* defined(PVRSRV_SYNC_CHECKPOINT_CCB) */ |
| |
| 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_ACTIVE) |
| { |
| PVR_DUMPDEBUG_LOG("\t- ID = %d, FWAddr = 0x%08x, r%d:e%d:f%d: %s", |
| psSyncCheckpoint->ui32UID, |
| psSyncCheckpoint->psSyncCheckpointBlock->ui32FirmwareAddr + |
| _SyncCheckpointGetOffset(psSyncCheckpoint), |
| OSAtomicRead(&psSyncCheckpoint->hRefCount), |
| OSAtomicRead(&psSyncCheckpoint->hEnqueuedCCBCount), |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32FwRefCount, |
| psSyncCheckpoint->azName); |
| } |
| } |
| |
| static void _SyncCheckpointDebugRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle, |
| IMG_UINT32 ui32VerbLevel, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile) |
| { |
| PVRSRV_DEVICE_NODE *psDevNode = (PVRSRV_DEVICE_NODE *)hDebugRequestHandle; |
| DLLIST_NODE *psNode, *psNext; |
| |
| if (DD_VERB_LVL_ENABLED(ui32VerbLevel, DEBUG_REQUEST_VERBOSITY_MEDIUM)) |
| { |
| PVR_DUMPDEBUG_LOG("------[ Active Sync Checkpoints ]------"); |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointSyncsList, psNode, psNext) |
| { |
| _SyncCheckpointState(psNode, pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| } |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointInit(PPVRSRV_DEVICE_NODE psDevNode) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!gbSyncCheckpointInit) |
| { |
| eError = OSLockCreate(&psDevNode->hSyncCheckpointListLock); |
| if (eError == PVRSRV_OK) |
| { |
| dllist_init(&psDevNode->sSyncCheckpointSyncsList); |
| |
| eError = PVRSRVRegisterDbgRequestNotify(&psDevNode->hSyncCheckpointNotify, |
| psDevNode, |
| _SyncCheckpointDebugRequest, |
| DEBUG_REQUEST_SYNCCHECKPOINT, |
| (PVRSRV_DBGREQ_HANDLE)psDevNode); |
| if (eError == PVRSRV_OK) |
| { |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_FULL_SYNC_TRACKING_ENABLED) |
| { |
| _SyncCheckpointRecordListInit(psDevNode); |
| } |
| gbSyncCheckpointInit = IMG_TRUE; |
| } |
| else |
| { |
| /* free the created lock */ |
| OSLockDestroy(psDevNode->hSyncCheckpointListLock); |
| psDevNode->hSyncCheckpointListLock = NULL; |
| } |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s FAILED to create psDevNode->hSyncCheckpointListLock", |
| __func__)); |
| } |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s called but already initialised", __func__)); |
| } |
| return eError; |
| } |
| |
| void SyncCheckpointDeinit(PPVRSRV_DEVICE_NODE psDevNode) |
| { |
| PVRSRVUnregisterDbgRequestNotify(psDevNode->hSyncCheckpointNotify); |
| psDevNode->hSyncCheckpointNotify = NULL; |
| OSLockDestroy(psDevNode->hSyncCheckpointListLock); |
| psDevNode->hSyncCheckpointListLock = NULL; |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_FULL_SYNC_TRACKING_ENABLED) |
| { |
| _SyncCheckpointRecordListDeinit(psDevNode); |
| } |
| gbSyncCheckpointInit = IMG_FALSE; |
| } |
| |
| void SyncCheckpointRecordLookup(PPVRSRV_DEVICE_NODE psDevNode, IMG_UINT32 ui32FwAddr, |
| IMG_CHAR * pszSyncInfo, size_t len) |
| { |
| DLLIST_NODE *psNode, *psNext; |
| IMG_BOOL bFound = IMG_FALSE; |
| |
| if (!pszSyncInfo) |
| { |
| return; |
| } |
| |
| pszSyncInfo[0] = '\0'; |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointRecordLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointRecordList, psNode, psNext) |
| { |
| struct SYNC_CHECKPOINT_RECORD *psSyncCheckpointRec = |
| IMG_CONTAINER_OF(psNode, struct SYNC_CHECKPOINT_RECORD, sNode); |
| if ((psSyncCheckpointRec->ui32FwBlockAddr + psSyncCheckpointRec->ui32SyncOffset + 1) == ui32FwAddr) |
| { |
| SYNC_CHECKPOINT_BLOCK *psSyncCheckpointBlock = psSyncCheckpointRec->psSyncCheckpointBlock; |
| if (psSyncCheckpointBlock && psSyncCheckpointBlock->pui32LinAddr) |
| { |
| void *pSyncCheckpointAddr = (void*)( ((IMG_BYTE*) |
| psSyncCheckpointBlock->pui32LinAddr) + psSyncCheckpointRec->ui32SyncOffset); |
| OSSNPrintf(pszSyncInfo, len, "%s Checkpoint:%05u (%s)", |
| (*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) ? |
| "SIGNALLED" : |
| ((*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_ERRORED) ? |
| "ERRORED" : "ACTIVE"), |
| psSyncCheckpointRec->uiPID, |
| psSyncCheckpointRec->szClassName); |
| } |
| else |
| { |
| OSSNPrintf(pszSyncInfo, len, "Checkpoint:%05u (%s)", |
| psSyncCheckpointRec->uiPID, |
| psSyncCheckpointRec->szClassName); |
| } |
| |
| bFound = IMG_TRUE; |
| break; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointRecordLock); |
| |
| if (!bFound && (psDevNode->ui32SyncCheckpointRecordCountHighWatermark == SYNC_CHECKPOINT_RECORD_LIMIT)) |
| { |
| OSSNPrintf(pszSyncInfo, len, "(Record may be lost)"); |
| } |
| } |
| |
| static PVRSRV_ERROR |
| _SyncCheckpointRecordAdd( |
| PSYNC_CHECKPOINT_RECORD_HANDLE * phRecord, |
| SYNC_CHECKPOINT_BLOCK *hSyncCheckpointBlock, |
| IMG_UINT32 ui32FwBlockAddr, |
| IMG_UINT32 ui32SyncOffset, |
| IMG_UINT32 ui32UID, |
| IMG_UINT32 ui32ClassNameSize, |
| const IMG_CHAR *pszClassName, PSYNC_CHECKPOINT pSyncCheckpt) |
| { |
| struct SYNC_CHECKPOINT_RECORD * psSyncRec; |
| _SYNC_CHECKPOINT_CONTEXT *psContext = hSyncCheckpointBlock->psContext; |
| PVRSRV_DEVICE_NODE *psDevNode = psContext->psDevNode; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (!phRecord) |
| { |
| return PVRSRV_ERROR_INVALID_PARAMS; |
| } |
| |
| *phRecord = NULL; |
| |
| psSyncRec = OSAllocMem(sizeof(*psSyncRec)); |
| PVR_LOGG_IF_NOMEM(psSyncRec, "OSAllocMem", eError, fail_alloc); /* Sets OOM error code */ |
| |
| psSyncRec->psDevNode = psDevNode; |
| psSyncRec->psSyncCheckpointBlock = hSyncCheckpointBlock; |
| psSyncRec->ui32SyncOffset = ui32SyncOffset; |
| psSyncRec->ui32FwBlockAddr = ui32FwBlockAddr; |
| psSyncRec->ui64OSTime = OSClockns64(); |
| psSyncRec->uiPID = OSGetCurrentProcessID(); |
| psSyncRec->ui32UID = ui32UID; |
| psSyncRec->pSyncCheckpt = pSyncCheckpt; |
| if (pszClassName) |
| { |
| if (ui32ClassNameSize >= PVRSRV_SYNC_NAME_LENGTH) |
| ui32ClassNameSize = PVRSRV_SYNC_NAME_LENGTH; |
| /* Copy over the class name annotation */ |
| OSStringLCopy(psSyncRec->szClassName, pszClassName, ui32ClassNameSize); |
| } |
| else |
| { |
| /* No class name annotation */ |
| psSyncRec->szClassName[0] = 0; |
| } |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointRecordLock); |
| if (psDevNode->ui32SyncCheckpointRecordCount < SYNC_CHECKPOINT_RECORD_LIMIT) |
| { |
| dllist_add_to_head(&psDevNode->sSyncCheckpointRecordList, &psSyncRec->sNode); |
| psDevNode->ui32SyncCheckpointRecordCount++; |
| |
| if (psDevNode->ui32SyncCheckpointRecordCount > psDevNode->ui32SyncCheckpointRecordCountHighWatermark) |
| { |
| psDevNode->ui32SyncCheckpointRecordCountHighWatermark = psDevNode->ui32SyncCheckpointRecordCount; |
| } |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed to add sync checkpoint record \"%s\". %u records already exist.", |
| __func__, |
| pszClassName, |
| psDevNode->ui32SyncCheckpointRecordCount)); |
| OSFreeMem(psSyncRec); |
| psSyncRec = NULL; |
| eError = PVRSRV_ERROR_TOOMANYBUFFERS; |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointRecordLock); |
| |
| *phRecord = (PSYNC_CHECKPOINT_RECORD_HANDLE)psSyncRec; |
| |
| fail_alloc: |
| return eError; |
| } |
| |
| static PVRSRV_ERROR |
| _SyncCheckpointRecordRemove(PSYNC_CHECKPOINT_RECORD_HANDLE hRecord) |
| { |
| struct SYNC_CHECKPOINT_RECORD **ppFreedSync; |
| struct SYNC_CHECKPOINT_RECORD *pSync = (struct SYNC_CHECKPOINT_RECORD*)hRecord; |
| PVRSRV_DEVICE_NODE *psDevNode; |
| |
| if (!hRecord) |
| { |
| return PVRSRV_ERROR_INVALID_PARAMS; |
| } |
| |
| psDevNode = pSync->psDevNode; |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointRecordLock); |
| |
| dllist_remove_node(&pSync->sNode); |
| |
| if (psDevNode->uiSyncCheckpointRecordFreeIdx >= PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: psDevNode->uiSyncCheckpointRecordFreeIdx out of range", |
| __func__)); |
| psDevNode->uiSyncCheckpointRecordFreeIdx = 0; |
| } |
| ppFreedSync = &psDevNode->apsSyncCheckpointRecordsFreed[psDevNode->uiSyncCheckpointRecordFreeIdx]; |
| psDevNode->uiSyncCheckpointRecordFreeIdx = |
| (psDevNode->uiSyncCheckpointRecordFreeIdx + 1) % PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN; |
| |
| if (*ppFreedSync) |
| { |
| OSFreeMem(*ppFreedSync); |
| } |
| pSync->psSyncCheckpointBlock = NULL; |
| pSync->ui64OSTime = OSClockns64(); |
| *ppFreedSync = pSync; |
| |
| psDevNode->ui32SyncCheckpointRecordCount--; |
| |
| OSLockRelease(psDevNode->hSyncCheckpointRecordLock); |
| |
| 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 *psSyncCheckpoint = (_SYNC_CHECKPOINT *)psSyncCheckpointRec->pSyncCheckpt; |
| 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*)( ((IMG_BYTE*) psSyncCheckpointBlock->pui32LinAddr) + psSyncCheckpointRec->ui32SyncOffset); |
| |
| PVR_DUMPDEBUG_LOG("\t%05u %05" IMG_UINT64_FMTSPEC ".%09u %010u FWAddr=0x%08x (r%d:e%d:f%d) State=%s (%s)", |
| psSyncCheckpointRec->uiPID, |
| ui64DeltaS, ui32DeltaF,psSyncCheckpointRec->ui32UID, |
| (psSyncCheckpointRec->ui32FwBlockAddr+psSyncCheckpointRec->ui32SyncOffset), |
| OSAtomicRead(&psSyncCheckpoint->hRefCount), |
| OSAtomicRead(&psSyncCheckpoint->hEnqueuedCCBCount), |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32FwRefCount, |
| (*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_SIGNALLED) ? |
| "SIGNALLED" : |
| ((*(IMG_UINT32*)pSyncCheckpointAddr == PVRSRV_SYNC_CHECKPOINT_ERRORED) ? |
| "ERRORED" : "ACTIVE"), |
| psSyncCheckpointRec->szClassName); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("\t%05u %05" IMG_UINT64_FMTSPEC ".%09u %010u FWAddr=0x%08x State=<null_ptr> (%s)", |
| psSyncCheckpointRec->uiPID, |
| ui64DeltaS, ui32DeltaF, psSyncCheckpointRec->ui32UID, |
| (psSyncCheckpointRec->ui32FwBlockAddr+psSyncCheckpointRec->ui32SyncOffset), |
| psSyncCheckpointRec->szClassName |
| ); |
| } |
| } |
| |
| static void _SyncCheckpointRecordRequest(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle, |
| IMG_UINT32 ui32VerbLevel, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile) |
| { |
| PVRSRV_DEVICE_NODE *psDevNode = (PVRSRV_DEVICE_NODE *)hDebugRequestHandle; |
| IMG_UINT64 ui64TimeNowS; |
| IMG_UINT32 ui32TimeNowF; |
| IMG_UINT64 ui64TimeNow = OSClockns64(); |
| DLLIST_NODE *psNode, *psNext; |
| |
| ui64TimeNowS = OSDivide64(ui64TimeNow, NS_IN_S, &ui32TimeNowF); |
| |
| if (DD_VERB_LVL_ENABLED(ui32VerbLevel, DEBUG_REQUEST_VERBOSITY_MEDIUM)) |
| { |
| IMG_UINT32 i; |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointRecordLock); |
| |
| PVR_DUMPDEBUG_LOG("Dumping allocated sync checkpoints. Allocated: %u High watermark: %u (time ref %05" IMG_UINT64_FMTSPEC ".%09u)", |
| psDevNode->ui32SyncCheckpointRecordCount, |
| psDevNode->ui32SyncCheckpointRecordCountHighWatermark, |
| ui64TimeNowS, |
| ui32TimeNowF); |
| if (psDevNode->ui32SyncCheckpointRecordCountHighWatermark == SYNC_CHECKPOINT_RECORD_LIMIT) |
| { |
| PVR_DUMPDEBUG_LOG("Warning: Record limit (%u) was reached. Some sync checkpoints may not have been recorded in the debug information.", |
| SYNC_CHECKPOINT_RECORD_LIMIT); |
| } |
| PVR_DUMPDEBUG_LOG("\t%-5s %-15s %-10s %-17s %-14s (%s)", |
| "PID", "Time Delta (s)", "UID", "Address", "State", "Annotation"); |
| |
| dllist_foreach_node(&psDevNode->sSyncCheckpointRecordList, 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 @ %05" IMG_UINT64_FMTSPEC ".%09u", |
| ui64TimeNowS, |
| ui32TimeNowF); |
| PVR_DUMPDEBUG_LOG("\t%-5s %-15s %-10s %-17s %-14s (%s)", |
| "PID", "Time Delta (s)", "UID", "Address", "State", "Annotation"); |
| for (i = DECREMENT_WITH_WRAP(psDevNode->uiSyncCheckpointRecordFreeIdx, PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN); |
| i != psDevNode->uiSyncCheckpointRecordFreeIdx; |
| i = DECREMENT_WITH_WRAP(i, PVRSRV_FULL_SYNC_TRACKING_HISTORY_LEN)) |
| { |
| if (psDevNode->apsSyncCheckpointRecordsFreed[i]) |
| { |
| _SyncCheckpointRecordPrint(psDevNode->apsSyncCheckpointRecordsFreed[i], |
| ui64TimeNow, pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| else |
| { |
| break; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointRecordLock); |
| } |
| } |
| #undef NS_IN_S |
| static PVRSRV_ERROR _SyncCheckpointRecordListInit(PVRSRV_DEVICE_NODE *psDevNode) |
| { |
| PVRSRV_ERROR eError; |
| |
| eError = OSLockCreate(&psDevNode->hSyncCheckpointRecordLock); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_lock_create; |
| } |
| dllist_init(&psDevNode->sSyncCheckpointRecordList); |
| |
| psDevNode->ui32SyncCheckpointRecordCount = 0; |
| psDevNode->ui32SyncCheckpointRecordCountHighWatermark = 0; |
| |
| eError = PVRSRVRegisterDbgRequestNotify(&psDevNode->hSyncCheckpointRecordNotify, |
| psDevNode, |
| _SyncCheckpointRecordRequest, |
| DEBUG_REQUEST_SYNCCHECKPOINT, |
| (PVRSRV_DBGREQ_HANDLE)psDevNode); |
| |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_dbg_register; |
| } |
| |
| return PVRSRV_OK; |
| |
| fail_dbg_register: |
| OSLockDestroy(psDevNode->hSyncCheckpointRecordLock); |
| fail_lock_create: |
| return eError; |
| } |
| |
| static void _SyncCheckpointRecordListDeinit(PVRSRV_DEVICE_NODE *psDevNode) |
| { |
| DLLIST_NODE *psNode, *psNext; |
| int i; |
| |
| OSLockAcquire(psDevNode->hSyncCheckpointRecordLock); |
| dllist_foreach_node(&psDevNode->sSyncCheckpointRecordList, 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 (psDevNode->apsSyncCheckpointRecordsFreed[i]) |
| { |
| OSFreeMem(psDevNode->apsSyncCheckpointRecordsFreed[i]); |
| psDevNode->apsSyncCheckpointRecordsFreed[i] = NULL; |
| } |
| } |
| OSLockRelease(psDevNode->hSyncCheckpointRecordLock); |
| |
| if (psDevNode->hSyncCheckpointRecordNotify) |
| { |
| PVRSRVUnregisterDbgRequestNotify(psDevNode->hSyncCheckpointRecordNotify); |
| } |
| OSLockDestroy(psDevNode->hSyncCheckpointRecordLock); |
| } |
| |
| PVRSRV_ERROR |
| SyncCheckpointPDumpPol(PSYNC_CHECKPOINT psSyncCheckpoint, PDUMP_FLAGS_T ui32PDumpFlags) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = (_SYNC_CHECKPOINT*)psSyncCheckpoint; |
| |
| DevmemPDumpDevmemPol32(psSyncCheckpointInt->psSyncCheckpointBlock->hMemDesc, |
| _SyncCheckpointGetOffset(psSyncCheckpointInt), |
| PVRSRV_SYNC_CHECKPOINT_SIGNALLED, |
| 0xFFFFFFFF, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| ui32PDumpFlags); |
| return PVRSRV_OK; |
| } |
| |
| #if defined(PDUMP) |
| static 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; |
| } |
| |
| static 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 |
| |
| static void _CheckDeferredCleanupList(_SYNC_CHECKPOINT_CONTEXT *psContext) |
| { |
| DLLIST_NODE *psNode, *psNext; |
| PVRSRV_DEVICE_NODE *psDevNode = (PVRSRV_DEVICE_NODE*)psContext->psDevNode; |
| |
| /* Check the deferred cleanup list and free any sync checkpoints we can */ |
| OSLockAcquire(psContext->psContextCtl->hDeferredCleanupListLock); |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s called", __func__)); |
| #endif |
| |
| if (dllist_is_empty(&psContext->psContextCtl->sDeferredCleanupListHead)) |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s: Defer free list is empty", __func__)); |
| #endif |
| } |
| |
| dllist_foreach_node(&psContext->psContextCtl->sDeferredCleanupListHead, psNode, psNext) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = |
| IMG_CONTAINER_OF(psNode, _SYNC_CHECKPOINT, sDeferredFreeListNode); |
| |
| if (psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount == |
| (IMG_UINT32)(OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount))) |
| { |
| if ((GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_FULL_SYNC_TRACKING_ENABLED) |
| && psSyncCheckpointInt->hRecord) |
| { |
| PVRSRV_ERROR eError; |
| /* remove this sync record */ |
| eError = _SyncCheckpointRecordRemove(psSyncCheckpointInt->hRecord); |
| PVR_LOG_IF_ERROR(eError, "_SyncCheckpointRecordRemove"); |
| } |
| |
| /* Remove the sync checkpoint from the deferred free list */ |
| dllist_remove_node(&psSyncCheckpointInt->sDeferredFreeListNode); |
| |
| /* Remove the sync checkpoint from the global list */ |
| OSLockAcquire(psDevNode->hSyncCheckpointListLock); |
| dllist_remove_node(&psSyncCheckpointInt->sListNode); |
| OSLockRelease(psDevNode->hSyncCheckpointListLock); |
| |
| RGXSRV_HWPERF_FREE(psDevNode, SYNC_CP, psSyncCheckpointInt->ui32FWAddr); |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s attempting to return sync(ID:%d),%p> to pool", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt)); |
| #endif |
| if (!_PutCheckpointInPool(psSyncCheckpointInt)) |
| #endif |
| { |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s pool is full, so just free it", __func__)); |
| #endif |
| #endif |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s CALLING RA_Free(psSyncCheckpoint(ID:%d)<%p>), " |
| "psSubAllocRA=<%p>, ui32SpanAddr=0x%llx", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt, |
| (void*)psSyncCheckpointInt->psSyncCheckpointBlock->psContext->psSubAllocRA, |
| psSyncCheckpointInt->uiSpanAddr)); |
| #endif |
| _FreeSyncCheckpoint(psSyncCheckpointInt); |
| } |
| } |
| #if (ENABLE_SYNC_CHECKPOINT_DEFERRED_CLEANUP_DEBUG == 1) |
| else |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint '%s'' (ID:%d)<%p>), still pending (enq=%d,FWRef=%d)", |
| __func__, |
| psSyncCheckpointInt->azName, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt, |
| (IMG_UINT32)(OSAtomicRead(&psSyncCheckpointInt->hEnqueuedCCBCount)), |
| psSyncCheckpointInt->psSyncCheckpointFwObj->ui32FwRefCount)); |
| } |
| #endif |
| } |
| OSLockRelease(psContext->psContextCtl->hDeferredCleanupListLock); |
| } |
| |
| #if (SYNC_CHECKPOINT_POOL_SIZE > 0) |
| static _SYNC_CHECKPOINT *_GetCheckpointFromPool(_SYNC_CHECKPOINT_CONTEXT *psContext) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpoint = NULL; |
| |
| /* Acquire sync checkpoint pool lock */ |
| OSLockAcquire(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| /* Check if we can allocate from the pool */ |
| if (psContext->psContextCtl->bSyncCheckpointPoolValid && |
| (psContext->psContextCtl->ui32SyncCheckpointPoolCount > SYNC_CHECKPOINT_POOL_SEDIMENT) && |
| (psContext->psContextCtl->ui32SyncCheckpointPoolWp != psContext->psContextCtl->ui32SyncCheckpointPoolRp)) |
| { |
| /* Get the next sync checkpoint from the pool */ |
| psSyncCheckpoint = psContext->psContextCtl->psSyncCheckpointPool[psContext->psContextCtl->ui32SyncCheckpointPoolRp++]; |
| if (psContext->psContextCtl->ui32SyncCheckpointPoolRp == SYNC_CHECKPOINT_POOL_SIZE) |
| { |
| psContext->psContextCtl->ui32SyncCheckpointPoolRp = 0; |
| } |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount--; |
| psContext->psContextCtl->bSyncCheckpointPoolFull = IMG_FALSE; |
| psSyncCheckpoint->ui32ValidationCheck = SYNC_CHECKPOINT_PATTERN_IN_USE; |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s checkpoint(old ID:%d)<-POOL(%d/%d), psContext=<%p>, poolRp=%d, poolWp=%d", |
| __func__, |
| psSyncCheckpoint->ui32UID, |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount, |
| SYNC_CHECKPOINT_POOL_SIZE, |
| (void*)psContext, psContext->psContextCtl->ui32SyncCheckpointPoolRp, psContext->psContextCtl->ui32SyncCheckpointPoolWp)); |
| #endif |
| } |
| /* Release sync checkpoint pool lock */ |
| OSLockRelease(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| return psSyncCheckpoint; |
| } |
| |
| static IMG_BOOL _PutCheckpointInPool(_SYNC_CHECKPOINT *psSyncCheckpoint) |
| { |
| IMG_BOOL bReturnedToPool = IMG_FALSE; |
| _SYNC_CHECKPOINT_CONTEXT *psContext = psSyncCheckpoint->psSyncCheckpointBlock->psContext; |
| |
| /* Acquire sync checkpoint pool lock */ |
| OSLockAcquire(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| /* Check if pool has space */ |
| if (psContext->psContextCtl->bSyncCheckpointPoolValid && |
| !psContext->psContextCtl->bSyncCheckpointPoolFull) |
| { |
| /* Put the sync checkpoint into the next write slot in the pool */ |
| psContext->psContextCtl->psSyncCheckpointPool[psContext->psContextCtl->ui32SyncCheckpointPoolWp++] = psSyncCheckpoint; |
| if (psContext->psContextCtl->ui32SyncCheckpointPoolWp == SYNC_CHECKPOINT_POOL_SIZE) |
| { |
| psContext->psContextCtl->ui32SyncCheckpointPoolWp = 0; |
| } |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount++; |
| psContext->psContextCtl->bSyncCheckpointPoolFull = |
| ((psContext->psContextCtl->ui32SyncCheckpointPoolCount > 0) && |
| (psContext->psContextCtl->ui32SyncCheckpointPoolWp == psContext->psContextCtl->ui32SyncCheckpointPoolRp)); |
| bReturnedToPool = IMG_TRUE; |
| psSyncCheckpoint->psSyncCheckpointFwObj->ui32State = PVRSRV_SYNC_CHECKPOINT_UNDEF; |
| psSyncCheckpoint->ui32ValidationCheck = SYNC_CHECKPOINT_PATTERN_IN_POOL; |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s checkpoint(ID:%d)->POOL(%d/%d), poolRp=%d, poolWp=%d", |
| __func__, |
| psSyncCheckpoint->ui32UID, |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount, |
| SYNC_CHECKPOINT_POOL_SIZE, psContext->psContextCtl->ui32SyncCheckpointPoolRp, psContext->psContextCtl->ui32SyncCheckpointPoolWp)); |
| #endif |
| } |
| /* Release sync checkpoint pool lock */ |
| OSLockRelease(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| return bReturnedToPool; |
| } |
| |
| static IMG_UINT32 _CleanCheckpointPool(_SYNC_CHECKPOINT_CONTEXT *psContext) |
| { |
| _SYNC_CHECKPOINT *psSyncCheckpointInt = NULL; |
| IMG_UINT32 ui32ItemsFreed = 0; |
| |
| /* Acquire sync checkpoint pool lock */ |
| OSLockAcquire(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psContext=<%p>, bSyncCheckpointPoolValid=%d, uiSyncCheckpointPoolCount=%d", |
| __func__, |
| (void*)psContext, |
| psContext->psContextCtl->bSyncCheckpointPoolValid, |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount)); |
| #endif |
| /* While the pool still contains sync checkpoints, free them */ |
| while (psContext->psContextCtl->bSyncCheckpointPoolValid && |
| (psContext->psContextCtl->ui32SyncCheckpointPoolCount > 0)) |
| { |
| /* Get the sync checkpoint from the next read slot in the pool */ |
| psSyncCheckpointInt = psContext->psContextCtl->psSyncCheckpointPool[psContext->psContextCtl->ui32SyncCheckpointPoolRp++]; |
| if (psContext->psContextCtl->ui32SyncCheckpointPoolRp == SYNC_CHECKPOINT_POOL_SIZE) |
| { |
| psContext->psContextCtl->ui32SyncCheckpointPoolRp = 0; |
| } |
| psContext->psContextCtl->ui32SyncCheckpointPoolCount--; |
| psContext->psContextCtl->bSyncCheckpointPoolFull = |
| ((psContext->psContextCtl->ui32SyncCheckpointPoolCount > 0) && |
| (psContext->psContextCtl->ui32SyncCheckpointPoolWp == psContext->psContextCtl->ui32SyncCheckpointPoolRp)); |
| |
| if (psSyncCheckpointInt) |
| { |
| if (psSyncCheckpointInt->ui32ValidationCheck != SYNC_CHECKPOINT_PATTERN_IN_POOL) |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s pool contains invalid entry (ui32ValidationCheck=0x%x)", |
| __func__, |
| psSyncCheckpointInt->ui32ValidationCheck)); |
| #endif |
| } |
| |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint(ID:%d)", |
| __func__, psSyncCheckpointInt->ui32UID)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint->ui32ValidationCheck=0x%x", |
| __func__, psSyncCheckpointInt->ui32ValidationCheck)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint->uiSpanAddr=0x%llx", |
| __func__, psSyncCheckpointInt->uiSpanAddr)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint->psSyncCheckpointBlock=<%p>", |
| __func__, (void*)psSyncCheckpointInt->psSyncCheckpointBlock)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint->psSyncCheckpointBlock->psContext=<%p>", |
| __func__, (void*)psSyncCheckpointInt->psSyncCheckpointBlock->psContext)); |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s psSyncCheckpoint->psSyncCheckpointBlock->psContext->psSubAllocRA=<%p>", |
| __func__, (void*)psSyncCheckpointInt->psSyncCheckpointBlock->psContext->psSubAllocRA)); |
| #endif |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, |
| "%s CALLING RA_Free(psSyncCheckpoint(ID:%d)<%p>), " |
| "psSubAllocRA=<%p>, ui32SpanAddr=0x%llx", |
| __func__, |
| psSyncCheckpointInt->ui32UID, |
| (void*)psSyncCheckpointInt, |
| (void*)psSyncCheckpointInt->psSyncCheckpointBlock->psContext->psSubAllocRA, |
| psSyncCheckpointInt->uiSpanAddr)); |
| #endif |
| _FreeSyncCheckpoint(psSyncCheckpointInt); |
| ui32ItemsFreed++; |
| } |
| else |
| { |
| #if (ENABLE_SYNC_CHECKPOINT_POOL_DEBUG == 1) |
| PVR_DPF((PVR_DBG_WARNING, "%s pool contains NULL entry", __func__)); |
| #endif |
| } |
| } |
| /* Release sync checkpoint pool lock */ |
| OSLockRelease(psContext->psContextCtl->hSyncCheckpointPoolLock); |
| |
| return ui32ItemsFreed; |
| } |
| #endif /* (SYNC_CHECKPOINT_POOL_SIZE > 0) */ |