gpu: pvr: pdumpfs: add Kconfig and debugfs pdump mode handling
[sgx.git] / pvr / sgxinit.c
index 33ff9b7..210c66d 100644 (file)
@@ -1,32 +1,37 @@
 /**********************************************************************
  *
  * 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. 
+ *
+ * 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 
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
  *
  ******************************************************************************/
 
 #include <stddef.h>
-#include <linux/spinlock.h>
+
 #include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
 
 #include "sgxdefs.h"
 #include "sgxmmu.h"
 #include "sgxconfig.h"
 #include "sysconfig.h"
 #include "pvr_bridge_km.h"
+#include "sgx_bridge_km.h"
+#include "resman.h"
+#include "bridged_support.h"
 
-#include "pdump_km.h"
+#include "pvr_pdump.h"
 #include "ra.h"
 #include "mmu.h"
+#include "mm.h"
 #include "handle.h"
 #include "perproc.h"
 
 #include "sgxutils.h"
+#include "pvrversion.h"
+#include "sgx_options.h"
 
+#ifdef CONFIG_DEBUG_FS
+#include "pvr_debugfs.h"
+#endif
 
-IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData);
-
-IMG_UINT32 gui32EventStatusServicesByISR = 0;
-
-IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO * psDevInfo, IMG_UINT32 ui32PDUMPFlags);
-
-static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo,
-                                 IMG_BOOL bHardwareRecovery);
-PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie);
+static IMG_BOOL SGX_ISRHandler(void *pvData);
 
-typedef enum _PVR_DEVICE_POWER_STATE_ {
-       PVR_DEVICE_POWER_STATE_ON = 0,
-       PVR_DEVICE_POWER_STATE_IDLE = 1,
-       PVR_DEVICE_POWER_STATE_OFF = 2,
+static u32 gui32EventStatusServicesByISR;
 
-       PVR_DEVICE_POWER_STATE_FORCE_I32 = 0x7fffffff
-} PVR_DEVICE_POWER_STATE, *PPVR_DEVICE_POWER_STATE;
+static enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo,
+                                   struct PVRSRV_DEVICE_NODE *psDeviceNode);
 
-static PVR_DEVICE_POWER_STATE MapDevicePowerState(PVR_POWER_STATE ePowerState)
+static void SGXCommandComplete(struct PVRSRV_DEVICE_NODE *psDeviceNode)
 {
-       PVR_DEVICE_POWER_STATE eDevicePowerState;
+       BUG_ON(in_irq());
 
-       switch (ePowerState) {
-       case PVRSRV_POWER_STATE_D0:
-               {
-                       eDevicePowerState = PVR_DEVICE_POWER_STATE_ON;
-                       break;
-               }
-       case PVRSRV_POWER_STATE_D3:
-               {
-                       eDevicePowerState = PVR_DEVICE_POWER_STATE_OFF;
-                       break;
-               }
-       default:
-               {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "MapDevicePowerState: Invalid state: %ld",
-                                ePowerState));
-                       eDevicePowerState = PVR_DEVICE_POWER_STATE_FORCE_I32;
-                       PVR_ASSERT(eDevicePowerState !=
-                                  PVR_DEVICE_POWER_STATE_FORCE_I32);
-               }
-       }
-
-       return eDevicePowerState;
-}
-
-static IMG_VOID SGXCommandComplete(PVRSRV_DEVICE_NODE * psDeviceNode)
-{
-       SGXScheduleProcessQueues(psDeviceNode);
+       SGXScheduleProcessQueuesKM(psDeviceNode);
 }
 
-static IMG_UINT32 DeinitDevInfo(PVRSRV_SGXDEV_INFO * psDevInfo)
+static u32 DeinitDevInfo(struct PVRSRV_SGXDEV_INFO *psDevInfo)
 {
-       if (psDevInfo->psKernelCCBInfo != IMG_NULL) {
-
-               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO),
-                         psDevInfo->psKernelCCBInfo, IMG_NULL);
-       }
+       if (psDevInfo->psKernelCCBInfo != NULL)
+               OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
+                         sizeof(struct PVRSRV_SGX_CCB_INFO),
+                         psDevInfo->psKernelCCBInfo, NULL);
 
        return PVRSRV_OK;
 }
 
