Exemple #1
0
/*
	Reserve space in the CCB and fill in the command and client sync data
*/
PVRSRV_ERROR RGXCmdHelperAcquireCmdCCB(IMG_UINT32 ui32CmdCount,
									   RGX_CCB_CMD_HELPER_DATA *asCmdHelperData,
									   IMG_BOOL *pbKickRequired)
{
	IMG_UINT32 ui32BeforeWOff = asCmdHelperData[0].psClientCCB->ui32HostWriteOffset;
	IMG_UINT32 ui32AllocSize = 0;
	IMG_UINT32 i;
	IMG_UINT8 *pui8StartPtr;
	PVRSRV_ERROR eError;

	*pbKickRequired = IMG_FALSE;

	/*
		Workout how much space we need for all the command(s)
	*/
	ui32AllocSize = RGXCmdHelperGetCommandSize(ui32CmdCount, asCmdHelperData);


	for (i = 0; i < ui32CmdCount; i++)
	{
		if (asCmdHelperData[0].bPDumpContinuous != asCmdHelperData[i].bPDumpContinuous)
		{
			PVR_DPF((PVR_DBG_ERROR, "%s: PDump continuous is not consistent (%s != %s) for command %d",
					 __FUNCTION__,
					 asCmdHelperData[0].bPDumpContinuous?"IMG_TRUE":"IMG_FALSE",
					 asCmdHelperData[i].bPDumpContinuous?"IMG_TRUE":"IMG_FALSE",
					 ui32CmdCount));
			return PVRSRV_ERROR_INVALID_PARAMS;
		}
	}

	/*
		Acquire space in the CCB for all the command(s).
	*/
	eError = RGXAcquireCCB(asCmdHelperData[0].psClientCCB,
						   ui32AllocSize,
						   (IMG_PVOID *)&pui8StartPtr,
						   asCmdHelperData[0].bPDumpContinuous);	
	if (eError != PVRSRV_OK)
	{
		/* Failed so bail out and allow the client side to retry */
		if (asCmdHelperData[0].psClientCCB->ui32HostWriteOffset != ui32BeforeWOff)
		{
			*pbKickRequired = IMG_TRUE;
		}
		return eError;
	}



	/*
		For each command fill in the fence, DM, and update command

		Note:
		We only fill in the client fences here, the server fences (and updates)
		will be filled in together at the end. This is because we might fail the
		kernel CCB alloc and would then have to rollback the server syncs if
		we took the operation here
	*/
	for (i = 0; i < ui32CmdCount; i++)
	{
		RGX_CCB_CMD_HELPER_DATA *psCmdHelperData = & asCmdHelperData[i];
		IMG_UINT8 *pui8CmdPtr;
		IMG_UINT8 *pui8ServerFenceStart = 0;
		IMG_UINT8 *pui8ServerUpdateStart = 0;
#if defined(PDUMP)
		IMG_UINT32 ui32CtxAddr = FWCommonContextGetFWAddress(asCmdHelperData->psClientCCB->psServerCommonContext).ui32Addr;
		IMG_UINT32 ui32CcbWoff = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(asCmdHelperData->psClientCCB->psServerCommonContext));
#endif

		if (psCmdHelperData->ui32ClientFenceCount+psCmdHelperData->ui32ClientUpdateCount != 0)
		{
			PDUMPCOMMENT("Start of %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
					psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
		}



		/*
			Create the fence command.
		*/
		if (psCmdHelperData->ui32FenceCmdSize)
		{
			RGXFWIF_CCB_CMD_HEADER *psHeader;
			IMG_UINT k;

			/* Fences are at the start of the command */
			pui8CmdPtr = pui8StartPtr;

			psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
			psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_FENCE;
			psHeader->ui32CmdSize = psCmdHelperData->ui32FenceCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
			pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);

			/* Fill in the client fences */
			for (k = 0; k < psCmdHelperData->ui32ClientFenceCount; k++)
			{
				RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *) pui8CmdPtr;
	
				psUFOPtr->puiAddrUFO = psCmdHelperData->pauiFenceUFOAddress[k];
				psUFOPtr->ui32Value = psCmdHelperData->paui32FenceValue[k];
				pui8CmdPtr += sizeof(RGXFWIF_UFO);

#if defined SYNC_COMMAND_DEBUG
				PVR_DPF((PVR_DBG_ERROR, "%s client sync fence - 0x%x -> 0x%x",
						psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value));
#endif
				PDUMPCOMMENT(".. %s client sync fence - 0x%x -> 0x%x",
						psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value);


			}
			pui8ServerFenceStart = pui8CmdPtr;
		}

		/* jump over the Server fences */
		pui8CmdPtr = pui8StartPtr + psCmdHelperData->ui32FenceCmdSize;


		/*
		  Create the pre DM timestamp commands. Pre and Post timestamp commands are supposed to
		  sandwich the DM cmd. The padding code with the CCB wrap upsets the FW if we don't have
		  the task type bit cleared for POST_TIMESTAMPs. That's why we have 2 different cmd types.
		*/
		if (psCmdHelperData->ui32PreTimeStampCmdSize != 0)
		{
			RGXWriteTimestampCommand(& pui8CmdPtr,
			                         RGXFWIF_CCB_CMD_TYPE_PRE_TIMESTAMP,
			                         psCmdHelperData->pPreTimestampAddr);
		}
	
		/*
			Create the DM command
		*/
		if (psCmdHelperData->ui32DMCmdSize)
		{
			RGXFWIF_CCB_CMD_HEADER *psHeader;

			psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
			psHeader->eCmdType = psCmdHelperData->eType;
			psHeader->ui32CmdSize = psCmdHelperData->ui32DMCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);



			pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);


			OSMemCopy(pui8CmdPtr, psCmdHelperData->pui8DMCmd, psCmdHelperData->ui32CmdSize);
			pui8CmdPtr += psCmdHelperData->ui32CmdSize;
		}



		if (psCmdHelperData->ui32PostTimeStampCmdSize != 0)
		{
			RGXWriteTimestampCommand(& pui8CmdPtr,
			                         RGXFWIF_CCB_CMD_TYPE_POST_TIMESTAMP,
			                         psCmdHelperData->pPostTimestampAddr);
		}


		if (psCmdHelperData->ui32RMWUFOCmdSize != 0)
		{
			RGXFWIF_CCB_CMD_HEADER * psHeader;
			RGXFWIF_UFO            * psUFO;

			psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
			psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_RMW_UPDATE;
			psHeader->ui32CmdSize = psCmdHelperData->ui32RMWUFOCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
			pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);

			psUFO = (RGXFWIF_UFO *) pui8CmdPtr;
			psUFO->puiAddrUFO = psCmdHelperData->pRMWUFOAddr;
			
			pui8CmdPtr += sizeof(RGXFWIF_UFO);
		}
	

		/*
			Create the update command.
			
			Note:
			We only fill in the client updates here, the server updates (and fences)
			will be filled in together at the end
		*/
		if (psCmdHelperData->ui32UpdateCmdSize)
		{
			RGXFWIF_CCB_CMD_HEADER *psHeader;
			IMG_UINT k;

			psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
			psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_UPDATE;
			psHeader->ui32CmdSize = psCmdHelperData->ui32UpdateCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
			pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);

			/* Fill in the client updates */
			for (k = 0; k < psCmdHelperData->ui32ClientUpdateCount; k++)
			{
				RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *) pui8CmdPtr;
	
				psUFOPtr->puiAddrUFO = psCmdHelperData->pauiUpdateUFOAddress[k];
				psUFOPtr->ui32Value = psCmdHelperData->paui32UpdateValue[k];
				pui8CmdPtr += sizeof(RGXFWIF_UFO);

