gpu: pvr: Disable driver if SGX HW recovery fails
authorImre Deak <imre.deak@nokia.com>
Wed, 5 May 2010 15:21:40 +0000 (18:21 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 20 May 2012 18:09:41 +0000 (21:09 +0300)
At the moment SGX HW recovery doesn't succeed always and keeps the
processes using the driver blocked. To avoid this give up after a
number of retries and disable further IOCTLs or interaction with
the HW. This would still allow a complete restart of the graphics
stack including reloading the drivers and restarting the relevant
processes.

The final fix is of course to find out why the recovery doesn't
succeed.

Signed-off-by: Imre Deak <imre.deak@nokia.com>
pvr/event.c
pvr/module.c
pvr/pvr_bridge_k.c
pvr/pvr_bridge_km.h
pvr/pvr_debug.c
pvr/pvrsrv.c
pvr/sgxinit.c
pvr/sysutils.c

index e1c2aee..5ce55aa 100644 (file)
@@ -254,6 +254,11 @@ enum PVRSRV_ERROR LinuxEventObjectWait(void *hOSEventObject, u32 ui32MSTimeout)
                    (u32) schedule_timeout((s32) ui32TimeOutJiffies);
 
                pvr_lock();
+
+               if (pvr_is_disabled()) {
+                       ui32TimeOutJiffies = 1;
+                       break;
+               }
 #if defined(CONFIG_PVR_DEBUG_EXTRA)
                psLinuxEventObject->ui32Stats++;
 #endif
index b7565dc..64ef368 100644 (file)
@@ -72,6 +72,11 @@ static int pvr_open(struct inode unref__ * inode, struct file *filp)
 
        pvr_lock();
 
+       if (pvr_is_disabled()) {
+               ret = -ENODEV;
+               goto err_unlock;
+       }
+
        pid = OSGetCurrentProcessIDKM();
 
        if (PVRSRVProcessConnect(pid) != PVRSRV_OK)
index a7f0cf4..f252b0a 100644 (file)
@@ -44,6 +44,7 @@
 DEFINE_MUTEX(gPVRSRVLock);
 int pvr_dvfs_active;
 DECLARE_WAIT_QUEUE_HEAD(pvr_dvfs_wq);
+int pvr_disabled;
 
 /*
  * The pvr_dvfs_* interface is needed to suppress a lockdep warning in
@@ -173,6 +174,11 @@ long PVRSRV_BridgeDispatchKM(struct file *filp, unsigned int cmd,
 
        pvr_lock();
 
+       if (pvr_is_disabled()) {
+               pvr_unlock();
+               return -ENODEV;
+       }
+
        if (!OSAccessOK(PVR_VERIFY_WRITE, psBridgePackageUM,
                        sizeof(struct PVRSRV_BRIDGE_PACKAGE))) {
                PVR_DPF(PVR_DBG_ERROR,
index 0846f48..ea981ad 100644 (file)
@@ -37,6 +37,7 @@
 extern int pvr_dvfs_active;
 extern struct mutex gPVRSRVLock;
 extern wait_queue_head_t pvr_dvfs_wq;
+extern int pvr_disabled;
 
 void pvr_dvfs_wait_active(void);
 
@@ -72,6 +73,16 @@ static inline int pvr_is_locked(void)
        return mutex_is_locked(&gPVRSRVLock);
 }
 
+static inline void pvr_disable(void)
+{
+       pvr_disabled = 1;
+}
+
+static inline int pvr_is_disabled(void)
+{
+       return unlikely(pvr_disabled);
+}
+
 enum PVRSRV_ERROR LinuxBridgeInit(void);
 void LinuxBridgeDeInit(void);
 
index 7cd60c1..0ac1322 100644 (file)
@@ -282,6 +282,11 @@ static int pvr_dbg_reset(void *data, u64 val)
 
        pvr_lock();
 
+       if (pvr_is_disabled()) {
+               r = -ENODEV;
+               goto exit;
+       }
+
        node = get_sgx_node();
        if (!node) {
                r =  -ENODEV;
index 53d09a9..f0c9efe 100644 (file)
@@ -788,6 +788,11 @@ void PVRSRVMISR(void *pvSysData)
 
        pvr_lock();
 
+       if (pvr_is_disabled()) {
+               pvr_unlock();
+               return;
+       }
+
        psDeviceNode = psSysData->psDeviceNodeList;
        while (psDeviceNode != NULL) {
                if (psDeviceNode->pfnDeviceMISR != NULL)
index 7b3982a..3b78d74 100644 (file)
@@ -672,6 +672,7 @@ void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode)
        struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
                                        psDevInfo->psSGXHostCtl;
        u32 l;
+       int max_retries = 10;
 
        BUG_ON(!pvr_is_locked());
 
@@ -679,7 +680,7 @@ void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode)
        l |= PVRSRV_USSE_EDM_INTERRUPT_HWR;
        writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
 
-       pr_err("HWRecoveryResetSGX: SGX Hardware Recovery triggered\n");
+       pr_err("%s: SGX Hardware Recovery triggered\n", __func__);
 
        dump_process_info(psDeviceNode);
        dump_sgx_registers(psDevInfo);
@@ -689,11 +690,19 @@ void HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode)
 
        do {
                eError = SGXInitialise(psDevInfo, IMG_TRUE);
-       } while (eError == PVRSRV_ERROR_RETRY);
-       if (eError != PVRSRV_OK)
-               PVR_DPF(PVR_DBG_ERROR,
-                        "HWRecoveryResetSGX: SGXInitialise failed (%d)",
-                        eError);
+               if (eError != PVRSRV_ERROR_RETRY)
+                       break;
+       } while (max_retries--);
+
+       if (eError != PVRSRV_OK) {
+               pr_err("%s: recovery failed (%d). Disabling the driver",
+                       __func__, eError);
+               pvr_disable();
+
+               PDUMPRESUME();
+
+               return;
+       }
 
        PDUMPRESUME();
 
@@ -719,7 +728,8 @@ static void SGXOSTimer(struct work_struct *work)
        IMG_BOOL bPoweredDown;
 
        pvr_lock();
-       if (!data->armed) {
+
+       if (!data->armed || pvr_is_disabled()) {
                pvr_unlock();
                return;
        }
index 044a8ee..a1dda0f 100644 (file)
@@ -267,8 +267,16 @@ static void sgx_lock_perf(struct work_struct *work)
            container_of(d_work, struct ENV_DATA, sPerfWork);
 
        pvr_lock();
+
+       if (pvr_is_disabled()) {
+               pvr_unlock();
+               return;
+       }
+
        load = sgx_current_load();
+
        pvr_unlock();
+
        if (load) {
                vdd1 = 500000000;
                vdd2 = 400000;