-static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA * psPerProc,
-                               PVRSRV_DEVICE_NODE * psDeviceNode,
-                               SGX_BRIDGE_INIT_INFO * psInitInfo)
+static enum PVRSRV_ERROR InitDevInfo(struct PVRSRV_PER_PROCESS_DATA *psPerProc,
+                               struct PVRSRV_DEVICE_NODE *psDeviceNode,
+                               struct SGX_BRIDGE_INIT_INFO *psInitInfo)
 {
-       PVRSRV_SGXDEV_INFO *psDevInfo =
-           (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
-       PVRSRV_ERROR eError;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo =
+           (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       enum PVRSRV_ERROR eError;
 
-       PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = IMG_NULL;
+       struct PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = NULL;
 
        PVR_UNREFERENCED_PARAMETER(psPerProc);
        psDevInfo->sScripts = psInitInfo->sScripts;
 
        psDevInfo->psKernelCCBMemInfo =
-           (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBMemInfo;
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBMemInfo;
        psDevInfo->psKernelCCB =
-           (PVRSRV_SGX_KERNEL_CCB *) psDevInfo->psKernelCCBMemInfo->
-           pvLinAddrKM;
+           (struct PVRSRV_SGX_KERNEL_CCB *)psDevInfo->psKernelCCBMemInfo->
+                                                   pvLinAddrKM;
 
        psDevInfo->psKernelCCBCtlMemInfo =
-           (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBCtlMemInfo;
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBCtlMemInfo;
        psDevInfo->psKernelCCBCtl =
-           (PVRSRV_SGX_CCB_CTL *) psDevInfo->psKernelCCBCtlMemInfo->
-           pvLinAddrKM;
+           (struct PVRSRV_SGX_CCB_CTL *)psDevInfo->psKernelCCBCtlMemInfo->
+                                                   pvLinAddrKM;
 
        psDevInfo->psKernelCCBEventKickerMemInfo =
-           (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBEventKickerMemInfo;
+           (struct PVRSRV_KERNEL_MEM_INFO *)
+                           psInitInfo->hKernelCCBEventKickerMemInfo;
        psDevInfo->pui32KernelCCBEventKicker =
-           (IMG_UINT32 *) psDevInfo->psKernelCCBEventKickerMemInfo->
-           pvLinAddrKM;
+           (u32 *)psDevInfo->psKernelCCBEventKickerMemInfo->pvLinAddrKM;
 
        psDevInfo->psKernelSGXHostCtlMemInfo =
-           (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelSGXHostCtlMemInfo;
-       psDevInfo->psSGXHostCtl =
-           (PVRSRV_SGX_HOST_CTL *) psDevInfo->psKernelSGXHostCtlMemInfo->
-           pvLinAddrKM;
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->
+                                                   hKernelSGXHostCtlMemInfo;
+       psDevInfo->psSGXHostCtl = (struct SGXMKIF_HOST_CTL __force __iomem *)
+               psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM;
+
+       psDevInfo->psKernelSGXTA3DCtlMemInfo =
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->
+                                                   hKernelSGXTA3DCtlMemInfo;
+
+       psDevInfo->psKernelSGXMiscMemInfo =
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXMiscMemInfo;
 
        psDevInfo->psKernelHWPerfCBMemInfo =
-           (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelHWPerfCBMemInfo;
+           (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWPerfCBMemInfo;
+       psDevInfo->psKernelEDMStatusBufferMemInfo =
+                                   psInitInfo->hKernelEDMStatusBufferMemInfo;
 
        eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
-                           sizeof(PVRSRV_SGX_CCB_INFO),
-                           (IMG_VOID **) & psKernelCCBInfo, 0);
+                           sizeof(struct PVRSRV_SGX_CCB_INFO),
+                           (void **)&psKernelCCBInfo, NULL);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR, "InitDevInfo: Failed to alloc memory"));
+               PVR_DPF(PVR_DBG_ERROR, "InitDevInfo: Failed to alloc memory");
                goto failed_allockernelccb;
        }
 
-       OSMemSet(psKernelCCBInfo, 0, sizeof(PVRSRV_SGX_CCB_INFO));
+       OSMemSet(psKernelCCBInfo, 0, sizeof(struct PVRSRV_SGX_CCB_INFO));
        psKernelCCBInfo->psCCBMemInfo = psDevInfo->psKernelCCBMemInfo;
        psKernelCCBInfo->psCCBCtlMemInfo = psDevInfo->psKernelCCBCtlMemInfo;
        psKernelCCBInfo->psCommands = psDevInfo->psKernelCCB->asCommands;
        psKernelCCBInfo->pui32WriteOffset =
-           &psDevInfo->psKernelCCBCtl->ui32WriteOffset;
+                               &psDevInfo->psKernelCCBCtl->ui32WriteOffset;
        psKernelCCBInfo->pui32ReadOffset =
-           &psDevInfo->psKernelCCBCtl->ui32ReadOffset;
+                               &psDevInfo->psKernelCCBCtl->ui32ReadOffset;
        psDevInfo->psKernelCCBInfo = psKernelCCBInfo;
 
-       psDevInfo->ui32TAKickAddress = psInitInfo->ui32TAKickAddress;
+       psDevInfo->ui32HostKickAddress = psInitInfo->ui32HostKickAddress;
 
-       psDevInfo->ui32VideoHandlerAddress =
-           psInitInfo->ui32VideoHandlerAddress;
+       psDevInfo->ui32GetMiscInfoAddress = psInitInfo->ui32GetMiscInfoAddress;
 
        psDevInfo->bForcePTOff = IMG_FALSE;
 
@@ -180,13 +163,14 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA * psPerProc,
 
        psDevInfo->ui32EDMTaskReg0 = psInitInfo->ui32EDMTaskReg0;
        psDevInfo->ui32EDMTaskReg1 = psInitInfo->ui32EDMTaskReg1;
-       psDevInfo->ui32ClkGateCtl = psInitInfo->ui32ClkGateCtl;
-       psDevInfo->ui32ClkGateCtl2 = psInitInfo->ui32ClkGateCtl2;
+       psDevInfo->ui32ClkGateStatusReg = psInitInfo->ui32ClkGateStatusReg;
        psDevInfo->ui32ClkGateStatusMask = psInitInfo->ui32ClkGateStatusMask;
 
        OSMemCopy(&psDevInfo->asSGXDevData, &psInitInfo->asInitDevData,
                  sizeof(psDevInfo->asSGXDevData));
 
+       psDevInfo->state_buf_ofs = psInitInfo->state_buf_ofs;
+
        return PVRSRV_OK;
 
 failed_allockernelccb:
@@ -195,321 +179,12 @@ failed_allockernelccb:
        return eError;
 }
 
-static IMG_VOID SGXGetTimingInfo(PVRSRV_DEVICE_NODE * psDeviceNode)
-{
-       PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-       SGX_TIMING_INFORMATION sSGXTimingInfo = { 0 };
-       IMG_UINT32 ui32ActivePowManSampleRate;
-       SGX_TIMING_INFORMATION *psSGXTimingInfo;
-
-       psSGXTimingInfo = &sSGXTimingInfo;
-       SysGetSGXTimingInformation(psSGXTimingInfo);
-
-       {
-               PVRSRV_ERROR eError;
-               IMG_UINT32 ui32OlduKernelFreq;
-
-               if (psDevInfo->hTimer != IMG_NULL) {
-                       ui32OlduKernelFreq =
-                           psDevInfo->ui32CoreClockSpeed /
-                           psDevInfo->ui32uKernelTimerClock;
-                       if (ui32OlduKernelFreq !=
-                           psSGXTimingInfo->ui32uKernelFreq) {
-                               eError = OSRemoveTimer(psDevInfo->hTimer);
-                               if (eError != PVRSRV_OK) {
-                                       PVR_DPF((PVR_DBG_ERROR,
-                                                "SGXGetTimingInfo: Failed to remove timer"));
-                               }
-                               psDevInfo->hTimer = IMG_NULL;
-                       }
-               }
-               if (psDevInfo->hTimer == IMG_NULL) {
-
-                       psDevInfo->hTimer = OSAddTimer(SGXOSTimer, psDeviceNode,
-                                                      1000 * 50 /
-                                                      psSGXTimingInfo->
-                                                      ui32uKernelFreq);
-                       if (psDevInfo->hTimer == IMG_NULL) {
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXGetTimingInfo : Failed to register timer callback function"));
-                       }
-               }
-
-               psDevInfo->psSGXHostCtl->ui32HWRecoverySampleRate =
-                   psSGXTimingInfo->ui32uKernelFreq /
-                   psSGXTimingInfo->ui32HWRecoveryFreq;
-       }
-
-       psDevInfo->ui32CoreClockSpeed = psSGXTimingInfo->ui32CoreClockSpeed;
-       psDevInfo->ui32uKernelTimerClock =
-           psSGXTimingInfo->ui32CoreClockSpeed /
-           psSGXTimingInfo->ui32uKernelFreq;
-
-       ui32ActivePowManSampleRate =
-           psSGXTimingInfo->ui32uKernelFreq *
-           psSGXTimingInfo->ui32ActivePowManLatencyms / 1000;
-       ui32ActivePowManSampleRate += 1;
-       psDevInfo->psSGXHostCtl->ui32ActivePowManSampleRate =
-           ui32ActivePowManSampleRate;
-}
-
-static IMG_VOID SGXStartTimer(PVRSRV_SGXDEV_INFO * psDevInfo,
-                             IMG_BOOL bStartOSTimer)
-{
-       IMG_UINT32 ui32RegVal;
-
-
-       ui32RegVal =
-           EUR_CR_EVENT_TIMER_ENABLE_MASK | psDevInfo->ui32uKernelTimerClock;
-       OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_TIMER, ui32RegVal);
-       PDUMPREGWITHFLAGS(EUR_CR_EVENT_TIMER, ui32RegVal,
-                         PDUMP_FLAGS_CONTINUOUS);
-
-       if (bStartOSTimer) {
-               PVRSRV_ERROR eError;
-               eError = OSEnableTimer(psDevInfo->hTimer);
-               if (eError != PVRSRV_OK) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "SGXStartTimer : Failed to enable host timer"));
-               }
-       }
-}
-
-static PVRSRV_ERROR SGXPrePowerState(IMG_HANDLE hDevHandle,
-                                    PVR_DEVICE_POWER_STATE eNewPowerState,
-                                    PVR_DEVICE_POWER_STATE eCurrentPowerState)
-{
-       if ((eNewPowerState != eCurrentPowerState) &&
-           (eNewPowerState != PVR_DEVICE_POWER_STATE_ON)) {
-               PVRSRV_ERROR eError;
-               PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
-               PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-               PVRSRV_SGX_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl;
-               IMG_UINT32 ui32PowManRequest, ui32PowManComplete;
-
-               eError = OSDisableTimer(psDevInfo->hTimer);
-               if (eError != PVRSRV_OK) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "SGXPrePowerState: Failed to disable timer"));
-                       return eError;
-               }
-
-               if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) {
-                       ui32PowManRequest =
-                           PVRSRV_USSE_EDM_POWMAN_POWEROFF_REQUEST;
-                       ui32PowManComplete =
-                           PVRSRV_USSE_EDM_POWMAN_POWEROFF_COMPLETE;
-                       PDUMPCOMMENT
-                           ("TA/3D CCB Control - SGX power off request");
-               } else {
-                       ui32PowManRequest = PVRSRV_USSE_EDM_POWMAN_IDLE_REQUEST;
-                       ui32PowManComplete =
-                           PVRSRV_USSE_EDM_POWMAN_IDLE_COMPLETE;
-                       PDUMPCOMMENT("TA/3D CCB Control - SGX idle request");
-               }
-
-               psSGXHostCtl->ui32PowManFlags |= ui32PowManRequest;
-#if defined(PDUMP)
-               PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo,
-                        offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags),
-                        sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS,
-                        MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo));
-#endif
-
-               if (PollForValueKM(&psSGXHostCtl->ui32PowManFlags,
-                                  ui32PowManComplete,
-                                  ui32PowManComplete,
-                                  MAX_HW_TIME_US / WAIT_TRY_COUNT,
-                                  WAIT_TRY_COUNT) != PVRSRV_OK) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "SGXPrePowerState: Wait for SGX ukernel power transition failed."));
-               }
-
-#if defined(PDUMP)
-               PDUMPCOMMENT
-                   ("TA/3D CCB Control - Wait for power event on uKernel.");
-               PDUMPMEMPOL(psDevInfo->psKernelSGXHostCtlMemInfo,
-                           offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags),
-                           ui32PowManComplete, ui32PowManComplete,
-                           PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE,
-                           MAKEUNIQUETAG(psDevInfo->
-                                         psKernelSGXHostCtlMemInfo));
-#endif
-
-
-               {
-                       if (PollForValueKM
-                           ((IMG_UINT32 *) psDevInfo->pvRegsBaseKM +
-                            (EUR_CR_CLKGATESTATUS >> 2), 0,
-                            psDevInfo->ui32ClkGateStatusMask,
-                            MAX_HW_TIME_US / WAIT_TRY_COUNT,
-                            WAIT_TRY_COUNT) != PVRSRV_OK) {
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXPrePowerState: Wait for SGX clock gating failed."));
-                       }
-
-                       PDUMPCOMMENT("Wait for SGX clock gating.");
-                       PDUMPREGPOL(EUR_CR_CLKGATESTATUS, 0,
-                                   psDevInfo->ui32ClkGateStatusMask);
-               }
-
-               if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) {
-                       eError = SGXDeinitialise(psDevInfo);
-                       if (eError != PVRSRV_OK) {
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXPrePowerState: SGXDeinitialise failed: %lu",
-                                        eError));
-                               return eError;
-                       }
-               }
-       }
-
-       return PVRSRV_OK;
-}
-
-static PVRSRV_ERROR SGXPostPowerState(IMG_HANDLE hDevHandle,
-                                     PVR_DEVICE_POWER_STATE eNewPowerState,
-                                     PVR_DEVICE_POWER_STATE eCurrentPowerState)
-{
-       if ((eNewPowerState != eCurrentPowerState) &&
-           (eCurrentPowerState != PVR_DEVICE_POWER_STATE_ON)) {
-               PVRSRV_ERROR eError;
-               PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
-               PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-               PVRSRV_SGX_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl;
-
-               psSGXHostCtl->ui32PowManFlags = 0;
-               PDUMPCOMMENT("TA/3D CCB Control - Reset Power Manager flags");
-#if defined(PDUMP)
-               PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo,
-                        offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags),
-                        sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS,
-                        MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo));
-#endif
-
-               if (eCurrentPowerState == PVR_DEVICE_POWER_STATE_OFF) {
-
-                       SGXGetTimingInfo(psDeviceNode);
-
-                       eError = SGXInitialise(psDevInfo, IMG_FALSE);
-                       if (eError != PVRSRV_OK) {
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXPostPowerState: SGXInitialise failed"));
-                               return eError;
-                       }
-               }
-       }
-
-       return PVRSRV_OK;
-}
-
-PVRSRV_ERROR SGXPrePowerStateExt(IMG_HANDLE hDevHandle,
-                                PVR_POWER_STATE eNewPowerState,
-                                PVR_POWER_STATE eCurrentPowerState)
-{
-       PVR_DEVICE_POWER_STATE eNewDevicePowerState =
-           MapDevicePowerState(eNewPowerState);
-       PVR_DEVICE_POWER_STATE eCurrentDevicePowerState =
-           MapDevicePowerState(eCurrentPowerState);
-
-       return SGXPrePowerState(hDevHandle, eNewDevicePowerState,
-                               eCurrentDevicePowerState);
-}
-
-PVRSRV_ERROR SGXPostPowerStateExt(IMG_HANDLE hDevHandle,
-                                 PVR_POWER_STATE eNewPowerState,
-                                 PVR_POWER_STATE eCurrentPowerState)
-{
-       PVRSRV_ERROR eError;
-       PVR_DEVICE_POWER_STATE eNewDevicePowerState =
-           MapDevicePowerState(eNewPowerState);
-       PVR_DEVICE_POWER_STATE eCurrentDevicePowerState =
-           MapDevicePowerState(eCurrentPowerState);
-
-       eError =
-           SGXPostPowerState(hDevHandle, eNewDevicePowerState,
-                             eCurrentDevicePowerState);
-       if (eError != PVRSRV_OK) {
-               return eError;
-       }
-
-       PVR_DPF((PVR_DBG_WARNING,
-                "SGXPostPowerState : SGX Power Transition from %d to %d OK",
-                eCurrentPowerState, eNewPowerState));
-
-       return eError;
-}
-
-static PVRSRV_ERROR SGXPreClockSpeedChange(IMG_HANDLE hDevHandle,
-                                          IMG_BOOL bIdleDevice,
-                                          PVR_POWER_STATE eCurrentPowerState)
+static enum PVRSRV_ERROR SGXRunScript(struct PVRSRV_SGXDEV_INFO *psDevInfo,
+                                union SGX_INIT_COMMAND *psScript,
+                                u32 ui32NumInitCommands)
 {
-       PVRSRV_ERROR eError;
-       PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
-       PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-
-       PVR_UNREFERENCED_PARAMETER(psDevInfo);
-
-       if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) {
-               if (bIdleDevice) {
-
-                       eError =
-                           SGXPrePowerState(hDevHandle,
-                                            PVR_DEVICE_POWER_STATE_IDLE,
-                                            PVR_DEVICE_POWER_STATE_ON);
-
-                       if (eError != PVRSRV_OK) {
-                               return eError;
-                       }
-               }
-       }
-
-       PVR_DPF((PVR_DBG_MESSAGE,
-                "SGXPreClockSpeedChange: SGX clock speed was %luHz",
-                psDevInfo->ui32CoreClockSpeed));
-
-       return PVRSRV_OK;
-}
-
-static PVRSRV_ERROR SGXPostClockSpeedChange(IMG_HANDLE hDevHandle,
-                                           IMG_BOOL bIdleDevice,
-                                           PVR_POWER_STATE eCurrentPowerState)
-{
-       PVRSRV_ERROR eError = PVRSRV_OK;
-       PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
-       PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-       IMG_UINT32 ui32OldClockSpeed = psDevInfo->ui32CoreClockSpeed;
-
-       PVR_UNREFERENCED_PARAMETER(ui32OldClockSpeed);
-
-       if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) {
-               SGXGetTimingInfo(psDeviceNode);
-               if (bIdleDevice) {
-                       eError =
-                           SGXPostPowerState(hDevHandle,
-                                             PVR_DEVICE_POWER_STATE_ON,
-                                             PVR_DEVICE_POWER_STATE_IDLE);
-
-                       if (eError != PVRSRV_OK) {
-                               return eError;
-                       }
-               }
-               SGXStartTimer(psDevInfo, IMG_TRUE);
-       }
-
-       PVR_DPF((PVR_DBG_MESSAGE,
-                "SGXPostClockSpeedChange: SGX clock speed changed from %luHz to %luHz",
-                ui32OldClockSpeed, psDevInfo->ui32CoreClockSpeed));
-
-       return PVRSRV_OK;
-}
-
-static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO * psDevInfo,
-                                SGX_INIT_COMMAND * psScript,
-                                IMG_UINT32 ui32NumInitCommands)
-{
-       IMG_UINT32 ui32PC;
-       SGX_INIT_COMMAND *psComm;
+       u32 ui32PC;
+       union SGX_INIT_COMMAND *psComm;
 
        for (ui32PC = 0, psComm = psScript;
             ui32PC < ui32NumInitCommands; ui32PC++, psComm++) {
@@ -539,28 +214,36 @@ static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO * psDevInfo,
 
                default:
                        {
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXRunScript: PC %d: Illegal command: %d",
-                                        ui32PC, psComm->eOp));
+                               PVR_DPF(PVR_DBG_ERROR,
+                                    "SGXRunScript: PC %d: Illegal command: %d",
+                                     ui32PC, psComm->eOp);
                                return PVRSRV_ERROR_GENERIC;
                        }
                }
 
        }
 