#if defined SYNC_COMMAND_DEBUG
				PVR_DPF((PVR_DBG_ERROR, "%s client sync update - 0x%x -> 0x%x",
						psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value));
#endif
				PDUMPCOMMENT(".. %s client sync update - 0x%x -> 0x%x",
						psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value);

			}
			pui8ServerUpdateStart = pui8CmdPtr;
		}
	
		/* Save the server sync fence & update offsets for submit time */
		psCmdHelperData->pui8ServerFenceStart  = pui8ServerFenceStart;
		psCmdHelperData->pui8ServerUpdateStart = pui8ServerUpdateStart;
	
		/* Save start for sanity checking at submit time */
		psCmdHelperData->pui8StartPtr = pui8StartPtr;

		/* Set the start pointer for the next iteration around the loop */
		pui8StartPtr +=
			psCmdHelperData->ui32FenceCmdSize         +
			psCmdHelperData->ui32PreTimeStampCmdSize  +
			psCmdHelperData->ui32DMCmdSize            +
			psCmdHelperData->ui32PostTimeStampCmdSize +
			psCmdHelperData->ui32RMWUFOCmdSize        + 
			psCmdHelperData->ui32UpdateCmdSize;

		if (psCmdHelperData->ui32ClientFenceCount+psCmdHelperData->ui32ClientUpdateCount != 0)
		{
			PDUMPCOMMENT("End of %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
					psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
		}
		else
		{
			PDUMPCOMMENT("No %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
					psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
		}
	}

	*pbKickRequired = IMG_TRUE;
	return PVRSRV_OK;
}
Exemple #2
0
/*
 * PVRSRVSubmitTQ3DKickKM
 */
