gpu: pvr: make sure the device is powered on in SGX_MISRHandler
authorImre Deak <imre.deak@nokia.com>
Wed, 31 Mar 2010 20:01:36 +0000 (23:01 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 20 May 2012 18:09:40 +0000 (21:09 +0300)
While SGX_MISRHandler is scheduled another code path of the driver
(IOCTL, SGXOSTimer) can race with it and turn the power off before
it starts to execute.

When this happens we get the following oops backtrace:

 HWRecoveryResetSGX: SGX Hardware Recovery triggered
 Unhandled fault: external abort on non-linefetch (0x1008)
 PC is at HWRecoveryResetSGX+0x74/0x1b8 [pvrsrvkm]
 LR is at preempt_schedule+0x44/0x54
 (HWRecoveryResetSGX+0x0/0x1b8) from (SGX_MISRHandler+0x5c/0x60)
 (SGX_MISRHandler+0x0/0x60) from (PVRSRVMISR+0x44/0xa0)
  r5:bf0a29cc r4:dfbbbcc0
 (PVRSRVMISR+0x0/0xa0) from (MISRWrapper+0x14/0x18)
  r5:00000002 r4:00000000
 (MISRWrapper+0x0/0x18) from (worker_thread+0x1d0/0x2cc)
 (worker_thread+0x0/0x2cc) from (kthread+0x88/0x90)
 (kthread+0x0/0x90) from (do_exit+0x0/0x680)

Signed-off-by: Imre Deak <imre.deak@nokia.com>
pvr/sgxinit.c

index 2efaf12..26eb61e 100644 (file)
@@ -894,6 +894,23 @@ static void SGX_MISRHandler(void *pvData)
        struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl =
                        psDevInfo->psSGXHostCtl;
        u32 l1, l2;
+       int dev_idx;
+       enum PVRSRV_ERROR err;
+
+       /*
+        * Yet again we have to cope with the caller ID argument, which
+        * determines whether the power lock is properly locked or just
+        * trylock'd. If trylock fails we just get back here with an error
+        * so we need a proper lock. Actually trylock should never fail
+        * either because of the next assumption.
+        * The code afterwards depends on noone turning off the power and
+        * also the power lock to be released, so ask for the lock to be
+        * released when returning from the function.
+        */
+       dev_idx = psDeviceNode->sDevId.ui32DeviceIndex;
+       err = PVRSRVSetDevicePowerStateKM(dev_idx, PVRSRV_POWER_STATE_D0,
+                                         ISR_ID, IMG_FALSE);
+       BUG_ON(err != PVRSRV_OK);
 
        l1 = readl(&psSGXHostCtl->ui32InterruptFlags);
        l2 = readl(&psSGXHostCtl->ui32InterruptClearFlags);