/****************************************************************************** FUNCTION : RGXReleaseCCB PURPOSE : Release a CCB that we have been writing to. PARAMETERS : psDevData - device data psCCB - the CCB RETURNS : None ******************************************************************************/ IMG_INTERNAL IMG_VOID RGXReleaseCCB(RGX_CLIENT_CCB *psClientCCB, IMG_UINT32 ui32CmdSize, IMG_BOOL bPDumpContinuous) { IMG_UINT32 ui32PDumpFlags = bPDumpContinuous ? PDUMP_FLAGS_CONTINUOUS : 0; IMG_BOOL bInCaptureRange; IMG_BOOL bPdumpEnabled; PDumpIsCaptureFrameKM(&bInCaptureRange); bPdumpEnabled = (bInCaptureRange || bPDumpContinuous); /* Dump the CCB data */ if (bPdumpEnabled) { DevmemPDumpLoadMem(psClientCCB->psClientCCBMemDesc, psClientCCB->ui32HostWriteOffset, ui32CmdSize, ui32PDumpFlags); } /* * Update the CCB write offset. */ UPDATE_CCB_OFFSET(psClientCCB->ui32HostWriteOffset, ui32CmdSize, psClientCCB->ui32Size); /* PDumpSetFrame will detect as we Transition out of capture range for frame based data but if we are PDumping continuous data then we need to inform the PDump layer ourselves */ if (bPDumpContinuous && !bInCaptureRange) { PVRSRV_ERROR eError; /* Only Transitioning into capture range can cause an error */ eError = PDumpTransition(psClientCCB->psPDumpConnectionData, IMG_FALSE, IMG_TRUE); PVR_ASSERT(eError == PVRSRV_OK); } if (bPdumpEnabled) { /* Update the PDump write offset to show we PDumped this command */ psClientCCB->ui32LastPDumpWriteOffset = psClientCCB->ui32HostWriteOffset; } #if defined(NO_HARDWARE) /* The firmware is not running, it cannot update these; we do here instead. */ psClientCCB->psClientCCBCtrl->ui32ReadOffset = psClientCCB->ui32HostWriteOffset; psClientCCB->psClientCCBCtrl->ui32DepOffset = psClientCCB->ui32HostWriteOffset; #endif }
static IMG_VOID _SCPInsert(SCP_CONTEXT *psContext, IMG_UINT32 ui32Size) { /* * Update the write offset. */ UPDATE_CCB_OFFSET(psContext->ui32WriteOffset, ui32Size, psContext->ui32CCBSize); }
/* SCPCommandComplete */ IMG_EXPORT IMG_VOID SCPCommandComplete(SCP_CONTEXT *psContext) { SCP_COMMAND *psCommand; IMG_UINT32 i; IMG_BOOL bContinue = IMG_TRUE; if (psContext == IMG_NULL) { return; } if (psContext->ui32ReadOffset == psContext->ui32DepOffset) { PVR_DPF((PVR_DBG_ERROR, "SCPCommandComplete: Called with no work to do!")); return; } while(bContinue) { psCommand = (SCP_COMMAND *) ((IMG_UINT8 *) psContext->pvCCB + psContext->ui32ReadOffset); if (psCommand->ui32CmdType == SCP_COMMAND_CALLBACK) { /* Do any fence updates */ for (i=0;i<psCommand->ui32SyncCount;i++) { SCP_SYNC_DATA *psSCPSyncData = &psCommand->pasSCPSyncData[i]; if (psSCPSyncData->ui32Flags & SCP_SYNC_DATA_UPDATE) { ServerSyncCompleteOp(psSCPSyncData->psSync, psSCPSyncData->ui32Update); } } bContinue = IMG_FALSE; } /* processed cmd so update queue */ UPDATE_CCB_OFFSET(psContext->ui32ReadOffset, psCommand->ui32CmdSize, psContext->ui32CCBSize); SCP_DEBUG_PRINT("%s: Complete command %p for ctx %p (continue: %d)", __FUNCTION__, psCommand, psContext, bContinue); } }
/* SCPRun */ IMG_EXPORT PVRSRV_ERROR SCPRun(SCP_CONTEXT *psContext) { SCP_COMMAND *psCommand; if (psContext == IMG_NULL) { return PVRSRV_ERROR_INVALID_PARAMS; } OSLockAcquire(psContext->hLock); while (psContext->ui32DepOffset != psContext->ui32WriteOffset) { PVRSRV_ERROR eError; psCommand = (SCP_COMMAND *)((IMG_UINT8 *)psContext->pvCCB + psContext->ui32DepOffset); /* See if the command is ready to go */ eError = _SCPCommandReady(psCommand); SCP_DEBUG_PRINT("%s: Processes command %p for ctx %p (%d)", __FUNCTION__, psCommand, psContext, eError); if (eError == PVRSRV_OK) { /* processed cmd so update queue */ UPDATE_CCB_OFFSET(psContext->ui32DepOffset, psCommand->ui32CmdSize, psContext->ui32CCBSize); } else { /* As soon as we hit a command that can't run break out */ break; } /* Run the command */ _SCPCommandDo(psCommand); } OSLockRelease(psContext->hLock); return PVRSRV_OK; }
static PVRSRV_ERROR _SCPAlloc(SCP_CONTEXT *psContext, IMG_UINT32 ui32Size, IMG_PVOID *ppvBufferSpace) { if ((ui32Size + PADDING_COMMAND_SIZE) > psContext->ui32CCBSize) { PVR_DPF((PVR_DBG_WARNING, "Command size (%d) too big for CCB\n", ui32Size)); return PVRSRV_ERROR_CMD_TOO_BIG; } /* Check we don't overflow the end of the buffer and make sure we have enough for the padding command */ if ((psContext->ui32WriteOffset + ui32Size + PADDING_COMMAND_SIZE) > psContext->ui32CCBSize) { SCP_COMMAND *psCommand; IMG_PVOID pvCommand; PVRSRV_ERROR eError; IMG_UINT32 ui32Remain = psContext->ui32CCBSize - psContext->ui32WriteOffset; /* We're at the end of the buffer without enough contiguous space */ eError = __SCPAlloc(psContext, ui32Remain, &pvCommand); if (eError != PVRSRV_OK) { PVR_ASSERT(eError == PVRSRV_ERROR_RETRY); return eError; } psCommand = pvCommand; psCommand->ui32CmdType = SCP_COMMAND_PADDING; psCommand->ui32CmdSize = ui32Remain; UPDATE_CCB_OFFSET(psContext->ui32WriteOffset, ui32Remain, psContext->ui32CCBSize); } return __SCPAlloc(psContext, ui32Size, ppvBufferSpace); }
/****************************************************************************** FUNCTION : RGXReleaseCCB PURPOSE : Release a CCB that we have been writing to. PARAMETERS : psDevData - device data psCCB - the CCB RETURNS : None ******************************************************************************/ IMG_INTERNAL IMG_VOID RGXReleaseCCB(RGX_CLIENT_CCB *psClientCCB, IMG_UINT32 ui32CmdSize, IMG_BOOL bPDumpContinuous) { IMG_UINT32 ui32PDumpFlags = bPDumpContinuous ? PDUMP_FLAGS_CONTINUOUS : 0; IMG_BOOL bInCaptureRange; IMG_BOOL bPdumpEnabled; PDumpIsCaptureFrameKM(&bInCaptureRange); bPdumpEnabled = (bInCaptureRange || bPDumpContinuous); /* Dump the CCB data */ if (bPdumpEnabled) { DevmemPDumpLoadMem(psClientCCB->psClientCCBMemDesc, psClientCCB->ui32HostWriteOffset, ui32CmdSize, ui32PDumpFlags); } /* * Check if there have been any fences written that will already be * satistified by a previously written update in this CCB. */ #if defined REDUNDANT_SYNCS_DEBUG { IMG_UINT8 *pui8BufferStart = (IMG_PVOID)((IMG_UINTPTR_T)psClientCCB->pui8ClientCCB + psClientCCB->ui32HostWriteOffset); IMG_UINT8 *pui8BufferEnd = (IMG_PVOID)((IMG_UINTPTR_T)psClientCCB->pui8ClientCCB + psClientCCB->ui32HostWriteOffset + ui32CmdSize); /* Walk through the commands in this section of CCB being released... */ while (pui8BufferStart < pui8BufferEnd) { RGXFWIF_CCB_CMD_HEADER *psCmdHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8BufferStart; if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_UPDATE) { /* If an UPDATE then record the value incase a later fence depends on it. */ IMG_UINT32 ui32NumUpdates = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO); IMG_UINT32 i; for (i = 0; i < ui32NumUpdates; i++) { RGXFWIF_UFO *psUFOPtr = ((RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER))) + i; psClientCCB->asFenceUpdateList[psClientCCB->ui32UpdateWriteIndex++] = *psUFOPtr; psClientCCB->ui32UpdateWriteIndex &= (RGX_CCCB_FENCE_UPDATE_LIST_SIZE-1); } } else if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_FENCE) { IMG_UINT32 ui32NumFences = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO); IMG_UINT32 i; for (i = 0; i < ui32NumFences; i++) { RGXFWIF_UFO *psUFOPtr = ((RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER))) + i; IMG_UINT32 ui32UpdateIndex; /* Check recently queued updates to see if this fence will be satisfied by the time it is checked. */ for (ui32UpdateIndex = 0; ui32UpdateIndex < RGX_CCCB_FENCE_UPDATE_LIST_SIZE; ui32UpdateIndex++) { RGXFWIF_UFO *psUpdatePtr = &psClientCCB->asFenceUpdateList[ui32UpdateIndex]; if (psUFOPtr->puiAddrUFO.ui32Addr == psUpdatePtr->puiAddrUFO.ui32Addr && psUFOPtr->ui32Value == psUpdatePtr->ui32Value) { PVR_DPF((PVR_DBG_WARNING, "Redundant fence found in cCCB(%p) - 0x%x -> 0x%x", psClientCCB, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value)); //psUFOPtr->puiAddrUFO.ui32Addr = 0; break; } } } } else if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_FENCE_PR) { IMG_UINT32 ui32NumFences = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO); IMG_UINT32 i; for (i = 0; i < ui32NumFences; i++) { RGXFWIF_UFO *psUFOPtr = ((RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER))) + i; IMG_UINT32 ui32UpdateIndex; /* Check recently queued updates to see if this fence will be satisfied by the time it is checked. */ for (ui32UpdateIndex = 0; ui32UpdateIndex < RGX_CCCB_FENCE_UPDATE_LIST_SIZE; ui32UpdateIndex++) { RGXFWIF_UFO *psUpdatePtr = &psClientCCB->asFenceUpdateList[ui32UpdateIndex]; /* * The PR-fence will be met if the update value is >= the required fence value. E.g. * the difference between the update value and fence value is positive. */ if (psUFOPtr->puiAddrUFO.ui32Addr == psUpdatePtr->puiAddrUFO.ui32Addr && ((psUpdatePtr->ui32Value - psUFOPtr->ui32Value) & (1U << 31)) == 0) { PVR_DPF((PVR_DBG_WARNING, "Redundant PR fence found in cCCB(%p) - 0x%x -> 0x%x", psClientCCB, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value)); //psUFOPtr->puiAddrUFO.ui32Addr = 0; break; } } } } /* Move to the next command in this section of CCB being released... */ pui8BufferStart += sizeof(RGXFWIF_CCB_CMD_HEADER) + psCmdHeader->ui32CmdSize; } } #endif /* REDUNDANT_SYNCS_DEBUG */ /* * Update the CCB write offset. */ UPDATE_CCB_OFFSET(psClientCCB->ui32HostWriteOffset, ui32CmdSize, psClientCCB->ui32Size); /* PDumpSetFrame will detect as we Transition out of capture range for frame based data but if we are PDumping continuous data then we need to inform the PDump layer ourselves */ if (bPDumpContinuous && !bInCaptureRange) { PVRSRV_ERROR eError; /* Only Transitioning into capture range can cause an error */ eError = PDumpTransition(psClientCCB->psPDumpConnectionData, IMG_FALSE, IMG_TRUE); PVR_ASSERT(eError == PVRSRV_OK); } if (bPdumpEnabled) { /* Update the PDump write offset to show we PDumped this command */ psClientCCB->ui32LastPDumpWriteOffset = psClientCCB->ui32HostWriteOffset; } #if defined(NO_HARDWARE) /* The firmware is not running, it cannot update these; we do here instead. */ psClientCCB->psClientCCBCtrl->ui32ReadOffset = psClientCCB->ui32HostWriteOffset; psClientCCB->psClientCCBCtrl->ui32DepOffset = psClientCCB->ui32HostWriteOffset; #endif }
/****************************************************************************** FUNCTION : RGXAcquireCCB PURPOSE : Obtains access to write some commands to a CCB PARAMETERS : psClientCCB - The client CCB ui32CmdSize - How much space is required ppvBufferSpace - Pointer to space in the buffer bPDumpContinuous - Should this be PDump continuous? RETURNS : PVRSRV_ERROR ******************************************************************************/ IMG_INTERNAL PVRSRV_ERROR RGXAcquireCCB(RGX_CLIENT_CCB *psClientCCB, IMG_UINT32 ui32CmdSize, IMG_PVOID *ppvBufferSpace, IMG_BOOL bPDumpContinuous) { PVRSRV_ERROR eError; IMG_UINT32 ui32PDumpFlags = bPDumpContinuous ? PDUMP_FLAGS_CONTINUOUS : 0; IMG_BOOL bInCaptureRange; IMG_BOOL bPdumpEnabled; PDumpIsCaptureFrameKM(&bInCaptureRange); bPdumpEnabled = (bInCaptureRange || bPDumpContinuous); /* PDumpSetFrame will detect as we Transition into capture range for frame based data but if we are PDumping continuous data then we need to inform the PDump layer ourselves */ if (bPDumpContinuous && !bInCaptureRange) { eError = PDumpTransition(psClientCCB->psPDumpConnectionData, IMG_TRUE, IMG_TRUE); if (eError != PVRSRV_OK) { return eError; } } /* Check that the CCB can hold this command + padding */ if ((ui32CmdSize + PADDING_COMMAND_SIZE + 1) > psClientCCB->ui32Size) { PVR_DPF((PVR_DBG_ERROR, "Command size (%d bytes) too big for CCB (%d bytes)\n", ui32CmdSize, psClientCCB->ui32Size)); return PVRSRV_ERROR_CMD_TOO_BIG; } /* Check we don't overflow the end of the buffer and make sure we have enough for the padding command. */ if ((psClientCCB->ui32HostWriteOffset + ui32CmdSize + PADDING_COMMAND_SIZE) > psClientCCB->ui32Size) { RGXFWIF_CCB_CMD_HEADER *psHeader; IMG_VOID *pvHeader; PVRSRV_ERROR eError; IMG_UINT32 ui32Remain = psClientCCB->ui32Size - psClientCCB->ui32HostWriteOffset; /* We're at the end of the buffer without enough contiguous space */ eError = _RGXAcquireCCB(psClientCCB, ui32Remain, &pvHeader); if (eError != PVRSRV_OK) { /* It's possible no commands have been processed in which case as we can fail the padding allocation due to that fact we never allow the client CCB to be full */ return eError; } psHeader = pvHeader; psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_PADDING; psHeader->ui32CmdSize = ui32Remain - sizeof(RGXFWIF_CCB_CMD_HEADER); PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags, "cCCB(%p): Padding cmd %d", psClientCCB, psHeader->ui32CmdSize); if (bPdumpEnabled) { DevmemPDumpLoadMem(psClientCCB->psClientCCBMemDesc, psClientCCB->ui32HostWriteOffset, ui32Remain, ui32PDumpFlags); } UPDATE_CCB_OFFSET(psClientCCB->ui32HostWriteOffset, ui32Remain, psClientCCB->ui32Size); } return _RGXAcquireCCB(psClientCCB, ui32CmdSize, ppvBufferSpace); }