IMG_EXPORT
PVRSRV_ERROR PVRSRVRGXSubmitTransferKM(RGX_SERVER_TQ_CONTEXT	*psTransferContext,
									   IMG_UINT32				ui32PrepareCount,
									   IMG_UINT32				*paui32ClientFenceCount,
									   PRGXFWIF_UFO_ADDR		**papauiClientFenceUFOAddress,
									   IMG_UINT32				**papaui32ClientFenceValue,
									   IMG_UINT32				*paui32ClientUpdateCount,
									   PRGXFWIF_UFO_ADDR		**papauiClientUpdateUFOAddress,
									   IMG_UINT32				**papaui32ClientUpdateValue,
									   IMG_UINT32				*paui32ServerSyncCount,
									   IMG_UINT32				**papaui32ServerSyncFlags,
									   SERVER_SYNC_PRIMITIVE	***papapsServerSyncs,
									   IMG_UINT32				ui32NumFenceFDs,
									   IMG_INT32				*paui32FenceFDs,
									   IMG_UINT32				*paui32FWCommandSize,
									   IMG_UINT8				**papaui8FWCommand,
									   IMG_UINT32				*pui32TQPrepareFlags)
{
	PVRSRV_DEVICE_NODE *psDeviceNode = psTransferContext->psDeviceNode;
#if defined(WDDM)
	RGX_CCB_CMD_HELPER_DATA as3DCmdHelper[TQ_MAX_PREPARES_PER_SUBMIT];
	RGX_CCB_CMD_HELPER_DATA as2DCmdHelper[TQ_MAX_PREPARES_PER_SUBMIT];
#endif
	RGX_CCB_CMD_HELPER_DATA *pas3DCmdHelper;
	RGX_CCB_CMD_HELPER_DATA *pas2DCmdHelper;
	IMG_UINT32 ui323DCmdCount = 0;
	IMG_UINT32 ui322DCmdCount = 0;
	IMG_BOOL bKick2D = IMG_FALSE;
	IMG_BOOL bKick3D = IMG_FALSE;
	IMG_BOOL bPDumpContinuous = IMG_FALSE;
	IMG_UINT32 i;
	IMG_UINT32 ui32IntClientFenceCount = 0;
	PRGXFWIF_UFO_ADDR *pauiIntFenceUFOAddress = IMG_NULL;
	IMG_UINT32 *paui32IntFenceValue = IMG_NULL;
	IMG_UINT32 ui32IntClientUpdateCount = 0;
	PRGXFWIF_UFO_ADDR *pauiIntUpdateUFOAddress = IMG_NULL;
	IMG_UINT32 *paui32IntUpdateValue = IMG_NULL;
	PVRSRV_ERROR eError;
	PVRSRV_ERROR eError2;

#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
	IMG_BOOL bSyncsMerged = IMG_FALSE;
#endif

	if (ui32PrepareCount == 0)
	{
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	if (ui32NumFenceFDs != 0)
	{
#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
		/* Fence FD's are only valid in the 3D case with no batching */
		if ((ui32PrepareCount !=1) && (!TQ_PREP_FLAGS_COMMAND_IS(pui32TQPrepareFlags[0], 3D)))
		{
			return PVRSRV_ERROR_INVALID_PARAMS;
		}

#else
		/* We only support Fence FD's if built with PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC */
		return PVRSRV_ERROR_INVALID_PARAMS;
#endif
	}
#if defined(WDDM)
	pas3DCmdHelper = &as3DCmdHelper;
	pas2DCmdHelper = &as2DCmdHelper;
#else
	/* We can't allocate the required amount of stack space on all consumer architectures */
	pas3DCmdHelper = OSAllocMem(sizeof(*pas3DCmdHelper) * ui32PrepareCount);
	if (pas3DCmdHelper == IMG_NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_alloc3dhelper;
	}
	pas2DCmdHelper = OSAllocMem(sizeof(*pas2DCmdHelper) * ui32PrepareCount);
	if (pas2DCmdHelper == IMG_NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_alloc2dhelper;
	}
#endif
	/*
		Ensure we do the right thing for server syncs which cross call bounderies
	*/
	for (i=0;i<ui32PrepareCount;i++)
	{
		IMG_BOOL bHaveStartPrepare = pui32TQPrepareFlags[i] & TQ_PREP_FLAGS_START;
		IMG_BOOL bHaveEndPrepare = IMG_FALSE;

		if (bHaveStartPrepare)
		{
			IMG_UINT32 k;
			/*
				We've at the start of a transfer operation (which might be made
				up of multiple HW operations) so check if we also have then
				end of the transfer operation in the batch
			*/
			for (k=i;k<ui32PrepareCount;k++)
			{
				if (pui32TQPrepareFlags[k] & TQ_PREP_FLAGS_END)
				{
					bHaveEndPrepare = IMG_TRUE;
					break;
				}
			}

			if (!bHaveEndPrepare)
			{
				/*
					We don't have the complete command passed in this call
					so drop the update request. When we get called again with
					the last HW command in this transfer operation we'll do
					the update at that point.
				*/
				for (k=0;k<paui32ServerSyncCount[i];k++)
				{
					papaui32ServerSyncFlags[i][k] &= ~PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE;
				}
			}
		}
	}


	/*
		Init the command helper commands for all the prepares
	*/
	for (i=0;i<ui32PrepareCount;i++)
	{
		RGX_CLIENT_CCB *psClientCCB;
		RGX_SERVER_COMMON_CONTEXT *psServerCommonCtx;
		IMG_CHAR *pszCommandName;
		RGX_CCB_CMD_HELPER_DATA *psCmdHelper;
		RGXFWIF_CCB_CMD_TYPE eType;

		if (TQ_PREP_FLAGS_COMMAND_IS(pui32TQPrepareFlags[i], 3D))
		{
			psServerCommonCtx = psTransferContext->s3DData.psServerCommonContext;
			psClientCCB = FWCommonContextGetClientCCB(psServerCommonCtx);
			pszCommandName = "TQ-3D";
			psCmdHelper = &pas3DCmdHelper[ui323DCmdCount++];
			eType = RGXFWIF_CCB_CMD_TYPE_TQ_3D;
		}
		else if (TQ_PREP_FLAGS_COMMAND_IS(pui32TQPrepareFlags[i], 2D))
		{
			psServerCommonCtx = psTransferContext->s2DData.psServerCommonContext;
			psClientCCB = FWCommonContextGetClientCCB(psServerCommonCtx);
			pszCommandName = "TQ-2D";
			psCmdHelper = &pas2DCmdHelper[ui322DCmdCount++];
			eType = RGXFWIF_CCB_CMD_TYPE_TQ_2D;
		}
		else
		{
			eError = PVRSRV_ERROR_INVALID_PARAMS;
			goto fail_cmdtype;
		}

		if (i == 0)
		{
			bPDumpContinuous = ((pui32TQPrepareFlags[i] & TQ_PREP_FLAGS_PDUMPCONTINUOUS) == TQ_PREP_FLAGS_PDUMPCONTINUOUS);
			PDUMPCOMMENTWITHFLAGS((bPDumpContinuous) ? PDUMP_FLAGS_CONTINUOUS : 0,
					"%s Command Server Submit on FWCtx %08x", pszCommandName, FWCommonContextGetFWAddress(psServerCommonCtx).ui32Addr);
		}
		else
		{
			IMG_BOOL bNewPDumpContinuous = ((pui32TQPrepareFlags[i] & TQ_PREP_FLAGS_PDUMPCONTINUOUS) == TQ_PREP_FLAGS_PDUMPCONTINUOUS);

			if (bNewPDumpContinuous != bPDumpContinuous)
			{
				eError = PVRSRV_ERROR_INVALID_PARAMS;
				PVR_DPF((PVR_DBG_ERROR, "%s: Mixing of continuous and non-continuous command in a batch is not permitted", __FUNCTION__));
				goto fail_pdumpcheck;
			}
		}

#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
		if (ui32NumFenceFDs)
		{
			IMG_UINT32 ui32NumFenceSyncs;
			PRGXFWIF_UFO_ADDR *puiFenceFWAddrs;
			IMG_UINT32 *pui32FenceValues;
			IMG_UINT32 ui32NumUpdateSyncs;
			PRGXFWIF_UFO_ADDR *puiUpdateFWAddrs;
			IMG_UINT32 *pui32UpdateValues;

			/*
				FIXME:
				We can't be taking the server sync operations here as we
				have no way to undo them should the acquire fail.
				If client/local syncs where used here would that remove the
				issue?
			*/
			eError = PVRFDSyncQueryFencesKM(ui32NumFenceFDs,
											paui32FenceFDs,
											IMG_TRUE,
											&ui32NumFenceSyncs,
											&puiFenceFWAddrs,
											&pui32FenceValues,
											&ui32NumUpdateSyncs,
											&puiUpdateFWAddrs,
											&pui32UpdateValues);
			if (eError != PVRSRV_OK)
			{
				goto fail_fdsync;
			}

			/*
				Merge the Android syncs and the client syncs together
			*/
			ui32IntClientFenceCount = paui32ClientFenceCount[i] + ui32NumFenceSyncs;
			pauiIntFenceUFOAddress = OSAllocMem(sizeof(*pauiIntFenceUFOAddress)* ui32IntClientFenceCount);
			if (pauiIntFenceUFOAddress == IMG_NULL)
			{
				/* Free memory created by PVRFDSyncQueryFencesKM */
				OSFreeMem(puiFenceFWAddrs);
				OSFreeMem(pui32FenceValues);
				OSFreeMem(puiUpdateFWAddrs);
				OSFreeMem(pui32UpdateValues);

				goto fail_fenceUFOarray;
			}	
			paui32IntFenceValue = OSAllocMem(sizeof(*paui32IntFenceValue)* ui32IntClientFenceCount);
			if (paui32IntFenceValue == IMG_NULL)
			{
				/* Free memory created by PVRFDSyncQueryFencesKM */
				OSFreeMem(puiFenceFWAddrs);
				OSFreeMem(pui32FenceValues);
				OSFreeMem(puiUpdateFWAddrs);
				OSFreeMem(pui32UpdateValues);

				OSFreeMem(pauiIntFenceUFOAddress);
				goto fail_fencevaluearray;
			}
			ui32IntClientUpdateCount = paui32ClientUpdateCount[i] + ui32NumUpdateSyncs;
			pauiIntUpdateUFOAddress = OSAllocMem(sizeof(*pauiIntUpdateUFOAddress)* ui32IntClientUpdateCount);
			if (pauiIntUpdateUFOAddress == IMG_NULL)
			{
				/* Free memory created by PVRFDSyncQueryFencesKM */
				OSFreeMem(puiFenceFWAddrs);
				OSFreeMem(pui32FenceValues);
				OSFreeMem(puiUpdateFWAddrs);
				OSFreeMem(pui32UpdateValues);

				OSFreeMem(pauiIntFenceUFOAddress);
				OSFreeMem(paui32IntFenceValue);
				goto fail_updateUFOarray;
			}
			paui32IntUpdateValue = OSAllocMem(sizeof(*paui32IntUpdateValue)* ui32IntClientUpdateCount);
			if (paui32IntUpdateValue == IMG_NULL)
			{
				/* Free memory created by PVRFDSyncQueryFencesKM */
				OSFreeMem(puiFenceFWAddrs);
				OSFreeMem(pui32FenceValues);
				OSFreeMem(puiUpdateFWAddrs);
				OSFreeMem(pui32UpdateValues);

				OSFreeMem(pauiIntFenceUFOAddress);
				OSFreeMem(paui32IntFenceValue);
				OSFreeMem(pauiIntUpdateUFOAddress);
				goto fail_updatevaluearray;
			}

			SYNC_MERGE_CLIENT_FENCES(ui32IntClientFenceCount, pauiIntFenceUFOAddress, paui32IntFenceValue,
									 ui32NumFenceSyncs, puiFenceFWAddrs, pui32FenceValues,
									 paui32ClientFenceCount[i], papauiClientFenceUFOAddress[i], papaui32ClientFenceValue[i]);

			SYNC_MERGE_CLIENT_UPDATES(ui32IntClientUpdateCount, pauiIntUpdateUFOAddress, paui32IntUpdateValue,
									 ui32NumUpdateSyncs, puiUpdateFWAddrs, pui32UpdateValues,
									 paui32ClientUpdateCount[i], papauiClientUpdateUFOAddress[i], papaui32ClientUpdateValue[i]);

			if (ui32NumFenceSyncs || ui32NumUpdateSyncs)
			{
				PDUMPCOMMENT("(TQ) Android native fences in use: %u fence syncs, %u update syncs",
							 ui32NumFenceSyncs, ui32NumUpdateSyncs);
			}		

			/*
				Free the data created by PVRFDSyncQueryFencesKM as it has now
				been merged into *IntClient*
			*/
			OSFreeMem(puiFenceFWAddrs);
			OSFreeMem(pui32FenceValues);
			OSFreeMem(puiUpdateFWAddrs);
			OSFreeMem(pui32UpdateValues);
			bSyncsMerged = IMG_TRUE;
		}
		else
#endif /* PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC */
		{
			/* No client sync merging so just copy across the pointers */
			ui32IntClientFenceCount = paui32ClientFenceCount[i];
			pauiIntFenceUFOAddress = papauiClientFenceUFOAddress[i];
			paui32IntFenceValue = papaui32ClientFenceValue[i];
			ui32IntClientUpdateCount = paui32ClientUpdateCount[i];
			pauiIntUpdateUFOAddress = papauiClientUpdateUFOAddress[i];
			paui32IntUpdateValue = papaui32ClientUpdateValue[i];
		}


		/*
			Create the command helper data for this command
		*/
		eError = RGXCmdHelperInitCmdCCB(psClientCCB,
										ui32IntClientFenceCount,
										pauiIntFenceUFOAddress,
										paui32IntFenceValue,
										ui32IntClientUpdateCount,
										pauiIntUpdateUFOAddress,
										paui32IntUpdateValue,
										paui32ServerSyncCount[i],
										papaui32ServerSyncFlags[i],
										papapsServerSyncs[i],
										paui32FWCommandSize[i],
										papaui8FWCommand[i],
										eType,
										bPDumpContinuous,
										pszCommandName,
										psCmdHelper);
		if (eError != PVRSRV_OK)
		{
			goto fail_initcmd;
		}
	}

	/*
		Acquire space for all the commands in one go
	*/
	if (ui323DCmdCount)
	{
		
		eError = RGXCmdHelperAcquireCmdCCB(ui323DCmdCount,
										   &pas3DCmdHelper[0],
										   &bKick3D);
		if (eError != PVRSRV_OK)
		{
			if (bKick3D)
			{
				ui323DCmdCount = 0;
				ui322DCmdCount = 0;
			}
			else
			{
				goto fail_3dcmdacquire;
			}
		}
	}

	if (ui322DCmdCount)
	{
		eError = RGXCmdHelperAcquireCmdCCB(ui322DCmdCount,
										   &pas2DCmdHelper[0],
										   &bKick2D);
	
		if (eError != PVRSRV_OK)
		{
			if (bKick2D || bKick3D)
			{
				ui323DCmdCount = 0;
				ui322DCmdCount = 0;
			}
			else
			{
				goto fail_2dcmdacquire;
			}
		}
	}

	/*
		We should acquire the kernel CCB(s) space here as the schedule could fail
		and we would have to roll back all the syncs
	*/

	/*
		Only do the command helper release (which takes the server sync
		operations if the acquire succeeded
	*/
	if (ui323DCmdCount)
	{
		RGXCmdHelperReleaseCmdCCB(ui323DCmdCount,
								  &pas3DCmdHelper[0],
								  "TQ_3D",
								  FWCommonContextGetFWAddress(psTransferContext->s3DData.psServerCommonContext).ui32Addr);
		
	}

	if (ui322DCmdCount)
	{
		RGXCmdHelperReleaseCmdCCB(ui322DCmdCount,
								  &pas2DCmdHelper[0],
								  "TQ_2D",
								  FWCommonContextGetFWAddress(psTransferContext->s2DData.psServerCommonContext).ui32Addr);
	}

	/*
		Even if we failed to acquire the client CCB space we might still need
		to kick the HW to process a padding packet to release space for us next
		time round
	*/
	if (bKick3D)
	{
		RGXFWIF_KCCB_CMD s3DKCCBCmd;

		/* Construct the kernel 3D CCB command. */
		s3DKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
		s3DKCCBCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psTransferContext->s3DData.psServerCommonContext);
		s3DKCCBCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psTransferContext->s3DData.psServerCommonContext));
		s3DKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;

		LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
		{
			eError2 = RGXScheduleCommand(psDeviceNode->pvDevice,
										RGXFWIF_DM_3D,
										&s3DKCCBCmd,
										sizeof(s3DKCCBCmd),
										bPDumpContinuous);
			if (eError2 != PVRSRV_ERROR_RETRY)
			{
				break;
			}
			OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
		} END_LOOP_UNTIL_TIMEOUT();
	}

	if (bKick2D)
	{
		RGXFWIF_KCCB_CMD s2DKCCBCmd;

		/* Construct the kernel 3D CCB command. */
		s2DKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
		s2DKCCBCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psTransferContext->s2DData.psServerCommonContext);
		s2DKCCBCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psTransferContext->s2DData.psServerCommonContext));
		s2DKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;

		LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
		{
			eError2 = RGXScheduleCommand(psDeviceNode->pvDevice,
										RGXFWIF_DM_2D,
										&s2DKCCBCmd,
										sizeof(s2DKCCBCmd),
										bPDumpContinuous);
			if (eError2 != PVRSRV_ERROR_RETRY)
			{
				break;
			}
			OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
		} END_LOOP_UNTIL_TIMEOUT();
	}

	/*
	 * Now check eError (which may have returned an error from our earlier calls
	 * to RGXCmdHelperAcquireCmdCCB) - we needed to process any flush command first
	 * so we check it now...
	 */
	if (eError != PVRSRV_OK )
	{
		goto fail_2dcmdacquire;
	}