-       return PVRSRV_ERROR_GENERIC;;
+       return PVRSRV_ERROR_GENERIC;
 }
 
-static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo,
+enum PVRSRV_ERROR SGXInitialise(struct PVRSRV_SGXDEV_INFO *psDevInfo,
                                  IMG_BOOL bHardwareRecovery)
 {
-       PVRSRV_ERROR eError;
-       IMG_UINT32 ui32ReadOffset, ui32WriteOffset;
+       enum PVRSRV_ERROR eError;
 
-       OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_CLKGATECTL,
-                    psDevInfo->ui32ClkGateCtl);
-       PDUMPREGWITHFLAGS(EUR_CR_CLKGATECTL, psDevInfo->ui32ClkGateCtl,
-                         PDUMP_FLAGS_CONTINUOUS);
+       PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
+                             "SGX initialisation script part 1\n");
+       eError =
+           SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart1,
+                        SGX_MAX_INIT_COMMANDS);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXInitialise: SGXRunScript (part 1) failed (%d)",
+                        eError);
+               return PVRSRV_ERROR_GENERIC;
+       }
+       PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
+                             "End of SGX initialisation script part 1\n");
 
        SGXReset(psDevInfo, PDUMP_FLAGS_CONTINUOUS);
 
@@ -568,134 +251,111 @@ static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo,
 
        *psDevInfo->pui32KernelCCBEventKicker = 0;
 #if defined(PDUMP)
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0,
+       PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0,
                 sizeof(*psDevInfo->pui32KernelCCBEventKicker),
                 PDUMP_FLAGS_CONTINUOUS,
                 MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo));
 #endif
 
-       psDevInfo->psSGXHostCtl->sTAHWPBDesc.uiAddr = 0;
-       psDevInfo->psSGXHostCtl->s3DHWPBDesc.uiAddr = 0;
-#if defined(PDUMP)
-       PDUMPCOMMENT(" CCB Control - Reset HW PBDesc records");
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo,
-                offsetof(PVRSRV_SGX_HOST_CTL, sTAHWPBDesc),
-                sizeof(IMG_DEV_VIRTADDR), PDUMP_FLAGS_CONTINUOUS,
-                MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo));
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo,
-                offsetof(PVRSRV_SGX_HOST_CTL, s3DHWPBDesc),
-                sizeof(IMG_DEV_VIRTADDR), PDUMP_FLAGS_CONTINUOUS,
-                MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo));
-#endif
-
+       PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
+                             "SGX initialisation script part 2\n");
        eError =
-           SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommands,
+           SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart2,
                         SGX_MAX_INIT_COMMANDS);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "SGXInitialise: SGXRunScript failed (%d)", eError));
-               return (PVRSRV_ERROR_GENERIC);
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXInitialise: SGXRunScript (part 2) failed (%d)",
+                        eError);
+               return PVRSRV_ERROR_GENERIC;
        }
+       PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
+                             "End of SGX initialisation script part 2\n");
 
-       SGXStartTimer(psDevInfo, !bHardwareRecovery);
+       SGXStartTimer(psDevInfo, (IMG_BOOL)!bHardwareRecovery);
 
        if (bHardwareRecovery) {
-               PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
-                   (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl;
+               struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
+                   psDevInfo->psSGXHostCtl;
 
-               if (PollForValueKM
-                   ((volatile IMG_UINT32 *)(&psSGXHostCtl->
-                                            ui32InterruptClearFlags), 0,
+               if (PollForValueKM(&psSGXHostCtl->ui32InterruptClearFlags, 0,
                     PVRSRV_USSE_EDM_INTERRUPT_HWR,
                     MAX_HW_TIME_US / WAIT_TRY_COUNT, 1000) != PVRSRV_OK) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "SGXInitialise: Wait for uKernel HW Recovery failed"));
+                       PVR_DPF(PVR_DBG_ERROR, "SGXInitialise: "
+                                       "Wait for uKernel HW Recovery failed");
+                       PVR_DBG_BREAK;
                        return PVRSRV_ERROR_RETRY;
                }
        }
 
-       for (ui32ReadOffset = psDevInfo->psKernelCCBCtl->ui32ReadOffset,
-            ui32WriteOffset = psDevInfo->psKernelCCBCtl->ui32WriteOffset;
-            ui32ReadOffset != ui32WriteOffset;
-            ui32ReadOffset = (ui32ReadOffset + 1) & 0xFF) {
-               *psDevInfo->pui32KernelCCBEventKicker =
-                   (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF;
-               OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_KICK,
-                            EUR_CR_EVENT_KICK_NOW_MASK);
-       }
+       PVR_ASSERT(psDevInfo->psKernelCCBCtl->ui32ReadOffset ==
+                  psDevInfo->psKernelCCBCtl->ui32WriteOffset);
 
        return PVRSRV_OK;
 }
 
-PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie)
+enum PVRSRV_ERROR SGXDeinitialise(void *hDevCookie)
 {
-       PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *) hDevCookie;
-       PVRSRV_ERROR eError;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *)
+                                                                  hDevCookie;
+       enum PVRSRV_ERROR eError;
 
-       if (psDevInfo->pvRegsBaseKM == IMG_NULL) {
+       if (psDevInfo->pvRegsBaseKM == NULL)
                return PVRSRV_OK;
-       }
 
-       eError =
-           SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands,
+       eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands,
                         SGX_MAX_DEINIT_COMMANDS);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "SGXDeinitialise: SGXRunScript failed (%d)", eError));
-               return (PVRSRV_ERROR_GENERIC);
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXDeinitialise: SGXRunScript failed (%d)", eError);
+               return PVRSRV_ERROR_GENERIC;
        }
 
        return PVRSRV_OK;
 }
 
-static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode)
+static enum PVRSRV_ERROR DevInitSGXPart1(void *pvDeviceNode)
 {
-       PVRSRV_SGXDEV_INFO *psDevInfo;
-       IMG_HANDLE hKernelDevMemContext;
-       IMG_DEV_PHYADDR sPDDevPAddr;
-       IMG_UINT32 i;
-       PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvDeviceNode;
-       DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap =
+       struct PVRSRV_SGXDEV_INFO *psDevInfo;
+       void *hKernelDevMemContext;
+       struct IMG_DEV_PHYADDR sPDDevPAddr;
+       u32 i;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode = (struct PVRSRV_DEVICE_NODE *)
+                                                                  pvDeviceNode;
+       struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap =
            psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
-       IMG_HANDLE hDevInfoOSMemHandle = (IMG_HANDLE) IMG_NULL;
-       PVRSRV_ERROR eError;
+       enum PVRSRV_ERROR eError;
 
        PDUMPCOMMENT("SGX Initialisation Part 1");
 
        PDUMPCOMMENT("SGX Core Version Information: %s",
                     SGX_CORE_FRIENDLY_NAME);
-#ifdef SGX_CORE_REV
-       PDUMPCOMMENT("SGX Core Revision Information: %d", SGX_CORE_REV);
-#else
-       PDUMPCOMMENT("SGX Core Revision Information: head rtl");
-#endif
-
-       if (OSAllocPages
-           (PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_HAP_MULTI_PROCESS |
-            PVRSRV_HAP_CACHED, sizeof(PVRSRV_SGXDEV_INFO),
-            (IMG_VOID **) & psDevInfo, &hDevInfoOSMemHandle) != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevInitSGXPart1 : Failed to alloc memory for DevInfo"));
-               return (PVRSRV_ERROR_OUT_OF_MEMORY);
+       PDUMPCOMMENT("SGX Core Revision Information: multi rev support");
+
+       if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                      sizeof(struct PVRSRV_SGXDEV_INFO),
+                      (void **)&psDevInfo, NULL) != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                       "DevInitSGXPart1 : Failed to alloc memory for DevInfo");
+               return PVRSRV_ERROR_OUT_OF_MEMORY;
        }
-       OSMemSet(psDevInfo, 0, sizeof(PVRSRV_SGXDEV_INFO));
+       OSMemSet(psDevInfo, 0, sizeof(struct PVRSRV_SGXDEV_INFO));
 
        psDevInfo->eDeviceType = DEV_DEVICE_TYPE;
        psDevInfo->eDeviceClass = DEV_DEVICE_CLASS;
 
-       psDeviceNode->pvDevice = (IMG_PVOID) psDevInfo;
-       psDeviceNode->hDeviceOSMemHandle = hDevInfoOSMemHandle;
+       psDeviceNode->pvDevice = (void *) psDevInfo;
 
-       psDevInfo->pvDeviceMemoryHeap = (IMG_VOID *) psDeviceMemoryHeap;
+       psDevInfo->pvDeviceMemoryHeap = (void *) psDeviceMemoryHeap;
 
-       hKernelDevMemContext = BM_CreateContext(psDeviceNode,
-                                               &sPDDevPAddr,
-                                               IMG_NULL, IMG_NULL);
+       hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr,
+                                               NULL, NULL);
+       if (!hKernelDevMemContext)
+               goto err1;
 
        psDevInfo->sKernelPDDevPAddr = sPDDevPAddr;
 
        for (i = 0; i < psDeviceNode->sDevMemoryInfo.ui32HeapCount; i++) {
-               IMG_HANDLE hDevMemHeap;
+               void *hDevMemHeap;
 
                switch (psDeviceMemoryHeap[i].DevMemHeapType) {
                case DEVICE_MEMORY_HEAP_KERNEL:
@@ -706,6 +366,9 @@ static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode)
                                    BM_CreateHeap(hKernelDevMemContext,
                                                  &psDeviceMemoryHeap[i]);
 
+                               if (!hDevMemHeap)
+                                       goto err2;
+
                                psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap;
                                break;
                        }
@@ -714,165 +377,182 @@ static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode)
 
        eError = MMU_BIFResetPDAlloc(psDevInfo);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevInitSGX : Failed to alloc memory for BIF reset"));
-               return PVRSRV_ERROR_GENERIC;
+               PVR_DPF(PVR_DBG_ERROR,
+                        "DevInitSGX : Failed to alloc memory for BIF reset");
+               goto err2;
        }
 
        return PVRSRV_OK;
+err2:
+       while (i) {
+               int type;
+
+               i--;
+               type = psDeviceMemoryHeap[i].DevMemHeapType;
+               if (type != DEVICE_MEMORY_HEAP_KERNEL &&
+                   type != DEVICE_MEMORY_HEAP_SHARED &&
+                   type != DEVICE_MEMORY_HEAP_SHARED_EXPORTED)
+                       continue;
+               BM_DestroyHeap(psDeviceMemoryHeap[i].hDevMemHeap);
+       }
+       BM_DestroyContext(hKernelDevMemContext);
+err1:
+       OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                 sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL);
+
+       return PVRSRV_ERROR_GENERIC;
 }
 
