From 533601cf83764b422588cf1eae33408dd4a62d63 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 5 May 2010 18:21:40 +0300 Subject: [PATCH] gpu: pvr: Disable driver if SGX HW recovery fails 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 --- pvr/event.c | 5 +++++ pvr/module.c | 5 +++++ pvr/pvr_bridge_k.c | 6 ++++++ pvr/pvr_bridge_km.h | 11 +++++++++++ pvr/pvr_debug.c | 5 +++++ pvr/pvrsrv.c | 5 +++++ pvr/sgxinit.c | 24 +++++++++++++++++------- pvr/sysutils.c | 8 ++++++++ 8 files changed, 62 insertions(+), 7 deletions(-) diff --git a/pvr/event.c b/pvr/event.c index e1c2aee..5ce55aa 100644 --- a/pvr/event.c +++ b/pvr/event.c @@ -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 diff --git a/pvr/module.c b/pvr/module.c index b7565dc..64ef368 100644 --- a/pvr/module.c +++ b/pvr/module.c @@ -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) diff --git a/pvr/pvr_bridge_k.c b/pvr/pvr_bridge_k.c index a7f0cf4..f252b0a 100644 --- a/pvr/pvr_bridge_k.c +++ b/pvr/pvr_bridge_k.c @@ -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, diff --git a/pvr/pvr_bridge_km.h b/pvr/pvr_bridge_km.h index 0846f48..ea981ad 100644 --- a/pvr/pvr_bridge_km.h +++ b/pvr/pvr_bridge_km.h @@ -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); diff --git a/pvr/pvr_debug.c b/pvr/pvr_debug.c index 7cd60c1..0ac1322 100644 --- a/pvr/pvr_debug.c +++ b/pvr/pvr_debug.c @@ -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; diff --git a/pvr/pvrsrv.c b/pvr/pvrsrv.c index 53d09a9..f0c9efe 100644 --- a/pvr/pvrsrv.c +++ b/pvr/pvrsrv.c @@ -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) diff --git a/pvr/sgxinit.c b/pvr/sgxinit.c index 7b3982a..3b78d74 100644 --- a/pvr/sgxinit.c +++ b/pvr/sgxinit.c @@ -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; } diff --git a/pvr/sysutils.c b/pvr/sysutils.c index 044a8ee..a1dda0f 100644 --- a/pvr/sysutils.c +++ b/pvr/sysutils.c @@ -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; -- 2.39.5