#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
	/*
		Free the merged sync memory if required
	*/
	if (bSyncsMerged)
	{
		OSFreeMem(pauiIntFenceUFOAddress);
		OSFreeMem(paui32IntFenceValue);
		OSFreeMem(pauiIntUpdateUFOAddress);
		OSFreeMem(paui32IntUpdateValue);
	}
#if defined(NO_HARDWARE)
    for (i = 0; i < ui32NumFenceFDs; i++) 
    {    
		eError = PVRFDSyncNoHwUpdateFenceKM(paui32FenceFDs[i]);
        if (eError != PVRSRV_OK)
        {    
            PVR_DPF((PVR_DBG_ERROR, "%s: Failed nohw update on fence fd=%d (%s)",
                     __func__, paui32FenceFDs[i], PVRSRVGetErrorStringKM(eError)));
        }    
    }    
#endif
#endif

#if !defined(WDDM)
	OSFreeMem(pas2DCmdHelper);
	OSFreeMem(pas3DCmdHelper);
#endif

	return PVRSRV_OK;

/*
	No resources are created in this function so there is nothing to free
	unless we had to merge syncs.
	If we fail after the client CCB acquire there is still nothing to do
	as only the client CCB release will modify the client CCB
*/
fail_2dcmdacquire:
fail_3dcmdacquire:
fail_initcmd:
#if defined(PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC)
	if (bSyncsMerged)
	{
		OSFreeMem(pauiIntFenceUFOAddress);
		OSFreeMem(paui32IntFenceValue);
		OSFreeMem(pauiIntUpdateUFOAddress);
		OSFreeMem(paui32IntUpdateValue);
	}