-IMG_EXPORT
-    PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle,
-                                       SGX_BRIDGE_INFO_FOR_SRVINIT *
-                                       psInitInfo)
+enum PVRSRV_ERROR SGXGetInfoForSrvinitKM(void *hDevHandle,
+                               struct SGX_BRIDGE_INFO_FOR_SRVINIT *psInitInfo)
 {
-       PVRSRV_DEVICE_NODE *psDeviceNode;
-       PVRSRV_SGXDEV_INFO *psDevInfo;
-       PVRSRV_ERROR eError;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo;
+       enum PVRSRV_ERROR eError;
 
        PDUMPCOMMENT("SGXGetInfoForSrvinit");
 
-       psDeviceNode = (PVRSRV_DEVICE_NODE *) hDevHandle;
-       psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
+       psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle;
+       psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
 
        psInitInfo->sPDDevPAddr = psDevInfo->sKernelPDDevPAddr;
 
        eError =
            PVRSRVGetDeviceMemHeapsKM(hDevHandle, &psInitInfo->asHeapInfo[0]);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "SGXGetInfoForSrvinit: PVRSRVGetDeviceMemHeapsKM failed (%d)",
-                        eError));
+               PVR_DPF(PVR_DBG_ERROR, "SGXGetInfoForSrvinit: "
+                               "PVRSRVGetDeviceMemHeapsKM failed (%d)",
+                        eError);
                return PVRSRV_ERROR_GENERIC;
        }
 
        return eError;
 }
 
-IMG_EXPORT
-    PVRSRV_ERROR DevInitSGXPart2KM(PVRSRV_PER_PROCESS_DATA * psPerProc,
-                                  IMG_HANDLE hDevHandle,
-                                  SGX_BRIDGE_INIT_INFO * psInitInfo)
+enum PVRSRV_ERROR DevInitSGXPart2KM(struct PVRSRV_PER_PROCESS_DATA *psPerProc,
+                                  void *hDevHandle,
+                                  struct SGX_BRIDGE_INIT_INFO *psInitInfo)
 {
-       PVRSRV_DEVICE_NODE *psDeviceNode;
-       PVRSRV_SGXDEV_INFO *psDevInfo;
-       PVRSRV_ERROR eError;
-       SGX_DEVICE_MAP *psSGXDeviceMap;
-       PVR_POWER_STATE eDefaultPowerState;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo;
+       enum PVRSRV_ERROR eError;
+       struct SGX_DEVICE_MAP *psSGXDeviceMap;
+       enum PVR_POWER_STATE eDefaultPowerState;
+       u32 l;
 
        PDUMPCOMMENT("SGX Initialisation Part 2");
 
-       psDeviceNode = (PVRSRV_DEVICE_NODE *) hDevHandle;
-       psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
+       psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle;
+       psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
 
        eError = InitDevInfo(psPerProc, psDeviceNode, psInitInfo);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevInitSGXPart2KM: Failed to load EDM program"));
+               PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: "
+                                       "Failed to load EDM program");
                goto failed_init_dev_info;
        }
 
 
        eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX,
-                                      (IMG_VOID **) & psSGXDeviceMap);
+                                      (void **) &psSGXDeviceMap);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevInitSGXPart2KM: Failed to get device memory map!"));
+               PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: "
+                                       "Failed to get device memory map!");
                return PVRSRV_ERROR_INIT_FAILURE;
        }
 
        if (psSGXDeviceMap->pvRegsCpuVBase) {
                psDevInfo->pvRegsBaseKM = psSGXDeviceMap->pvRegsCpuVBase;
        } else {
-
                psDevInfo->pvRegsBaseKM =
                    OSMapPhysToLin(psSGXDeviceMap->sRegsCpuPBase,
                                   psSGXDeviceMap->ui32RegsSize,
                                   PVRSRV_HAP_KERNEL_ONLY | PVRSRV_HAP_UNCACHED,
-                                  IMG_NULL);
+                                  NULL);
                if (!psDevInfo->pvRegsBaseKM) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "DevInitSGXPart2KM: Failed to map in regs\n"));
+                       PVR_DPF(PVR_DBG_ERROR,
+                                "DevInitSGXPart2KM: Failed to map in regs\n");
                        return PVRSRV_ERROR_BAD_MAPPING;
                }
        }
        psDevInfo->ui32RegSize = psSGXDeviceMap->ui32RegsSize;
        psDevInfo->sRegsPhysBase = psSGXDeviceMap->sRegsSysPBase;
 
-
-
        psDeviceNode->pvISRData = psDeviceNode;
 
        PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler);
 
-
-
-       psDevInfo->psSGXHostCtl->ui32PowManFlags |=
-           PVRSRV_USSE_EDM_POWMAN_NO_WORK;
+       pvr_dev_lock();
+       l = readl(&psDevInfo->psSGXHostCtl->ui32PowerStatus);
+       l |= PVRSRV_USSE_EDM_POWMAN_NO_WORK;
+       writel(l, &psDevInfo->psSGXHostCtl->ui32PowerStatus);
+       pvr_dev_unlock();
        eDefaultPowerState = PVRSRV_POWER_STATE_D3;
+
        eError = PVRSRVRegisterPowerDevice(psDeviceNode->sDevId.ui32DeviceIndex,
                                           SGXPrePowerStateExt,
                                           SGXPostPowerStateExt,
                                           SGXPreClockSpeedChange,
                                           SGXPostClockSpeedChange,
-                                          (IMG_HANDLE) psDeviceNode,
+                                          (void *) psDeviceNode,
                                           PVRSRV_POWER_STATE_D3,
                                           eDefaultPowerState);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevInitSGXPart2KM: failed to register device with power manager"));
+               PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: "
+                               "failed to register device with power manager");
                return eError;
        }
 
-       OSMemSet(psDevInfo->psKernelCCB, 0, sizeof(PVRSRV_SGX_KERNEL_CCB));
-       OSMemSet(psDevInfo->psKernelCCBCtl, 0, sizeof(PVRSRV_SGX_CCB_CTL));
+       OSMemSet(psDevInfo->psKernelCCB, 0,
+                sizeof(struct PVRSRV_SGX_KERNEL_CCB));
+       OSMemSet(psDevInfo->psKernelCCBCtl, 0,
+                sizeof(struct PVRSRV_SGX_CCB_CTL));
        OSMemSet(psDevInfo->pui32KernelCCBEventKicker, 0,
                 sizeof(*psDevInfo->pui32KernelCCBEventKicker));
-       PDUMPCOMMENT("Kernel CCB");
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBMemInfo, 0,
-                sizeof(PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS,
+       PDUMPCOMMENT("Initialise Kernel CCB");
+       PDUMPMEM(NULL, psDevInfo->psKernelCCBMemInfo, 0,
+                sizeof(struct PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS,
                 MAKEUNIQUETAG(psDevInfo->psKernelCCBMemInfo));
-       PDUMPCOMMENT("Kernel CCB Control");
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBCtlMemInfo, 0,
-                sizeof(PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS,
+       PDUMPCOMMENT("Initialise Kernel CCB Control");
+       PDUMPMEM(NULL, psDevInfo->psKernelCCBCtlMemInfo, 0,
+                sizeof(struct PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS,
                 MAKEUNIQUETAG(psDevInfo->psKernelCCBCtlMemInfo));
-       PDUMPCOMMENT("Kernel CCB Event Kicker");
-       PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0,
+       PDUMPCOMMENT("Initialise Kernel CCB Event Kicker");
+       PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0,
                 sizeof(*psDevInfo->pui32KernelCCBEventKicker),
                 PDUMP_FLAGS_CONTINUOUS,
                 MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo));
 
+       psDevInfo->hTimer = SGXOSTimerInit(psDeviceNode);
+       if (!psDevInfo->hTimer)
+               PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM : "
+                       "Failed to initialize HW recovery timer");
+
        return PVRSRV_OK;
 
 failed_init_dev_info:
        return eError;
 }
 
-static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode)
+static enum PVRSRV_ERROR DevDeInitSGX(void *pvDeviceNode)
 {
-       PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvDeviceNode;
-       PVRSRV_SGXDEV_INFO *psDevInfo =
-           (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
-       IMG_HANDLE hDevInfoOSMemHandle = psDeviceNode->hDeviceOSMemHandle;
-       PVRSRV_ERROR eError = PVRSRV_ERROR_INVALID_PARAMS;
-       IMG_UINT32 ui32Heap;
-       DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
-       SGX_DEVICE_MAP *psSGXDeviceMap;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode =
+               (struct PVRSRV_DEVICE_NODE *)pvDeviceNode;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo =
+               (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       enum PVRSRV_ERROR eError;
+       u32 ui32Heap;
+       struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
+       struct SGX_DEVICE_MAP *psSGXDeviceMap;
 
        if (!psDevInfo) {
-
-               PVR_DPF((PVR_DBG_ERROR, "DevDeInitSGX: Null DevInfo"));
+               PVR_DPF(PVR_DBG_ERROR, "DevDeInitSGX: Null DevInfo");
                return PVRSRV_OK;
        }
        if (psDevInfo->hTimer) {
-               eError = OSRemoveTimer(psDevInfo->hTimer);
-               if (eError != PVRSRV_OK) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "DevDeInitSGX: Failed to remove timer"));
-                       return eError;
-               }
-               psDevInfo->hTimer = IMG_NULL;
+               SGXOSTimerCancel(psDevInfo->hTimer);
+               SGXOSTimerDeInit(psDevInfo->hTimer);
+               psDevInfo->hTimer = NULL;
        }
 
        MMU_BIFResetPDFree(psDevInfo);
@@ -881,7 +561,7 @@ static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode)
 
 
        psDeviceMemoryHeap =
-           (DEVICE_MEMORY_HEAP_INFO *) psDevInfo->pvDeviceMemoryHeap;
+           (struct DEVICE_MEMORY_HEAP_INFO *)psDevInfo->pvDeviceMemoryHeap;
        for (ui32Heap = 0;
             ui32Heap < psDeviceNode->sDevMemoryInfo.ui32HeapCount;
             ui32Heap++) {
@@ -891,159 +571,211 @@ static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode)
                case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
                        {
                                if (psDeviceMemoryHeap[ui32Heap].hDevMemHeap !=
-                                   IMG_NULL) {
+                                   NULL)
                                        BM_DestroyHeap(psDeviceMemoryHeap
                                                       [ui32Heap].hDevMemHeap);
-                               }
                                break;
                        }
                }
        }
 
-       eError =
-           BM_DestroyContext(psDeviceNode->sDevMemoryInfo.pBMKernelContext,
-                             IMG_NULL);
-       if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevDeInitSGX : Failed to destroy kernel context"));
-               return eError;
-       }
+       if (!pvr_put_ctx(psDeviceNode->sDevMemoryInfo.pBMKernelContext))
+               pr_err("%s: kernel context still in use, can't free it",
+                       __func__);
 
-       eError =
-           PVRSRVRemovePowerDevice(((PVRSRV_DEVICE_NODE *) pvDeviceNode)->
-                                   sDevId.ui32DeviceIndex);
-       if (eError != PVRSRV_OK) {
+       eError = PVRSRVRemovePowerDevice(
+                               ((struct PVRSRV_DEVICE_NODE *)pvDeviceNode)->
+                                 sDevId.ui32DeviceIndex);
+       if (eError != PVRSRV_OK)
                return eError;
-       }
 
        eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX,
-                                      (IMG_VOID **) & psSGXDeviceMap);
+                                      (void **)&psSGXDeviceMap);
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "DevDeInitSGX: Failed to get device memory map!"));
+               PVR_DPF(PVR_DBG_ERROR,
+                        "DevDeInitSGX: Failed to get device memory map!");
                return eError;
        }
 
