From f7f6f734b6763eb2075b8dbec6dc14905cd3d2c7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 31 Mar 2010 23:01:36 +0300 Subject: [PATCH] gpu: pvr: make sure the device is powered on in SGX_MISRHandler 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 --- pvr/sgxinit.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pvr/sgxinit.c b/pvr/sgxinit.c index 2efaf12..26eb61e 100644 --- a/pvr/sgxinit.c +++ b/pvr/sgxinit.c @@ -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); -- 2.39.5