Maemo patchset 20101501+0m5
[h-e-n] / drivers / gpu / pvr / sgxutils.c
diff --git a/drivers/gpu/pvr/sgxutils.c b/drivers/gpu/pvr/sgxutils.c
new file mode 100644 (file)
index 0000000..8749d23
--- /dev/null
@@ -0,0 +1,755 @@
+/**********************************************************************
+ *
+ * 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 <stddef.h>
+
+#include "sgxdefs.h"
+#include "services_headers.h"
+#include "buffer_manager.h"
+#include "sgxapi_km.h"
+#include "sgxinfo.h"
+#include "sgxinfokm.h"
+#include "sysconfig.h"
+#include "pdump_km.h"
+#include "mmu.h"
+#include "pvr_bridge_km.h"
+#include "sgx_bridge_km.h"
+#include "osfunc.h"
+#include "pvr_debug.h"
+#include "sgxutils.h"
+
+#include <linux/tty.h>
+
+
+static IMG_BOOL gbPowerUpPDumped = IMG_FALSE;
+
+void SGXTestActivePowerEvent(struct PVRSRV_DEVICE_NODE *psDeviceNode,
+                                u32 ui32CallerID)
+{
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
+       struct PVRSRV_SGX_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl;
+
+       if ((psSGXHostCtl->ui32InterruptFlags &
+                       PVRSRV_USSE_EDM_INTERRUPT_ACTIVE_POWER) &&
+           !(psSGXHostCtl->ui32PowManFlags &
+                       PVRSRV_USSE_EDM_POWMAN_POWEROFF_REQUEST)) {
+               PDUMPSUSPEND();
+               eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.
+                                       ui32DeviceIndex, PVRSRV_POWER_STATE_D3,
+                                       ui32CallerID, IMG_FALSE);
+               if (eError == PVRSRV_OK) {
+                       psSGXHostCtl->ui32NumActivePowerEvents++;
+                       if ((*(volatile u32 *)(&psSGXHostCtl->ui32PowManFlags) &
+                            PVRSRV_USSE_EDM_POWMAN_POWEROFF_RESTART_IMMEDIATE)
+                            != 0) {
+                               if (ui32CallerID == ISR_ID)
+                                       psDeviceNode->
+                                       bReProcessDeviceCommandComplete =
+                                                                    IMG_TRUE;
+                               else
+                                       SGXScheduleProcessQueues
+                                               (psDeviceNode);
+                       }
+               }
+               if (eError == PVRSRV_ERROR_RETRY)
+                       eError = PVRSRV_OK;
+
+               PDUMPRESUME();
+       }
+
+       if (eError != PVRSRV_OK)
+               PVR_DPF(PVR_DBG_ERROR, "SGXTestActivePowerEvent error:%lu",
+                                       eError);
+}
+
+static inline struct PVRSRV_SGX_COMMAND *SGXAcquireKernelCCBSlot(
+                                       struct PVRSRV_SGX_CCB_INFO *psCCB)
+{
+       IMG_BOOL bStart = IMG_FALSE;
+       u32 uiStart = 0;
+
+       do {
+               if (((*psCCB->pui32WriteOffset + 1) & 255) !=
+                   *psCCB->pui32ReadOffset)
+                       return &psCCB->psCommands[*psCCB->pui32WriteOffset];
+
+               if (bStart == IMG_FALSE) {
+                       bStart = IMG_TRUE;
+                       uiStart = OSClockus();
+               }
+               OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
+       } while ((OSClockus() - uiStart) < MAX_HW_TIME_US);
+
+       return NULL;
+}
+
+enum PVRSRV_ERROR SGXScheduleCCBCommandKM(
+                                    struct PVRSRV_DEVICE_NODE *psDeviceNode,
+                                    enum PVRSRV_SGX_COMMAND_TYPE eCommandType,
+                                    struct PVRSRV_SGX_COMMAND *psCommandData,
+                                    u32 ui32CallerID)
+{
+       struct PVRSRV_SGX_CCB_INFO *psKernelCCB;
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo;
+       struct PVRSRV_SGX_COMMAND *psSGXCommand;
+#if defined(PDUMP)
+       void *pvDumpCommand;
+#endif
+
+       psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       psKernelCCB = psDevInfo->psKernelCCBInfo;
+
+       {
+               if (ui32CallerID == ISR_ID || gbPowerUpPDumped)
+                       PDUMPSUSPEND();
+
+               eError =
+                   PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.
+                                               ui32DeviceIndex,
+                                               PVRSRV_POWER_STATE_D0,
+                                               ui32CallerID, IMG_TRUE);
+
+               if (ui32CallerID == ISR_ID || gbPowerUpPDumped)
+                       PDUMPRESUME();
+               else if (eError == PVRSRV_OK)
+                       gbPowerUpPDumped = IMG_TRUE;
+       }
+
+       if (eError == PVRSRV_OK) {
+               psDeviceNode->bReProcessDeviceCommandComplete = IMG_FALSE;
+       } else {
+               if (eError == PVRSRV_ERROR_RETRY)
+                       if (ui32CallerID == ISR_ID) {
+
+                               psDeviceNode->bReProcessDeviceCommandComplete =
+                                   IMG_TRUE;
+                               eError = PVRSRV_OK;
+                       } else {
+
+                       }
+               else
+                       PVR_DPF(PVR_DBG_ERROR,
+                            "SGXScheduleCCBCommandKM failed to acquire lock - "
+                            "ui32CallerID:%ld eError:%lu", ui32CallerID,
+                            eError);
+
+               return eError;
+       }
+
+       psSGXCommand = SGXAcquireKernelCCBSlot(psKernelCCB);
+
+       if (!psSGXCommand) {
+               eError = PVRSRV_ERROR_TIMEOUT;
+               goto Exit;
+       }
+
+       psCommandData->ui32Data[2] = psDevInfo->ui32CacheControl;
+
+#if defined(PDUMP)
+
+       psDevInfo->sPDContext.ui32CacheControl |= psDevInfo->ui32CacheControl;
+#endif
+
+       psDevInfo->ui32CacheControl = 0;
+
+       *psSGXCommand = *psCommandData;
+
+       switch (eCommandType) {
+       case PVRSRV_SGX_COMMAND_EDM_KICK:
+               psSGXCommand->ui32ServiceAddress = psDevInfo->ui32TAKickAddress;
+               break;
+       case PVRSRV_SGX_COMMAND_VIDEO_KICK:
+               psSGXCommand->ui32ServiceAddress =
+                   psDevInfo->ui32VideoHandlerAddress;
+               break;
+       default:
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXScheduleCCBCommandKM: Unknown command type: %d",
+                        eCommandType);
+               eError = PVRSRV_ERROR_GENERIC;
+               goto Exit;
+       }
+
+#if defined(PDUMP)
+       if (ui32CallerID != ISR_ID) {
+
+               PDUMPCOMMENTWITHFLAGS(0,
+                                     "Poll for space in the Kernel CCB\r\n");
+               PDUMPMEMPOL(psKernelCCB->psCCBCtlMemInfo,
+                           offsetof(struct PVRSRV_SGX_CCB_CTL, ui32ReadOffset),
+                           (psKernelCCB->ui32CCBDumpWOff + 1) & 0xff, 0xff,
+                           PDUMP_POLL_OPERATOR_NOTEQUAL, IMG_FALSE, IMG_FALSE,
+                           MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo));
+
+               PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB command\r\n");
+               pvDumpCommand =
+                   (void *) ((u8 *) psKernelCCB->psCCBMemInfo->
+                                 pvLinAddrKM +
+                                 (*psKernelCCB->pui32WriteOffset *
+                                  sizeof(struct PVRSRV_SGX_COMMAND)));
+
+               PDUMPMEM(pvDumpCommand,
+                        psKernelCCB->psCCBMemInfo,
+                        psKernelCCB->ui32CCBDumpWOff *
+                        sizeof(struct PVRSRV_SGX_COMMAND),
+                        sizeof(struct PVRSRV_SGX_COMMAND),
+                        0, MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo));
+
+               PDUMPMEM(&psDevInfo->sPDContext.ui32CacheControl,
+                        psKernelCCB->psCCBMemInfo,
+                        psKernelCCB->ui32CCBDumpWOff *
+                        sizeof(struct PVRSRV_SGX_COMMAND) +
+                        offsetof(struct PVRSRV_SGX_COMMAND, ui32Data[2]),
+                        sizeof(u32), 0,
+                        MAKEUNIQUETAG(psKernelCCB->psCCBMemInfo));
+
+               if (PDumpIsCaptureFrameKM())
+                       psDevInfo->sPDContext.ui32CacheControl = 0;
+       }
+#endif
+       *psKernelCCB->pui32WriteOffset =
+           (*psKernelCCB->pui32WriteOffset + 1) & 255;
+
+#if defined(PDUMP)
+       if (ui32CallerID != ISR_ID) {
+               if (PDumpIsCaptureFrameKM())
+                       psKernelCCB->ui32CCBDumpWOff =
+                           (psKernelCCB->ui32CCBDumpWOff + 1) & 0xFF;
+
+               PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB write offset\r\n");
+               PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff,
+                        psKernelCCB->psCCBCtlMemInfo,
+                        offsetof(struct PVRSRV_SGX_CCB_CTL, ui32WriteOffset),
+                        sizeof(u32),
+                        0, MAKEUNIQUETAG(psKernelCCB->psCCBCtlMemInfo));
+               PDUMPCOMMENTWITHFLAGS(0, "Kernel CCB event kicker\r\n");
+               PDUMPMEM(&psKernelCCB->ui32CCBDumpWOff,
+                        psDevInfo->psKernelCCBEventKickerMemInfo,
+                        0,
+                        sizeof(u32),
+                        0,
+                        MAKEUNIQUETAG(psDevInfo->
+                                      psKernelCCBEventKickerMemInfo));
+               PDUMPCOMMENTWITHFLAGS(0, "Event kick\r\n");
+               PDUMPREGWITHFLAGS(EUR_CR_EVENT_KICK, EUR_CR_EVENT_KICK_NOW_MASK,
+                                 0);
+       }
+#endif
+       *psDevInfo->pui32KernelCCBEventKicker =
+           (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF;
+       OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_KICK,
+                    EUR_CR_EVENT_KICK_NOW_MASK);
+
+Exit:
+       PVRSRVPowerUnlock(ui32CallerID);
+
+       if (ui32CallerID != ISR_ID)
+
+               SGXTestActivePowerEvent(psDeviceNode, ui32CallerID);
+
+       return eError;
+}
+
+void SGXScheduleProcessQueues(struct PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       enum PVRSRV_ERROR eError;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
+       struct PVRSRV_SGX_HOST_CTL *psHostCtl =
+           psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM;
+       u32 ui32PowManFlags;
+       struct PVRSRV_SGX_COMMAND sCommand = { 0 };
+
+       ui32PowManFlags = psHostCtl->ui32PowManFlags;
+       if ((ui32PowManFlags & PVRSRV_USSE_EDM_POWMAN_NO_WORK) != 0)
+               return;
+
+       sCommand.ui32Data[0] = PVRSRV_CCBFLAGS_PROCESS_QUEUESCMD;
+       eError =
+           SGXScheduleCCBCommandKM(psDeviceNode, PVRSRV_SGX_COMMAND_EDM_KICK,
+                                   &sCommand, ISR_ID);
+       if (eError != PVRSRV_OK)
+               PVR_DPF(PVR_DBG_ERROR, "SGXScheduleProcessQueues failed to "
+                                       "schedule CCB command: %lu",
+                        eError);
+}
+
+#if defined(PDUMP)
+void DumpBufferArray(struct PVR3DIF4_KICKTA_DUMP_BUFFER *psBufferArray,
+                        u32 ui32BufferArrayLength, IMG_BOOL bDumpPolls)
+{
+       u32 i;
+
+       for (i = 0; i < ui32BufferArrayLength; i++) {
+               struct PVR3DIF4_KICKTA_DUMP_BUFFER *psBuffer;
+               struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo;
+               char *pszName;
+               void *hUniqueTag;
+
+               psBuffer = &psBufferArray[i];
+               pszName = psBuffer->pszName;
+               if (!pszName)
+                       pszName = "Nameless buffer";
+
+               hUniqueTag =
+                   MAKEUNIQUETAG((struct PVRSRV_KERNEL_MEM_INFO *)psBuffer->
+                                 hKernelMemInfo);
+               psSyncInfo = ((struct PVRSRV_KERNEL_MEM_INFO *)
+                               psBuffer->hKernelMemInfo)->psKernelSyncInfo;
+
+               if (psBuffer->ui32Start <= psBuffer->ui32End) {
+                       if (bDumpPolls) {
+                               PDUMPCOMMENTWITHFLAGS(0,
+                                                     "Wait for %s space\r\n",
+                                                     pszName);
+                               PDUMPCBP(psSyncInfo->psSyncDataMemInfoKM,
+                                        offsetof(struct PVRSRV_SYNC_DATA,
+                                                 ui32ReadOpsComplete),
+                                        psBuffer->ui32Start,
+                                        psBuffer->ui32SpaceUsed,
+                                        psBuffer->ui32BufferSize, 0,
+                                        MAKEUNIQUETAG(psSyncInfo->
+                                                      psSyncDataMemInfoKM));
+                       }
+
+                       PDUMPCOMMENTWITHFLAGS(0, "%s\r\n", pszName);
+                       PDUMPMEM(NULL,
+                                (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer->
+                                hKernelMemInfo, psBuffer->ui32Start,
+                                psBuffer->ui32End - psBuffer->ui32Start, 0,
+                                hUniqueTag);
+               } else {
+                       if (bDumpPolls) {
+                               PDUMPCOMMENTWITHFLAGS(0,
+                                                     "Wait for %s space\r\n",
+                                                     pszName);
+                               PDUMPCBP(psSyncInfo->psSyncDataMemInfoKM,
+                                        offsetof(struct PVRSRV_SYNC_DATA,
+                                                 ui32ReadOpsComplete),
+                                        psBuffer->ui32Start,
+                                        psBuffer->ui32BackEndLength,
+                                        psBuffer->ui32BufferSize, 0,
+                                        MAKEUNIQUETAG(psSyncInfo->
+                                                      psSyncDataMemInfoKM));
+                       }
+                       PDUMPCOMMENTWITHFLAGS(0, "%s (part 1)\r\n", pszName);
+                       PDUMPMEM(NULL,
+                                (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer->
+                                hKernelMemInfo, psBuffer->ui32Start,
+                                psBuffer->ui32BackEndLength, 0, hUniqueTag);
+
+                       if (bDumpPolls) {
+                               PDUMPMEMPOL(psSyncInfo->psSyncDataMemInfoKM,
+                                           offsetof(struct PVRSRV_SYNC_DATA,
+                                                    ui32ReadOpsComplete), 0,
+                                           0xFFFFFFFF,
+                                           PDUMP_POLL_OPERATOR_NOTEQUAL,
+                                           IMG_FALSE, IMG_FALSE,
+                                           MAKEUNIQUETAG(psSyncInfo->
+                                                         psSyncDataMemInfoKM));
+
+                               PDUMPCOMMENTWITHFLAGS(0,
+                                                     "Wait for %s space\r\n",
+                                                     pszName);
+                               PDUMPCBP(psSyncInfo->psSyncDataMemInfoKM,
+                                        offsetof(struct PVRSRV_SYNC_DATA,
+                                                 ui32ReadOpsComplete), 0,
+                                        psBuffer->ui32End,
+                                        psBuffer->ui32BufferSize, 0,
+                                        MAKEUNIQUETAG(psSyncInfo->
+                                                      psSyncDataMemInfoKM));
+                       }
+                       PDUMPCOMMENTWITHFLAGS(0, "%s (part 2)\r\n", pszName);
+                       PDUMPMEM(NULL,
+                                (struct PVRSRV_KERNEL_MEM_INFO *)psBuffer->
+                                hKernelMemInfo, 0, psBuffer->ui32End, 0,
+                                hUniqueTag);
+               }
+       }
+}
+#endif
+
+IMG_BOOL SGXIsDevicePowered(struct PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       return PVRSRVIsDevicePowered(psDeviceNode->sDevId.ui32DeviceIndex);
+}
+
+enum PVRSRV_ERROR SGXGetInternalDevInfoKM(void *hDevCookie,
+                        struct PVR3DIF4_INTERNAL_DEVINFO *psSGXInternalDevInfo)
+{
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *)
+                       ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice;
+
+       psSGXInternalDevInfo->ui32Flags = psDevInfo->ui32Flags;
+       psSGXInternalDevInfo->bForcePTOff = (IMG_BOOL)psDevInfo->bForcePTOff;
+
+       psSGXInternalDevInfo->hCtlKernelMemInfoHandle = (void *)
+                       psDevInfo->psKernelSGXHostCtlMemInfo;
+
+       return PVRSRV_OK;
+}
+
+static void SGXCleanupRequest(struct PVRSRV_DEVICE_NODE *psDeviceNode,
+                                 struct IMG_DEV_VIRTADDR *psHWDataDevVAddr,
+                                 u32 ui32ResManRequestFlag)
+{
+       struct PVRSRV_SGXDEV_INFO *psSGXDevInfo =
+           (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       struct PVRSRV_KERNEL_MEM_INFO *psSGXHostCtlMemInfo =
+           psSGXDevInfo->psKernelSGXHostCtlMemInfo;
+       struct PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
+           (struct PVRSRV_SGX_HOST_CTL *)psSGXHostCtlMemInfo->pvLinAddrKM;
+       u32 ui32PowManFlags;
+#if defined(PDUMP)
+       void *hUniqueTag = MAKEUNIQUETAG(psSGXHostCtlMemInfo);
+#endif
+
+       ui32PowManFlags = psSGXHostCtl->ui32PowManFlags;
+       if ((ui32PowManFlags & PVRSRV_USSE_EDM_POWMAN_NO_WORK) != 0) {
+               ;
+       } else {
+               if (psSGXDevInfo->ui32CacheControl &
+                                       SGX_BIF_INVALIDATE_PDCACHE) {
+                       psSGXHostCtl->ui32ResManFlags |=
+                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPD;
+                       psSGXDevInfo->ui32CacheControl ^=
+                           SGX_BIF_INVALIDATE_PDCACHE;
+               }
+               if (psSGXDevInfo->ui32CacheControl &
+                                       SGX_BIF_INVALIDATE_PTCACHE) {
+                       psSGXHostCtl->ui32ResManFlags |=
+                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_INVALPT;
+                       psSGXDevInfo->ui32CacheControl ^=
+                           SGX_BIF_INVALIDATE_PTCACHE;
+               }
+
+               psSGXHostCtl->sResManCleanupData.uiAddr =
+                   psHWDataDevVAddr->uiAddr;
+
+               psSGXHostCtl->ui32ResManFlags |= ui32ResManRequestFlag;
+
+               PDUMPCOMMENT
+                  ("TA/3D CCB Control - Request clean-up event on uKernel...");
+               PDUMPMEM(NULL, psSGXHostCtlMemInfo,
+                        offsetof(struct PVRSRV_SGX_HOST_CTL,
+                                 sResManCleanupData.uiAddr),
+                        sizeof(u32), PDUMP_FLAGS_CONTINUOUS,
+                        hUniqueTag);
+               PDUMPMEM(NULL, psSGXHostCtlMemInfo,
+                        offsetof(struct PVRSRV_SGX_HOST_CTL, ui32ResManFlags),
+                        sizeof(u32), PDUMP_FLAGS_CONTINUOUS,
+                        hUniqueTag);
+
+               SGXScheduleProcessQueues(psDeviceNode);
+
+               if (PollForValueKM
+                   ((volatile u32 *)(&psSGXHostCtl->ui32ResManFlags),
+                    PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
+                    PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
+                    MAX_HW_TIME_US / WAIT_TRY_COUNT,
+                    WAIT_TRY_COUNT) != PVRSRV_OK)
+                       PVR_DPF(PVR_DBG_ERROR, "SGXCleanupRequest: "
+                        "Wait for uKernel to clean up render context failed");
+
+#ifdef PDUMP
+
+               PDUMPCOMMENT
+              ("TA/3D CCB Control - Wait for clean-up request to complete...");
+               PDUMPMEMPOL(psSGXHostCtlMemInfo,
+                           offsetof(struct PVRSRV_SGX_HOST_CTL,
+                           ui32ResManFlags),
+                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
+                           PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE,
+                           PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE,
+                           hUniqueTag);
+#endif
+
+               psSGXHostCtl->ui32ResManFlags &= ~(ui32ResManRequestFlag);
+               psSGXHostCtl->ui32ResManFlags &=
+                   ~(PVRSRV_USSE_EDM_RESMAN_CLEANUP_COMPLETE);
+               PDUMPMEM(NULL, psSGXHostCtlMemInfo,
+                        offsetof(struct PVRSRV_SGX_HOST_CTL, ui32ResManFlags),
+                        sizeof(u32), PDUMP_FLAGS_CONTINUOUS,
+                        hUniqueTag);
+       }
+}
+
+struct SGX_HW_RENDER_CONTEXT_CLEANUP {
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+       struct IMG_DEV_VIRTADDR sHWRenderContextDevVAddr;
+       void *hBlockAlloc;
+       struct RESMAN_ITEM *psResItem;
+};
+
+static enum PVRSRV_ERROR SGXCleanupHWRenderContextCallback(void *pvParam,
+                                                     u32 ui32Param)
+{
+       struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup = pvParam;
+
+       PVR_UNREFERENCED_PARAMETER(ui32Param);
+
+       SGXCleanupRequest(psCleanup->psDeviceNode,
+                         &psCleanup->sHWRenderContextDevVAddr,
+                         PVRSRV_USSE_EDM_RESMAN_CLEANUP_RC_REQUEST);
+
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
+                 sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
+                 psCleanup, psCleanup->hBlockAlloc);
+
+       return PVRSRV_OK;
+}
+
+struct SGX_HW_TRANSFER_CONTEXT_CLEANUP {
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+       struct IMG_DEV_VIRTADDR sHWTransferContextDevVAddr;
+       void *hBlockAlloc;
+       struct RESMAN_ITEM *psResItem;
+};
+
+static enum PVRSRV_ERROR SGXCleanupHWTransferContextCallback(void *pvParam,
+                                                       u32 ui32Param)
+{
+       struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup =
+           (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)pvParam;
+
+       PVR_UNREFERENCED_PARAMETER(ui32Param);
+
+       SGXCleanupRequest(psCleanup->psDeviceNode,
+                         &psCleanup->sHWTransferContextDevVAddr,
+                         PVRSRV_USSE_EDM_RESMAN_CLEANUP_TC_REQUEST);
+
+       OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
+                 sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
+                 psCleanup, psCleanup->hBlockAlloc);
+
+       return PVRSRV_OK;
+}
+
+void *SGXRegisterHWRenderContextKM(void *psDeviceNode,
+                           struct IMG_DEV_VIRTADDR *psHWRenderContextDevVAddr,
+                           struct PVRSRV_PER_PROCESS_DATA *psPerProc)
+{
+       enum PVRSRV_ERROR eError;
+       void *hBlockAlloc;
+       struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup;
+       struct RESMAN_ITEM *psResItem;
+
+       eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                           sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
+                           (void **) &psCleanup, &hBlockAlloc);
+
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "%s: alloc failed", __func__);
+               return NULL;
+       }
+
+       psCleanup->hBlockAlloc = hBlockAlloc;
+       psCleanup->psDeviceNode = psDeviceNode;
+       psCleanup->sHWRenderContextDevVAddr = *psHWRenderContextDevVAddr;
+
+       psResItem = ResManRegisterRes(psPerProc->hResManContext,
+                                     RESMAN_TYPE_HW_RENDER_CONTEXT,
+                                     (void *) psCleanup,
+                                     0, &SGXCleanupHWRenderContextCallback);
+
+       if (psResItem == NULL) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "%s: can't register resource", __func__);
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
+                         sizeof(struct SGX_HW_RENDER_CONTEXT_CLEANUP),
+                         psCleanup, psCleanup->hBlockAlloc);
+
+               return NULL;
+       }
+
+       psCleanup->psResItem = psResItem;
+
+       return (void *)psCleanup;
+}
+
+enum PVRSRV_ERROR SGXUnregisterHWRenderContextKM(void *hHWRenderContext)
+{
+       struct SGX_HW_RENDER_CONTEXT_CLEANUP *psCleanup;
+
+       PVR_ASSERT(hHWRenderContext != NULL);
+
+       psCleanup = (struct SGX_HW_RENDER_CONTEXT_CLEANUP *)hHWRenderContext;
+
+       ResManFreeResByPtr(psCleanup->psResItem);
+
+       return PVRSRV_OK;
+}
+
+void *SGXRegisterHWTransferContextKM(void *psDeviceNode,
+                     struct IMG_DEV_VIRTADDR *psHWTransferContextDevVAddr,
+                     struct PVRSRV_PER_PROCESS_DATA *psPerProc)
+{
+       enum PVRSRV_ERROR eError;
+       void *hBlockAlloc;
+       struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup;
+       struct RESMAN_ITEM *psResItem;
+
+       eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
+                           sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
+                           (void **) &psCleanup, &hBlockAlloc);
+
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "%s: alloc failed", __func__);
+               return NULL;
+       }
+
+       psCleanup->hBlockAlloc = hBlockAlloc;
+       psCleanup->psDeviceNode = psDeviceNode;
+       psCleanup->sHWTransferContextDevVAddr = *psHWTransferContextDevVAddr;
+
+       psResItem = ResManRegisterRes(psPerProc->hResManContext,
+                                     RESMAN_TYPE_HW_TRANSFER_CONTEXT,
+                                     psCleanup,
+                                     0, &SGXCleanupHWTransferContextCallback);
+
+       if (psResItem == NULL) {
+               PVR_DPF(PVR_DBG_ERROR,
+                       "%s: can't register resource", __func__);
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
+                         sizeof(struct SGX_HW_TRANSFER_CONTEXT_CLEANUP),
+                         psCleanup, psCleanup->hBlockAlloc);
+
+               return NULL;
+       }
+
+       psCleanup->psResItem = psResItem;
+
+       return (void *)psCleanup;
+}
+
+enum PVRSRV_ERROR SGXUnregisterHWTransferContextKM(void *hHWTransferContext)
+{
+       struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *psCleanup;
+
+       PVR_ASSERT(hHWTransferContext != NULL);
+
+       psCleanup = (struct SGX_HW_TRANSFER_CONTEXT_CLEANUP *)
+                                                       hHWTransferContext;
+
+       ResManFreeResByPtr(psCleanup->psResItem);
+
+       return PVRSRV_OK;
+}
+
+
+static inline IMG_BOOL SGX2DQuerySyncOpsComplete(
+                               struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo)
+{
+       struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData;
+
+       return (IMG_BOOL)((psSyncData->ui32ReadOpsComplete ==
+                         psSyncData->ui32ReadOpsPending) &&
+                         (psSyncData->ui32WriteOpsComplete ==
+                         psSyncData->ui32WriteOpsPending));
+}
+
+enum PVRSRV_ERROR SGX2DQueryBlitsCompleteKM(
+                                   struct PVRSRV_SGXDEV_INFO *psDevInfo,
+                                   struct PVRSRV_KERNEL_SYNC_INFO *psSyncInfo,
+                                   IMG_BOOL bWaitForComplete)
+{
+       IMG_BOOL bStart = IMG_FALSE;
+       u32 uiStart = 0;
+
+       PVR_UNREFERENCED_PARAMETER(psDevInfo);
+
+       PVR_DPF(PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: Start");
+
+       if (SGX2DQuerySyncOpsComplete(psSyncInfo)) {
+
+               PVR_DPF(PVR_DBG_CALLTRACE, "SGX2DQueryBlitsCompleteKM: "
+                                       "No wait. Blits complete.");
+               return PVRSRV_OK;
+       }
+
+       if (!bWaitForComplete) {
+
+               PVR_DPF(PVR_DBG_CALLTRACE,
+                        "SGX2DQueryBlitsCompleteKM: No wait. Ops pending.");
+               return PVRSRV_ERROR_CMD_NOT_PROCESSED;
+       }
+
+       PVR_DPF(PVR_DBG_MESSAGE,
+                "SGX2DQueryBlitsCompleteKM: Ops pending. Start polling.");
+       do {
+               OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
+
+               if (SGX2DQuerySyncOpsComplete(psSyncInfo)) {
+
+                       PVR_DPF(PVR_DBG_CALLTRACE,
+                                "SGX2DQueryBlitsCompleteKM: "
+                                "Wait over.  Blits complete.");
+                       return PVRSRV_OK;
+               }
+
+               if (bStart == IMG_FALSE) {
+                       uiStart = OSClockus();
+                       bStart = IMG_TRUE;
+               }
+
+               OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
+       } while ((OSClockus() - uiStart) < MAX_HW_TIME_US);
+
+       PVR_DPF(PVR_DBG_ERROR,
+                "SGX2DQueryBlitsCompleteKM: Timed out. Ops pending.");
+
+#if defined(DEBUG)
+       {
+               struct PVRSRV_SYNC_DATA *psSyncData = psSyncInfo->psSyncData;
+
+               PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
+                          "Syncinfo: %p, Syncdata: %p",
+                          psSyncInfo, psSyncData);
+
+               PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
+                          "Read ops complete: %d, Read ops pending: %d",
+                          psSyncData->ui32ReadOpsComplete,
+                          psSyncData->ui32ReadOpsPending);
+               PVR_TRACE("SGX2DQueryBlitsCompleteKM: "
+                         "Write ops complete: %d, Write ops pending: %d",
+                         psSyncData->ui32WriteOpsComplete,
+                         psSyncData->ui32WriteOpsPending);
+
+       }
+#endif
+       return PVRSRV_ERROR_TIMEOUT;
+}
+
+void SGXFlushHWRenderTargetKM(void *psDeviceNode,
+                             struct IMG_DEV_VIRTADDR sHWRTDataSetDevVAddr)
+{
+       PVR_ASSERT(sHWRTDataSetDevVAddr.uiAddr != 0);
+
+       SGXCleanupRequest((struct PVRSRV_DEVICE_NODE *)psDeviceNode,
+                         &sHWRTDataSetDevVAddr,
+                         PVRSRV_USSE_EDM_RESMAN_CLEANUP_RT_REQUEST);
+}