/* Global driver lock protecting all HW and SW state tracking objects. */
DEFINE_MUTEX(gPVRSRVLock);
-int pvr_dvfs_active;
-DECLARE_WAIT_QUEUE_HEAD(pvr_dvfs_wq);
+static int pvr_dvfs_active;
+static DECLARE_WAIT_QUEUE_HEAD(pvr_dvfs_wq);
int pvr_disabled;
/*
* lead to a dead lock though since at 3. we always release A, before it's
* again acquired at 4. To avoid the warning use a wait queue based approach
* so that we can unlock B before 3.
- *
- * Must be called with gPVRSRVLock held.
*/
-void pvr_dvfs_wait_active(void)
+void pvr_dvfs_lock(void)
{
- while (pvr_dvfs_active) {
+ while (cmpxchg(&pvr_dvfs_active, 0, 1)) {
DEFINE_WAIT(pvr_dvfs_wait);
prepare_to_wait(&pvr_dvfs_wq, &pvr_dvfs_wait,
TASK_UNINTERRUPTIBLE);
- mutex_unlock(&gPVRSRVLock);
- schedule();
- mutex_lock(&gPVRSRVLock);
+ if (pvr_dvfs_active)
+ schedule();
finish_wait(&pvr_dvfs_wq, &pvr_dvfs_wait);
}
}
+void pvr_dvfs_unlock(void)
+{
+ BUG_ON(!pvr_dvfs_active);
+ pvr_dvfs_active = 0;
+ wake_up(&pvr_dvfs_wq);
+}
+
#if defined(DEBUG_BRIDGE_KM)
static off_t printLinuxBridgeStats(char *buffer, size_t size, off_t off);
#endif
#include "pvr_bridge.h"
#include "perproc.h"
-extern int pvr_dvfs_active;
+extern void pvr_dvfs_lock(void);
+extern void pvr_dvfs_unlock(void);
extern struct mutex gPVRSRVLock;
-extern wait_queue_head_t pvr_dvfs_wq;
extern int pvr_disabled;
-void pvr_dvfs_wait_active(void);
-
-static inline void pvr_dvfs_lock(void)
-{
- mutex_lock(&gPVRSRVLock);
- pvr_dvfs_active = 1;
- mutex_unlock(&gPVRSRVLock);
-}
-
-static inline void pvr_dvfs_unlock(void)
-{
- mutex_lock(&gPVRSRVLock);
- pvr_dvfs_active = 0;
- wake_up(&pvr_dvfs_wq);
- mutex_unlock(&gPVRSRVLock);
-}
-
static inline void pvr_lock(void)
{
mutex_lock(&gPVRSRVLock);
- if (pvr_dvfs_active)
- pvr_dvfs_wait_active();
}
static inline void pvr_unlock(void)
PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler);
+ pvr_dvfs_lock();
l = readl(&psDevInfo->psSGXHostCtl->ui32PowerStatus);
l |= PVRSRV_USSE_EDM_POWMAN_NO_WORK;
writel(l, &psDevInfo->psSGXHostCtl->ui32PowerStatus);
+ pvr_dvfs_unlock();
eDefaultPowerState = PVRSRV_POWER_STATE_D3;
eError = PVRSRVRegisterPowerDevice(psDeviceNode->sDevId.ui32DeviceIndex,
BUG_ON(!pvr_is_locked());
+ pvr_dvfs_lock();
l = readl(&psSGXHostCtl->ui32InterruptClearFlags);
l |= PVRSRV_USSE_EDM_INTERRUPT_HWR;
writel(l, &psSGXHostCtl->ui32InterruptClearFlags);
pvr_disable();
PDUMPRESUME();
+ pvr_dvfs_unlock();
return;
}
SGXScheduleProcessQueues(psDeviceNode);
+ pvr_dvfs_unlock();
+
PVRSRVProcessQueues(IMG_TRUE);
}
if (bPoweredDown) {
ui32LockupCounter = 0;
} else {
+ pvr_dvfs_lock();
ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM,
psDevInfo->ui32EDMTaskReg0);
if (psDevInfo->ui32EDMTaskReg1 != 0)
ui32EDMTasks = ui32CurrentEDMTasks;
ui32NumResets = psDevInfo->ui32NumResets;
}
+ pvr_dvfs_unlock();
}
bLockup |= cmpxchg(&sgx_reset_forced, 1, 0);
psDevInfo->psSGXHostCtl;
u32 l;
+ pvr_dvfs_lock();
l = readl(&psSGXHostCtl->ui32HostDetectedLockups);
l++;
writel(l, &psSGXHostCtl->ui32HostDetectedLockups);
+ pvr_dvfs_unlock();
HWRecoveryResetSGX(psDeviceNode);
}
enum PVRSRV_ERROR err;
dev_idx = psDeviceNode->sDevId.ui32DeviceIndex;
+
+ pvr_dvfs_lock();
+
err = PVRSRVSetDevicePowerStateKM(dev_idx, PVRSRV_POWER_STATE_D0);
BUG_ON(err != PVRSRV_OK);
SGXScheduleProcessQueues(psDeviceNode);
SGXTestActivePowerEvent(psDeviceNode);
+
+ pvr_dvfs_unlock();
}
enum PVRSRV_ERROR SGXRegisterDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode)
return PVRSRV_ERROR_INVALID_PARAMS;
}
+ pvr_dvfs_lock();
ui32MatchingFlags = readl(&psDevInfo->
psSGXHostCtl->ui32HWPerfFlags);
ui32MatchingFlags &=
writel(psMiscInfo->uData.ui32NewHWPerfStatus,
&psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+ pvr_dvfs_unlock();
#if defined(PDUMP)
PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS,
"SGX ukernel HWPerf status %u\n",
psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffffUL;
+ pvr_dvfs_lock();;
l = readl(&psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
l |= PVRSRV_SGX_HWPERF_GRAPHICS_ON;
writel(l, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+ pvr_dvfs_unlock();
return PVRSRV_OK;
}
case SGX_MISC_INFO_REQUEST_HWPERF_CB_OFF:
{
+ pvr_dvfs_lock();
writel(0, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags);
+ pvr_dvfs_unlock();
return PVRSRV_OK;
}
*pbActive = bPowered;
+ pvr_dvfs_lock();
+
{
struct PVRSRV_SGXDEV_DIFF_INFO sNew,
*psPrev = &psDevInfo->sDiffInfo;
SGXTestActivePowerEvent(psDeviceNode);
+ pvr_dvfs_unlock();
+
return PVRSRV_OK;
}
PDUMPSUSPEND();
+ pvr_dvfs_lock();
+
eError =
PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex,
PVRSRV_POWER_STATE_D0);
} else {
PVR_DPF(PVR_DBG_ERROR, "%s: can't power on device (%d)",
__func__, eError);
+ pvr_dvfs_unlock();
return eError;
}
if (ui32CallerID != ISR_ID)
SGXTestActivePowerEvent(psDeviceNode);
+ pvr_dvfs_unlock();
+
return eError;
}
{
enum PVRSRV_ERROR eError;
+ pvr_dvfs_lock();
eError = SGXScheduleProcessQueues(psDeviceNode);
+ pvr_dvfs_unlock();
return eError;
}
#endif
u32 l;
+ pvr_dvfs_lock();
if (readl(&psSGXHostCtl->ui32PowerStatus) &
PVRSRV_USSE_EDM_POWMAN_NO_WORK) {
;
sizeof(u32), 0, hUniqueTag);
#endif
}
+ pvr_dvfs_unlock();
}
struct SGX_HW_RENDER_CONTEXT_CLEANUP {