-       if (!psSGXDeviceMap->pvRegsCpuVBase) {
-
-               if (psDevInfo->pvRegsBaseKM != IMG_NULL) {
+       if (!psSGXDeviceMap->pvRegsCpuVBase)
+               if (psDevInfo->pvRegsBaseKM != NULL)
                        OSUnMapPhysToLin(psDevInfo->pvRegsBaseKM,
                                         psDevInfo->ui32RegSize,
                                         PVRSRV_HAP_KERNEL_ONLY |
-                                        PVRSRV_HAP_UNCACHED, IMG_NULL);
-               }
-       }
+                                                PVRSRV_HAP_UNCACHED,
+                                        NULL);
 
-       OSFreePages(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_HAP_MULTI_PROCESS,
-                   sizeof(PVRSRV_SGXDEV_INFO), psDevInfo, hDevInfoOSMemHandle);
-       psDeviceNode->pvDevice = IMG_NULL;
+       OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                 sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL);
 
-       if (psDeviceMemoryHeap != IMG_NULL) {
+       psDeviceNode->pvDevice = NULL;
 
+       if (psDeviceMemoryHeap != NULL)
                OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
-                         sizeof(DEVICE_MEMORY_HEAP_INFO) *
+                         sizeof(struct DEVICE_MEMORY_HEAP_INFO) *
                          psDeviceNode->sDevMemoryInfo.ui32HeapCount,
-                         psDeviceMemoryHeap, 0);
-       }
+                         psDeviceMemoryHeap, NULL);
 
        return PVRSRV_OK;
 }
 
-static
-IMG_VOID HWRecoveryResetSGX(PVRSRV_DEVICE_NODE * psDeviceNode,
-                           IMG_UINT32 ui32Component, IMG_UINT32 ui32CallerID)
+static struct PVRSRV_PER_PROCESS_DATA *find_cur_proc_data(
+                                       struct PVRSRV_DEVICE_NODE *dev)
 {
-       PVRSRV_ERROR eError;
-       PVRSRV_SGXDEV_INFO *psDevInfo =
-           (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
-       PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
-           (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl;
+       struct PVRSRV_SGXDEV_INFO *dev_info = dev->pvDevice;
+       u32 page_dir = readl(dev_info->pvRegsBaseKM +
+                               EUR_CR_BIF_DIR_LIST_BASE0);
+       struct BM_CONTEXT *bm_ctx;
+       struct RESMAN_CONTEXT *res_ctx = NULL;
+       struct PVRSRV_PER_PROCESS_DATA *proc_data = NULL;
 
-       PVR_UNREFERENCED_PARAMETER(ui32Component);
+       bm_ctx = bm_find_context(dev->sDevMemoryInfo.pBMContext, page_dir);
+       if (bm_ctx)
+               res_ctx = pvr_get_resman_ctx(bm_ctx);
 
-       eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE);
-       if (eError != PVRSRV_OK) {
+       if (res_ctx)
+               proc_data = pvr_get_proc_by_ctx(res_ctx);
 
-               PVR_DPF((PVR_DBG_WARNING,
-                        "HWRecoveryResetSGX: Power transition in progress"));
+       return proc_data;
+}
+
+static void pr_err_process_info(struct PVRSRV_PER_PROCESS_DATA *proc)
+{
+       struct task_struct *tsk;
+       int pid;
+
+       if (!proc)
                return;
-       }
 
-       psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_HWR;
+       pid = proc->ui32PID;
+       rcu_read_lock();
+       tsk = pid_task(find_vpid(pid), PIDTYPE_PID);
+       pr_err("PID = %d, process name = %s\n", pid, tsk->comm);
+       rcu_read_unlock();
+}
+
+static void pr_err_sgx_registers(struct PVRSRV_SGXDEV_INFO *psDevInfo)
+{
+       pr_err("EVENT_STATUS =     0x%08X\n"
+               "EVENT_STATUS2 =    0x%08X\n"
+               "BIF_CTRL =         0x%08X\n"
+               "BIF_INT_STAT =     0x%08X\n"
+               "BIF_MEM_REQ_STAT = 0x%08X\n"
+               "BIF_FAULT  =       0x%08X\n"
+               "CLKGATECTL =       0x%08X\n",
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS2),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_CTRL),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_INT_STAT),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_MEM_REQ_STAT),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_FAULT),
+               readl(psDevInfo->pvRegsBaseKM + EUR_CR_CLKGATECTL));
+}
+
+/* Should be called with pvr_lock held */
+void
+HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode, const char *caller)
+{
+       enum PVRSRV_ERROR eError;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo =
+           (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
+                                       psDevInfo->psSGXHostCtl;
+       struct PVRSRV_PER_PROCESS_DATA *proc;
+       u32 l;
+       int max_retries = 10;
+
+       BUG_ON(!pvr_is_locked());
+
+       l = readl(&psSGXHostCtl->ui32InterruptClearFlags);
+       l |= PVRSRV_USSE_EDM_INTERRUPT_HWR;
+       writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
 
-       pr_err("HWRecoveryResetSGX: SGX Hardware Recovery triggered\n");
+       pr_err("SGX Hardware Recovery triggered (from %s)\n", caller);
+
+       proc = find_cur_proc_data(psDeviceNode);
+
+       pr_err_process_info(proc);
+       pr_err_sgx_registers(psDevInfo);
+
+#ifdef CONFIG_DEBUG_FS
+       pvr_hwrec_dump(proc, psDevInfo);
+#endif
 
        PDUMPSUSPEND();
 
        do {
                eError = SGXInitialise(psDevInfo, IMG_TRUE);
-       }
-       while (eError == PVRSRV_ERROR_RETRY);
+               if (eError != PVRSRV_ERROR_RETRY)
+                       break;
+       } while (max_retries--);
+
        if (eError != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "HWRecoveryResetSGX: SGXInitialise failed (%d)",
-                        eError));
+               pr_err("%s: recovery failed (%d). Disabling the driver",
+                       __func__, eError);
+               pvr_disable();
+
+               PDUMPRESUME();
+
+               return;
        }
 
        PDUMPRESUME();
 
-       PVRSRVPowerUnlock(ui32CallerID);
-
        SGXScheduleProcessQueues(psDeviceNode);
 
-       PVRSRVProcessQueues(ui32CallerID, IMG_TRUE);
-}
-
-static struct workdata {
-       PVRSRV_DEVICE_NODE *psDeviceNode;
-       IMG_UINT32 ui32Component;
-       IMG_UINT32 ui32CallerID;
-} gHWRecoveryParams;
-
-static void HWRecoveryWrapper(struct work_struct *work)
-{
-       HWRecoveryResetSGX(gHWRecoveryParams.psDeviceNode,
-                          gHWRecoveryParams.ui32Component,
-                          gHWRecoveryParams.ui32CallerID);
+       PVRSRVProcessQueues(IMG_TRUE);
 }
 
-DECLARE_WORK(gWork, HWRecoveryWrapper);
+static unsigned long sgx_reset_forced;
 
-IMG_VOID SGXOSTimer(IMG_VOID * pvData)
+static void SGXOSTimer(struct work_struct *work)
 {
-       PVRSRV_DEVICE_NODE *psDeviceNode = pvData;
-       PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
-       static IMG_UINT32 ui32EDMTasks = 0;
-       static IMG_UINT32 ui32LockupCounter = 0;
-       static IMG_UINT32 ui32NumResets = 0;
-       IMG_UINT32 ui32CurrentEDMTasks;
+       struct timer_work_data *data = container_of(work,
+                                                   struct timer_work_data,
+                                                   work.work);
+       struct PVRSRV_DEVICE_NODE *psDeviceNode = data->psDeviceNode;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
+       static u32 ui32EDMTasks;
+       static u32 ui32LockupCounter;
+       static u32 ui32NumResets;
+       u32 ui32CurrentEDMTasks;
        IMG_BOOL bLockup = IMG_FALSE;
        IMG_BOOL bPoweredDown;
 
+       pvr_lock();
+
+       if (!data->armed || pvr_is_disabled()) {
+               pvr_unlock();
+               return;
+       }
+
        psDevInfo->ui32TimeStamp++;
 
-       bPoweredDown = (IMG_BOOL) ! SGXIsDevicePowered(psDeviceNode);
+#if defined(NO_HARDWARE)
+       bPoweredDown = IMG_TRUE;
+#else
+       bPoweredDown = (IMG_BOOL) !SGXIsDevicePowered(psDeviceNode);
+#endif
 
        if (bPoweredDown) {
                ui32LockupCounter = 0;
        } else {
-
-               ui32CurrentEDMTasks =
-                   OSReadHWReg(psDevInfo->pvRegsBaseKM,
-                               psDevInfo->ui32EDMTaskReg0);
-               if (psDevInfo->ui32EDMTaskReg1 != 0) {
+               pvr_dev_lock();
+               ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM,
+                                               psDevInfo->ui32EDMTaskReg0);
+               if (psDevInfo->ui32EDMTaskReg1 != 0)
                        ui32CurrentEDMTasks ^=
                            OSReadHWReg(psDevInfo->pvRegsBaseKM,
                                        psDevInfo->ui32EDMTaskReg1);
-               }
                if ((ui32CurrentEDMTasks == ui32EDMTasks) &&
                    (psDevInfo->ui32NumResets == ui32NumResets)) {
                        ui32LockupCounter++;
                        if (ui32LockupCounter == 3) {
                                ui32LockupCounter = 0;
-                               PVR_DPF((PVR_DBG_ERROR,
-                                        "SGXOSTimer() detected SGX lockup (0x%x tasks)",
-                                        ui32EDMTasks));
+                               PVR_DPF(PVR_DBG_ERROR, "SGXOSTimer() "
+                                       "detected SGX lockup (0x%x tasks)",
+                                        ui32EDMTasks);
 
                                bLockup = IMG_TRUE;
                        }
@@ -1052,58 +784,120 @@ IMG_VOID SGXOSTimer(IMG_VOID * pvData)
                        ui32EDMTasks = ui32CurrentEDMTasks;
                        ui32NumResets = psDevInfo->ui32NumResets;
                }
+               pvr_dev_unlock();
        }
 
+       bLockup |= cmpxchg(&sgx_reset_forced, 1, 0);
+
        if (bLockup) {
-               PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
-                   (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl;
-
-               psSGXHostCtl->ui32HostDetectedLockups++;
-
-               /*
-                * schedule HWRecoveryResetSGX from a work
-                * in the shared queue
-                */
-               gHWRecoveryParams.psDeviceNode = psDeviceNode;
-               gHWRecoveryParams.ui32Component = 0;
-               gHWRecoveryParams.ui32CallerID = TIMER_ID;
-               schedule_work(&gWork);
+               struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
+                                               psDevInfo->psSGXHostCtl;
+               u32 l;
+
+               pvr_dev_lock();
+               l = readl(&psSGXHostCtl->ui32HostDetectedLockups);
+               l++;
+               writel(l, &psSGXHostCtl->ui32HostDetectedLockups);
+
+               HWRecoveryResetSGX(psDeviceNode, __func__);
+               pvr_dev_unlock();
        }
+
+       queue_delayed_work(data->work_queue, &data->work,
+                          msecs_to_jiffies(data->interval));
+
+       pvr_unlock();
 }
 
+struct timer_work_data *
+SGXOSTimerInit(struct PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       struct timer_work_data *data;
+
+       data = kzalloc(sizeof(struct timer_work_data), GFP_KERNEL);
+       if (!data)
+               return NULL;
+
+       data->work_queue = create_workqueue("SGXOSTimer");
+       if (!data->work_queue) {
+               kfree(data);
+               return NULL;
+       }
+
+       data->interval = 150;
+       data->psDeviceNode = psDeviceNode;
+       INIT_DELAYED_WORK(&data->work, SGXOSTimer);
+
+       return data;
+}
 
-IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData)
+void SGXOSTimerDeInit(struct timer_work_data *data)
+{
+       data->armed = false;
+       destroy_workqueue(data->work_queue);
+       kfree(data);
+}
+
+enum PVRSRV_ERROR SGXOSTimerEnable(struct timer_work_data *data)
+{
+       if (!data)
+               return PVRSRV_ERROR_GENERIC;
+
+       if (queue_delayed_work(data->work_queue, &data->work,
+                              msecs_to_jiffies(data->interval))) {
+               data->armed = true;
+               return PVRSRV_OK;
+       }
+
+       return PVRSRV_ERROR_GENERIC;
+}
+
+enum PVRSRV_ERROR SGXOSTimerCancel(struct timer_work_data *data)
+{
+       if (!data)
+               return PVRSRV_ERROR_GENERIC;
+
+       data->armed = false;
+       cancel_delayed_work(&data->work);
+
+       return PVRSRV_OK;
+}
+
+int sgx_force_reset(void)
+{
+       return !cmpxchg(&sgx_reset_forced, 0, 1);
+}
+
+static IMG_BOOL SGX_ISRHandler(void *pvData)
 {
        IMG_BOOL bInterruptProcessed = IMG_FALSE;
 
        {
-               IMG_UINT32 ui32EventStatus, ui32EventEnable;
-               IMG_UINT32 ui32EventClear = 0;
-               PVRSRV_DEVICE_NODE *psDeviceNode;
-               PVRSRV_SGXDEV_INFO *psDevInfo;
-
-               if (pvData == IMG_NULL) {
-                       PVR_DPF((PVR_DBG_ERROR,
-                                "SGX_ISRHandler: Invalid params\n"));
+               u32 ui32EventStatus, ui32EventEnable;
+               u32 ui32EventClear = 0;
+               struct PVRSRV_DEVICE_NODE *psDeviceNode;
+               struct PVRSRV_SGXDEV_INFO *psDevInfo;
+
+               if (pvData == NULL) {
+                       PVR_DPF(PVR_DBG_ERROR,
+                                "SGX_ISRHandler: Invalid params\n");
                        return bInterruptProcessed;
                }
 
-               psDeviceNode = (PVRSRV_DEVICE_NODE *) pvData;
-               psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
+               psDeviceNode = (struct PVRSRV_DEVICE_NODE *)pvData;
+               psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
 
                ui32EventStatus =
                    OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS);
-               ui32EventEnable =
-                   OSReadHWReg(psDevInfo->pvRegsBaseKM,
-                               EUR_CR_EVENT_HOST_ENABLE);
+               ui32EventEnable = OSReadHWReg(psDevInfo->pvRegsBaseKM,
+                                               EUR_CR_EVENT_HOST_ENABLE);
 
                gui32EventStatusServicesByISR = ui32EventStatus;
 
                ui32EventStatus &= ui32EventEnable;
 
-               if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) {
+               if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK)
                        ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_MASK;
-               }
 
                if (ui32EventClear) {
                        bInterruptProcessed = IMG_TRUE;
@@ -1119,26 +913,44 @@ IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData)
        return bInterruptProcessed;
 }
 
-IMG_VOID SGX_MISRHandler(IMG_VOID * pvData)
+static void SGX_MISRHandler(void *pvData)
 {
-       PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvData;
-       PVRSRV_SGXDEV_INFO *psDevInfo =
-           (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice;
-       PVRSRV_SGX_HOST_CTL *psSGXHostCtl =
-           (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl;
-
-       if ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR)
-           && !(psSGXHostCtl->
-                ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR)) {
-               HWRecoveryResetSGX(psDeviceNode, 0, ISR_ID);
-       }
-       SGXTestActivePowerEvent(psDeviceNode, ISR_ID);
+       struct PVRSRV_DEVICE_NODE *psDeviceNode =
+                       (struct PVRSRV_DEVICE_NODE *)pvData;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo =
+                       (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
+       struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
+                       psDevInfo->psSGXHostCtl;
+       u32 l1, l2;
+       int dev_idx;
+       enum PVRSRV_ERROR err;
+
+       dev_idx = psDeviceNode->sDevId.ui32DeviceIndex;
+
+       pvr_dev_lock();
+
+       err = PVRSRVSetDevicePowerStateKM(dev_idx, PVRSRV_POWER_STATE_D0);
+       BUG_ON(err != PVRSRV_OK);
+
+       l1 = readl(&psSGXHostCtl->ui32InterruptFlags);
+       l2 = readl(&psSGXHostCtl->ui32InterruptClearFlags);
+
+       if ((l1 & PVRSRV_USSE_EDM_INTERRUPT_HWR) &&
+           !(l2 & PVRSRV_USSE_EDM_INTERRUPT_HWR))
+               HWRecoveryResetSGX(psDeviceNode, __func__);
+
+       if (psDeviceNode->bReProcessDeviceCommandComplete)
+               SGXScheduleProcessQueues(psDeviceNode);
+
+       SGXTestActivePowerEvent(psDeviceNode);
+
+       pvr_dev_unlock();
 }
 
-PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
+enum PVRSRV_ERROR SGXRegisterDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode)
 {
-       DEVICE_MEMORY_INFO *psDevMemoryInfo;
-       DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
+       struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
+       struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
 
        psDeviceNode->sDevId.eDeviceType = DEV_DEVICE_TYPE;
        psDeviceNode->sDevId.eDeviceClass = DEV_DEVICE_CLASS;
@@ -1146,6 +958,8 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceNode->pfnInitDevice = DevInitSGXPart1;
        psDeviceNode->pfnDeInitDevice = DevDeInitSGX;
 
+       psDeviceNode->pfnInitDeviceCompatCheck = SGXDevInitCompatCheck;
+
        psDeviceNode->pfnMMUInitialise = MMU_Initialise;
        psDeviceNode->pfnMMUFinalise = MMU_Finalise;
        psDeviceNode->pfnMMUInsertHeap = MMU_InsertHeap;
@@ -1160,7 +974,6 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceNode->pfnMMUGetPhysPageAddr = MMU_GetPhysPageAddr;
        psDeviceNode->pfnMMUGetPDDevPAddr = MMU_GetPDDevPAddr;
 
-
        psDeviceNode->pfnDeviceISR = SGX_ISRHandler;
        psDeviceNode->pfnDeviceMISR = SGX_MISRHandler;
 
@@ -1168,27 +981,27 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
 
        psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo;
 
-       psDevMemoryInfo->ui32AddressSpaceSizeLog2 = SGX_ADDRESS_SPACE_SIZE;
+       psDevMemoryInfo->ui32AddressSpaceSizeLog2 =
+           SGX_FEATURE_ADDRESS_SPACE_SIZE;
 
        psDevMemoryInfo->ui32Flags = 0;
-
        psDevMemoryInfo->ui32HeapCount = SGX_MAX_HEAP_ID;
-
        psDevMemoryInfo->ui32SyncHeapID = SGX_SYNCINFO_HEAP_ID;
 
-       psDevMemoryInfo->ui32MappingHeapID = SGX_GENERAL_MAPPING_HEAP_ID;
+       psDevMemoryInfo->ui32MappingHeapID = SGX_GENERAL_HEAP_ID;
 
        if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
-                      sizeof(DEVICE_MEMORY_HEAP_INFO) *
+                      sizeof(struct DEVICE_MEMORY_HEAP_INFO) *
                       psDevMemoryInfo->ui32HeapCount,
-                      (IMG_VOID **) & psDevMemoryInfo->psDeviceMemoryHeap,
-                      0) != PVRSRV_OK) {
-               PVR_DPF((PVR_DBG_ERROR,
-                        "SGXRegisterDevice : Failed to alloc memory for DEVICE_MEMORY_HEAP_INFO"));
-               return (PVRSRV_ERROR_OUT_OF_MEMORY);
+                      (void **) &psDevMemoryInfo->psDeviceMemoryHeap,
+                      NULL) != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "SGXRegisterDevice : "
+                               "Failed to alloc memory for "
+                               "struct DEVICE_MEMORY_HEAP_INFO");
+               return PVRSRV_ERROR_OUT_OF_MEMORY;
        }
        OSMemSet(psDevMemoryInfo->psDeviceMemoryHeap, 0,
-                sizeof(DEVICE_MEMORY_HEAP_INFO) *
+                sizeof(struct DEVICE_MEMORY_HEAP_INFO) *
                 psDevMemoryInfo->ui32HeapCount);
 
        psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
@@ -1207,6 +1020,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID);
        psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1221,6 +1037,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID);
        psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1228,43 +1047,34 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapSize =
            SGX_KERNEL_CODE_HEAP_SIZE;
        psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32Attribs =
-           PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION
-           | PVRSRV_HAP_MULTI_PROCESS;
-       psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszName = "Kernel";
-       psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszBSName = "Kernel BS";
+           PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION |
+           PVRSRV_HAP_MULTI_PROCESS;
+       psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszName = "Kernel Code";
+       psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszBSName =
+           "Kernel Code BS";
        psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
 
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32HeapID =
-           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_VIDEO_CODE_HEAP_ID);
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].sDevVAddrBase.uiAddr =
-           SGX_VIDEO_CODE_HEAP_BASE;
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32HeapSize =
-           SGX_VIDEO_CODE_HEAP_SIZE;
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32Attribs =
-           PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION |
-           PVRSRV_HAP_KERNEL_ONLY;
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].pszName = "Video";
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].pszBSName = "Video BS";
-       psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].DevMemHeapType =
-           DEVICE_MEMORY_HEAP_SHARED;
-
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32HeapID =
-           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_VIDEO_DATA_HEAP_ID);
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].sDevVAddrBase.uiAddr =
-           SGX_KERNEL_VIDEO_DATA_HEAP_BASE;
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32HeapSize =
-           SGX_KERNEL_VIDEO_DATA_HEAP_SIZE;
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32Attribs =
+       psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapID =
+           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID);
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].sDevVAddrBase.uiAddr =
+           SGX_KERNEL_DATA_HEAP_BASE;
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapSize =
+           SGX_KERNEL_DATA_HEAP_SIZE;
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32Attribs =
            PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION |
            PVRSRV_HAP_MULTI_PROCESS;
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].pszName =
-           "KernelVideoData";
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].pszBSName =
-           "KernelVideoData BS";
-       psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].DevMemHeapType =
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszName = "KernelData";
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszBSName = "KernelData BS";
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
 
+       psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID);
        psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1280,6 +1090,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID);
        psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1296,6 +1109,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID);
        psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1312,6 +1128,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID);
        psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].sDevVAddrBase.
@@ -1328,6 +1147,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
+       psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID);
        psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1344,6 +1166,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
 
+       psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
+
        psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32HeapID =
            HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_3DPARAMETERS_HEAP_ID);
        psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].sDevVAddrBase.uiAddr =
@@ -1359,71 +1184,24 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode)
        psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].DevMemHeapType =
            DEVICE_MEMORY_HEAP_PERCONTEXT;
 
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32HeapID =
-           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_MAPPING_HEAP_ID);
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr =
-           SGX_GENERAL_MAPPING_HEAP_BASE;
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32HeapSize =
-           SGX_GENERAL_MAPPING_HEAP_SIZE;
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32Attribs =
-           PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS;
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].pszName =
-           "GeneralMapping";
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].pszBSName =
-           "GeneralMapping BS";
-
-       psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].DevMemHeapType =
-           DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
-
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32HeapID =
-           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_FB_MAPPING_HEAP_ID);
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr =
-           SGX_FB_MAPPING_HEAP_BASE;
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32HeapSize =
-           SGX_FB_MAPPING_HEAP_SIZE;
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32Attribs =
-           PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS;
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].pszName =
-           "FramebufferMapping";
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].pszBSName =
-           "FramebufferMapping BS";
-
-       psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].DevMemHeapType =
-           DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
-
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32HeapID =
-           HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_ALT_MAPPING_HEAP_ID);
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr =
-           SGX_ALT_MAPPING_HEAP_BASE;
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32HeapSize =
-           SGX_ALT_MAPPING_HEAP_SIZE;
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32Attribs =
-           PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS;
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].pszName = "AltMapping";
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].pszBSName = "AltMapping BS";
-
-       psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].DevMemHeapType =
-           DEVICE_MEMORY_HEAP_SHARED_EXPORTED;
-
+       psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32DataPageSize =
+           SGX_MMU_PAGE_SIZE;
 
        return PVRSRV_OK;
 }
 
