Maemo patchset 20101501+0m5
[h-e-n] / drivers / gpu / pvr / queue.c
diff --git a/drivers/gpu/pvr/queue.c b/drivers/gpu/pvr/queue.c
new file mode 100644 (file)
index 0000000..05644c0
--- /dev/null
@@ -0,0 +1,833 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 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 "proc.h"
+
+static int QueuePrintCommands(struct PVRSRV_QUEUE_INFO *psQueue, char *buffer,
+                             size_t size)
+{
+       off_t off = 0;
+       int cmds = 0;
+       u32 ui32ReadOffset = psQueue->ui32ReadOffset;
+       u32 ui32WriteOffset = psQueue->ui32WriteOffset;
+       struct PVRSRV_COMMAND *psCmd;
+
+       while (ui32ReadOffset != ui32WriteOffset) {
+               psCmd =
+                   (struct PVRSRV_COMMAND *)((u32) psQueue->pvLinQueueKM +
+                                       ui32ReadOffset);
+
+               off =
+                   printAppend(buffer, size, off,
+                       "%p %p  %5u  %6u  %3u  %5u   %2u   %2u    %3u  \n",
+                               psQueue, psCmd, psCmd->ui32ProcessID,
+                               psCmd->CommandType, psCmd->ui32CmdSize,
+                               psCmd->ui32DevIndex, psCmd->ui32DstSyncCount,
+                               psCmd->ui32SrcSyncCount, psCmd->ui32DataSize);
+
+               ui32ReadOffset += psCmd->ui32CmdSize;
+               ui32ReadOffset &= psQueue->ui32QueueSize - 1;
+               cmds++;
+       }
+       if (cmds == 0)
+               off = printAppend(buffer, size, off, "%p <empty>\n", psQueue);
+       return off;
+}
+
+off_t QueuePrintQueues(char *buffer, size_t size, off_t off)
+{
+       struct SYS_DATA *psSysData;
+       struct PVRSRV_QUEUE_INFO *psQueue;
+
+       if (SysAcquireData(&psSysData) != PVRSRV_OK)
+               return END_OF_FILE;
+
+       if (!off)
+               return printAppend(buffer, size, 0,
+                       "Command Queues\n"
+                       "Queue    CmdPtr      Pid Command Size DevInd  "
+                       "DSC  SSC  #Data ...\n");
+
+       for (psQueue = psSysData->psQueueList; --off && psQueue;
+            psQueue = psQueue->psNextKM)
+               ;
+
+       return psQueue ?
+               QueuePrintCommands(psQueue, buffer, size) : END_OF_FILE;
+}
+
+#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)
+
+static u32 NearestPower2(u32 ui32Value)
+{
+       u32 ui32Temp, ui32Result = 1;
+
+       if (!ui32Value)
+               return 0;
+
+       ui32Temp = ui32Value - 1;
+       while (ui32Temp) {
+               ui32Result <<= 1;
+               ui32Temp >>= 1;
+       }
+
+       return ui32Result;
+}
+
+enum PVRSRV_ERROR PVRSRVCreateCommandQueueKM(u32 ui32QueueSize,
+                                struct PVRSRV_QUEUE_INFO **ppsQueueInfo)
+{
+       struct PVRSRV_QUEUE_INFO *psQueueInfo;
+       u32 ui32Power2QueueSize = NearestPower2(ui32QueueSize);
+       struct SYS_DATA *psSysData;
+       enum PVRSRV_ERROR eError;
+       void *hMemBlock;
+
+       eError = SysAcquireData(&psSysData);
+       if (eError != PVRSRV_OK)
+               return eError;
+
+       if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                      sizeof(struct PVRSRV_QUEUE_INFO),
+                      (void **) &psQueueInfo, &hMemBlock) != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateCommandQueueKM: "
+                               "Failed to alloc queue struct");
+               goto ErrorExit;
+       }
+       OSMemSet(psQueueInfo, 0, sizeof(struct PVRSRV_QUEUE_INFO));
+
+       psQueueInfo->hMemBlock[0] = hMemBlock;
+       psQueueInfo->ui32ProcessID = OSGetCurrentProcessIDKM();
+
+       if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                      ui32Power2QueueSize + PVRSRV_MAX_CMD_SIZE,
+                      &psQueueInfo->pvLinQueueKM, &hMemBlock) != 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 == NULL) {
+               eError = OSCreateResource(&psSysData->sQProcessResource);
+               if (eError != PVRSRV_OK)
+                       goto ErrorExit;
+       }
+
+       if (OSLockResource(&psSysData->sQProcessResource,
+                          KERNEL_ID) != PVRSRV_OK)
+               goto ErrorExit;
+
+       psQueueInfo->psNextKM = psSysData->psQueueList;
+       psSysData->psQueueList = psQueueInfo;
+
+       if (OSUnlockResource(&psSysData->sQProcessResource, KERNEL_ID) !=
+           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]);
+
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         sizeof(struct PVRSRV_QUEUE_INFO),
+                         psQueueInfo, psQueueInfo->hMemBlock[0]);
+       }
+
+       return PVRSRV_ERROR_GENERIC;
+}
+
+enum PVRSRV_ERROR PVRSRVDestroyCommandQueueKM(
+                               struct PVRSRV_QUEUE_INFO *psQueueInfo)
+{
+       struct PVRSRV_QUEUE_INFO *psQueue;
+       struct SYS_DATA *psSysData;
+       enum PVRSRV_ERROR eError;
+       IMG_BOOL bTimeout = IMG_TRUE;
+       IMG_BOOL bStart = IMG_FALSE;
+       u32 uiStart = 0;
+
+       eError = SysAcquireData(&psSysData);
+       if (eError != PVRSRV_OK)
+               return eError;
+
+       psQueue = psSysData->psQueueList;
+
+       do {
+               if (psQueueInfo->ui32ReadOffset ==
+                   psQueueInfo->ui32WriteOffset) {
+                       bTimeout = IMG_FALSE;
+                       break;
+               }
+
+               if (bStart == IMG_FALSE) {
+                       bStart = IMG_TRUE;
+                       uiStart = OSClockus();
+               }
+               OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
+       } while ((OSClockus() - uiStart) < MAX_HW_TIME_US);
+
+       if (bTimeout) {
+
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVDestroyCommandQueueKM : "
+                                       "Failed to empty queue");
+               eError = PVRSRV_ERROR_CANNOT_FLUSH_QUEUE;
+       }
+
+       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,
+                         psQueueInfo->ui32QueueSize,
+                         psQueueInfo->pvLinQueueKM, psQueueInfo->hMemBlock[1]);
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         sizeof(struct PVRSRV_QUEUE_INFO),
+                         psQueueInfo, psQueueInfo->hMemBlock[0]);
+       } else {
+               while (psQueue) {
+                       if (psQueue->psNextKM == psQueueInfo) {
+                               psQueue->psNextKM = psQueueInfo->psNextKM;
+
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                         psQueueInfo->ui32QueueSize,
+                                         psQueueInfo->pvLinQueueKM,
+                                         psQueueInfo->hMemBlock[1]);
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                         sizeof(struct PVRSRV_QUEUE_INFO),
+                                         psQueueInfo,
+                                         psQueueInfo->hMemBlock[0]);
+                               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 == NULL) {
+               eError = OSDestroyResource(&psSysData->sQProcessResource);
+               if (eError != PVRSRV_OK)
+                       goto ErrorExit;
+       }
+
+ErrorExit:
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVGetQueueSpaceKM(struct PVRSRV_QUEUE_INFO *psQueue,
+                                   u32 ui32ParamSize, void **ppvSpace)
+{
+       IMG_BOOL bTimeout = IMG_TRUE;
+       IMG_BOOL bStart = IMG_FALSE;
+       u32 uiStart = 0, uiCurrent = 0;
+
+       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;
+       }
+
+       do {
+               if (GET_SPACE_IN_CMDQ(psQueue) > ui32ParamSize) {
+                       bTimeout = IMG_FALSE;
+                       break;
+               }
+
+               if (bStart == IMG_FALSE) {
+                       bStart = IMG_TRUE;
+                       uiStart = OSClockus();
+               }
+               OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
+
+               uiCurrent = OSClockus();
+               if (uiCurrent < uiStart)
+
+                       uiStart = 0;
+       } while ((uiCurrent - uiStart) < MAX_HW_TIME_US);
+
+       if (bTimeout == IMG_TRUE) {
+               *ppvSpace = NULL;
+
+               return PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE;
+       } else {
+               *ppvSpace =
+                   (void *) (psQueue->ui32WriteOffset +
+                                 (u32) psQueue->pvLinQueueUM);
+       }
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVInsertCommandKM(struct PVRSRV_QUEUE_INFO *psQueue,
+                                  struct PVRSRV_COMMAND **ppsCommand,
+                                  u32 ui32DevIndex, u16 CommandType,
+                                  u32 ui32DstSyncCount,
+                                  struct PVRSRV_KERNEL_SYNC_INFO *apsDstSync[],
+                                  u32 ui32SrcSyncCount,
+                                  struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[],
+                                  u32 ui32DataByteSize)
+{
+       enum PVRSRV_ERROR eError;
+       struct PVRSRV_COMMAND *psCommand;
+       u32 ui32CommandSize;
+       u32 i;
+
+       ui32DataByteSize = (ui32DataByteSize + 3) & 0xFFFFFFFC;
+
+       ui32CommandSize = sizeof(struct PVRSRV_COMMAND) +
+           ((ui32DstSyncCount + ui32SrcSyncCount) *
+            sizeof(struct PVRSRV_SYNC_OBJECT)) + ui32DataByteSize;
+
+       eError = PVRSRVGetQueueSpaceKM(psQueue, ui32CommandSize,
+                                 (void **) &psCommand);
+       if (eError != PVRSRV_OK)
+               return eError;
+
+       psCommand->ui32ProcessID = OSGetCurrentProcessIDKM();
+
+       psCommand->ui32CmdSize = ui32CommandSize;
+       psCommand->ui32DevIndex = ui32DevIndex;
+       psCommand->CommandType = CommandType;
+       psCommand->ui32DstSyncCount = ui32DstSyncCount;
+       psCommand->ui32SrcSyncCount = ui32SrcSyncCount;
+       psCommand->psDstSync =
+           (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand) +
+                                   sizeof(struct PVRSRV_COMMAND));
+
+       psCommand->psSrcSync =
+           (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psDstSync) +
+                                   (ui32DstSyncCount *
+                                    sizeof(struct PVRSRV_SYNC_OBJECT)));
+
+       psCommand->pvData =
+           (struct PVRSRV_SYNC_OBJECT *)(((u8 *) psCommand->psSrcSync) +
+                                   (ui32SrcSyncCount *
+                                    sizeof(struct PVRSRV_SYNC_OBJECT)));
+
+       psCommand->ui32DataSize = ui32DataByteSize;
+
+       for (i = 0; i < ui32DstSyncCount; i++) {
+               psCommand->psDstSync[i].psKernelSyncInfoKM = apsDstSync[i];
+               psCommand->psDstSync[i].ui32WriteOpsPending =
+                   PVRSRVGetWriteOpsPending(apsDstSync[i], IMG_FALSE);
+               psCommand->psDstSync[i].ui32ReadOpsPending =
+                   PVRSRVGetReadOpsPending(apsDstSync[i], IMG_FALSE);
+       }
+
+       for (i = 0; i < ui32SrcSyncCount; i++) {
+               psCommand->psSrcSync[i].psKernelSyncInfoKM = apsSrcSync[i];
+               psCommand->psSrcSync[i].ui32WriteOpsPending =
+                   PVRSRVGetWriteOpsPending(apsSrcSync[i], IMG_TRUE);
+               psCommand->psSrcSync[i].ui32ReadOpsPending =
+                   PVRSRVGetReadOpsPending(apsSrcSync[i], IMG_TRUE);
+       }
+
+       *ppsCommand = psCommand;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVSubmitCommandKM(struct PVRSRV_QUEUE_INFO *psQueue,
+                                   struct PVRSRV_COMMAND *psCommand)
+{
+       if (psCommand->ui32DstSyncCount > 0)
+               psCommand->psDstSync = (struct PVRSRV_SYNC_OBJECT *)
+                       (((u8 *) psQueue->pvLinQueueKM) +
+                        psQueue->ui32WriteOffset +
+                        sizeof(struct PVRSRV_COMMAND));
+
+       if (psCommand->ui32SrcSyncCount > 0)
+               psCommand->psSrcSync = (struct PVRSRV_SYNC_OBJECT *)
+                       (((u8 *) psQueue->pvLinQueueKM) +
+                        psQueue->ui32WriteOffset +
+                        sizeof(struct PVRSRV_COMMAND) +
+                        (psCommand->ui32DstSyncCount *
+                               sizeof(struct PVRSRV_SYNC_OBJECT)));
+
+       psCommand->pvData = (struct PVRSRV_SYNC_OBJECT *)
+                       (((u8 *) psQueue->pvLinQueueKM) +
+                        psQueue->ui32WriteOffset +
+                        sizeof(struct PVRSRV_COMMAND) +
+                        (psCommand->ui32DstSyncCount *
+                               sizeof(struct PVRSRV_SYNC_OBJECT)) +
+                        (psCommand->ui32SrcSyncCount *
+                               sizeof(struct PVRSRV_SYNC_OBJECT)));
+
+       UPDATE_QUEUE_WOFF(psQueue, psCommand->ui32CmdSize);
+
+       return PVRSRV_OK;
+}
+
+static enum PVRSRV_ERROR PVRSRVProcessCommand(struct SYS_DATA *psSysData,
+                                             struct PVRSRV_COMMAND *psCommand,
+                                             IMG_BOOL bFlush)
+{
+       struct PVRSRV_SYNC_OBJECT *psWalkerObj;
+       struct PVRSRV_SYNC_OBJECT *psEndObj;
+       u32 i;
+       struct COMMAND_COMPLETE_DATA *psCmdCompleteData;
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+       u32 ui32WriteOpsComplete;
+       u32 ui32ReadOpsComplete;
+
+       psWalkerObj = psCommand->psDstSync;
+       psEndObj = psWalkerObj + psCommand->ui32DstSyncCount;
+       while (psWalkerObj < psEndObj) {
+               struct PVRSRV_SYNC_DATA *psSyncData =
+                   psWalkerObj->psKernelSyncInfoKM->psSyncData;
+
+               ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
+               ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete;
+
+               if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
+                   || (ui32ReadOpsComplete != psWalkerObj->ui32ReadOpsPending))
+                       if (!bFlush ||
+                           !SYNCOPS_STALE(ui32WriteOpsComplete,
+                                          psWalkerObj->ui32WriteOpsPending)
+                           || !SYNCOPS_STALE(ui32ReadOpsComplete,
+                                             psWalkerObj->
+                                             ui32ReadOpsPending))
+                               return PVRSRV_ERROR_FAILED_DEPENDENCIES;
+
+               psWalkerObj++;
+       }
+
+       psWalkerObj = psCommand->psSrcSync;
+       psEndObj = psWalkerObj + psCommand->ui32SrcSyncCount;
+       while (psWalkerObj < psEndObj) {
+               struct PVRSRV_SYNC_DATA *psSyncData =
+                   psWalkerObj->psKernelSyncInfoKM->psSyncData;
+
+               ui32ReadOpsComplete = psSyncData->ui32ReadOpsComplete;
+               ui32WriteOpsComplete = psSyncData->ui32WriteOpsComplete;
+
+               if ((ui32WriteOpsComplete != psWalkerObj->ui32WriteOpsPending)
+                   || (ui32ReadOpsComplete !=
+                                       psWalkerObj->ui32ReadOpsPending)) {
+                       if (!bFlush && SYNCOPS_STALE(ui32WriteOpsComplete,
+                           psWalkerObj->ui32WriteOpsPending) &&
+                           SYNCOPS_STALE(ui32ReadOpsComplete,
+                                            psWalkerObj->ui32ReadOpsPending))
+                               PVR_DPF(PVR_DBG_WARNING,
+                                        "PVRSRVProcessCommand: "
+                                        "Stale syncops psSyncData:0x%x "
+                                        "ui32WriteOpsComplete:0x%x "
+                                        "ui32WriteOpsPending:0x%x",
+                                        psSyncData, ui32WriteOpsComplete,
+                                        psWalkerObj->ui32WriteOpsPending);
+
+                       if (!bFlush || !SYNCOPS_STALE(ui32WriteOpsComplete,
+                           psWalkerObj->ui32WriteOpsPending) ||
+                           !SYNCOPS_STALE(ui32ReadOpsComplete,
+                                           psWalkerObj->ui32ReadOpsPending))
+                               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;
+       }
+
+       psCmdCompleteData =
+           psSysData->ppsCmdCompleteData[psCommand->ui32DevIndex][psCommand->
+                                                                  CommandType];
+       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];
+
+       psCmdCompleteData->ui32SrcSyncCount = psCommand->ui32SrcSyncCount;
+       for (i = 0; i < psCommand->ui32SrcSyncCount; i++)
+               psCmdCompleteData->psSrcSync[i] = psCommand->psSrcSync[i];
+
+       if (psSysData->ppfnCmdProcList[psCommand->ui32DevIndex]
+                                     [psCommand->CommandType]((void *)
+                                          psCmdCompleteData,
+                                          psCommand->ui32DataSize,
+                                          psCommand->pvData) == IMG_FALSE) {
+               psCmdCompleteData->bInUse = IMG_FALSE;
+               eError = PVRSRV_ERROR_CMD_NOT_PROCESSED;
+       }
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVProcessQueues(u32 ui32CallerID, IMG_BOOL bFlush)
+{
+       struct PVRSRV_QUEUE_INFO *psQueue;
+       struct SYS_DATA *psSysData;
+       struct PVRSRV_COMMAND *psCommand;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+       enum PVRSRV_ERROR eError;
+
+       eError = SysAcquireData(&psSysData);
+       if (eError != PVRSRV_OK)
+               return eError;
+
+       psSysData->bReProcessQueues = IMG_FALSE;
+
+       eError = OSLockResource(&psSysData->sQProcessResource, ui32CallerID);
+       if (eError != PVRSRV_OK) {
+               psSysData->bReProcessQueues = IMG_TRUE;
+
+               if (ui32CallerID == ISR_ID) {
+                       if (bFlush) {
+                               PVR_DPF(PVR_DBG_ERROR, "PVRSRVProcessQueues: "
+                                       "Couldn't acquire queue processing "
+                                       "lock for FLUSH");
+                       } else {
+                               PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVProcessQueues:"
+                                  " Couldn't acquire queue processing lock");
+                       }
+               } else {
+                       PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVProcessQueues: "
+                               "Queue processing lock-acquire failed when "
+                               "called from the Services driver.");
+                       PVR_DPF(PVR_DBG_MESSAGE, "                     "
+                               "This is due to MISR queue processing being "
+                               "interrupted by the Services driver.");
+               }
+
+               return PVRSRV_OK;
+       }
+
+       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 = (struct PVRSRV_COMMAND *)((u32) psQueue->
+                                       pvLinQueueKM + psQueue->ui32ReadOffset);
+
+                       if (PVRSRVProcessCommand(psSysData, psCommand, bFlush)
+                           == PVRSRV_OK) {
+                               UPDATE_QUEUE_ROFF(psQueue,
+                                                 psCommand->ui32CmdSize)
+                               if (bFlush)
+                                       continue;
+                       }
+                       break;
+               }
+               psQueue = psQueue->psNextKM;
+       }
+
+       if (bFlush)
+               PVRSRVSetDCState(DC_STATE_NO_FLUSH_COMMANDS);
+
+       psDeviceNode = psSysData->psDeviceNodeList;
+       while (psDeviceNode != NULL) {
+               if (psDeviceNode->bReProcessDeviceCommandComplete &&
+                   psDeviceNode->pfnDeviceCommandComplete != NULL) {
+                       (*psDeviceNode->
+                        pfnDeviceCommandComplete) (psDeviceNode);
+               }
+               psDeviceNode = psDeviceNode->psNext;
+       }
+
+       OSUnlockResource(&psSysData->sQProcessResource, ui32CallerID);
+
+       if (psSysData->bReProcessQueues)
+               return PVRSRV_ERROR_PROCESSING_BLOCKED;
+
+       return PVRSRV_OK;
+}
+
+void PVRSRVCommandCompleteKM(void *hCmdCookie, IMG_BOOL bScheduleMISR)
+{
+       u32 i;
+       struct COMMAND_COMPLETE_DATA *psCmdCompleteData =
+           (struct COMMAND_COMPLETE_DATA *)hCmdCookie;
+       struct SYS_DATA *psSysData;
+
+       if (SysAcquireData(&psSysData) != PVRSRV_OK)
+               return;
+
+       for (i = 0; i < psCmdCompleteData->ui32DstSyncCount; i++)
+               psCmdCompleteData->psDstSync[i].psKernelSyncInfoKM->psSyncData->
+                   ui32WriteOpsComplete++;
+
+       for (i = 0; i < psCmdCompleteData->ui32SrcSyncCount; i++)
+               psCmdCompleteData->psSrcSync[i].psKernelSyncInfoKM->psSyncData->
+                   ui32ReadOpsComplete++;
+
+       psCmdCompleteData->bInUse = IMG_FALSE;
+
+       PVRSRVCommandCompleteCallbacks();
+
+       if (bScheduleMISR)
+               OSScheduleMISR(psSysData);
+}
+
+void PVRSRVCommandCompleteCallbacks(void)
+{
+       struct SYS_DATA *psSysData;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+
+       if (SysAcquireData(&psSysData) != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVCommandCompleteCallbacks: "
+                        "SysAcquireData failed");
+               return;
+       }
+
+       psDeviceNode = psSysData->psDeviceNodeList;
+       while (psDeviceNode != NULL) {
+               if (psDeviceNode->pfnDeviceCommandComplete != NULL)
+
+                       (*psDeviceNode->
+                        pfnDeviceCommandComplete) (psDeviceNode);
+               psDeviceNode = psDeviceNode->psNext;
+       }
+}
+
+enum PVRSRV_ERROR PVRSRVRegisterCmdProcListKM(u32 ui32DevIndex,
+                            IMG_BOOL (**ppfnCmdProcList)(void *, u32, void *),
+                            u32 ui32MaxSyncsPerCmd[][2], u32 ui32CmdCount)
+{
+       struct SYS_DATA *psSysData;
+       enum PVRSRV_ERROR eError;
+       u32 i;
+       u32 ui32AllocSize;
+       IMG_BOOL (**ppfnCmdProc)(void *, u32, void *);
+       struct 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;
+       }
+
+       eError = SysAcquireData(&psSysData);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVRegisterCmdProcListKM: SysAcquireData failed");
+               return eError;
+       }
+
+       eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, ui32CmdCount *
+                                    sizeof(IMG_BOOL (*)(void *, u32, void *)),
+                           (void **) &psSysData->ppfnCmdProcList[ui32DevIndex],
+                           NULL);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVRegisterCmdProcListKM: Failed to alloc queue");
+               return eError;
+       }
+
+       ppfnCmdProc = psSysData->ppfnCmdProcList[ui32DevIndex];
+
+       for (i = 0; i < ui32CmdCount; i++)
+               ppfnCmdProc[i] = ppfnCmdProcList[i];
+
+       ui32AllocSize = ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *);
+       eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                           ui32AllocSize,
+                           (void **) &psSysData->
+                           ppsCmdCompleteData[ui32DevIndex], NULL);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterCmdProcListKM: "
+                        "Failed to alloc CC data");
+               goto ErrorExit;
+       }
+       /*
+          clear the list to ensure that we don't try to access
+          uninitialised pointer in the 'error' execution path
+        */
+       OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex], 0x00,
+                ui32AllocSize);
+
+       for (i = 0; i < ui32CmdCount; i++) {
+               ui32AllocSize = sizeof(struct COMMAND_COMPLETE_DATA)
+                   + ((ui32MaxSyncsPerCmd[i][0] + ui32MaxSyncsPerCmd[i][1])
+                      * sizeof(struct PVRSRV_SYNC_OBJECT));
+
+               eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                   ui32AllocSize,
+                                   (void **)&psSysData->
+                                   ppsCmdCompleteData[ui32DevIndex][i],
+                                   NULL);
+               if (eError != PVRSRV_OK) {
+                       PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterCmdProcListKM: "
+                                               "Failed to alloc cmd %d", i);
+                       goto ErrorExit;
+               }
+
+               OSMemSet(psSysData->ppsCmdCompleteData[ui32DevIndex][i], 0x00,
+                        ui32AllocSize);
+
+               psCmdCompleteData =
+                   psSysData->ppsCmdCompleteData[ui32DevIndex][i];
+
+               psCmdCompleteData->psDstSync = (struct PVRSRV_SYNC_OBJECT *)
+                    (((u32) psCmdCompleteData) +
+                                       sizeof(struct COMMAND_COMPLETE_DATA));
+               psCmdCompleteData->psSrcSync = (struct PVRSRV_SYNC_OBJECT *)
+                    (((u32) psCmdCompleteData->psDstSync) +
+                                       (sizeof(struct PVRSRV_SYNC_OBJECT) *
+                                        ui32MaxSyncsPerCmd[i][0]));
+               psCmdCompleteData->ui32AllocSize = ui32AllocSize;
+       }
+
+       return PVRSRV_OK;
+
+ErrorExit:
+
+       if (psSysData->ppsCmdCompleteData[ui32DevIndex] != NULL) {
+               for (i = 0; i < ui32CmdCount; i++)
+                       if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] !=
+                           NULL) {
+                               psCmdCompleteData =
+                                   psSysData->
+                                   ppsCmdCompleteData[ui32DevIndex][i];
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                         psCmdCompleteData->ui32AllocSize,
+                                         psCmdCompleteData, NULL);
+                       }
+
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *),
+                         psSysData->ppsCmdCompleteData[ui32DevIndex],
+                         NULL);
+       }
+
+       if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL)
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         ui32CmdCount *
+                                    sizeof(IMG_BOOL (*)(void *, u32, void *)),
+                         psSysData->ppfnCmdProcList[ui32DevIndex], NULL);
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVRemoveCmdProcListKM(u32 ui32DevIndex, u32 ui32CmdCount)
+{
+       struct SYS_DATA *psSysData;
+       enum PVRSRV_ERROR eError;
+       u32 i;
+
+       if (ui32DevIndex >= SYS_DEVICE_COUNT) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVRemoveCmdProcListKM: invalid DeviceType 0x%x",
+                        ui32DevIndex);
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       eError = SysAcquireData(&psSysData);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVRemoveCmdProcListKM: SysAcquireData failed");
+               return eError;
+       }
+
+       if (psSysData->ppsCmdCompleteData[ui32DevIndex] != NULL) {
+               for (i = 0; i < ui32CmdCount; i++)
+
+                       if (psSysData->ppsCmdCompleteData[ui32DevIndex][i] !=
+                           NULL) {
+                               struct COMMAND_COMPLETE_DATA *
+                                       psCmdCompleteData = psSysData->
+                                       ppsCmdCompleteData[ui32DevIndex][i];
+                               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                                         psCmdCompleteData->ui32AllocSize,
+                                         psCmdCompleteData, NULL);
+                       }
+
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         ui32CmdCount * sizeof(struct COMMAND_COMPLETE_DATA *),
+                         psSysData->ppsCmdCompleteData[ui32DevIndex], NULL);
+       }
+
+       if (psSysData->ppfnCmdProcList[ui32DevIndex] != NULL)
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                         ui32CmdCount *
+                               sizeof(IMG_BOOL (*)(void *, u32, void *)),
+                         psSysData->ppfnCmdProcList[ui32DevIndex], NULL);
+
+       return PVRSRV_OK;
+}