blob: 4682094df699a9bfc36dbb21b7993eefcfc7c0f0 [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) Imagination Technologies Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful but, except
* as otherwise stated in writing, without any warranty; without even the
* implied warranty of merchantability or fitness for a particular purpose.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* Imagination Technologies Ltd. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#include "services_headers.h"
#include "lists.h"
#include "ttrace.h"
#if defined(SUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED)
#define DC_NUM_COMMANDS_PER_TYPE 2
#else
#define DC_NUM_COMMANDS_PER_TYPE 1
#endif
typedef struct _DEVICE_COMMAND_DATA_
{
PFN_CMD_PROC pfnCmdProc;
PCOMMAND_COMPLETE_DATA apsCmdCompleteData[DC_NUM_COMMANDS_PER_TYPE];
IMG_UINT32 ui32CCBOffset;
IMG_UINT32 ui32MaxDstSyncCount;
IMG_UINT32 ui32MaxSrcSyncCount;
} DEVICE_COMMAND_DATA;
#if defined(__linux__) && defined(__KERNEL__)
#include "proc.h"
void ProcSeqShowQueue(struct seq_file *sfile,void* el)
{
PVRSRV_QUEUE_INFO *psQueue = (PVRSRV_QUEUE_INFO*)el;
IMG_INT cmds = 0;
IMG_SIZE_T ui32ReadOffset;
IMG_SIZE_T ui32WriteOffset;
PVRSRV_COMMAND *psCmd;
if(el == PVR_PROC_SEQ_START_TOKEN)
{
seq_printf( sfile,
"Command Queues\n"
"Queue CmdPtr Pid Command Size DevInd DSC SSC #Data ...\n");
return;
}
ui32ReadOffset = psQueue->ui32ReadOffset;
ui32WriteOffset = psQueue->ui32WriteOffset;
while (ui32ReadOffset != ui32WriteOffset)
{
psCmd= (PVRSRV_COMMAND *)((IMG_UINTPTR_T)psQueue->pvLinQueueKM + ui32ReadOffset);
seq_printf(sfile, "%x %x %5u %6u %3u %5u %2u %2u %3u \n",
(IMG_UINTPTR_T)psQueue,
(IMG_UINTPTR_T)psCmd,
psCmd->ui32ProcessID,
psCmd->CommandType,
psCmd->uCmdSize,
psCmd->ui32DevIndex,
psCmd->ui32DstSyncCount,
psCmd->ui32SrcSyncCount,
psCmd->uDataSize);
{
IMG_UINT32 i;
for (i = 0; i < psCmd->ui32SrcSyncCount; i++)
{
PVRSRV_SYNC_DATA *psSyncData = psCmd->psSrcSync[i].psKernelSyncInfoKM->psSyncData;
seq_printf(sfile, " Sync %u: ROP/ROC: 0x%x/0x%x WOP/WOC: 0x%x/0x%x ROC-VA: 0x%x WOC-VA: 0x%x\n",
i,
psCmd->psSrcSync[i].ui32ReadOps2Pending,
psSyncData->ui32ReadOps2Complete,
psCmd->psSrcSync[i].ui32WriteOpsPending,
psSyncData->ui32WriteOpsComplete,
psCmd->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCmd->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr);
}
}
ui32ReadOffset += psCmd->uCmdSize;
ui32ReadOffset &= psQueue->ui32QueueSize - 1;
cmds++;
}
if (cmds == 0)
{
seq_printf(sfile, "%x <empty>\n", (IMG_UINTPTR_T)psQueue);
}
}
void* ProcSeqOff2ElementQueue(struct seq_file * sfile, loff_t off)
{
PVRSRV_QUEUE_INFO *psQueue = IMG_NULL;
SYS_DATA *psSysData;
PVR_UNREFERENCED_PARAMETER(sfile);
if(!off)
{
return PVR_PROC_SEQ_START_TOKEN;
}
psSysData = SysAcquireDataNoCheck();
if (psSysData != IMG_NULL)
{
for (psQueue = psSysData->psQueueList; (((--off) > 0) && (psQueue != IMG_NULL)); psQueue = psQueue->psNextKM);
}
return psQueue;
}
#endif
#define GET_SPACE_IN_CMDQ(psQueue) \
((((psQueue)->ui32ReadOffset - (psQueue)->ui32WriteOffset) \
+ ((psQueue)->ui32QueueSize - 1)) & ((psQueue)->ui32QueueSize - 1))
#define UPDATE_QUEUE_WOFF(psQueue, ui32Size) \
(psQueue)->ui32WriteOffset = ((psQueue)->ui32WriteOffset + (ui32Size)) \
& ((psQueue)->ui32QueueSize - 1);
#define SYNCOPS_STALE(ui32OpsComplete, ui32OpsPending) \
((ui32OpsComplete) >= (ui32OpsPending))
#ifdef INLINE_IS_PRAGMA
#pragma inline(PVRSRVGetWriteOpsPending)
#endif
static INLINE
IMG_UINT32 PVRSRVGetWriteOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
{
IMG_UINT32 ui32WriteOpsPending;
if(bIsReadOp)
{
ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending;
}
else
{
ui32WriteOpsPending = psSyncInfo->psSyncData->ui32WriteOpsPending++;
}
return ui32WriteOpsPending;
}
#ifdef INLINE_IS_PRAGMA
#pragma inline(PVRSRVGetReadOpsPending)
#endif
static INLINE
IMG_UINT32 PVRSRVGetReadOpsPending(PVRSRV_KERNEL_SYNC_INFO *psSyncInfo, IMG_BOOL bIsReadOp)
{
IMG_UINT32 ui32ReadOpsPending;
if(bIsReadOp)
{
ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOps2Pending++;
}
else
{
ui32ReadOpsPending = psSyncInfo->psSyncData->ui32ReadOps2Pending;
}
return ui32ReadOpsPending;
}
static IMG_VOID QueueDumpCmdComplete(COMMAND_COMPLETE_DATA *psCmdCompleteData,
IMG_UINT32 i,
IMG_BOOL bIsSrc)
{
PVRSRV_SYNC_OBJECT *psSyncObject;
psSyncObject = bIsSrc ? psCmdCompleteData->psSrcSync : psCmdCompleteData->psDstSync;
if (psCmdCompleteData->bInUse)
{
PVR_LOG(("\t%s %u: ROC DevVAddr:0x%X ROP:0x%x ROC:0x%x, WOC DevVAddr:0x%X WOP:0x%x WOC:0x%x",
bIsSrc ? "SRC" : "DEST", i,
psSyncObject[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Pending,
psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete,
psSyncObject[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsPending,
psSyncObject[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete))
}
else
{
PVR_LOG(("\t%s %u: (Not in use)", bIsSrc ? "SRC" : "DEST", i))
}
}
static IMG_VOID QueueDumpDebugInfo_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
{
if (psDeviceNode->sDevId.eDeviceClass == PVRSRV_DEVICE_CLASS_DISPLAY)
{
IMG_UINT32 ui32CmdCounter, ui32SyncCounter;
SYS_DATA *psSysData;
DEVICE_COMMAND_DATA *psDeviceCommandData;
PCOMMAND_COMPLETE_DATA psCmdCompleteData;
SysAcquireData(&psSysData);
psDeviceCommandData = psSysData->apsDeviceCommandData[psDeviceNode->sDevId.ui32DeviceIndex];
if (psDeviceCommandData != IMG_NULL)
{
for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
{
psCmdCompleteData = psDeviceCommandData[DC_FLIP_COMMAND].apsCmdCompleteData[ui32CmdCounter];
PVR_LOG(("Flip Command Complete Data %u for display device %u:",
ui32CmdCounter, psDeviceNode->sDevId.ui32DeviceIndex))
for (ui32SyncCounter = 0;
ui32SyncCounter < psCmdCompleteData->ui32SrcSyncCount;
ui32SyncCounter++)
{
QueueDumpCmdComplete(psCmdCompleteData, ui32SyncCounter, IMG_TRUE);
}
for (ui32SyncCounter = 0;
ui32SyncCounter < psCmdCompleteData->ui32DstSyncCount;
ui32SyncCounter++)
{
QueueDumpCmdComplete(psCmdCompleteData, ui32SyncCounter, IMG_FALSE);
}
}
}
else
{
PVR_LOG(("There is no Command Complete Data for display device %u", psDeviceNode->sDevId.ui32DeviceIndex))
}
}
}
IMG_VOID QueueDumpDebugInfo(IMG_VOID)
{
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, &QueueDumpDebugInfo_ForEachCb);
}
static IMG_SIZE_T NearestPower2(IMG_SIZE_T ui32Value)
{
IMG_SIZE_T ui32Temp, ui32Result = 1;
if(!ui32Value)
return 0;
ui32Temp = ui32Value - 1;
while(ui32Temp)
{
ui32Result <<= 1;
ui32Temp >>= 1;
}
return ui32Result;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateCommandQueueKM(IMG_SIZE_T ui32QueueSize,
PVRSRV_QUEUE_INFO **ppsQueueInfo)
{
PVRSRV_QUEUE_INFO *psQueueInfo;
IMG_SIZE_T ui32Power2QueueSize = NearestPower2(ui32QueueSize);
SYS_DATA *psSysData;
PVRSRV_ERROR eError;
IMG_HANDLE hMemBlock;
SysAcquireData(&psSysData);
eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_QUEUE_INFO),
(IMG_VOID **)&psQueueInfo, &hMemBlock,
"Queue Info");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: Failed to alloc queue struct"));
goto ErrorExit;
}
OSMemSet(psQueueInfo, 0, sizeof(PVRSRV_QUEUE_INFO));
psQueueInfo->hMemBlock[0] = hMemBlock;
psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM();
eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
ui32Power2QueueSize + PVRSRV_MAX_CMD_SIZE,
&psQueueInfo->pvLinQueueKM, &hMemBlock,
"Command Queue");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVCreateCommandQueueKM: Failed to alloc queue buffer"));
goto ErrorExit;
}
psQueueInfo->hMemBlock[1] = hMemBlock;
psQueueInfo->pvLinQueueUM = psQueueInfo->pvLinQueueKM;
PVR_ASSERT(psQueueInfo->ui32ReadOffset == 0);
PVR_ASSERT(psQueueInfo->ui32WriteOffset == 0);
psQueueInfo->ui32QueueSize = ui32Power2QueueSize;
if (psSysData->psQueueList == IMG_NULL)
{
eError = OSCreateResource(&psSysData->sQProcessResource);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
}
eError = OSLockResource(&psSysData->sQProcessResource,
KERNEL_ID);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
psQueueInfo->psNextKM = psSysData->psQueueList;
psSysData->psQueueList = psQueueInfo;
eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
*ppsQueueInfo = psQueueInfo;
return PVRSRV_OK;
ErrorExit:
if(psQueueInfo)
{
if(psQueueInfo->pvLinQueueKM)
{
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
psQueueInfo->ui32QueueSize,
psQueueInfo->pvLinQueueKM,
psQueueInfo->hMemBlock[1]);
psQueueInfo->pvLinQueueKM = IMG_NULL;
}
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_QUEUE_INFO),
psQueueInfo,
psQueueInfo->hMemBlock[0]);
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyCommandQueueKM(PVRSRV_QUEUE_INFO *psQueueInfo)
{
PVRSRV_QUEUE_INFO *psQueue;
SYS_DATA *psSysData;
PVRSRV_ERROR eError;
IMG_BOOL bTimeout = IMG_TRUE;
SysAcquireData(&psSysData);
psQueue = psSysData->psQueueList;
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
if(psQueueInfo->ui32ReadOffset == psQueueInfo->ui32WriteOffset)
{
bTimeout = IMG_FALSE;
break;
}
OSSleepms(1);
} END_LOOP_UNTIL_TIMEOUT();
if (bTimeout)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVDestroyCommandQueueKM : Failed to empty queue"));
eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE;
goto ErrorExit;
}
eError = OSLockResource(&psSysData->sQProcessResource,
KERNEL_ID);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
if(psQueue == psQueueInfo)
{
psSysData->psQueueList = psQueueInfo->psNextKM;
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
NearestPower2(psQueueInfo->ui32QueueSize) + PVRSRV_MAX_CMD_SIZE,
psQueueInfo->pvLinQueueKM,
psQueueInfo->hMemBlock[1]);
psQueueInfo->pvLinQueueKM = IMG_NULL;
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_QUEUE_INFO),
psQueueInfo,
psQueueInfo->hMemBlock[0]);
psQueueInfo = IMG_NULL;
}
else
{
while(psQueue)
{
if(psQueue->psNextKM == psQueueInfo)
{
psQueue->psNextKM = psQueueInfo->psNextKM;
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
psQueueInfo->ui32QueueSize,
psQueueInfo->pvLinQueueKM,
psQueueInfo->hMemBlock[1]);
psQueueInfo->pvLinQueueKM = IMG_NULL;
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_QUEUE_INFO),
psQueueInfo,
psQueueInfo->hMemBlock[0]);
psQueueInfo = IMG_NULL;
break;
}
psQueue = psQueue->psNextKM;
}
if(!psQueue)
{
eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
eError = PVRSRV_ERROR_INVALID_PARAMS;
goto ErrorExit;
}
}
eError = OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
if (psSysData->psQueueList == IMG_NULL)
{
eError = OSDestroyResource(&psSysData->sQProcessResource);
if (eError != PVRSRV_OK)
{
goto ErrorExit;
}
}
ErrorExit:
return eError;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVGetQueueSpaceKM(PVRSRV_QUEUE_INFO *psQueue,
IMG_SIZE_T ui32ParamSize,
IMG_VOID **ppvSpace)
{
IMG_BOOL bTimeout = IMG_TRUE;
ui32ParamSize = (ui32ParamSize+3) & 0xFFFFFFFC;
if (ui32ParamSize > PVRSRV_MAX_CMD_SIZE)
{
PVR_DPF((PVR_DBG_WARNING,"PVRSRVGetQueueSpace: max command size is %d bytes", PVRSRV_MAX_CMD_SIZE));
return PVRSRV_ERROR_CMD_TOO_BIG;
}
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
if (GET_SPACE_IN_CMDQ(psQueue) > ui32ParamSize)
{
bTimeout = IMG_FALSE;
break;
}
OSSleepms(1);
} END_LOOP_UNTIL_TIMEOUT();
if (bTimeout == IMG_TRUE)
{
*ppvSpace = IMG_NULL;
return PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE;
}
else
{
*ppvSpace = (IMG_VOID *)((IMG_UINTPTR_T)psQueue->pvLinQueueUM + psQueue->ui32WriteOffset);
}
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVInsertCommandKM(PVRSRV_QUEUE_INFO *psQueue,
PVRSRV_COMMAND **ppsCommand,
IMG_UINT32 ui32DevIndex,
IMG_UINT16 CommandType,
IMG_UINT32 ui32DstSyncCount,
PVRSRV_KERNEL_SYNC_INFO *apsDstSync[],
IMG_UINT32 ui32SrcSyncCount,
PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[],
IMG_SIZE_T ui32DataByteSize,
PFN_QUEUE_COMMAND_COMPLETE pfnCommandComplete,
IMG_HANDLE hCallbackData)
{
PVRSRV_ERROR eError;
PVRSRV_COMMAND *psCommand;
IMG_SIZE_T ui32CommandSize;
IMG_UINT32 i;
SYS_DATA *psSysData;
DEVICE_COMMAND_DATA *psDeviceCommandData;
SysAcquireData(&psSysData);
psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex];
if ((psDeviceCommandData[CommandType].ui32MaxDstSyncCount < ui32DstSyncCount) ||
(psDeviceCommandData[CommandType].ui32MaxSrcSyncCount < ui32SrcSyncCount))
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVInsertCommandKM: Too many syncs"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
ui32DataByteSize = (ui32DataByteSize + 3UL) & ~3UL;
ui32CommandSize = sizeof(PVRSRV_COMMAND)
+ ((ui32DstSyncCount + ui32SrcSyncCount) * sizeof(PVRSRV_SYNC_OBJECT))
+ ui32DataByteSize;
eError = PVRSRVGetQueueSpaceKM (psQueue, ui32CommandSize, (IMG_VOID**)&psCommand);
if(eError != PVRSRV_OK)
{
return eError;
}
psCommand->ui32ProcessID = OSGetCurrentProcessIDKM();
psCommand->uCmdSize = ui32CommandSize;
psCommand->ui32DevIndex = ui32DevIndex;
psCommand->CommandType = CommandType;
psCommand->ui32DstSyncCount = ui32DstSyncCount;
psCommand->ui32SrcSyncCount = ui32SrcSyncCount;
psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand) + sizeof(PVRSRV_COMMAND));
psCommand->psSrcSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand->psDstSync)
+ (ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
psCommand->pvData = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psCommand->psSrcSync)
+ (ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
psCommand->uDataSize = ui32DataByteSize;
psCommand->pfnCommandComplete = pfnCommandComplete;
psCommand->hCallbackData = hCallbackData;
PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_START, QUEUE_TOKEN_INSERTKM);
PVR_TTRACE_UI32(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_NONE,
QUEUE_TOKEN_COMMAND_TYPE, CommandType);
for (i=0; i<ui32DstSyncCount; i++)
{
PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC,
apsDstSync[i], PVRSRV_SYNCOP_SAMPLE);
psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i];
psCommand->psDstSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE);
psCommand->psDstSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE);
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
i, psCommand->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCommand->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCommand->psDstSync[i].ui32ReadOps2Pending,
psCommand->psDstSync[i].ui32WriteOpsPending));
}
for (i=0; i<ui32SrcSyncCount; i++)
{
PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_DST_SYNC,
apsSrcSync[i], PVRSRV_SYNCOP_SAMPLE);
psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i];
psCommand->psSrcSync[i].ui32WriteOpsPending = PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE);
psCommand->psSrcSync[i].ui32ReadOps2Pending = PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE);
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInsertCommandKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
i, psCommand->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCommand->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCommand->psSrcSync[i].ui32ReadOps2Pending,
psCommand->psSrcSync[i].ui32WriteOpsPending));
}
PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_END, QUEUE_TOKEN_INSERTKM);
*ppsCommand = psCommand;
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVSubmitCommandKM(PVRSRV_QUEUE_INFO *psQueue,
PVRSRV_COMMAND *psCommand)
{
if (psCommand->ui32DstSyncCount > 0)
{
psCommand->psDstSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
+ psQueue->ui32WriteOffset + sizeof(PVRSRV_COMMAND));
}
if (psCommand->ui32SrcSyncCount > 0)
{
psCommand->psSrcSync = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
+ psQueue->ui32WriteOffset + sizeof(PVRSRV_COMMAND)
+ (psCommand->ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
}
psCommand->pvData = (PVRSRV_SYNC_OBJECT*)(((IMG_UINTPTR_T)psQueue->pvLinQueueKM)
+ psQueue->ui32WriteOffset + sizeof(PVRSRV_COMMAND)
+ (psCommand->ui32DstSyncCount * sizeof(PVRSRV_SYNC_OBJECT))
+ (psCommand->ui32SrcSyncCount * sizeof(PVRSRV_SYNC_OBJECT)));
UPDATE_QUEUE_WOFF(psQueue, psCommand->uCmdSize);
return PVRSRV_OK;
}
static
PVRSRV_ERROR CheckIfSyncIsQueued(PVRSRV_SYNC_OBJECT *psSync, COMMAND_COMPLETE_DATA *psCmdData)
{
IMG_UINT32 k;
if (psCmdData->bInUse)
{
for (k=0;k<psCmdData->ui32SrcSyncCount;k++)
{
if (psSync->psKernelSyncInfoKM == psCmdData->psSrcSync[k].psKernelSyncInfoKM)
{
PVRSRV_SYNC_DATA *psSyncData = psSync->psKernelSyncInfoKM->psSyncData;
IMG_UINT32 ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
if (ui32WriteOpsComplete == psSync->ui32WriteOpsPending)
{
return PVRSRV_OK;
}
else
{
if (SYNCOPS_STALE(ui32WriteOpsComplete, psSync->ui32WriteOpsPending))
{
PVR_DPF((PVR_DBG_WARNING,
"CheckIfSyncIsQueued: Stale syncops psSyncData:0x%x ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x",
(IMG_UINTPTR_T)psSyncData, ui32WriteOpsComplete, psSync->ui32WriteOpsPending));
return PVRSRV_OK;
}
}
}
}
}
return PVRSRV_ERROR_FAILED_DEPENDENCIES;
}
static
PVRSRV_ERROR PVRSRVProcessCommand(SYS_DATA *psSysData,
PVRSRV_COMMAND *psCommand,
IMG_BOOL bFlush)
{
PVRSRV_SYNC_OBJECT *psWalkerObj;
PVRSRV_SYNC_OBJECT *psEndObj;
IMG_UINT32 i;
COMMAND_COMPLETE_DATA *psCmdCompleteData;
PVRSRV_ERROR eError = PVRSRV_OK;
IMG_UINT32 ui32WriteOpsComplete;
IMG_UINT32 ui32ReadOpsComplete;
DEVICE_COMMAND_DATA *psDeviceCommandData;
IMG_UINT32 ui32CCBOffset;
psWalkerObj = psCommand->psDstSync;
psEndObj = psWalkerObj + psCommand->ui32DstSyncCount;
while (psWalkerObj < psEndObj)
{
PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData;
ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete;
if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
|| (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending))
{
if (!bFlush ||
!SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) ||
!SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
{
return PVRSRV_ERROR_FAILED_DEPENDENCIES;
}
}
psWalkerObj++;
}
psWalkerObj = psCommand->psSrcSync;
psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount;
while (psWalkerObj < psEndObj)
{
PVRSRV_SYNC_DATA *psSyncData = psWalkerObj->psKernelSyncInfoKM->psSyncData;
ui32ReadOpsComplete = psSyncData->ui32ReadOps2Complete;
ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
|| (ui32ReadOpsComplete != psWalkerObj->ui32ReadOps2Pending))
{
if (!bFlush &&
SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) &&
SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
{
PVR_DPF((PVR_DBG_WARNING,
"PVRSRVProcessCommand: Stale syncops psSyncData:0x%x ui32WriteOpsComplete:0x%x ui32WriteOpsPending:0x%x",
(IMG_UINTPTR_T)psSyncData, ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending));
}
if (!bFlush ||
!SYNCOPS_STALE(ui32WriteOpsComplete, psWalkerObj->ui32WriteOpsPending) ||
!SYNCOPS_STALE(ui32ReadOpsComplete, psWalkerObj->ui32ReadOps2Pending))
{
IMG_UINT32 j;
PVRSRV_ERROR eError;
IMG_BOOL bFound = IMG_FALSE;
psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex];
for (j=0;j<DC_NUM_COMMANDS_PER_TYPE;j++)
{
eError = CheckIfSyncIsQueued(psWalkerObj, psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[j]);
if (eError == PVRSRV_OK)
{
bFound = IMG_TRUE;
}
}
if (!bFound)
return PVRSRV_ERROR_FAILED_DEPENDENCIES;
}
}
psWalkerObj++;
}
if (psCommand->ui32DevIndex >= SYS_DEVICE_COUNT)
{
PVR_DPF((PVR_DBG_ERROR,
"PVRSRVProcessCommand: invalid DeviceType 0x%x",
psCommand->ui32DevIndex));
return PVRSRV_ERROR_INVALID_PARAMS;
}
psDeviceCommandData = psSysData->apsDeviceCommandData[psCommand->ui32DevIndex];
ui32CCBOffset = psDeviceCommandData[psCommand->CommandType].ui32CCBOffset;
psCmdCompleteData = psDeviceCommandData[psCommand->CommandType].apsCmdCompleteData[ui32CCBOffset];
if (psCmdCompleteData->bInUse)
{
return PVRSRV_ERROR_FAILED_DEPENDENCIES;
}
psCmdCompleteData->bInUse = IMG_TRUE;
psCmdCompleteData->ui32DstSyncCount = psCommand->ui32DstSyncCount;
for (i=0; i<psCommand->ui32DstSyncCount; i++)
{
psCmdCompleteData->psDstSync[i] = psCommand->psDstSync[i];
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)",
i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending,
psCmdCompleteData->psDstSync[i].ui32WriteOpsPending,
ui32CCBOffset));
}
psCmdCompleteData->pfnCommandComplete = psCommand->pfnCommandComplete;
psCmdCompleteData->hCallbackData = psCommand->hCallbackData;
psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount;
for (i=0; i<psCommand->ui32SrcSyncCount; i++)
{
psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i];
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVProcessCommand: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x (CCB:%u)",
i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending,
psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending,
ui32CCBOffset));
}
if (psDeviceCommandData[psCommand->CommandType].pfnCmdProc((IMG_HANDLE)psCmdCompleteData,
(IMG_UINT32)psCommand->uDataSize,
psCommand->pvData) == IMG_FALSE)
{
psCmdCompleteData->bInUse = IMG_FALSE;
eError = PVRSRV_ERROR_CMD_NOT_PROCESSED;
}
psDeviceCommandData[psCommand->CommandType].ui32CCBOffset = (ui32CCBOffset + 1) % DC_NUM_COMMANDS_PER_TYPE;
return eError;
}
static IMG_VOID PVRSRVProcessQueues_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
{
if (psDeviceNode->bReProcessDeviceCommandComplete &&
psDeviceNode->pfnDeviceCommandComplete != IMG_NULL)
{
(*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode);
}
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVProcessQueues(IMG_BOOL bFlush)
{
PVRSRV_QUEUE_INFO *psQueue;
SYS_DATA *psSysData;
PVRSRV_COMMAND *psCommand;
SysAcquireData(&psSysData);
while (OSLockResource(&psSysData->sQProcessResource, ISR_ID) != PVRSRV_OK)
{
OSWaitus(1);
};
psQueue = psSysData->psQueueList;
if(!psQueue)
{
PVR_DPF((PVR_DBG_MESSAGE,"No Queues installed - cannot process commands"));
}
if (bFlush)
{
PVRSRVSetDCState(DC_STATE_FLUSH_COMMANDS);
}
while (psQueue)
{
while (psQueue->ui32ReadOffset != psQueue->ui32WriteOffset)
{
psCommand = (PVRSRV_COMMAND*)((IMG_UINTPTR_T)psQueue->pvLinQueueKM + psQueue->ui32ReadOffset);
if (PVRSRVProcessCommand(psSysData, psCommand, bFlush) == PVRSRV_OK)
{
UPDATE_QUEUE_ROFF(psQueue, psCommand->uCmdSize)
continue;
}
break;
}
psQueue = psQueue->psNextKM;
}
if (bFlush)
{
PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS);
}
List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
&PVRSRVProcessQueues_ForEachCb);
OSUnlockResource(&psSysData->sQProcessResource, ISR_ID);
return PVRSRV_OK;
}
#if defined(SUPPORT_CUSTOM_SWAP_OPERATIONS)
IMG_INTERNAL
IMG_VOID PVRSRVFreeCommandCompletePacketKM(IMG_HANDLE hCmdCookie,
IMG_BOOL bScheduleMISR)
{
COMMAND_COMPLETE_DATA *psCmdCompleteData = (COMMAND_COMPLETE_DATA *)hCmdCookie;
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
psCmdCompleteData->bInUse = IMG_FALSE;
PVRSRVScheduleDeviceCallbacks();
if(bScheduleMISR)
{
OSScheduleMISR(psSysData);
}
}
#endif
IMG_EXPORT
IMG_VOID PVRSRVCommandCompleteKM(IMG_HANDLE hCmdCookie,
IMG_BOOL bScheduleMISR)
{
IMG_UINT32 i;
COMMAND_COMPLETE_DATA *psCmdCompleteData = (COMMAND_COMPLETE_DATA *)hCmdCookie;
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_START,
QUEUE_TOKEN_COMMAND_COMPLETE);
for (i=0; i<psCmdCompleteData->ui32DstSyncCount; i++)
{
psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData->ui32WriteOpsComplete++;
PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_DST,
psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM,
PVRSRV_SYNCOP_COMPLETE);
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Dst %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
i, psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCmdCompleteData->psDstSync[i].ui32ReadOps2Pending,
psCmdCompleteData->psDstSync[i].ui32WriteOpsPending));
}
for (i=0; i<psCmdCompleteData->ui32SrcSyncCount; i++)
{
psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->ui32ReadOps2Complete++;
PVR_TTRACE_SYNC_OBJECT(PVRSRV_TRACE_GROUP_QUEUE, QUEUE_TOKEN_UPDATE_SRC,
psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM,
PVRSRV_SYNCOP_COMPLETE);
PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVCommandCompleteKM: Src %u RO-VA:0x%x WO-VA:0x%x ROP:0x%x WOP:0x%x",
i, psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sReadOps2CompleteDevVAddr.uiAddr,
psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->sWriteOpsCompleteDevVAddr.uiAddr,
psCmdCompleteData->psSrcSync[i].ui32ReadOps2Pending,
psCmdCompleteData->psSrcSync[i].ui32WriteOpsPending));
}
PVR_TTRACE(PVRSRV_TRACE_GROUP_QUEUE, PVRSRV_TRACE_CLASS_CMD_COMP_END,
QUEUE_TOKEN_COMMAND_COMPLETE);
if (psCmdCompleteData->pfnCommandComplete)
{
psCmdCompleteData->pfnCommandComplete(psCmdCompleteData->hCallbackData);
}
psCmdCompleteData->bInUse = IMG_FALSE;
PVRSRVScheduleDeviceCallbacks();
if(bScheduleMISR)
{
OSScheduleMISR(psSysData);
}
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(IMG_UINT32 ui32DevIndex,
PFN_CMD_PROC *ppfnCmdProcList,
IMG_UINT32 ui32MaxSyncsPerCmd[][2],
IMG_UINT32 ui32CmdCount)
{
SYS_DATA *psSysData;
PVRSRV_ERROR eError;
IMG_UINT32 ui32CmdCounter, ui32CmdTypeCounter;
IMG_SIZE_T ui32AllocSize;
DEVICE_COMMAND_DATA *psDeviceCommandData;
COMMAND_COMPLETE_DATA *psCmdCompleteData;
if(ui32DevIndex >= SYS_DEVICE_COUNT)
{
PVR_DPF((PVR_DBG_ERROR,
"PVRSRVRegisterCmdProcListKM: invalid DeviceType 0x%x",
ui32DevIndex));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData);
eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
ui32AllocSize,
(IMG_VOID **)&psDeviceCommandData, IMG_NULL,
"Array of Pointers for Command Store");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterCmdProcListKM: Failed to alloc CC data"));
goto ErrorExit;
}
psSysData->apsDeviceCommandData[ui32DevIndex] = psDeviceCommandData;
for (ui32CmdTypeCounter = 0; ui32CmdTypeCounter < ui32CmdCount; ui32CmdTypeCounter++)
{
psDeviceCommandData[ui32CmdTypeCounter].pfnCmdProc = ppfnCmdProcList[ui32CmdTypeCounter];
psDeviceCommandData[ui32CmdTypeCounter].ui32CCBOffset = 0;
psDeviceCommandData[ui32CmdTypeCounter].ui32MaxDstSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0];
psDeviceCommandData[ui32CmdTypeCounter].ui32MaxSrcSyncCount = ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1];
for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
{
ui32AllocSize = sizeof(COMMAND_COMPLETE_DATA)
+ ((ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0]
+ ui32MaxSyncsPerCmd[ui32CmdTypeCounter][1])
* sizeof(PVRSRV_SYNC_OBJECT));
eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
ui32AllocSize,
(IMG_VOID **)&psCmdCompleteData,
IMG_NULL,
"Command Complete Data");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterCmdProcListKM: Failed to alloc cmd %d", ui32CmdTypeCounter));
goto ErrorExit;
}
psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = psCmdCompleteData;
OSMemSet(psCmdCompleteData, 0x00, ui32AllocSize);
psCmdCompleteData->psDstSync = (PVRSRV_SYNC_OBJECT*)
(((IMG_UINTPTR_T)psCmdCompleteData)
+ sizeof(COMMAND_COMPLETE_DATA));
psCmdCompleteData->psSrcSync = (PVRSRV_SYNC_OBJECT*)
(((IMG_UINTPTR_T)psCmdCompleteData->psDstSync)
+ (sizeof(PVRSRV_SYNC_OBJECT) * ui32MaxSyncsPerCmd[ui32CmdTypeCounter][0]));
psCmdCompleteData->ui32AllocSize = (IMG_UINT32)ui32AllocSize;
}
}
return PVRSRV_OK;
ErrorExit:
if (PVRSRVRemoveCmdProcListKM(ui32DevIndex, ui32CmdCount) != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"PVRSRVRegisterCmdProcListKM: Failed to clean up after error, device 0x%x",
ui32DevIndex));
}
return eError;
}
IMG_EXPORT
PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(IMG_UINT32 ui32DevIndex,
IMG_UINT32 ui32CmdCount)
{
SYS_DATA *psSysData;
IMG_UINT32 ui32CmdTypeCounter, ui32CmdCounter;
DEVICE_COMMAND_DATA *psDeviceCommandData;
COMMAND_COMPLETE_DATA *psCmdCompleteData;
IMG_SIZE_T ui32AllocSize;
if(ui32DevIndex >= SYS_DEVICE_COUNT)
{
PVR_DPF((PVR_DBG_ERROR,
"PVRSRVRemoveCmdProcListKM: invalid DeviceType 0x%x",
ui32DevIndex));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
psDeviceCommandData = psSysData->apsDeviceCommandData[ui32DevIndex];
if(psDeviceCommandData != IMG_NULL)
{
for (ui32CmdTypeCounter = 0; ui32CmdTypeCounter < ui32CmdCount; ui32CmdTypeCounter++)
{
for (ui32CmdCounter = 0; ui32CmdCounter < DC_NUM_COMMANDS_PER_TYPE; ui32CmdCounter++)
{
psCmdCompleteData = psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter];
if (psCmdCompleteData != IMG_NULL)
{
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, psCmdCompleteData->ui32AllocSize,
psCmdCompleteData, IMG_NULL);
psDeviceCommandData[ui32CmdTypeCounter].apsCmdCompleteData[ui32CmdCounter] = IMG_NULL;
}
}
}
ui32AllocSize = ui32CmdCount * sizeof(*psDeviceCommandData);
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, ui32AllocSize, psDeviceCommandData, IMG_NULL);
psSysData->apsDeviceCommandData[ui32DevIndex] = IMG_NULL;
}
return PVRSRV_OK;
}