X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=pvr%2Fsgxinit.c;h=210c66d20a05647a7db555ed21e2f717f978ec7e;hb=4713ddfef267393154536ce3f4edb8ae3c5d6d72;hp=33ff9b74e49555ecbb2f247a265bdcbf7a2d534d;hpb=52fbd97e3764774611ea4052f88ebe80e9c1085f;p=sgx.git diff --git a/pvr/sgxinit.c b/pvr/sgxinit.c index 33ff9b7..210c66d 100644 --- a/pvr/sgxinit.c +++ b/pvr/sgxinit.c @@ -1,32 +1,37 @@ /********************************************************************** * * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. - * + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful but, except - * as otherwise stated in writing, without any warranty; without even the - * implied warranty of merchantability or fitness for a particular purpose. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, without any warranty; without even the + * implied warranty of merchantability or fitness for a particular purpose. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * + * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * * Contact Information: * Imagination Technologies Ltd. - * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK * ******************************************************************************/ #include -#include + #include +#include +#include +#include +#include +#include #include "sgxdefs.h" #include "sgxmmu.h" @@ -38,141 +43,119 @@ #include "sgxconfig.h" #include "sysconfig.h" #include "pvr_bridge_km.h" +#include "sgx_bridge_km.h" +#include "resman.h" +#include "bridged_support.h" -#include "pdump_km.h" +#include "pvr_pdump.h" #include "ra.h" #include "mmu.h" +#include "mm.h" #include "handle.h" #include "perproc.h" #include "sgxutils.h" +#include "pvrversion.h" +#include "sgx_options.h" +#ifdef CONFIG_DEBUG_FS +#include "pvr_debugfs.h" +#endif -IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData); - -IMG_UINT32 gui32EventStatusServicesByISR = 0; - -IMG_VOID SGXReset(PVRSRV_SGXDEV_INFO * psDevInfo, IMG_UINT32 ui32PDUMPFlags); - -static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo, - IMG_BOOL bHardwareRecovery); -PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie); +static IMG_BOOL SGX_ISRHandler(void *pvData); -typedef enum _PVR_DEVICE_POWER_STATE_ { - PVR_DEVICE_POWER_STATE_ON = 0, - PVR_DEVICE_POWER_STATE_IDLE = 1, - PVR_DEVICE_POWER_STATE_OFF = 2, +static u32 gui32EventStatusServicesByISR; - PVR_DEVICE_POWER_STATE_FORCE_I32 = 0x7fffffff -} PVR_DEVICE_POWER_STATE, *PPVR_DEVICE_POWER_STATE; +static enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode); -static PVR_DEVICE_POWER_STATE MapDevicePowerState(PVR_POWER_STATE ePowerState) +static void SGXCommandComplete(struct PVRSRV_DEVICE_NODE *psDeviceNode) { - PVR_DEVICE_POWER_STATE eDevicePowerState; + BUG_ON(in_irq()); - switch (ePowerState) { - case PVRSRV_POWER_STATE_D0: - { - eDevicePowerState = PVR_DEVICE_POWER_STATE_ON; - break; - } - case PVRSRV_POWER_STATE_D3: - { - eDevicePowerState = PVR_DEVICE_POWER_STATE_OFF; - break; - } - default: - { - PVR_DPF((PVR_DBG_ERROR, - "MapDevicePowerState: Invalid state: %ld", - ePowerState)); - eDevicePowerState = PVR_DEVICE_POWER_STATE_FORCE_I32; - PVR_ASSERT(eDevicePowerState != - PVR_DEVICE_POWER_STATE_FORCE_I32); - } - } - - return eDevicePowerState; -} - -static IMG_VOID SGXCommandComplete(PVRSRV_DEVICE_NODE * psDeviceNode) -{ - SGXScheduleProcessQueues(psDeviceNode); + SGXScheduleProcessQueuesKM(psDeviceNode); } -static IMG_UINT32 DeinitDevInfo(PVRSRV_SGXDEV_INFO * psDevInfo) +static u32 DeinitDevInfo(struct PVRSRV_SGXDEV_INFO *psDevInfo) { - if (psDevInfo->psKernelCCBInfo != IMG_NULL) { - - OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO), - psDevInfo->psKernelCCBInfo, IMG_NULL); - } + if (psDevInfo->psKernelCCBInfo != NULL) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGX_CCB_INFO), + psDevInfo->psKernelCCBInfo, NULL); return PVRSRV_OK; } -static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA * psPerProc, - PVRSRV_DEVICE_NODE * psDeviceNode, - SGX_BRIDGE_INIT_INFO * psInitInfo) +static enum PVRSRV_ERROR InitDevInfo(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + struct PVRSRV_DEVICE_NODE *psDeviceNode, + struct SGX_BRIDGE_INIT_INFO *psInitInfo) { - PVRSRV_SGXDEV_INFO *psDevInfo = - (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; - PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + enum PVRSRV_ERROR eError; - PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = IMG_NULL; + struct PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = NULL; PVR_UNREFERENCED_PARAMETER(psPerProc); psDevInfo->sScripts = psInitInfo->sScripts; psDevInfo->psKernelCCBMemInfo = - (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBMemInfo; + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBMemInfo; psDevInfo->psKernelCCB = - (PVRSRV_SGX_KERNEL_CCB *) psDevInfo->psKernelCCBMemInfo-> - pvLinAddrKM; + (struct PVRSRV_SGX_KERNEL_CCB *)psDevInfo->psKernelCCBMemInfo-> + pvLinAddrKM; psDevInfo->psKernelCCBCtlMemInfo = - (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBCtlMemInfo; + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBCtlMemInfo; psDevInfo->psKernelCCBCtl = - (PVRSRV_SGX_CCB_CTL *) psDevInfo->psKernelCCBCtlMemInfo-> - pvLinAddrKM; + (struct PVRSRV_SGX_CCB_CTL *)psDevInfo->psKernelCCBCtlMemInfo-> + pvLinAddrKM; psDevInfo->psKernelCCBEventKickerMemInfo = - (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelCCBEventKickerMemInfo; + (struct PVRSRV_KERNEL_MEM_INFO *) + psInitInfo->hKernelCCBEventKickerMemInfo; psDevInfo->pui32KernelCCBEventKicker = - (IMG_UINT32 *) psDevInfo->psKernelCCBEventKickerMemInfo-> - pvLinAddrKM; + (u32 *)psDevInfo->psKernelCCBEventKickerMemInfo->pvLinAddrKM; psDevInfo->psKernelSGXHostCtlMemInfo = - (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelSGXHostCtlMemInfo; - psDevInfo->psSGXHostCtl = - (PVRSRV_SGX_HOST_CTL *) psDevInfo->psKernelSGXHostCtlMemInfo-> - pvLinAddrKM; + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo-> + hKernelSGXHostCtlMemInfo; + psDevInfo->psSGXHostCtl = (struct SGXMKIF_HOST_CTL __force __iomem *) + psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM; + + psDevInfo->psKernelSGXTA3DCtlMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo-> + hKernelSGXTA3DCtlMemInfo; + + psDevInfo->psKernelSGXMiscMemInfo = + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXMiscMemInfo; psDevInfo->psKernelHWPerfCBMemInfo = - (PVRSRV_KERNEL_MEM_INFO *) psInitInfo->hKernelHWPerfCBMemInfo; + (struct PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWPerfCBMemInfo; + psDevInfo->psKernelEDMStatusBufferMemInfo = + psInitInfo->hKernelEDMStatusBufferMemInfo; eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, - sizeof(PVRSRV_SGX_CCB_INFO), - (IMG_VOID **) & psKernelCCBInfo, 0); + sizeof(struct PVRSRV_SGX_CCB_INFO), + (void **)&psKernelCCBInfo, NULL); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, "InitDevInfo: Failed to alloc memory")); + PVR_DPF(PVR_DBG_ERROR, "InitDevInfo: Failed to alloc memory"); goto failed_allockernelccb; } - OSMemSet(psKernelCCBInfo, 0, sizeof(PVRSRV_SGX_CCB_INFO)); + OSMemSet(psKernelCCBInfo, 0, sizeof(struct PVRSRV_SGX_CCB_INFO)); psKernelCCBInfo->psCCBMemInfo = psDevInfo->psKernelCCBMemInfo; psKernelCCBInfo->psCCBCtlMemInfo = psDevInfo->psKernelCCBCtlMemInfo; psKernelCCBInfo->psCommands = psDevInfo->psKernelCCB->asCommands; psKernelCCBInfo->pui32WriteOffset = - &psDevInfo->psKernelCCBCtl->ui32WriteOffset; + &psDevInfo->psKernelCCBCtl->ui32WriteOffset; psKernelCCBInfo->pui32ReadOffset = - &psDevInfo->psKernelCCBCtl->ui32ReadOffset; + &psDevInfo->psKernelCCBCtl->ui32ReadOffset; psDevInfo->psKernelCCBInfo = psKernelCCBInfo; - psDevInfo->ui32TAKickAddress = psInitInfo->ui32TAKickAddress; + psDevInfo->ui32HostKickAddress = psInitInfo->ui32HostKickAddress; - psDevInfo->ui32VideoHandlerAddress = - psInitInfo->ui32VideoHandlerAddress; + psDevInfo->ui32GetMiscInfoAddress = psInitInfo->ui32GetMiscInfoAddress; psDevInfo->bForcePTOff = IMG_FALSE; @@ -180,13 +163,14 @@ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA * psPerProc, psDevInfo->ui32EDMTaskReg0 = psInitInfo->ui32EDMTaskReg0; psDevInfo->ui32EDMTaskReg1 = psInitInfo->ui32EDMTaskReg1; - psDevInfo->ui32ClkGateCtl = psInitInfo->ui32ClkGateCtl; - psDevInfo->ui32ClkGateCtl2 = psInitInfo->ui32ClkGateCtl2; + psDevInfo->ui32ClkGateStatusReg = psInitInfo->ui32ClkGateStatusReg; psDevInfo->ui32ClkGateStatusMask = psInitInfo->ui32ClkGateStatusMask; OSMemCopy(&psDevInfo->asSGXDevData, &psInitInfo->asInitDevData, sizeof(psDevInfo->asSGXDevData)); + psDevInfo->state_buf_ofs = psInitInfo->state_buf_ofs; + return PVRSRV_OK; failed_allockernelccb: @@ -195,321 +179,12 @@ failed_allockernelccb: return eError; } -static IMG_VOID SGXGetTimingInfo(PVRSRV_DEVICE_NODE * psDeviceNode) -{ - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - SGX_TIMING_INFORMATION sSGXTimingInfo = { 0 }; - IMG_UINT32 ui32ActivePowManSampleRate; - SGX_TIMING_INFORMATION *psSGXTimingInfo; - - psSGXTimingInfo = &sSGXTimingInfo; - SysGetSGXTimingInformation(psSGXTimingInfo); - - { - PVRSRV_ERROR eError; - IMG_UINT32 ui32OlduKernelFreq; - - if (psDevInfo->hTimer != IMG_NULL) { - ui32OlduKernelFreq = - psDevInfo->ui32CoreClockSpeed / - psDevInfo->ui32uKernelTimerClock; - if (ui32OlduKernelFreq != - psSGXTimingInfo->ui32uKernelFreq) { - eError = OSRemoveTimer(psDevInfo->hTimer); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXGetTimingInfo: Failed to remove timer")); - } - psDevInfo->hTimer = IMG_NULL; - } - } - if (psDevInfo->hTimer == IMG_NULL) { - - psDevInfo->hTimer = OSAddTimer(SGXOSTimer, psDeviceNode, - 1000 * 50 / - psSGXTimingInfo-> - ui32uKernelFreq); - if (psDevInfo->hTimer == IMG_NULL) { - PVR_DPF((PVR_DBG_ERROR, - "SGXGetTimingInfo : Failed to register timer callback function")); - } - } - - psDevInfo->psSGXHostCtl->ui32HWRecoverySampleRate = - psSGXTimingInfo->ui32uKernelFreq / - psSGXTimingInfo->ui32HWRecoveryFreq; - } - - psDevInfo->ui32CoreClockSpeed = psSGXTimingInfo->ui32CoreClockSpeed; - psDevInfo->ui32uKernelTimerClock = - psSGXTimingInfo->ui32CoreClockSpeed / - psSGXTimingInfo->ui32uKernelFreq; - - ui32ActivePowManSampleRate = - psSGXTimingInfo->ui32uKernelFreq * - psSGXTimingInfo->ui32ActivePowManLatencyms / 1000; - ui32ActivePowManSampleRate += 1; - psDevInfo->psSGXHostCtl->ui32ActivePowManSampleRate = - ui32ActivePowManSampleRate; -} - -static IMG_VOID SGXStartTimer(PVRSRV_SGXDEV_INFO * psDevInfo, - IMG_BOOL bStartOSTimer) -{ - IMG_UINT32 ui32RegVal; - - - ui32RegVal = - EUR_CR_EVENT_TIMER_ENABLE_MASK | psDevInfo->ui32uKernelTimerClock; - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_TIMER, ui32RegVal); - PDUMPREGWITHFLAGS(EUR_CR_EVENT_TIMER, ui32RegVal, - PDUMP_FLAGS_CONTINUOUS); - - if (bStartOSTimer) { - PVRSRV_ERROR eError; - eError = OSEnableTimer(psDevInfo->hTimer); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXStartTimer : Failed to enable host timer")); - } - } -} - -static PVRSRV_ERROR SGXPrePowerState(IMG_HANDLE hDevHandle, - PVR_DEVICE_POWER_STATE eNewPowerState, - PVR_DEVICE_POWER_STATE eCurrentPowerState) -{ - if ((eNewPowerState != eCurrentPowerState) && - (eNewPowerState != PVR_DEVICE_POWER_STATE_ON)) { - PVRSRV_ERROR eError; - PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; - IMG_UINT32 ui32PowManRequest, ui32PowManComplete; - - eError = OSDisableTimer(psDevInfo->hTimer); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXPrePowerState: Failed to disable timer")); - return eError; - } - - if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) { - ui32PowManRequest = - PVRSRV_USSE_EDM_POWMAN_POWEROFF_REQUEST; - ui32PowManComplete = - PVRSRV_USSE_EDM_POWMAN_POWEROFF_COMPLETE; - PDUMPCOMMENT - ("TA/3D CCB Control - SGX power off request"); - } else { - ui32PowManRequest = PVRSRV_USSE_EDM_POWMAN_IDLE_REQUEST; - ui32PowManComplete = - PVRSRV_USSE_EDM_POWMAN_IDLE_COMPLETE; - PDUMPCOMMENT("TA/3D CCB Control - SGX idle request"); - } - - psSGXHostCtl->ui32PowManFlags |= ui32PowManRequest; -#if defined(PDUMP) - PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, - offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags), - sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, - MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); -#endif - - if (PollForValueKM(&psSGXHostCtl->ui32PowManFlags, - ui32PowManComplete, - ui32PowManComplete, - MAX_HW_TIME_US / WAIT_TRY_COUNT, - WAIT_TRY_COUNT) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXPrePowerState: Wait for SGX ukernel power transition failed.")); - } - -#if defined(PDUMP) - PDUMPCOMMENT - ("TA/3D CCB Control - Wait for power event on uKernel."); - PDUMPMEMPOL(psDevInfo->psKernelSGXHostCtlMemInfo, - offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags), - ui32PowManComplete, ui32PowManComplete, - PDUMP_POLL_OPERATOR_EQUAL, IMG_FALSE, IMG_FALSE, - MAKEUNIQUETAG(psDevInfo-> - psKernelSGXHostCtlMemInfo)); -#endif - - - { - if (PollForValueKM - ((IMG_UINT32 *) psDevInfo->pvRegsBaseKM + - (EUR_CR_CLKGATESTATUS >> 2), 0, - psDevInfo->ui32ClkGateStatusMask, - MAX_HW_TIME_US / WAIT_TRY_COUNT, - WAIT_TRY_COUNT) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXPrePowerState: Wait for SGX clock gating failed.")); - } - - PDUMPCOMMENT("Wait for SGX clock gating."); - PDUMPREGPOL(EUR_CR_CLKGATESTATUS, 0, - psDevInfo->ui32ClkGateStatusMask); - } - - if (eNewPowerState == PVR_DEVICE_POWER_STATE_OFF) { - eError = SGXDeinitialise(psDevInfo); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXPrePowerState: SGXDeinitialise failed: %lu", - eError)); - return eError; - } - } - } - - return PVRSRV_OK; -} - -static PVRSRV_ERROR SGXPostPowerState(IMG_HANDLE hDevHandle, - PVR_DEVICE_POWER_STATE eNewPowerState, - PVR_DEVICE_POWER_STATE eCurrentPowerState) -{ - if ((eNewPowerState != eCurrentPowerState) && - (eCurrentPowerState != PVR_DEVICE_POWER_STATE_ON)) { - PVRSRV_ERROR eError; - PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; - - psSGXHostCtl->ui32PowManFlags = 0; - PDUMPCOMMENT("TA/3D CCB Control - Reset Power Manager flags"); -#if defined(PDUMP) - PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, - offsetof(PVRSRV_SGX_HOST_CTL, ui32PowManFlags), - sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, - MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); -#endif - - if (eCurrentPowerState == PVR_DEVICE_POWER_STATE_OFF) { - - SGXGetTimingInfo(psDeviceNode); - - eError = SGXInitialise(psDevInfo, IMG_FALSE); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXPostPowerState: SGXInitialise failed")); - return eError; - } - } - } - - return PVRSRV_OK; -} - -PVRSRV_ERROR SGXPrePowerStateExt(IMG_HANDLE hDevHandle, - PVR_POWER_STATE eNewPowerState, - PVR_POWER_STATE eCurrentPowerState) -{ - PVR_DEVICE_POWER_STATE eNewDevicePowerState = - MapDevicePowerState(eNewPowerState); - PVR_DEVICE_POWER_STATE eCurrentDevicePowerState = - MapDevicePowerState(eCurrentPowerState); - - return SGXPrePowerState(hDevHandle, eNewDevicePowerState, - eCurrentDevicePowerState); -} - -PVRSRV_ERROR SGXPostPowerStateExt(IMG_HANDLE hDevHandle, - PVR_POWER_STATE eNewPowerState, - PVR_POWER_STATE eCurrentPowerState) -{ - PVRSRV_ERROR eError; - PVR_DEVICE_POWER_STATE eNewDevicePowerState = - MapDevicePowerState(eNewPowerState); - PVR_DEVICE_POWER_STATE eCurrentDevicePowerState = - MapDevicePowerState(eCurrentPowerState); - - eError = - SGXPostPowerState(hDevHandle, eNewDevicePowerState, - eCurrentDevicePowerState); - if (eError != PVRSRV_OK) { - return eError; - } - - PVR_DPF((PVR_DBG_WARNING, - "SGXPostPowerState : SGX Power Transition from %d to %d OK", - eCurrentPowerState, eNewPowerState)); - - return eError; -} - -static PVRSRV_ERROR SGXPreClockSpeedChange(IMG_HANDLE hDevHandle, - IMG_BOOL bIdleDevice, - PVR_POWER_STATE eCurrentPowerState) +static enum PVRSRV_ERROR SGXRunScript(struct PVRSRV_SGXDEV_INFO *psDevInfo, + union SGX_INIT_COMMAND *psScript, + u32 ui32NumInitCommands) { - PVRSRV_ERROR eError; - PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - - PVR_UNREFERENCED_PARAMETER(psDevInfo); - - if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) { - if (bIdleDevice) { - - eError = - SGXPrePowerState(hDevHandle, - PVR_DEVICE_POWER_STATE_IDLE, - PVR_DEVICE_POWER_STATE_ON); - - if (eError != PVRSRV_OK) { - return eError; - } - } - } - - PVR_DPF((PVR_DBG_MESSAGE, - "SGXPreClockSpeedChange: SGX clock speed was %luHz", - psDevInfo->ui32CoreClockSpeed)); - - return PVRSRV_OK; -} - -static PVRSRV_ERROR SGXPostClockSpeedChange(IMG_HANDLE hDevHandle, - IMG_BOOL bIdleDevice, - PVR_POWER_STATE eCurrentPowerState) -{ - PVRSRV_ERROR eError = PVRSRV_OK; - PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - IMG_UINT32 ui32OldClockSpeed = psDevInfo->ui32CoreClockSpeed; - - PVR_UNREFERENCED_PARAMETER(ui32OldClockSpeed); - - if (eCurrentPowerState == PVRSRV_POWER_STATE_D0) { - SGXGetTimingInfo(psDeviceNode); - if (bIdleDevice) { - eError = - SGXPostPowerState(hDevHandle, - PVR_DEVICE_POWER_STATE_ON, - PVR_DEVICE_POWER_STATE_IDLE); - - if (eError != PVRSRV_OK) { - return eError; - } - } - SGXStartTimer(psDevInfo, IMG_TRUE); - } - - PVR_DPF((PVR_DBG_MESSAGE, - "SGXPostClockSpeedChange: SGX clock speed changed from %luHz to %luHz", - ui32OldClockSpeed, psDevInfo->ui32CoreClockSpeed)); - - return PVRSRV_OK; -} - -static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO * psDevInfo, - SGX_INIT_COMMAND * psScript, - IMG_UINT32 ui32NumInitCommands) -{ - IMG_UINT32 ui32PC; - SGX_INIT_COMMAND *psComm; + u32 ui32PC; + union SGX_INIT_COMMAND *psComm; for (ui32PC = 0, psComm = psScript; ui32PC < ui32NumInitCommands; ui32PC++, psComm++) { @@ -539,28 +214,36 @@ static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO * psDevInfo, default: { - PVR_DPF((PVR_DBG_ERROR, - "SGXRunScript: PC %d: Illegal command: %d", - ui32PC, psComm->eOp)); + PVR_DPF(PVR_DBG_ERROR, + "SGXRunScript: PC %d: Illegal command: %d", + ui32PC, psComm->eOp); return PVRSRV_ERROR_GENERIC; } } } - return PVRSRV_ERROR_GENERIC;; + return PVRSRV_ERROR_GENERIC; } -static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo, +enum PVRSRV_ERROR SGXInitialise(struct PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bHardwareRecovery) { - PVRSRV_ERROR eError; - IMG_UINT32 ui32ReadOffset, ui32WriteOffset; + enum PVRSRV_ERROR eError; - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_CLKGATECTL, - psDevInfo->ui32ClkGateCtl); - PDUMPREGWITHFLAGS(EUR_CR_CLKGATECTL, psDevInfo->ui32ClkGateCtl, - PDUMP_FLAGS_CONTINUOUS); + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX initialisation script part 1\n"); + eError = + SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart1, + SGX_MAX_INIT_COMMANDS); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXInitialise: SGXRunScript (part 1) failed (%d)", + eError); + return PVRSRV_ERROR_GENERIC; + } + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "End of SGX initialisation script part 1\n"); SGXReset(psDevInfo, PDUMP_FLAGS_CONTINUOUS); @@ -568,134 +251,111 @@ static PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO * psDevInfo, *psDevInfo->pui32KernelCCBEventKicker = 0; #if defined(PDUMP) - PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, + PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); #endif - psDevInfo->psSGXHostCtl->sTAHWPBDesc.uiAddr = 0; - psDevInfo->psSGXHostCtl->s3DHWPBDesc.uiAddr = 0; -#if defined(PDUMP) - PDUMPCOMMENT(" CCB Control - Reset HW PBDesc records"); - PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, - offsetof(PVRSRV_SGX_HOST_CTL, sTAHWPBDesc), - sizeof(IMG_DEV_VIRTADDR), PDUMP_FLAGS_CONTINUOUS, - MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); - PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, - offsetof(PVRSRV_SGX_HOST_CTL, s3DHWPBDesc), - sizeof(IMG_DEV_VIRTADDR), PDUMP_FLAGS_CONTINUOUS, - MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); -#endif - + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX initialisation script part 2\n"); eError = - SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommands, + SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart2, SGX_MAX_INIT_COMMANDS); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXInitialise: SGXRunScript failed (%d)", eError)); - return (PVRSRV_ERROR_GENERIC); + PVR_DPF(PVR_DBG_ERROR, + "SGXInitialise: SGXRunScript (part 2) failed (%d)", + eError); + return PVRSRV_ERROR_GENERIC; } + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "End of SGX initialisation script part 2\n"); - SGXStartTimer(psDevInfo, !bHardwareRecovery); + SGXStartTimer(psDevInfo, (IMG_BOOL)!bHardwareRecovery); if (bHardwareRecovery) { - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = - (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; - if (PollForValueKM - ((volatile IMG_UINT32 *)(&psSGXHostCtl-> - ui32InterruptClearFlags), 0, + if (PollForValueKM(&psSGXHostCtl->ui32InterruptClearFlags, 0, PVRSRV_USSE_EDM_INTERRUPT_HWR, MAX_HW_TIME_US / WAIT_TRY_COUNT, 1000) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXInitialise: Wait for uKernel HW Recovery failed")); + PVR_DPF(PVR_DBG_ERROR, "SGXInitialise: " + "Wait for uKernel HW Recovery failed"); + PVR_DBG_BREAK; return PVRSRV_ERROR_RETRY; } } - for (ui32ReadOffset = psDevInfo->psKernelCCBCtl->ui32ReadOffset, - ui32WriteOffset = psDevInfo->psKernelCCBCtl->ui32WriteOffset; - ui32ReadOffset != ui32WriteOffset; - ui32ReadOffset = (ui32ReadOffset + 1) & 0xFF) { - *psDevInfo->pui32KernelCCBEventKicker = - (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF; - OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_KICK, - EUR_CR_EVENT_KICK_NOW_MASK); - } + PVR_ASSERT(psDevInfo->psKernelCCBCtl->ui32ReadOffset == + psDevInfo->psKernelCCBCtl->ui32WriteOffset); return PVRSRV_OK; } -PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie) +enum PVRSRV_ERROR SGXDeinitialise(void *hDevCookie) { - PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *) hDevCookie; - PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = (struct PVRSRV_SGXDEV_INFO *) + hDevCookie; + enum PVRSRV_ERROR eError; - if (psDevInfo->pvRegsBaseKM == IMG_NULL) { + if (psDevInfo->pvRegsBaseKM == NULL) return PVRSRV_OK; - } - eError = - SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands, + eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands, SGX_MAX_DEINIT_COMMANDS); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXDeinitialise: SGXRunScript failed (%d)", eError)); - return (PVRSRV_ERROR_GENERIC); + PVR_DPF(PVR_DBG_ERROR, + "SGXDeinitialise: SGXRunScript failed (%d)", eError); + return PVRSRV_ERROR_GENERIC; } return PVRSRV_OK; } -static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode) +static enum PVRSRV_ERROR DevInitSGXPart1(void *pvDeviceNode) { - PVRSRV_SGXDEV_INFO *psDevInfo; - IMG_HANDLE hKernelDevMemContext; - IMG_DEV_PHYADDR sPDDevPAddr; - IMG_UINT32 i; - PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvDeviceNode; - DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = + struct PVRSRV_SGXDEV_INFO *psDevInfo; + void *hKernelDevMemContext; + struct IMG_DEV_PHYADDR sPDDevPAddr; + u32 i; + struct PVRSRV_DEVICE_NODE *psDeviceNode = (struct PVRSRV_DEVICE_NODE *) + pvDeviceNode; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; - IMG_HANDLE hDevInfoOSMemHandle = (IMG_HANDLE) IMG_NULL; - PVRSRV_ERROR eError; + enum PVRSRV_ERROR eError; PDUMPCOMMENT("SGX Initialisation Part 1"); PDUMPCOMMENT("SGX Core Version Information: %s", SGX_CORE_FRIENDLY_NAME); -#ifdef SGX_CORE_REV - PDUMPCOMMENT("SGX Core Revision Information: %d", SGX_CORE_REV); -#else - PDUMPCOMMENT("SGX Core Revision Information: head rtl"); -#endif - - if (OSAllocPages - (PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_HAP_MULTI_PROCESS | - PVRSRV_HAP_CACHED, sizeof(PVRSRV_SGXDEV_INFO), - (IMG_VOID **) & psDevInfo, &hDevInfoOSMemHandle) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGXPart1 : Failed to alloc memory for DevInfo")); - return (PVRSRV_ERROR_OUT_OF_MEMORY); + PDUMPCOMMENT("SGX Core Revision Information: multi rev support"); + + if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGXDEV_INFO), + (void **)&psDevInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart1 : Failed to alloc memory for DevInfo"); + return PVRSRV_ERROR_OUT_OF_MEMORY; } - OSMemSet(psDevInfo, 0, sizeof(PVRSRV_SGXDEV_INFO)); + OSMemSet(psDevInfo, 0, sizeof(struct PVRSRV_SGXDEV_INFO)); psDevInfo->eDeviceType = DEV_DEVICE_TYPE; psDevInfo->eDeviceClass = DEV_DEVICE_CLASS; - psDeviceNode->pvDevice = (IMG_PVOID) psDevInfo; - psDeviceNode->hDeviceOSMemHandle = hDevInfoOSMemHandle; + psDeviceNode->pvDevice = (void *) psDevInfo; - psDevInfo->pvDeviceMemoryHeap = (IMG_VOID *) psDeviceMemoryHeap; + psDevInfo->pvDeviceMemoryHeap = (void *) psDeviceMemoryHeap; - hKernelDevMemContext = BM_CreateContext(psDeviceNode, - &sPDDevPAddr, - IMG_NULL, IMG_NULL); + hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr, + NULL, NULL); + if (!hKernelDevMemContext) + goto err1; psDevInfo->sKernelPDDevPAddr = sPDDevPAddr; for (i = 0; i < psDeviceNode->sDevMemoryInfo.ui32HeapCount; i++) { - IMG_HANDLE hDevMemHeap; + void *hDevMemHeap; switch (psDeviceMemoryHeap[i].DevMemHeapType) { case DEVICE_MEMORY_HEAP_KERNEL: @@ -706,6 +366,9 @@ static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode) BM_CreateHeap(hKernelDevMemContext, &psDeviceMemoryHeap[i]); + if (!hDevMemHeap) + goto err2; + psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap; break; } @@ -714,165 +377,182 @@ static PVRSRV_ERROR DevInitSGXPart1(IMG_VOID * pvDeviceNode) eError = MMU_BIFResetPDAlloc(psDevInfo); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGX : Failed to alloc memory for BIF reset")); - return PVRSRV_ERROR_GENERIC; + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGX : Failed to alloc memory for BIF reset"); + goto err2; } return PVRSRV_OK; +err2: + while (i) { + int type; + + i--; + type = psDeviceMemoryHeap[i].DevMemHeapType; + if (type != DEVICE_MEMORY_HEAP_KERNEL && + type != DEVICE_MEMORY_HEAP_SHARED && + type != DEVICE_MEMORY_HEAP_SHARED_EXPORTED) + continue; + BM_DestroyHeap(psDeviceMemoryHeap[i].hDevMemHeap); + } + BM_DestroyContext(hKernelDevMemContext); +err1: + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL); + + return PVRSRV_ERROR_GENERIC; } -IMG_EXPORT - PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle, - SGX_BRIDGE_INFO_FOR_SRVINIT * - psInitInfo) +enum PVRSRV_ERROR SGXGetInfoForSrvinitKM(void *hDevHandle, + struct SGX_BRIDGE_INFO_FOR_SRVINIT *psInitInfo) { - PVRSRV_DEVICE_NODE *psDeviceNode; - PVRSRV_SGXDEV_INFO *psDevInfo; - PVRSRV_ERROR eError; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + enum PVRSRV_ERROR eError; PDUMPCOMMENT("SGXGetInfoForSrvinit"); - psDeviceNode = (PVRSRV_DEVICE_NODE *) hDevHandle; - psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; psInitInfo->sPDDevPAddr = psDevInfo->sKernelPDDevPAddr; eError = PVRSRVGetDeviceMemHeapsKM(hDevHandle, &psInitInfo->asHeapInfo[0]); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXGetInfoForSrvinit: PVRSRVGetDeviceMemHeapsKM failed (%d)", - eError)); + PVR_DPF(PVR_DBG_ERROR, "SGXGetInfoForSrvinit: " + "PVRSRVGetDeviceMemHeapsKM failed (%d)", + eError); return PVRSRV_ERROR_GENERIC; } return eError; } -IMG_EXPORT - PVRSRV_ERROR DevInitSGXPart2KM(PVRSRV_PER_PROCESS_DATA * psPerProc, - IMG_HANDLE hDevHandle, - SGX_BRIDGE_INIT_INFO * psInitInfo) +enum PVRSRV_ERROR DevInitSGXPart2KM(struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDevHandle, + struct SGX_BRIDGE_INIT_INFO *psInitInfo) { - PVRSRV_DEVICE_NODE *psDeviceNode; - PVRSRV_SGXDEV_INFO *psDevInfo; - PVRSRV_ERROR eError; - SGX_DEVICE_MAP *psSGXDeviceMap; - PVR_POWER_STATE eDefaultPowerState; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + enum PVRSRV_ERROR eError; + struct SGX_DEVICE_MAP *psSGXDeviceMap; + enum PVR_POWER_STATE eDefaultPowerState; + u32 l; PDUMPCOMMENT("SGX Initialisation Part 2"); - psDeviceNode = (PVRSRV_DEVICE_NODE *) hDevHandle; - psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevHandle; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; eError = InitDevInfo(psPerProc, psDeviceNode, psInitInfo); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGXPart2KM: Failed to load EDM program")); + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "Failed to load EDM program"); goto failed_init_dev_info; } eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, - (IMG_VOID **) & psSGXDeviceMap); + (void **) &psSGXDeviceMap); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGXPart2KM: Failed to get device memory map!")); + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "Failed to get device memory map!"); return PVRSRV_ERROR_INIT_FAILURE; } if (psSGXDeviceMap->pvRegsCpuVBase) { psDevInfo->pvRegsBaseKM = psSGXDeviceMap->pvRegsCpuVBase; } else { - psDevInfo->pvRegsBaseKM = OSMapPhysToLin(psSGXDeviceMap->sRegsCpuPBase, psSGXDeviceMap->ui32RegsSize, PVRSRV_HAP_KERNEL_ONLY | PVRSRV_HAP_UNCACHED, - IMG_NULL); + NULL); if (!psDevInfo->pvRegsBaseKM) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGXPart2KM: Failed to map in regs\n")); + PVR_DPF(PVR_DBG_ERROR, + "DevInitSGXPart2KM: Failed to map in regs\n"); return PVRSRV_ERROR_BAD_MAPPING; } } psDevInfo->ui32RegSize = psSGXDeviceMap->ui32RegsSize; psDevInfo->sRegsPhysBase = psSGXDeviceMap->sRegsSysPBase; - - psDeviceNode->pvISRData = psDeviceNode; PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler); - - - psDevInfo->psSGXHostCtl->ui32PowManFlags |= - PVRSRV_USSE_EDM_POWMAN_NO_WORK; + pvr_dev_lock(); + l = readl(&psDevInfo->psSGXHostCtl->ui32PowerStatus); + l |= PVRSRV_USSE_EDM_POWMAN_NO_WORK; + writel(l, &psDevInfo->psSGXHostCtl->ui32PowerStatus); + pvr_dev_unlock(); eDefaultPowerState = PVRSRV_POWER_STATE_D3; + eError = PVRSRVRegisterPowerDevice(psDeviceNode->sDevId.ui32DeviceIndex, SGXPrePowerStateExt, SGXPostPowerStateExt, SGXPreClockSpeedChange, SGXPostClockSpeedChange, - (IMG_HANDLE) psDeviceNode, + (void *) psDeviceNode, PVRSRV_POWER_STATE_D3, eDefaultPowerState); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevInitSGXPart2KM: failed to register device with power manager")); + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM: " + "failed to register device with power manager"); return eError; } - OSMemSet(psDevInfo->psKernelCCB, 0, sizeof(PVRSRV_SGX_KERNEL_CCB)); - OSMemSet(psDevInfo->psKernelCCBCtl, 0, sizeof(PVRSRV_SGX_CCB_CTL)); + OSMemSet(psDevInfo->psKernelCCB, 0, + sizeof(struct PVRSRV_SGX_KERNEL_CCB)); + OSMemSet(psDevInfo->psKernelCCBCtl, 0, + sizeof(struct PVRSRV_SGX_CCB_CTL)); OSMemSet(psDevInfo->pui32KernelCCBEventKicker, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker)); - PDUMPCOMMENT("Kernel CCB"); - PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBMemInfo, 0, - sizeof(PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS, + PDUMPCOMMENT("Initialise Kernel CCB"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBMemInfo, 0, + sizeof(struct PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBMemInfo)); - PDUMPCOMMENT("Kernel CCB Control"); - PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBCtlMemInfo, 0, - sizeof(PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS, + PDUMPCOMMENT("Initialise Kernel CCB Control"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBCtlMemInfo, 0, + sizeof(struct PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBCtlMemInfo)); - PDUMPCOMMENT("Kernel CCB Event Kicker"); - PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, + PDUMPCOMMENT("Initialise Kernel CCB Event Kicker"); + PDUMPMEM(NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); + psDevInfo->hTimer = SGXOSTimerInit(psDeviceNode); + if (!psDevInfo->hTimer) + PVR_DPF(PVR_DBG_ERROR, "DevInitSGXPart2KM : " + "Failed to initialize HW recovery timer"); + return PVRSRV_OK; failed_init_dev_info: return eError; } -static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode) +static enum PVRSRV_ERROR DevDeInitSGX(void *pvDeviceNode) { - PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvDeviceNode; - PVRSRV_SGXDEV_INFO *psDevInfo = - (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; - IMG_HANDLE hDevInfoOSMemHandle = psDeviceNode->hDeviceOSMemHandle; - PVRSRV_ERROR eError = PVRSRV_ERROR_INVALID_PARAMS; - IMG_UINT32 ui32Heap; - DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; - SGX_DEVICE_MAP *psSGXDeviceMap; + struct PVRSRV_DEVICE_NODE *psDeviceNode = + (struct PVRSRV_DEVICE_NODE *)pvDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + enum PVRSRV_ERROR eError; + u32 ui32Heap; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + struct SGX_DEVICE_MAP *psSGXDeviceMap; if (!psDevInfo) { - - PVR_DPF((PVR_DBG_ERROR, "DevDeInitSGX: Null DevInfo")); + PVR_DPF(PVR_DBG_ERROR, "DevDeInitSGX: Null DevInfo"); return PVRSRV_OK; } if (psDevInfo->hTimer) { - eError = OSRemoveTimer(psDevInfo->hTimer); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevDeInitSGX: Failed to remove timer")); - return eError; - } - psDevInfo->hTimer = IMG_NULL; + SGXOSTimerCancel(psDevInfo->hTimer); + SGXOSTimerDeInit(psDevInfo->hTimer); + psDevInfo->hTimer = NULL; } MMU_BIFResetPDFree(psDevInfo); @@ -881,7 +561,7 @@ static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode) psDeviceMemoryHeap = - (DEVICE_MEMORY_HEAP_INFO *) psDevInfo->pvDeviceMemoryHeap; + (struct DEVICE_MEMORY_HEAP_INFO *)psDevInfo->pvDeviceMemoryHeap; for (ui32Heap = 0; ui32Heap < psDeviceNode->sDevMemoryInfo.ui32HeapCount; ui32Heap++) { @@ -891,159 +571,211 @@ static PVRSRV_ERROR DevDeInitSGX(IMG_VOID * pvDeviceNode) case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { if (psDeviceMemoryHeap[ui32Heap].hDevMemHeap != - IMG_NULL) { + NULL) BM_DestroyHeap(psDeviceMemoryHeap [ui32Heap].hDevMemHeap); - } break; } } } - eError = - BM_DestroyContext(psDeviceNode->sDevMemoryInfo.pBMKernelContext, - IMG_NULL); - if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevDeInitSGX : Failed to destroy kernel context")); - return eError; - } + if (!pvr_put_ctx(psDeviceNode->sDevMemoryInfo.pBMKernelContext)) + pr_err("%s: kernel context still in use, can't free it", + __func__); - eError = - PVRSRVRemovePowerDevice(((PVRSRV_DEVICE_NODE *) pvDeviceNode)-> - sDevId.ui32DeviceIndex); - if (eError != PVRSRV_OK) { + eError = PVRSRVRemovePowerDevice( + ((struct PVRSRV_DEVICE_NODE *)pvDeviceNode)-> + sDevId.ui32DeviceIndex); + if (eError != PVRSRV_OK) return eError; - } eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, - (IMG_VOID **) & psSGXDeviceMap); + (void **)&psSGXDeviceMap); if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "DevDeInitSGX: Failed to get device memory map!")); + PVR_DPF(PVR_DBG_ERROR, + "DevDeInitSGX: Failed to get device memory map!"); return eError; } - if (!psSGXDeviceMap->pvRegsCpuVBase) { - - if (psDevInfo->pvRegsBaseKM != IMG_NULL) { + if (!psSGXDeviceMap->pvRegsCpuVBase) + if (psDevInfo->pvRegsBaseKM != NULL) OSUnMapPhysToLin(psDevInfo->pvRegsBaseKM, psDevInfo->ui32RegSize, PVRSRV_HAP_KERNEL_ONLY | - PVRSRV_HAP_UNCACHED, IMG_NULL); - } - } + PVRSRV_HAP_UNCACHED, + NULL); - OSFreePages(PVRSRV_OS_PAGEABLE_HEAP | PVRSRV_HAP_MULTI_PROCESS, - sizeof(PVRSRV_SGXDEV_INFO), psDevInfo, hDevInfoOSMemHandle); - psDeviceNode->pvDevice = IMG_NULL; + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(struct PVRSRV_SGXDEV_INFO), psDevInfo, NULL); - if (psDeviceMemoryHeap != IMG_NULL) { + psDeviceNode->pvDevice = NULL; + if (psDeviceMemoryHeap != NULL) OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, - sizeof(DEVICE_MEMORY_HEAP_INFO) * + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * psDeviceNode->sDevMemoryInfo.ui32HeapCount, - psDeviceMemoryHeap, 0); - } + psDeviceMemoryHeap, NULL); return PVRSRV_OK; } -static -IMG_VOID HWRecoveryResetSGX(PVRSRV_DEVICE_NODE * psDeviceNode, - IMG_UINT32 ui32Component, IMG_UINT32 ui32CallerID) +static struct PVRSRV_PER_PROCESS_DATA *find_cur_proc_data( + struct PVRSRV_DEVICE_NODE *dev) { - PVRSRV_ERROR eError; - PVRSRV_SGXDEV_INFO *psDevInfo = - (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = - (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl; + struct PVRSRV_SGXDEV_INFO *dev_info = dev->pvDevice; + u32 page_dir = readl(dev_info->pvRegsBaseKM + + EUR_CR_BIF_DIR_LIST_BASE0); + struct BM_CONTEXT *bm_ctx; + struct RESMAN_CONTEXT *res_ctx = NULL; + struct PVRSRV_PER_PROCESS_DATA *proc_data = NULL; - PVR_UNREFERENCED_PARAMETER(ui32Component); + bm_ctx = bm_find_context(dev->sDevMemoryInfo.pBMContext, page_dir); + if (bm_ctx) + res_ctx = pvr_get_resman_ctx(bm_ctx); - eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); - if (eError != PVRSRV_OK) { + if (res_ctx) + proc_data = pvr_get_proc_by_ctx(res_ctx); - PVR_DPF((PVR_DBG_WARNING, - "HWRecoveryResetSGX: Power transition in progress")); + return proc_data; +} + +static void pr_err_process_info(struct PVRSRV_PER_PROCESS_DATA *proc) +{ + struct task_struct *tsk; + int pid; + + if (!proc) return; - } - psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_HWR; + pid = proc->ui32PID; + rcu_read_lock(); + tsk = pid_task(find_vpid(pid), PIDTYPE_PID); + pr_err("PID = %d, process name = %s\n", pid, tsk->comm); + rcu_read_unlock(); +} + +static void pr_err_sgx_registers(struct PVRSRV_SGXDEV_INFO *psDevInfo) +{ + pr_err("EVENT_STATUS = 0x%08X\n" + "EVENT_STATUS2 = 0x%08X\n" + "BIF_CTRL = 0x%08X\n" + "BIF_INT_STAT = 0x%08X\n" + "BIF_MEM_REQ_STAT = 0x%08X\n" + "BIF_FAULT = 0x%08X\n" + "CLKGATECTL = 0x%08X\n", + readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_EVENT_STATUS2), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_CTRL), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_INT_STAT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_MEM_REQ_STAT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_BIF_FAULT), + readl(psDevInfo->pvRegsBaseKM + EUR_CR_CLKGATECTL)); +} + +/* Should be called with pvr_lock held */ +void +HWRecoveryResetSGX(struct PVRSRV_DEVICE_NODE *psDeviceNode, const char *caller) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + struct PVRSRV_PER_PROCESS_DATA *proc; + u32 l; + int max_retries = 10; + + BUG_ON(!pvr_is_locked()); + + l = readl(&psSGXHostCtl->ui32InterruptClearFlags); + l |= PVRSRV_USSE_EDM_INTERRUPT_HWR; + writel(l, &psSGXHostCtl->ui32InterruptClearFlags); - pr_err("HWRecoveryResetSGX: SGX Hardware Recovery triggered\n"); + pr_err("SGX Hardware Recovery triggered (from %s)\n", caller); + + proc = find_cur_proc_data(psDeviceNode); + + pr_err_process_info(proc); + pr_err_sgx_registers(psDevInfo); + +#ifdef CONFIG_DEBUG_FS + pvr_hwrec_dump(proc, psDevInfo); +#endif PDUMPSUSPEND(); do { eError = SGXInitialise(psDevInfo, IMG_TRUE); - } - while (eError == PVRSRV_ERROR_RETRY); + if (eError != PVRSRV_ERROR_RETRY) + break; + } while (max_retries--); + if (eError != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "HWRecoveryResetSGX: SGXInitialise failed (%d)", - eError)); + pr_err("%s: recovery failed (%d). Disabling the driver", + __func__, eError); + pvr_disable(); + + PDUMPRESUME(); + + return; } PDUMPRESUME(); - PVRSRVPowerUnlock(ui32CallerID); - SGXScheduleProcessQueues(psDeviceNode); - PVRSRVProcessQueues(ui32CallerID, IMG_TRUE); -} - -static struct workdata { - PVRSRV_DEVICE_NODE *psDeviceNode; - IMG_UINT32 ui32Component; - IMG_UINT32 ui32CallerID; -} gHWRecoveryParams; - -static void HWRecoveryWrapper(struct work_struct *work) -{ - HWRecoveryResetSGX(gHWRecoveryParams.psDeviceNode, - gHWRecoveryParams.ui32Component, - gHWRecoveryParams.ui32CallerID); + PVRSRVProcessQueues(IMG_TRUE); } -DECLARE_WORK(gWork, HWRecoveryWrapper); +static unsigned long sgx_reset_forced; -IMG_VOID SGXOSTimer(IMG_VOID * pvData) +static void SGXOSTimer(struct work_struct *work) { - PVRSRV_DEVICE_NODE *psDeviceNode = pvData; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - static IMG_UINT32 ui32EDMTasks = 0; - static IMG_UINT32 ui32LockupCounter = 0; - static IMG_UINT32 ui32NumResets = 0; - IMG_UINT32 ui32CurrentEDMTasks; + struct timer_work_data *data = container_of(work, + struct timer_work_data, + work.work); + struct PVRSRV_DEVICE_NODE *psDeviceNode = data->psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + static u32 ui32EDMTasks; + static u32 ui32LockupCounter; + static u32 ui32NumResets; + u32 ui32CurrentEDMTasks; IMG_BOOL bLockup = IMG_FALSE; IMG_BOOL bPoweredDown; + pvr_lock(); + + if (!data->armed || pvr_is_disabled()) { + pvr_unlock(); + return; + } + psDevInfo->ui32TimeStamp++; - bPoweredDown = (IMG_BOOL) ! SGXIsDevicePowered(psDeviceNode); +#if defined(NO_HARDWARE) + bPoweredDown = IMG_TRUE; +#else + bPoweredDown = (IMG_BOOL) !SGXIsDevicePowered(psDeviceNode); +#endif if (bPoweredDown) { ui32LockupCounter = 0; } else { - - ui32CurrentEDMTasks = - OSReadHWReg(psDevInfo->pvRegsBaseKM, - psDevInfo->ui32EDMTaskReg0); - if (psDevInfo->ui32EDMTaskReg1 != 0) { + pvr_dev_lock(); + ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM, + psDevInfo->ui32EDMTaskReg0); + if (psDevInfo->ui32EDMTaskReg1 != 0) ui32CurrentEDMTasks ^= OSReadHWReg(psDevInfo->pvRegsBaseKM, psDevInfo->ui32EDMTaskReg1); - } if ((ui32CurrentEDMTasks == ui32EDMTasks) && (psDevInfo->ui32NumResets == ui32NumResets)) { ui32LockupCounter++; if (ui32LockupCounter == 3) { ui32LockupCounter = 0; - PVR_DPF((PVR_DBG_ERROR, - "SGXOSTimer() detected SGX lockup (0x%x tasks)", - ui32EDMTasks)); + PVR_DPF(PVR_DBG_ERROR, "SGXOSTimer() " + "detected SGX lockup (0x%x tasks)", + ui32EDMTasks); bLockup = IMG_TRUE; } @@ -1052,58 +784,120 @@ IMG_VOID SGXOSTimer(IMG_VOID * pvData) ui32EDMTasks = ui32CurrentEDMTasks; ui32NumResets = psDevInfo->ui32NumResets; } + pvr_dev_unlock(); } + bLockup |= cmpxchg(&sgx_reset_forced, 1, 0); + if (bLockup) { - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = - (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl; - - psSGXHostCtl->ui32HostDetectedLockups++; - - /* - * schedule HWRecoveryResetSGX from a work - * in the shared queue - */ - gHWRecoveryParams.psDeviceNode = psDeviceNode; - gHWRecoveryParams.ui32Component = 0; - gHWRecoveryParams.ui32CallerID = TIMER_ID; - schedule_work(&gWork); + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l; + + pvr_dev_lock(); + l = readl(&psSGXHostCtl->ui32HostDetectedLockups); + l++; + writel(l, &psSGXHostCtl->ui32HostDetectedLockups); + + HWRecoveryResetSGX(psDeviceNode, __func__); + pvr_dev_unlock(); } + + queue_delayed_work(data->work_queue, &data->work, + msecs_to_jiffies(data->interval)); + + pvr_unlock(); } +struct timer_work_data * +SGXOSTimerInit(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct timer_work_data *data; + + data = kzalloc(sizeof(struct timer_work_data), GFP_KERNEL); + if (!data) + return NULL; + + data->work_queue = create_workqueue("SGXOSTimer"); + if (!data->work_queue) { + kfree(data); + return NULL; + } + + data->interval = 150; + data->psDeviceNode = psDeviceNode; + INIT_DELAYED_WORK(&data->work, SGXOSTimer); + + return data; +} -IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData) +void SGXOSTimerDeInit(struct timer_work_data *data) +{ + data->armed = false; + destroy_workqueue(data->work_queue); + kfree(data); +} + +enum PVRSRV_ERROR SGXOSTimerEnable(struct timer_work_data *data) +{ + if (!data) + return PVRSRV_ERROR_GENERIC; + + if (queue_delayed_work(data->work_queue, &data->work, + msecs_to_jiffies(data->interval))) { + data->armed = true; + return PVRSRV_OK; + } + + return PVRSRV_ERROR_GENERIC; +} + +enum PVRSRV_ERROR SGXOSTimerCancel(struct timer_work_data *data) +{ + if (!data) + return PVRSRV_ERROR_GENERIC; + + data->armed = false; + cancel_delayed_work(&data->work); + + return PVRSRV_OK; +} + +int sgx_force_reset(void) +{ + return !cmpxchg(&sgx_reset_forced, 0, 1); +} + +static IMG_BOOL SGX_ISRHandler(void *pvData) { IMG_BOOL bInterruptProcessed = IMG_FALSE; { - IMG_UINT32 ui32EventStatus, ui32EventEnable; - IMG_UINT32 ui32EventClear = 0; - PVRSRV_DEVICE_NODE *psDeviceNode; - PVRSRV_SGXDEV_INFO *psDevInfo; - - if (pvData == IMG_NULL) { - PVR_DPF((PVR_DBG_ERROR, - "SGX_ISRHandler: Invalid params\n")); + u32 ui32EventStatus, ui32EventEnable; + u32 ui32EventClear = 0; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct PVRSRV_SGXDEV_INFO *psDevInfo; + + if (pvData == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "SGX_ISRHandler: Invalid params\n"); return bInterruptProcessed; } - psDeviceNode = (PVRSRV_DEVICE_NODE *) pvData; - psDevInfo = (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)pvData; + psDevInfo = (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; ui32EventStatus = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); - ui32EventEnable = - OSReadHWReg(psDevInfo->pvRegsBaseKM, - EUR_CR_EVENT_HOST_ENABLE); + ui32EventEnable = OSReadHWReg(psDevInfo->pvRegsBaseKM, + EUR_CR_EVENT_HOST_ENABLE); gui32EventStatusServicesByISR = ui32EventStatus; ui32EventStatus &= ui32EventEnable; - if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) { + if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_MASK; - } if (ui32EventClear) { bInterruptProcessed = IMG_TRUE; @@ -1119,26 +913,44 @@ IMG_BOOL SGX_ISRHandler(IMG_VOID * pvData) return bInterruptProcessed; } -IMG_VOID SGX_MISRHandler(IMG_VOID * pvData) +static void SGX_MISRHandler(void *pvData) { - PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *) pvData; - PVRSRV_SGXDEV_INFO *psDevInfo = - (PVRSRV_SGXDEV_INFO *) psDeviceNode->pvDevice; - PVRSRV_SGX_HOST_CTL *psSGXHostCtl = - (PVRSRV_SGX_HOST_CTL *) psDevInfo->psSGXHostCtl; - - if ((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR) - && !(psSGXHostCtl-> - ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR)) { - HWRecoveryResetSGX(psDeviceNode, 0, ISR_ID); - } - SGXTestActivePowerEvent(psDeviceNode, ISR_ID); + struct PVRSRV_DEVICE_NODE *psDeviceNode = + (struct PVRSRV_DEVICE_NODE *)pvData; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; + struct SGXMKIF_HOST_CTL __iomem *psSGXHostCtl = + psDevInfo->psSGXHostCtl; + u32 l1, l2; + int dev_idx; + enum PVRSRV_ERROR err; + + dev_idx = psDeviceNode->sDevId.ui32DeviceIndex; + + pvr_dev_lock(); + + err = PVRSRVSetDevicePowerStateKM(dev_idx, PVRSRV_POWER_STATE_D0); + BUG_ON(err != PVRSRV_OK); + + l1 = readl(&psSGXHostCtl->ui32InterruptFlags); + l2 = readl(&psSGXHostCtl->ui32InterruptClearFlags); + + if ((l1 & PVRSRV_USSE_EDM_INTERRUPT_HWR) && + !(l2 & PVRSRV_USSE_EDM_INTERRUPT_HWR)) + HWRecoveryResetSGX(psDeviceNode, __func__); + + if (psDeviceNode->bReProcessDeviceCommandComplete) + SGXScheduleProcessQueues(psDeviceNode); + + SGXTestActivePowerEvent(psDeviceNode); + + pvr_dev_unlock(); } -PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) +enum PVRSRV_ERROR SGXRegisterDevice(struct PVRSRV_DEVICE_NODE *psDeviceNode) { - DEVICE_MEMORY_INFO *psDevMemoryInfo; - DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + struct DEVICE_MEMORY_INFO *psDevMemoryInfo; + struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; psDeviceNode->sDevId.eDeviceType = DEV_DEVICE_TYPE; psDeviceNode->sDevId.eDeviceClass = DEV_DEVICE_CLASS; @@ -1146,6 +958,8 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceNode->pfnInitDevice = DevInitSGXPart1; psDeviceNode->pfnDeInitDevice = DevDeInitSGX; + psDeviceNode->pfnInitDeviceCompatCheck = SGXDevInitCompatCheck; + psDeviceNode->pfnMMUInitialise = MMU_Initialise; psDeviceNode->pfnMMUFinalise = MMU_Finalise; psDeviceNode->pfnMMUInsertHeap = MMU_InsertHeap; @@ -1160,7 +974,6 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceNode->pfnMMUGetPhysPageAddr = MMU_GetPhysPageAddr; psDeviceNode->pfnMMUGetPDDevPAddr = MMU_GetPDDevPAddr; - psDeviceNode->pfnDeviceISR = SGX_ISRHandler; psDeviceNode->pfnDeviceMISR = SGX_MISRHandler; @@ -1168,27 +981,27 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; - psDevMemoryInfo->ui32AddressSpaceSizeLog2 = SGX_ADDRESS_SPACE_SIZE; + psDevMemoryInfo->ui32AddressSpaceSizeLog2 = + SGX_FEATURE_ADDRESS_SPACE_SIZE; psDevMemoryInfo->ui32Flags = 0; - psDevMemoryInfo->ui32HeapCount = SGX_MAX_HEAP_ID; - psDevMemoryInfo->ui32SyncHeapID = SGX_SYNCINFO_HEAP_ID; - psDevMemoryInfo->ui32MappingHeapID = SGX_GENERAL_MAPPING_HEAP_ID; + psDevMemoryInfo->ui32MappingHeapID = SGX_GENERAL_HEAP_ID; if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, - sizeof(DEVICE_MEMORY_HEAP_INFO) * + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * psDevMemoryInfo->ui32HeapCount, - (IMG_VOID **) & psDevMemoryInfo->psDeviceMemoryHeap, - 0) != PVRSRV_OK) { - PVR_DPF((PVR_DBG_ERROR, - "SGXRegisterDevice : Failed to alloc memory for DEVICE_MEMORY_HEAP_INFO")); - return (PVRSRV_ERROR_OUT_OF_MEMORY); + (void **) &psDevMemoryInfo->psDeviceMemoryHeap, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "SGXRegisterDevice : " + "Failed to alloc memory for " + "struct DEVICE_MEMORY_HEAP_INFO"); + return PVRSRV_ERROR_OUT_OF_MEMORY; } OSMemSet(psDevMemoryInfo->psDeviceMemoryHeap, 0, - sizeof(DEVICE_MEMORY_HEAP_INFO) * + sizeof(struct DEVICE_MEMORY_HEAP_INFO) * psDevMemoryInfo->ui32HeapCount); psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; @@ -1207,6 +1020,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_GENERAL_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID); psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1221,6 +1037,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_TADATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID); psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1228,43 +1047,34 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32HeapSize = SGX_KERNEL_CODE_HEAP_SIZE; psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32Attribs = - PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION - | PVRSRV_HAP_MULTI_PROCESS; - psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszName = "Kernel"; - psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszBSName = "Kernel BS"; + PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | + PVRSRV_HAP_MULTI_PROCESS; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszName = "Kernel Code"; + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].pszBSName = + "Kernel Code BS"; psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32HeapID = - HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_VIDEO_CODE_HEAP_ID); - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].sDevVAddrBase.uiAddr = - SGX_VIDEO_CODE_HEAP_BASE; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32HeapSize = - SGX_VIDEO_CODE_HEAP_SIZE; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].ui32Attribs = - PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | - PVRSRV_HAP_KERNEL_ONLY; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].pszName = "Video"; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].pszBSName = "Video BS"; - psDeviceMemoryHeap[SGX_VIDEO_CODE_HEAP_ID].DevMemHeapType = - DEVICE_MEMORY_HEAP_SHARED; - - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32HeapID = - HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_VIDEO_DATA_HEAP_ID); - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].sDevVAddrBase.uiAddr = - SGX_KERNEL_VIDEO_DATA_HEAP_BASE; - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32HeapSize = - SGX_KERNEL_VIDEO_DATA_HEAP_SIZE; - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].ui32Attribs = + psDeviceMemoryHeap[SGX_KERNEL_CODE_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapID = + HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID); + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].sDevVAddrBase.uiAddr = + SGX_KERNEL_DATA_HEAP_BASE; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32HeapSize = + SGX_KERNEL_DATA_HEAP_SIZE; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].pszName = - "KernelVideoData"; - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].pszBSName = - "KernelVideoData BS"; - psDeviceMemoryHeap[SGX_KERNEL_VIDEO_DATA_HEAP_ID].DevMemHeapType = + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszName = "KernelData"; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].pszBSName = "KernelData BS"; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; + psDeviceMemoryHeap[SGX_KERNEL_DATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID); psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1280,6 +1090,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_PIXELSHADER_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID); psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1296,6 +1109,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_VERTEXSHADER_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID); psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1312,6 +1128,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_PDSPIXEL_CODEDATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID); psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].sDevVAddrBase. @@ -1328,6 +1147,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; + psDeviceMemoryHeap[SGX_PDSVERTEX_CODEDATA_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID); psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1344,6 +1166,9 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; + psDeviceMemoryHeap[SGX_SYNCINFO_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32HeapID = HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_3DPARAMETERS_HEAP_ID); psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].sDevVAddrBase.uiAddr = @@ -1359,71 +1184,24 @@ PVRSRV_ERROR SGXRegisterDevice(PVRSRV_DEVICE_NODE * psDeviceNode) psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32HeapID = - HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_MAPPING_HEAP_ID); - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr = - SGX_GENERAL_MAPPING_HEAP_BASE; - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32HeapSize = - SGX_GENERAL_MAPPING_HEAP_SIZE; - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].ui32Attribs = - PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS; - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].pszName = - "GeneralMapping"; - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].pszBSName = - "GeneralMapping BS"; - - psDeviceMemoryHeap[SGX_GENERAL_MAPPING_HEAP_ID].DevMemHeapType = - DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32HeapID = - HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_FB_MAPPING_HEAP_ID); - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr = - SGX_FB_MAPPING_HEAP_BASE; - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32HeapSize = - SGX_FB_MAPPING_HEAP_SIZE; - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].ui32Attribs = - PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS; - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].pszName = - "FramebufferMapping"; - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].pszBSName = - "FramebufferMapping BS"; - - psDeviceMemoryHeap[SGX_FB_MAPPING_HEAP_ID].DevMemHeapType = - DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32HeapID = - HEAP_ID(PVRSRV_DEVICE_TYPE_SGX, SGX_ALT_MAPPING_HEAP_ID); - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].sDevVAddrBase.uiAddr = - SGX_ALT_MAPPING_HEAP_BASE; - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32HeapSize = - SGX_ALT_MAPPING_HEAP_SIZE; - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].ui32Attribs = - PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_MULTI_PROCESS; - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].pszName = "AltMapping"; - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].pszBSName = "AltMapping BS"; - - psDeviceMemoryHeap[SGX_ALT_MAPPING_HEAP_ID].DevMemHeapType = - DEVICE_MEMORY_HEAP_SHARED_EXPORTED; - + psDeviceMemoryHeap[SGX_3DPARAMETERS_HEAP_ID].ui32DataPageSize = + SGX_MMU_PAGE_SIZE; return PVRSRV_OK; } -IMG_EXPORT - PVRSRV_ERROR SGXGetClientInfoKM(IMG_HANDLE hDevCookie, - PVR3DIF4_CLIENT_INFO * psClientInfo) +enum PVRSRV_ERROR SGXGetClientInfoKM(void *hDevCookie, + struct SGX_CLIENT_INFO *psClientInfo) { - PVRSRV_SGXDEV_INFO *psDevInfo = - (PVRSRV_SGXDEV_INFO *) ((PVRSRV_DEVICE_NODE *) hDevCookie)-> - pvDevice; + struct PVRSRV_SGXDEV_INFO *psDevInfo = + (struct PVRSRV_SGXDEV_INFO *) + ((struct PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; psDevInfo->ui32ClientRefCount++; #ifdef PDUMP - if (psDevInfo->ui32ClientRefCount == 1) { + if (psDevInfo->ui32ClientRefCount == 1) psDevInfo->psKernelCCBInfo->ui32CCBDumpWOff = 0; - } #endif - psClientInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); OSMemCopy(&psClientInfo->asDevData, &psDevInfo->asSGXDevData, @@ -1432,9 +1210,142 @@ IMG_EXPORT return PVRSRV_OK; } -IMG_EXPORT - PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO * psDevInfo, - SGX_MISC_INFO * psMiscInfo) +enum PVRSRV_ERROR SGXDevInitCompatCheck(struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + struct PVRSRV_SGXDEV_INFO *psDevInfo; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo; + enum PVRSRV_ERROR eError; +#if !defined(NO_HARDWARE) + u32 opts; + u32 opt_mismatch; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; +#endif + + if (psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_SGX) { + PVR_DPF(PVR_DBG_ERROR, + "SGXDevInitCompatCheck: Device not of type SGX"); + eError = PVRSRV_ERROR_INVALID_PARAMS; + goto exit; + } + psDevInfo = psDeviceNode->pvDevice; + psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; + +#if !defined(NO_HARDWARE) + + eError = SGXGetBuildInfoKM(psDevInfo, psDeviceNode); + if (eError != PVRSRV_OK) { + pr_err("pvr: unable to validate device DDK version\n"); + goto exit; + } + psSGXFeatures = + &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo->pvLinAddrKM))-> + sSGXFeatures; + if ((psSGXFeatures->ui32DDKVersion != + ((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) | + PVRVERSION_BRANCH)) || + (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD)) { + pr_err("pvr: incompatible driver DDK revision (%d)" + "/device DDK revision (%d).\n", + PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild); + eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH; + goto exit; + } else { + PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: " + "driver DDK (%ld) and device DDK (%ld) match", + PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild); + } + + opts = psSGXFeatures->ui32BuildOptions; + opt_mismatch = opts ^ SGX_BUILD_OPTIONS; + /* we support the ABIs both with and without EDM tracing option */ + opt_mismatch &= ~PVRSRV_USSE_EDM_STATUS_DEBUG_SET_OFFSET; + if (opt_mismatch) { + if (SGX_BUILD_OPTIONS & opt_mismatch) + pr_err("pvr: mismatch in driver and microkernel build " + "options; extra options present in driver: " + "(0x%x)", SGX_BUILD_OPTIONS & opt_mismatch); + + if (opts & opt_mismatch) + pr_err("pvr: Mismatch in driver and microkernel build " + "options; extra options present in " + "microkernel: (0x%x)", opts & opt_mismatch); + eError = PVRSRV_ERROR_BUILD_MISMATCH; + goto exit; + } else { + PVR_DPF(PVR_DBG_WARNING, "(Success) SGXInit: " + "Driver and microkernel build options match."); + } + +#endif + eError = PVRSRV_OK; +exit: + return eError; +} + +static +enum PVRSRV_ERROR SGXGetBuildInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode) +{ + enum PVRSRV_ERROR eError; + struct SGXMKIF_COMMAND sCommandData; + struct PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + + if (!psMemInfo->pvLinAddrKM) { + PVR_DPF(PVR_DBG_ERROR, "SGXGetMiscInfoKM: Invalid address."); + return PVRSRV_ERROR_INVALID_PARAMS; + } + psSGXMiscInfoInt = psMemInfo->pvLinAddrKM; + psSGXMiscInfoInt->ui32MiscInfoFlags &= ~PVRSRV_USSE_MISCINFO_READY; + psSGXFeatures = &psSGXMiscInfoInt->sSGXFeatures; + + OSMemSet(psMemInfo->pvLinAddrKM, 0, + sizeof(struct PVRSRV_SGX_MISCINFO_INFO)); + + sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr; + + OSMemSet(psSGXFeatures, 0, sizeof(*psSGXFeatures)); + + mb(); + + eError = SGXScheduleCCBCommandKM(psDeviceNode, + SGXMKIF_COMMAND_REQUEST_SGXMISCINFO, + &sCommandData, KERNEL_ID, 0); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "SGXGetMiscInfoKM: SGXScheduleCCBCommandKM failed."); + return eError; + } + +#if !defined(NO_HARDWARE) + { + IMG_BOOL bTimeout = IMG_TRUE; + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if ((psSGXMiscInfoInt-> + ui32MiscInfoFlags & PVRSRV_USSE_MISCINFO_READY) != + 0) { + bTimeout = IMG_FALSE; + break; + } + } + END_LOOP_UNTIL_TIMEOUT(); + + if (bTimeout) + return PVRSRV_ERROR_TIMEOUT; + } +#endif + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXGetMiscInfoKM(struct PVRSRV_SGXDEV_INFO *psDevInfo, + struct SGX_MISC_INFO *psMiscInfo, + struct PVRSRV_DEVICE_NODE *psDeviceNode) { switch (psMiscInfo->eRequest) { case SGX_MISC_INFO_REQUEST_CLOCKSPEED: @@ -1443,42 +1354,163 @@ IMG_EXPORT psDevInfo->ui32CoreClockSpeed; return PVRSRV_OK; } + + case SGX_MISC_INFO_REQUEST_SGXREV: + { + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + + SGXGetBuildInfoKM(psDevInfo, psDeviceNode); + psSGXFeatures = + &((struct PVRSRV_SGX_MISCINFO_INFO *)(psMemInfo-> + pvLinAddrKM))->sSGXFeatures; + + psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; + + PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: " + "Core 0x%lx, sw ID 0x%lx, " + "sw Rev 0x%lx\n", + psSGXFeatures->ui32CoreRev, + psSGXFeatures->ui32CoreIdSW, + psSGXFeatures->ui32CoreRevSW); + PVR_DPF(PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: " + "DDK version 0x%lx, DDK build 0x%lx\n", + psSGXFeatures->ui32DDKVersion, + psSGXFeatures->ui32DDKBuild); + + return PVRSRV_OK; + } + + case SGX_MISC_INFO_REQUEST_DRIVER_SGXREV: + { + struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = + psDevInfo->psKernelSGXMiscMemInfo; + struct PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; + + psSGXFeatures = &((struct PVRSRV_SGX_MISCINFO_INFO *)( + psMemInfo->pvLinAddrKM))->sSGXFeatures; + + OSMemSet(psMemInfo->pvLinAddrKM, 0, + sizeof(struct PVRSRV_SGX_MISCINFO_INFO)); + + psSGXFeatures->ui32DDKVersion = + (PVRVERSION_MAJ << 16) | + (PVRVERSION_MIN << 8) | PVRVERSION_BRANCH; + psSGXFeatures->ui32DDKBuild = PVRVERSION_BUILD; + + psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; + return PVRSRV_OK; + } + + case SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS: + { + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned ui32MatchingFlags; + + if ((psMiscInfo->uData.ui32NewHWPerfStatus & + ~(PVRSRV_SGX_HWPERF_GRAPHICS_ON | + PVRSRV_SGX_HWPERF_MK_EXECUTION_ON)) != 0) { + return PVRSRV_ERROR_INVALID_PARAMS; + } + + pvr_dev_lock(); + ui32MatchingFlags = readl(&psDevInfo-> + psSGXHostCtl->ui32HWPerfFlags); + ui32MatchingFlags &= + psMiscInfo->uData.ui32NewHWPerfStatus; + if ((ui32MatchingFlags & PVRSRV_SGX_HWPERF_GRAPHICS_ON) + == 0UL) { + psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffff; + } + if ((ui32MatchingFlags & + PVRSRV_SGX_HWPERF_MK_EXECUTION_ON) == 0UL) { + psHWPerfCB->ui32OrdinalMK_EXECUTION = + 0xffffffffUL; + } + + + writel(psMiscInfo->uData.ui32NewHWPerfStatus, + &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); +#if defined(PDUMP) + PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, + "SGX ukernel HWPerf status %u\n", + readl(&psDevInfo->psSGXHostCtl-> + ui32HWPerfFlags)); + PDUMPMEM(NULL, psDevInfo->psKernelSGXHostCtlMemInfo, + offsetof(struct SGXMKIF_HOST_CTL, + ui32HWPerfFlags), + sizeof(psDevInfo->psSGXHostCtl-> + ui32HWPerfFlags), + PDUMP_FLAGS_CONTINUOUS, + MAKEUNIQUETAG(psDevInfo-> + psKernelSGXHostCtlMemInfo)); +#endif + + return PVRSRV_OK; + } case SGX_MISC_INFO_REQUEST_HWPERF_CB_ON: { - psDevInfo->psSGXHostCtl->ui32HWPerfFlags |= - PVRSRV_SGX_HWPERF_ON; + + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + u32 l; + + psHWPerfCB->ui32OrdinalGRAPHICS = 0xffffffffUL; + + pvr_dev_lock();; + l = readl(&psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + l |= PVRSRV_SGX_HWPERF_GRAPHICS_ON; + writel(l, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); + return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_HWPERF_CB_OFF: { - psDevInfo->psSGXHostCtl->ui32HWPerfFlags &= - ~PVRSRV_SGX_HWPERF_ON; + pvr_dev_lock(); + writel(0, &psDevInfo->psSGXHostCtl->ui32HWPerfFlags); + pvr_dev_unlock(); + return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_HWPERF_RETRIEVE_CB: { - SGX_MISC_INFO_HWPERF_RETRIEVE_CB *psRetrieve = + struct SGX_MISC_INFO_HWPERF_RETRIEVE_CB *psRetrieve = &psMiscInfo->uData.sRetrieveCB; - PVRSRV_SGX_HWPERF_CB *psHWPerfCB = - (PVRSRV_SGX_HWPERF_CB *) psDevInfo-> - psKernelHWPerfCBMemInfo->pvLinAddrKM; - IMG_UINT i = 0; + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned i; - for (; + for (i = 0; psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff && i < psRetrieve->ui32ArraySize; i++) { - PVRSRV_SGX_HWPERF_CBDATA *psData = + struct SGXMKIF_HWPERF_CB_ENTRY *psData = &psHWPerfCB->psHWPerfCBData[psHWPerfCB-> ui32Roff]; - OSMemCopy(&psRetrieve->psHWPerfData[i], psData, - sizeof(PVRSRV_SGX_HWPERF_CBDATA)); + + psRetrieve->psHWPerfData[i].ui32FrameNo = + psData->ui32FrameNo; + psRetrieve->psHWPerfData[i].ui32Type = + (psData->ui32Type & + PVRSRV_SGX_HWPERF_TYPE_OP_MASK); + psRetrieve->psHWPerfData[i].ui32StartTime = + psData->ui32Time; + psRetrieve->psHWPerfData[i].ui32StartTimeWraps = + psData->ui32TimeWraps; + psRetrieve->psHWPerfData[i].ui32EndTime = + psData->ui32Time; + psRetrieve->psHWPerfData[i].ui32EndTimeWraps = + psData->ui32TimeWraps; psRetrieve->psHWPerfData[i].ui32ClockSpeed = psDevInfo->ui32CoreClockSpeed; psRetrieve->psHWPerfData[i].ui32TimeMax = psDevInfo->ui32uKernelTimerClock; psHWPerfCB->ui32Roff = - (psHWPerfCB->ui32Roff + - 1) & (PVRSRV_SGX_HWPERF_CBSIZE - 1); + (psHWPerfCB->ui32Roff + 1) & + (SGXMKIF_HWPERF_CB_SIZE - 1); } psRetrieve->ui32DataCount = i; psRetrieve->ui32Time = OSClockus(); @@ -1486,49 +1518,68 @@ IMG_EXPORT } default: { - return PVRSRV_ERROR_INVALID_PARAMS; } } } -IMG_EXPORT - PVRSRV_ERROR SGXReadDiffCountersKM(IMG_HANDLE hDevHandle, - IMG_UINT32 ui32Reg, - IMG_UINT32 * pui32Old, - IMG_BOOL bNew, - IMG_UINT32 ui32New, - IMG_UINT32 ui32NewReset, - IMG_UINT32 ui32CountersReg, - IMG_UINT32 * pui32Time, - IMG_BOOL * pbActive, - PVRSRV_SGXDEV_DIFF_INFO * psDiffs) + + +static bool sgxps_active; +static unsigned long sgxps_timeout; + +IMG_BOOL isSGXPerfServerActive(void) +{ + if (!sgxps_active) + return 0; + + if (time_before_eq((unsigned long)OSClockus(), sgxps_timeout)) + return 1; + + sgxps_active = false; + PVR_DPF(DBGPRIV_WARNING, "pvr: perf server inactive\n"); + + return 0; +} + + +void SGXPerfServerMonitor(u32 u32TimeStamp) { - PVRSRV_ERROR eError; - SYS_DATA *psSysData; - PVRSRV_POWER_DEV *psPowerDevice; + if (!sgxps_active) { + PVR_DPF(DBGPRIV_WARNING, "pvr: perf server active\n"); + sgxps_active = true; + } + + /* turn off after 1 second of inactivity */ + sgxps_timeout = u32TimeStamp + 1000000; +} + + +enum PVRSRV_ERROR SGXReadDiffCountersKM(void *hDevHandle, u32 ui32Reg, + u32 *pui32Old, IMG_BOOL bNew, u32 ui32New, + u32 ui32NewReset, u32 ui32CountersReg, + u32 *pui32Time, IMG_BOOL *pbActive, + struct PVRSRV_SGXDEV_DIFF_INFO *psDiffs) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_POWER_DEV *psPowerDevice; IMG_BOOL bPowered = IMG_FALSE; - PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; - PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; - if (bNew) { + if (bNew) psDevInfo->ui32HWGroupRequested = ui32New; - } psDevInfo->ui32HWReset |= ui32NewReset; - eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); - if (eError != PVRSRV_OK) { - return eError; - } - - SysAcquireData(&psSysData); + if (SysAcquireData(&psSysData) != PVRSRV_OK) + return PVRSRV_ERROR_GENERIC; psPowerDevice = psSysData->psPowerDeviceList; while (psPowerDevice) { if (psPowerDevice->ui32DeviceIndex == psDeviceNode->sDevId.ui32DeviceIndex) { bPowered = - (IMG_BOOL) (psPowerDevice->eCurrentPowerState == + (IMG_BOOL)(psPowerDevice->eCurrentPowerState == PVRSRV_POWER_STATE_D0); break; } @@ -1538,16 +1589,19 @@ IMG_EXPORT *pbActive = bPowered; + pvr_dev_lock(); + { - PVRSRV_SGXDEV_DIFF_INFO sNew, *psPrev = &psDevInfo->sDiffInfo; - IMG_UINT32 i; + struct PVRSRV_SGXDEV_DIFF_INFO sNew, + *psPrev = &psDevInfo->sDiffInfo; + u32 i; sNew.ui32Time[0] = OSClockus(); - *pui32Time = sNew.ui32Time[0]; - if (sNew.ui32Time[0] != psPrev->ui32Time[0] && bPowered) { + SGXPerfServerMonitor(*pui32Time); + *pui32Old = OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32Reg); @@ -1558,7 +1612,6 @@ IMG_EXPORT } if (psDevInfo->ui32HWGroupRequested != *pui32Old) { - if (psDevInfo->ui32HWReset != 0) { OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Reg, @@ -1567,7 +1620,6 @@ IMG_EXPORT psDevInfo->ui32HWReset); psDevInfo->ui32HWReset = 0; } - OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Reg, psDevInfo->ui32HWGroupRequested); } @@ -1575,8 +1627,8 @@ IMG_EXPORT sNew.ui32Marker[0] = psDevInfo->ui32KickTACounter; sNew.ui32Marker[1] = psDevInfo->ui32KickTARenderCounter; - sNew.ui32Time[1] = - psDevInfo->psSGXHostCtl->ui32TimeWraps; + sNew.ui32Time[1] = readl( + &psDevInfo->psSGXHostCtl->ui32TimeWraps); for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) { psDiffs->aui32Counters[i] = @@ -1596,10 +1648,8 @@ IMG_EXPORT *psPrev = sNew; } else { - - for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) { + for (i = 0; i < PVRSRV_SGX_DIFF_NUM_COUNTERS; ++i) psDiffs->aui32Counters[i] = 0; - } psDiffs->ui32Marker[0] = 0; psDiffs->ui32Marker[1] = 0; @@ -1609,9 +1659,48 @@ IMG_EXPORT } } - PVRSRVPowerUnlock(KERNEL_ID); + SGXTestActivePowerEvent(psDeviceNode); + + pvr_dev_unlock(); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR SGXReadHWPerfCBKM(void *hDevHandle, u32 ui32ArraySize, + struct PVRSRV_SGX_HWPERF_CB_ENTRY *psClientHWPerfEntry, + u32 *pui32DataCount, u32 *pui32ClockSpeed, + u32 *pui32HostTimeStamp) +{ + enum PVRSRV_ERROR eError = PVRSRV_OK; + struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; + struct PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; + struct SGXMKIF_HWPERF_CB *psHWPerfCB = + psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; + unsigned i; + + for (i = 0; + psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff && i < ui32ArraySize; + i++) { + struct SGXMKIF_HWPERF_CB_ENTRY *psMKPerfEntry = + &psHWPerfCB->psHWPerfCBData[psHWPerfCB->ui32Roff]; + + psClientHWPerfEntry[i].ui32FrameNo = psMKPerfEntry->ui32FrameNo; + psClientHWPerfEntry[i].ui32Type = psMKPerfEntry->ui32Type; + psClientHWPerfEntry[i].ui32Ordinal = psMKPerfEntry->ui32Ordinal; + psClientHWPerfEntry[i].ui32Clocksx16 = + SGXConvertTimeStamp(psDevInfo, psMKPerfEntry->ui32TimeWraps, + psMKPerfEntry->ui32Time); + OSMemCopy(&psClientHWPerfEntry[i].ui32Counters[0], + &psMKPerfEntry->ui32Counters[0], + sizeof(psMKPerfEntry->ui32Counters)); + + psHWPerfCB->ui32Roff = + (psHWPerfCB->ui32Roff + 1) & (SGXMKIF_HWPERF_CB_SIZE - 1); + } - SGXTestActivePowerEvent(psDeviceNode, KERNEL_ID); + *pui32DataCount = i; + *pui32ClockSpeed = psDevInfo->ui32CoreClockSpeed; + *pui32HostTimeStamp = OSClockus(); return eError; }