fail_updatevaluearray:
fail_updateUFOarray:
fail_fencevaluearray:
fail_fenceUFOarray:
fail_fdsync:
#endif
fail_pdumpcheck:
fail_cmdtype:
	PVR_ASSERT(eError != PVRSRV_OK);
#if !defined(WDDM)
	OSFreeMem(pas2DCmdHelper);
fail_alloc2dhelper:
	OSFreeMem(pas3DCmdHelper);
fail_alloc3dhelper:
#endif
	return eError;
}
Exemple #3
0
IMG_EXPORT
PVRSRV_ERROR PVRSRVRGXKickCDMKM(RGX_SERVER_COMPUTE_CONTEXT	*psComputeContext,
								IMG_UINT32					ui32ClientFenceCount,
								PRGXFWIF_UFO_ADDR			*pauiClientFenceUFOAddress,
								IMG_UINT32					*paui32ClientFenceValue,
								IMG_UINT32					ui32ClientUpdateCount,
								PRGXFWIF_UFO_ADDR			*pauiClientUpdateUFOAddress,
								IMG_UINT32					*paui32ClientUpdateValue,
								IMG_UINT32					ui32ServerSyncPrims,
								IMG_UINT32					*paui32ServerSyncFlags,
								SERVER_SYNC_PRIMITIVE 		**pasServerSyncs,
								IMG_UINT32					ui32CmdSize,
								IMG_PBYTE					pui8DMCmd,
								IMG_BOOL					bPDumpContinuous)
{
	RGXFWIF_KCCB_CMD		sCmpKCCBCmd;
	RGX_CCB_CMD_HELPER_DATA	sCmdHelperData;
	IMG_BOOL				bKickRequired;
	PVRSRV_ERROR			eError;
	PVRSRV_ERROR			eError2;
	IMG_UINT32				i;
	
	/* Sanity check the server fences */
	for (i=0;i<ui32ServerSyncPrims;i++)
	{
		if (!(paui32ServerSyncFlags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK))
		{
			PVR_DPF((PVR_DBG_ERROR, "%s: Server fence (on SH) must fence", __FUNCTION__));
			return PVRSRV_ERROR_INVALID_SYNC_PRIM_OP;
		}
	}

	eError = RGXCmdHelperInitCmdCCB(FWCommonContextGetClientCCB(psComputeContext->psServerCommonContext),
									  ui32ClientFenceCount,
									  pauiClientFenceUFOAddress,
									  paui32ClientFenceValue,
									  ui32ClientUpdateCount,
									  pauiClientUpdateUFOAddress,
									  paui32ClientUpdateValue,
									  ui32ServerSyncPrims,
									  paui32ServerSyncFlags,
									  pasServerSyncs,
									  ui32CmdSize,
									  pui8DMCmd,
									  RGXFWIF_CCB_CMD_TYPE_CDM,
									  bPDumpContinuous,
									  "Compute",
									  &sCmdHelperData);
	if (eError != PVRSRV_OK)
	{
		goto fail_cmdinit;
	}

	eError = RGXCmdHelperAcquireCmdCCB(1, &sCmdHelperData, &bKickRequired);
	if ((eError != PVRSRV_OK) && (!bKickRequired))
	{
		/*
			Only bail if no new data was submitted into the client CCB, we might
			have already submitted a padding packet which we should flush through
			the FW.
		*/
		PVR_DPF((PVR_DBG_ERROR, "RGXKickCDM: Failed to create client CCB command"));
		goto fail_cmdaquire;
	}


	/*
		We should reserved space in the kernel CCB here and fill in the command
		directly.
		This is so if there isn't space in the kernel CCB we can return with
		retry back to services client before we take any operations
	*/

	/*
		We might only be kicking for flush out a padding packet so only submit
		the command if the create was successful
	*/
	if (eError == PVRSRV_OK)
	{
		/*
			All the required resources are ready at this point, we can't fail so
			take the required server sync operations and commit all the resources
		*/
		RGXCmdHelperReleaseCmdCCB(1, &sCmdHelperData, "CDM", FWCommonContextGetFWAddress(psComputeContext->psServerCommonContext).ui32Addr);
	}

	/* Construct the kernel compute CCB command. */
	sCmpKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
	sCmpKCCBCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psComputeContext->psServerCommonContext);
	sCmpKCCBCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psComputeContext->psServerCommonContext));
	sCmpKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;

	/*
	 * Submit the compute command to the firmware.
	 */
	LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
	{
		eError2 = RGXScheduleCommand(psComputeContext->psDeviceNode->pvDevice,
									RGXFWIF_DM_CDM,
									&sCmpKCCBCmd,
									sizeof(sCmpKCCBCmd),
									bPDumpContinuous);
		if (eError2 != PVRSRV_ERROR_RETRY)
		{
			break;
		}
		OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
	} END_LOOP_UNTIL_TIMEOUT();
	
	if (eError2 != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "PVRSRVRGXKickCDMKM failed to schedule kernel CCB command. (0x%x)", eError));
	}
	/*
	 * Now check eError (which may have returned an error from our earlier call
	 * to RGXCmdHelperAcquireCmdCCB) - we needed to process any flush command first
	 * so we check it now...
	 */
	if (eError != PVRSRV_OK )
	{
		goto fail_cmdaquire;
	}

	return PVRSRV_OK;

fail_cmdaquire:
fail_cmdinit:
	return eError;
}