-IMG_EXPORT
-    PVRSRV_ERROR SGXGetClientInfoKM(IMG_HANDLE hDevCookie,
-                                   PVR3DIF4_CLIENT_INFO * psClientInfo)
+enum PVRSRV_ERROR SGXGetClientInfoKM(void *hDevCookie,
+                                        struct SGX_CLIENT_INFO *psClientInfo)
 {
-       PVRSRV_SGXDEV_INFO *psDevInfo =
-           (PVRSRV_SGXDEV_INFO *) ((PVRSRV_DEVICE_NODE *) hDevCookie)->
-           pvDevice;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo =
+           (struct PVRSRV_SGXDEV_INFO *)
+                       ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice;
 
        psDevInfo->ui32ClientRefCount++;
 #ifdef PDUMP
-       if (psDevInfo->ui32ClientRefCount == 1) {
+       if (psDevInfo->ui32ClientRefCount == 1)
                psDevInfo->psKernelCCBInfo->ui32CCBDumpWOff = 0;
-       }
 #endif
-
        psClientInfo->ui32ProcessID = OSGetCurrentProcessIDKM();
 
        OSMemCopy(&psClientInfo->asDevData, &psDevInfo->asSGXDevData,
@@ -1432,9 +1210,142 @@ IMG_EXPORT
        return PVRSRV_OK;
 }
 
-IMG_EXPORT
-    PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO * psDevInfo,
-                                 SGX_MISC_INFO * psMiscInfo)
+enum PVRSRV_ERROR SGXDevInitCompatCheck(struct PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       struct PVRSRV_SGXDEV_INFO *psDevInfo;
+       struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
+       enum PVRSRV_ERROR eError;
+#if !defined(NO_HARDWARE)
+       u32 opts;
+       u32 opt_mismatch;
+       struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures;
+#endif
+
+       if (psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_SGX) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXDevInitCompatCheck: Device not of type SGX");
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto exit;
+       }
+       psDevInfo = psDeviceNode->pvDevice;
+       psMemInfo = psDevInfo->psKernelSGXMiscMemInfo;
+
+#if !defined(NO_HARDWARE)
+
+       eError = SGXGetBuildInfoKM(psDevInfo, psDeviceNode);
+       if (eError != PVRSRV_OK) {
+               pr_err("pvr: unable to validate device DDK version\n");
+               goto exit;
+       }
+       psSGXFeatures =
+           &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo->pvLinAddrKM))->
+                                                           sSGXFeatures;
+       if ((psSGXFeatures->ui32DDKVersion !=
+            ((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) |
+             PVRVERSION_BRANCH)) ||
+            (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD)) {
+               pr_err("pvr: incompatible driver DDK revision (%d)"
+                       "/device DDK revision (%d).\n",
+                        PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild);
+               eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH;
+               goto exit;
+       } else {
+               PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: "
+                               "driver DDK (%ld) and device DDK (%ld) match",
+                        PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild);
+       }
+
+       opts = psSGXFeatures->ui32BuildOptions;
+       opt_mismatch = opts ^ SGX_BUILD_OPTIONS;
+       /* we support the ABIs both with and without EDM tracing option */
+       opt_mismatch &= ~PVRSRV_USSE_EDM_STATUS_DEBUG_SET_OFFSET;
+       if (opt_mismatch) {
+               if (SGX_BUILD_OPTIONS & opt_mismatch)
+                       pr_err("pvr: mismatch in driver and microkernel build "
+                               "options; extra options present in driver: "
+                               "(0x%x)", SGX_BUILD_OPTIONS & opt_mismatch);
+
+               if (opts & opt_mismatch)
+                       pr_err("pvr: Mismatch in driver and microkernel build "
+                               "options; extra options present in "
+                               "microkernel: (0x%x)", opts & opt_mismatch);
+               eError = PVRSRV_ERROR_BUILD_MISMATCH;
+               goto exit;
+       } else {
+               PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: "
+                               "Driver and microkernel build options match.");
+       }
+
+#endif
+       eError = PVRSRV_OK;
+exit:
+       return eError;
+}
+
+static
+enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo,
+                                   struct PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       enum PVRSRV_ERROR eError;
+       struct SGXMKIF_COMMAND sCommandData;
+       struct PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt;
+       struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures;
+
+       struct PVRSRV_KERNEL_MEM_INFO *psMemInfo =
+           psDevInfo->psKernelSGXMiscMemInfo;
+
+       if (!psMemInfo->pvLinAddrKM) {
+               PVR_DPF(PVR_DBG_ERROR, "SGXGetMiscInfoKM: Invalid address.");
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+       psSGXMiscInfoInt = psMemInfo->pvLinAddrKM;
+       psSGXMiscInfoInt->ui32MiscInfoFlags &= ~PVRSRV_USSE_MISCINFO_READY;
+       psSGXFeatures = &psSGXMiscInfoInt->sSGXFeatures;
+
+       OSMemSet(psMemInfo->pvLinAddrKM, 0,
+                sizeof(struct PVRSRV_SGX_MISCINFO_INFO));
+
+       sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr;
+
+       OSMemSet(psSGXFeatures, 0, sizeof(*psSGXFeatures));
+
+       mb();
+
+       eError = SGXScheduleCCBCommandKM(psDeviceNode,
+                                        SGXMKIF_COMMAND_REQUEST_SGXMISCINFO,
+                                        &sCommandData, KERNEL_ID, 0);
+
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "SGXGetMiscInfoKM: SGXScheduleCCBCommandKM failed.");
+               return eError;
+       }
+
+#if !defined(NO_HARDWARE)
+       {
+               IMG_BOOL bTimeout = IMG_TRUE;
+
+               LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
+                       if ((psSGXMiscInfoInt->
+                            ui32MiscInfoFlags & PVRSRV_USSE_MISCINFO_READY) !=
+                           0) {
+                               bTimeout = IMG_FALSE;
+                               break;
+                       }
+               }
+               END_LOOP_UNTIL_TIMEOUT();
+
+               if (bTimeout)
+                       return PVRSRV_ERROR_TIMEOUT;
+       }
+#endif
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR SGXGetMiscInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo,
+                                      struct SGX_MISC_INFO *psMiscInfo,
+                                      struct PVRSRV_DEVICE_NODE *psDeviceNode)
 {
        switch (psMiscInfo->eRequest) {
        case SGX_MISC_INFO_REQUEST_CLOCKSPEED:
@@ -1443,42 +1354,163 @@ IMG_EXPORT
                            psDevInfo->ui32CoreClockSpeed;
                        return PVRSRV_OK;
                }
+
+       case SGX_MISC_INFO_REQUEST_SGXREV:
+               {
+                       struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures;
+                       struct PVRSRV_KERNEL_MEM_INFO *psMemInfo =
+                           psDevInfo->psKernelSGXMiscMemInfo;
+
+                       SGXGetBuildInfoKM(psDevInfo, psDeviceNode);
+                       psSGXFeatures =
+                           &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo->
+                                                 pvLinAddrKM))->sSGXFeatures;
+
+                       psMiscInfo->uData.sSGXFeatures = *psSGXFeatures;
+
+                       PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: "
+                                       "Core 0x%lx, sw ID 0x%lx, "
+                                       "sw Rev 0x%lx\n",
+                                psSGXFeatures->ui32CoreRev,
+                                psSGXFeatures->ui32CoreIdSW,
+                                psSGXFeatures->ui32CoreRevSW);
+                       PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: "
+                                       "DDK version 0x%lx, DDK build 0x%lx\n",
+                                psSGXFeatures->ui32DDKVersion,
+                                psSGXFeatures->ui32DDKBuild);
+
+                       return PVRSRV_OK;
+               }
+
+       case SGX_MISC_INFO_REQUEST_DRIVER_SGXREV:
+               {
+                       struct PVRSRV_KERNEL_MEM_INFO *psMemInfo =
+                           psDevInfo->psKernelSGXMiscMemInfo;
+                       struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures;
+
+                       psSGXFeatures = &((struct PVRSRV_SGX_MISCINFO_INFO *)(
+                                       psMemInfo->pvLinAddrKM))->sSGXFeatures;
+
+                       OSMemSet(psMemInfo->pvLinAddrKM, 0,
+                                sizeof(struct PVRSRV_SGX_MISCINFO_INFO));
+
+                       psSGXFeatures->ui32DDKVersion =
+                           (PVRVERSION_MAJ << 16) |
+                           (PVRVERSION_MIN << 8) | PVRVERSION_BRANCH;
+                       psSGXFeatures->ui32DDKBuild = PVRVERSION_BUILD;
+
+                       psMiscInfo->uData.sSGXFeatures = *psSGXFeatures;
+                       return PVRSRV_OK;
+               }
+
+       case SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS:
+               {
+                       struct SGXMKIF_HWPERF_CB *psHWPerfCB =
+                           psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM;
+                       unsigned ui32MatchingFlags;
+
+                       if ((psMiscInfo->uData.ui32NewHWPerfStatus &
+                            ~(PVRSRV_SGX_HWPERF_GRAPHICS_ON |
+                              PVRSRV_SGX_HWPERF_MK_EXECUTION_ON)) != 0) {
+                               return PVRSRV_ERROR_INVALID_PARAMS;
+                       }
+
+                       pvr_dev_lock();
+                       ui32MatchingFlags = readl(&psDevInfo->
+                                                psSGXHostCtl->ui32HWPerfFlags);
+                       ui32MatchingFlags &=
+                               psMiscInfo->uData.ui32NewHWPerfStatus;
+                       if ((ui32MatchingFlags & PVRSRV_SGX_HWPERF_GRAPHICS_ON)
+                           == 0UL) {
+                               psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffff;
+                       }
+                       if ((ui32MatchingFlags &
+                            PVRSRV_SGX_HWPERF_MK_EXECUTION_ON) == 0UL) {
+                               psHWPerfCB->ui32OrdinalMK_EXECUTION =
+                                   0xffffffffUL;
+                       }
+
+
+                       writel(psMiscInfo->uData.ui32NewHWPerfStatus,
+                               &psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+                       pvr_dev_unlock();
+#if defined(PDUMP)
+                       PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
+                                             "SGX ukernel HWPerf status %u\n",
+                                             readl(&psDevInfo->psSGXHostCtl->
+                                                             ui32HWPerfFlags));
+                       PDUMPMEM(NULL, psDevInfo->psKernelSGXHostCtlMemInfo,
+                                offsetof(struct SGXMKIF_HOST_CTL,
+                                         ui32HWPerfFlags),
+                                sizeof(psDevInfo->psSGXHostCtl->
+                                       ui32HWPerfFlags),
+                                PDUMP_FLAGS_CONTINUOUS,
+                                MAKEUNIQUETAG(psDevInfo->
+                                              psKernelSGXHostCtlMemInfo));
+#endif
+
+                       return PVRSRV_OK;
+               }
        case SGX_MISC_INFO_REQUEST_HWPERF_CB_ON:
                {
-                       psDevInfo->psSGXHostCtl->ui32HWPerfFlags |=
-                           PVRSRV_SGX_HWPERF_ON;
+
+                       struct SGXMKIF_HWPERF_CB *psHWPerfCB =
+                           psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM;
+                       u32 l;
+
+                       psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffffUL;
+
+                       pvr_dev_lock();;
+                       l = readl(&psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+                       l |= PVRSRV_SGX_HWPERF_GRAPHICS_ON;
+                       writel(l, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+                       pvr_dev_unlock();
+
                        return PVRSRV_OK;
                }
        case SGX_MISC_INFO_REQUEST_HWPERF_CB_OFF:
                {
-                       psDevInfo->psSGXHostCtl->ui32HWPerfFlags &=
-                           ~PVRSRV_SGX_HWPERF_ON;
+                       pvr_dev_lock();
+                       writel(0, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+                       pvr_dev_unlock();
+
                        return PVRSRV_OK;
                }
        case SGX_MISC_INFO_REQUEST_HWPERF_RETRIEVE_CB:
                {
-                       SGX_MISC_INFO_HWPERF_RETRIEVE_CB *psRetrieve =
+                       struct SGX_MISC_INFO_HWPERF_RETRIEVE_CB *psRetrieve =
                            &psMiscInfo->uData.sRetrieveCB;
-                       PVRSRV_SGX_HWPERF_CB *psHWPerfCB =
-                           (PVRSRV_SGX_HWPERF_CB *) psDevInfo->
-                           psKernelHWPerfCBMemInfo->pvLinAddrKM;
-                       IMG_UINT i = 0;
+                       struct SGXMKIF_HWPERF_CB *psHWPerfCB =
+                           psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM;
+                       unsigned i;
 
-                       for (;
+                       for (i = 0;
                             psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff
                             && i < psRetrieve->ui32ArraySize; i++) {
-                               PVRSRV_SGX_HWPERF_CBDATA *psData =
+                               struct SGXMKIF_HWPERF_CB_ENTRY *psData =
                                    &psHWPerfCB->psHWPerfCBData[psHWPerfCB->
                                                                ui32Roff];
-                               OSMemCopy(&psRetrieve->psHWPerfData[i], psData,
-                                         sizeof(PVRSRV_SGX_HWPERF_CBDATA));
+
+                               psRetrieve->psHWPerfData[i].ui32FrameNo =
+                                   psData->ui32FrameNo;
+                               psRetrieve->psHWPerfData[i].ui32Type =
+                                   (psData->ui32Type &
+                                    PVRSRV_SGX_HWPERF_TYPE_OP_MASK);
+                               psRetrieve->psHWPerfData[i].ui32StartTime =
+                                   psData->ui32Time;
+                               psRetrieve->psHWPerfData[i].ui32StartTimeWraps =
+                                   psData->ui32TimeWraps;
+                               psRetrieve->psHWPerfData[i].ui32EndTime =
+                                   psData->ui32Time;
+                               psRetrieve->psHWPerfData[i].ui32EndTimeWraps =
+                                   psData->ui32TimeWraps;
                                psRetrieve->psHWPerfData[i].ui32ClockSpeed =
                                    psDevInfo->ui32CoreClockSpeed;
                                psRetrieve->psHWPerfData[i].ui32TimeMax =
                                    psDevInfo->ui32uKernelTimerClock;
                                psHWPerfCB->ui32Roff =
-                                   (psHWPerfCB->ui32Roff +
-                                    1) & (PVRSRV_SGX_HWPERF_CBSIZE - 1);
+                                   (psHWPerfCB->ui32Roff + 1) &
+                                   (SGXMKIF_HWPERF_CB_SIZE - 1);
                        }
                        psRetrieve->ui32DataCount = i;
                        psRetrieve->ui32Time = OSClockus();
@@ -1486,49 +1518,68 @@ IMG_EXPORT
                }
        default:
                {
-
                        return PVRSRV_ERROR_INVALID_PARAMS;
                }
        }
 }
 
-IMG_EXPORT
-    PVRSRV_ERROR SGXReadDiffCountersKM(IMG_HANDLE hDevHandle,
-                                      IMG_UINT32 ui32Reg,
-                                      IMG_UINT32 * pui32Old,
-                                      IMG_BOOL bNew,
-                                      IMG_UINT32 ui32New,
-                                      IMG_UINT32 ui32NewReset,
-                                      IMG_UINT32 ui32CountersReg,
-                                      IMG_UINT32 * pui32Time,
-                                      IMG_BOOL * pbActive,
-                                      PVRSRV_SGXDEV_DIFF_INFO * psDiffs)
+
+
+static bool sgxps_active;
+static unsigned long sgxps_timeout;
+
+IMG_BOOL isSGXPerfServerActive(void)
+{
+       if (!sgxps_active)
+               return 0;
+
+       if (time_before_eq((unsigned long)OSClockus(), sgxps_timeout))
+               return 1;
+
+       sgxps_active = false;
+       PVR_DPF(DBGPRIV_WARNING, "pvr: perf server inactive\n");
+
+       return 0;
+}
+
+
+void SGXPerfServerMonitor(u32 u32TimeStamp)
 {
-       PVRSRV_ERROR eError;
-       SYS_DATA *psSysData;
-       PVRSRV_POWER_DEV *psPowerDevice;
+       if (!sgxps_active) {
+               PVR_DPF(DBGPRIV_WARNING, "pvr: perf server active\n");
+               sgxps_active = true;
+       }
+
+       /* turn off after 1 second of inactivity */
+       sgxps_timeout = u32TimeStamp + 1000000;
+}
+
+
+enum PVRSRV_ERROR SGXReadDiffCountersKM(void *hDevHandle, u32 ui32Reg,
+                                  u32 *pui32Old, IMG_BOOL bNew, u32 ui32New,
+                                  u32 ui32NewReset, u32 ui32CountersReg,
+                                  u32 *pui32Time, IMG_BOOL *pbActive,
+                                  struct PVRSRV_SGXDEV_DIFF_INFO *psDiffs)
+{
+       struct SYS_DATA *psSysData;
+       struct PVRSRV_POWER_DEV *psPowerDevice;
        IMG_BOOL bPowered = IMG_FALSE;
-       PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
-       PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
 
-       if (bNew) {
+       if (bNew)
                psDevInfo->ui32HWGroupRequested = ui32New;
-       }
        psDevInfo->ui32HWReset |= ui32NewReset;
 
-       eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE);
-       if (eError != PVRSRV_OK) {
-               return eError;
-       }
-
-       SysAcquireData(&psSysData);
+       if (SysAcquireData(&psSysData) != PVRSRV_OK)
+               return PVRSRV_ERROR_GENERIC;
 
        psPowerDevice = psSysData->psPowerDeviceList;
        while (psPowerDevice) {
                if (psPowerDevice->ui32DeviceIndex ==
                    psDeviceNode->sDevId.ui32DeviceIndex) {
                        bPowered =
-                           (IMG_BOOL) (psPowerDevice->eCurrentPowerState ==
+                           (IMG_BOOL)(psPowerDevice->eCurrentPowerState ==
                                        PVRSRV_POWER_STATE_D0);
                        break;
                }
@@ -1538,16 +1589,19 @@ IMG_EXPORT
 
        *pbActive = bPowered;
 
+       pvr_dev_lock();
+
        {
-               PVRSRV_SGXDEV_DIFF_INFO sNew, *psPrev = &psDevInfo->sDiffInfo;
-               IMG_UINT32 i;
+               struct PVRSRV_SGXDEV_DIFF_INFO sNew,
+                                              *psPrev = &psDevInfo->sDiffInfo;
+               u32 i;
 
                sNew.ui32Time[0] = OSClockus();
-
                *pui32Time = sNew.ui32Time[0];
-
                if (sNew.ui32Time[0] != psPrev->ui32Time[0] && bPowered) {
 
+                       SGXPerfServerMonitor(*pui32Time);
+
                        *pui32Old =
                            OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32Reg);
 
@@ -1558,7 +1612,6 @@ IMG_EXPORT
                        }
 
                        if (psDevInfo->ui32HWGroupRequested != *pui32Old) {
-
                                if (psDevInfo->ui32HWReset != 0) {
                                        OSWriteHWReg(psDevInfo->pvRegsBaseKM,
                                                     ui32Reg,
@@ -1567,7 +1620,6 @@ IMG_EXPORT
                                                     psDevInfo->ui32HWReset);
                                        psDevInfo->ui32HWReset = 0;
                                }
-
                                OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Reg,
                                             psDevInfo->ui32HWGroupRequested);
                        }
@@ -1575,8 +1627,8 @@ IMG_EXPORT
                        sNew.ui32Marker[0] = psDevInfo->ui32KickTACounter;
                        sNew.ui32Marker[1] = psDevInfo->ui32KickTARenderCounter;
 
-                       sNew.ui32Time[1] =
-                           psDevInfo->psSGXHostCtl->ui32TimeWraps;
+                       sNew.ui32Time[1] = readl(
+                               &psDevInfo->psSGXHostCtl->ui32TimeWraps);
 
                        for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) {
                                psDiffs->aui32Counters[i] =
@@ -1596,10 +1648,8 @@ IMG_EXPORT
 
                        *psPrev = sNew;
                } else {
-
-                       for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) {
+                       for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i)
                                psDiffs->aui32Counters[i] = 0;
-                       }
 
                        psDiffs->ui32Marker[0] = 0;
                        psDiffs->ui32Marker[1] = 0;
@@ -1609,9 +1659,48 @@ IMG_EXPORT
                }
        }
 
-       PVRSRVPowerUnlock(KERNEL_ID);
+       SGXTestActivePowerEvent(psDeviceNode);
+
+       pvr_dev_unlock();
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR SGXReadHWPerfCBKM(void *hDevHandle, u32 ui32ArraySize,
+                       struct PVRSRV_SGX_HWPERF_CB_ENTRY *psClientHWPerfEntry,
+                       u32 *pui32DataCount, u32 *pui32ClockSpeed,
+                       u32 *pui32HostTimeStamp)
+{
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+       struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
+       struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
+       struct SGXMKIF_HWPERF_CB *psHWPerfCB =
+           psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM;
+       unsigned i;
+
+       for (i = 0;
+            psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff && i < ui32ArraySize;
+            i++) {
+               struct SGXMKIF_HWPERF_CB_ENTRY *psMKPerfEntry =
+                   &psHWPerfCB->psHWPerfCBData[psHWPerfCB->ui32Roff];
+
+               psClientHWPerfEntry[i].ui32FrameNo = psMKPerfEntry->ui32FrameNo;
+               psClientHWPerfEntry[i].ui32Type = psMKPerfEntry->ui32Type;
+               psClientHWPerfEntry[i].ui32Ordinal = psMKPerfEntry->ui32Ordinal;
+               psClientHWPerfEntry[i].ui32Clocksx16 =
+                   SGXConvertTimeStamp(psDevInfo, psMKPerfEntry->ui32TimeWraps,
+                                       psMKPerfEntry->ui32Time);
+               OSMemCopy(&psClientHWPerfEntry[i].ui32Counters[0],
+                         &psMKPerfEntry->ui32Counters[0],
+                         sizeof(psMKPerfEntry->ui32Counters));
+
+               psHWPerfCB->ui32Roff =
+                   (psHWPerfCB->ui32Roff + 1) & (SGXMKIF_HWPERF_CB_SIZE - 1);
+       }
 
-       SGXTestActivePowerEvent(psDeviceNode, KERNEL_ID);
+       *pui32DataCount = i;
+       *pui32ClockSpeed = psDevInfo->ui32CoreClockSpeed;
+       *pui32HostTimeStamp = OSClockus();
 
        return eError;
 }