diff options
Diffstat (limited to 'pvr-source/services4/srvkm/common/pvrsrv.c')
-rw-r--r-- | pvr-source/services4/srvkm/common/pvrsrv.c | 1846 |
1 files changed, 1846 insertions, 0 deletions
diff --git a/pvr-source/services4/srvkm/common/pvrsrv.c b/pvr-source/services4/srvkm/common/pvrsrv.c new file mode 100644 index 0000000..1b5312c --- /dev/null +++ b/pvr-source/services4/srvkm/common/pvrsrv.c @@ -0,0 +1,1846 @@ +/*************************************************************************/ /*! +@Title core services functions +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description Main APIs for core services functions +@License Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#include "services_headers.h" +#include "buffer_manager.h" +#include "pvr_bridge_km.h" +#include "handle.h" +#include "perproc.h" +#include "pdump_km.h" +#include "deviceid.h" +#include "ra.h" +#if defined(__linux__) +#include "sysfs.h" +#endif +#if defined(TTRACE) +#include "ttrace.h" +#endif +#include "perfkm.h" + +#include "pvrversion.h" + +#include "lists.h" + +IMG_UINT32 g_ui32InitFlags; +extern int powering_down; + +/* mark which parts of Services were initialised */ +#define INIT_DATA_ENABLE_PDUMPINIT 0x1U +#define INIT_DATA_ENABLE_TTARCE 0x2U + +/*! +****************************************************************************** + + @Function AllocateDeviceID + + @Description + + allocates a device id from the pool of valid ids + + @input psSysData : system data + + @input pui32DevID : device id to return + + @Return device id + +******************************************************************************/ +PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID) +{ + SYS_DEVICE_ID* psDeviceWalker; + SYS_DEVICE_ID* psDeviceEnd; + + psDeviceWalker = &psSysData->sDeviceID[0]; + psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; + + /* find a free ID */ + while (psDeviceWalker < psDeviceEnd) + { + if (!psDeviceWalker->bInUse) + { + psDeviceWalker->bInUse = IMG_TRUE; + *pui32DevID = psDeviceWalker->uiID; + return PVRSRV_OK; + } + psDeviceWalker++; + } + + PVR_DPF((PVR_DBG_ERROR,"AllocateDeviceID: No free and valid device IDs available!")); + + /* Should never get here: sDeviceID[] may have been setup too small */ + PVR_ASSERT(psDeviceWalker < psDeviceEnd); + + return PVRSRV_ERROR_NO_FREE_DEVICEIDS_AVALIABLE; +} + + +/*! +****************************************************************************** + + @Function FreeDeviceID + + @Description + + frees a device id from the pool of valid ids + + @input psSysData : system data + + @input ui32DevID : device id to free + + @Return device id + +******************************************************************************/ +PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID) +{ + SYS_DEVICE_ID* psDeviceWalker; + SYS_DEVICE_ID* psDeviceEnd; + + psDeviceWalker = &psSysData->sDeviceID[0]; + psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices; + + /* find the ID to free */ + while (psDeviceWalker < psDeviceEnd) + { + /* if matching id and in use, free */ + if ( + (psDeviceWalker->uiID == ui32DevID) && + (psDeviceWalker->bInUse) + ) + { + psDeviceWalker->bInUse = IMG_FALSE; + return PVRSRV_OK; + } + psDeviceWalker++; + } + + PVR_DPF((PVR_DBG_ERROR,"FreeDeviceID: no matching dev ID that is in use!")); + + /* should never get here */ + PVR_ASSERT(psDeviceWalker < psDeviceEnd); + + return PVRSRV_ERROR_INVALID_DEVICEID; +} + + +/*! +****************************************************************************** + + @Function ReadHWReg + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : byte offset from register base + + @Return register value + +******************************************************************************/ +#ifndef ReadHWReg +IMG_EXPORT +IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset) +{ + return *(volatile IMG_UINT32*)((IMG_UINTPTR_T)pvLinRegBaseAddr+ui32Offset); +} +#endif + + +/*! +****************************************************************************** + + @Function WriteHWReg + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : byte offset from register base + + @input ui32Value : value to write to register + + @Return register value : original reg. value + +******************************************************************************/ +#ifndef WriteHWReg +IMG_EXPORT +IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value) +{ + PVR_DPF((PVR_DBG_MESSAGE,"WriteHWReg Base:%x, Offset: %x, Value %x", + (IMG_UINTPTR_T)pvLinRegBaseAddr,ui32Offset,ui32Value)); + + *(IMG_UINT32*)((IMG_UINTPTR_T)pvLinRegBaseAddr+ui32Offset) = ui32Value; +} +#endif + + +/*! +****************************************************************************** + + @Function WriteHWRegs + + @Description + + register access function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Count : register count + + @input psHWRegs : address/value register list + + @Return none + +******************************************************************************/ +#ifndef WriteHWRegs +IMG_EXPORT +IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HWREG *psHWRegs) +{ + while (ui32Count) + { + WriteHWReg (pvLinRegBaseAddr, psHWRegs->ui32RegAddr, psHWRegs->ui32RegVal); + psHWRegs++; + ui32Count--; + } +} +#endif + +/*! +****************************************************************************** + @Function PVRSRVEnumerateDCKM_ForEachVaCb + + @Description + + Enumerates the device node (if is of the same class as given). + + @Input psDeviceNode - The device node to be enumerated + va - variable arguments list, with: + pui32DevCount - The device count pointer (to be increased) + ppui32DevID - The pointer to the device IDs pointer (to be updated and increased) +******************************************************************************/ +static IMG_VOID PVRSRVEnumerateDevicesKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) +{ + IMG_UINT *pui32DevCount; + PVRSRV_DEVICE_IDENTIFIER **ppsDevIdList; + + pui32DevCount = va_arg(va, IMG_UINT*); + ppsDevIdList = va_arg(va, PVRSRV_DEVICE_IDENTIFIER**); + + if (psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_EXT) + { + *(*ppsDevIdList) = psDeviceNode->sDevId; + (*ppsDevIdList)++; + (*pui32DevCount)++; + } +} + + + +/*! +****************************************************************************** + + @Function PVRSRVEnumerateDevicesKM + + @Description + This function will enumerate all the devices supported by the + PowerVR services within the target system. + The function returns a list of the device ID strcutres stored either in + the services or constructed in the user mode glue component in certain + environments. The number of devices in the list is also returned. + + In a binary layered component which does not support dynamic runtime selection, + the glue code should compile to return the supported devices statically, + e.g. multiple instances of the same device if multiple devices are supported, + or the target combination of MBX and display device. + + In the case of an environment (for instance) where one MBX1 may connect to two + display devices this code would enumerate all three devices and even + non-dynamic MBX1 selection code should retain the facility to parse the list + to find the index of the MBX device + + @output pui32NumDevices : On success, contains the number of devices present + in the system + + @output psDevIdList : Pointer to called supplied buffer to receive the + list of PVRSRV_DEVICE_IDENTIFIER + + @return PVRSRV_ERROR : PVRSRV_NO_ERROR + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices, + PVRSRV_DEVICE_IDENTIFIER *psDevIdList) +{ + SYS_DATA *psSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode; */ + IMG_UINT32 i; + + if (!pui32NumDevices || !psDevIdList) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumerateDevicesKM: Invalid params")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + SysAcquireData(&psSysData); + + /* + setup input buffer to be `empty' + */ + for (i=0; i<PVRSRV_MAX_DEVICES; i++) + { + psDevIdList[i].eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN; + } + + /* and zero device count */ + *pui32NumDevices = 0; + + /* + Search through the device list for services managed devices + return id info for each device and the number of devices + available + */ + List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList, + &PVRSRVEnumerateDevicesKM_ForEachVaCb, + pui32NumDevices, + &psDevIdList); + + + return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function PVRSRVInit + + @Description Initialise services + + @Input psSysData : sysdata structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData) +{ + PVRSRV_ERROR eError; + +#if defined(__linux__) + eError = PVRSRVCreateSysfsEntry(); + if (eError != PVRSRV_OK) + { + goto Error; + } +#endif + + /* Initialise Resource Manager */ + eError = ResManInit(); + if (eError != PVRSRV_OK) + { + goto Error; + } + + eError = PVRSRVPerProcessDataInit(); + if(eError != PVRSRV_OK) + { + goto Error; + } + + /* Initialise handles */ + eError = PVRSRVHandleInit(); + if(eError != PVRSRV_OK) + { + goto Error; + } + + /* Initialise Power Manager Lock */ + eError = OSCreateResource(&psSysData->sPowerStateChangeResource); + if (eError != PVRSRV_OK) + { + goto Error; + } + + /* Initialise system power state */ + psSysData->eCurrentPowerState = PVRSRV_SYS_POWER_STATE_D0; + psSysData->eFailedPowerState = PVRSRV_SYS_POWER_STATE_Unspecified; + + /* Create an event object */ + if(OSAllocMem( PVRSRV_PAGEABLE_SELECT, + sizeof(PVRSRV_EVENTOBJECT) , + (IMG_VOID **)&psSysData->psGlobalEventObject, 0, + "Event Object") != PVRSRV_OK) + { + + goto Error; + } + + if(OSEventObjectCreateKM("PVRSRV_GLOBAL_EVENTOBJECT", psSysData->psGlobalEventObject) != PVRSRV_OK) + { + goto Error; + } + + /* Store OS high res timer fallbacks, the system is free to overide these */ + psSysData->pfnHighResTimerCreate = OSFuncHighResTimerCreate; + psSysData->pfnHighResTimerGetus = OSFuncHighResTimerGetus; + psSysData->pfnHighResTimerDestroy = OSFuncHighResTimerDestroy; + +#if defined(TTRACE) + eError = PVRSRVTimeTraceInit(); + if (eError != PVRSRV_OK) + goto Error; + g_ui32InitFlags |= INIT_DATA_ENABLE_TTARCE; +#endif + + /* Initialise pdump */ + PDUMPINIT(); + g_ui32InitFlags |= INIT_DATA_ENABLE_PDUMPINIT; + + PERFINIT(); + return eError; + +Error: + PVRSRVDeInit(psSysData); + return eError; +} + + + +/*! +****************************************************************************** + + @Function PVRSRVDeInit + + @Description De-Initialise services + + @Input psSysData : sysdata structure + + @Return PVRSRV_ERROR : + +******************************************************************************/ +IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData) +{ + PVRSRV_ERROR eError; + + PVR_UNREFERENCED_PARAMETER(psSysData); + + if (psSysData == IMG_NULL) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVHandleDeInit failed - invalid param")); + return; + } + + PERFDEINIT(); + +#if defined(TTRACE) + /* deinitialise ttrace */ + if ((g_ui32InitFlags & INIT_DATA_ENABLE_TTARCE) > 0) + { + PVRSRVTimeTraceDeinit(); + } +#endif + /* deinitialise pdump */ + if( (g_ui32InitFlags & INIT_DATA_ENABLE_PDUMPINIT) > 0) + { + PDUMPDEINIT(); + } + + /* destroy event object */ + if(psSysData->psGlobalEventObject) + { + OSEventObjectDestroyKM(psSysData->psGlobalEventObject); + OSFreeMem( PVRSRV_PAGEABLE_SELECT, + sizeof(PVRSRV_EVENTOBJECT), + psSysData->psGlobalEventObject, + 0); + psSysData->psGlobalEventObject = IMG_NULL; + } + + eError = PVRSRVHandleDeInit(); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVHandleDeInit failed")); + } + + eError = PVRSRVPerProcessDataDeInit(); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVPerProcessDataDeInit failed")); + } + + ResManDeInit(); +} + + +/*! +****************************************************************************** + + @Function PVRSRVRegisterDevice + + @Description + + registers a device with the system + + @Input psSysData : sysdata structure + + @Input pfnRegisterDevice : device registration function + + @Input ui32SOCInterruptBit : SoC interrupt bit for this device + + @Output pui32DeviceIndex : unique device key (for case of multiple identical devices) + + @Return PVRSRV_ERROR : + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVRegisterDevice(PSYS_DATA psSysData, + PVRSRV_ERROR (*pfnRegisterDevice)(PVRSRV_DEVICE_NODE*), + IMG_UINT32 ui32SOCInterruptBit, + IMG_UINT32 *pui32DeviceIndex) +{ + PVRSRV_ERROR eError; + PVRSRV_DEVICE_NODE *psDeviceNode; + + /* Allocate device node */ + if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(PVRSRV_DEVICE_NODE), + (IMG_VOID **)&psDeviceNode, IMG_NULL, + "Device Node") != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to alloc memory for psDeviceNode")); + return (PVRSRV_ERROR_OUT_OF_MEMORY); + } + OSMemSet (psDeviceNode, 0, sizeof(PVRSRV_DEVICE_NODE)); + + eError = pfnRegisterDevice(psDeviceNode); + if (eError != PVRSRV_OK) + { + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); + /*not nulling pointer, out of scope*/ + PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to register device")); + return (PVRSRV_ERROR_DEVICE_REGISTER_FAILED); + } + + /* + make the refcount 1 and test on this to initialise device + at acquiredevinfo. On release if refcount is 1, deinitialise + and when refcount is 0 (sysdata de-alloc) deallocate the device + structures + */ + psDeviceNode->ui32RefCount = 1; + psDeviceNode->psSysData = psSysData; + psDeviceNode->ui32SOCInterruptBit = ui32SOCInterruptBit; + + /* all devices need a unique identifier */ + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + + /* and finally insert the device into the dev-list */ + List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode); + + /* and copy back index */ + *pui32DeviceIndex = psDeviceNode->sDevId.ui32DeviceIndex; + + return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function PVRSRVInitialiseDevice + + @Description + + initialises device by index + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex) +{ + PVRSRV_DEVICE_NODE *psDeviceNode; + SYS_DATA *psSysData; + PVRSRV_ERROR eError; + + PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInitialiseDevice")); + + SysAcquireData(&psSysData); + + /* Find device in the list */ + psDeviceNode = (PVRSRV_DEVICE_NODE*) + List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, + &MatchDeviceKM_AnyVaCb, + ui32DevIndex, + IMG_TRUE); + if(!psDeviceNode) + { + /* Devinfo not in the list */ + PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: requested device is not present")); + return PVRSRV_ERROR_INIT_FAILURE; + } +/* +FoundDevice: +*/ + + PVR_ASSERT (psDeviceNode->ui32RefCount > 0); + + /* + Create the device's resource manager context. + */ + eError = PVRSRVResManConnect(IMG_NULL, &psDeviceNode->hResManContext); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: Failed PVRSRVResManConnect call")); + return eError; + } + + /* Initialise the device */ + if(psDeviceNode->pfnInitDevice != IMG_NULL) + { + eError = psDeviceNode->pfnInitDevice(psDeviceNode); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: Failed InitDevice call")); + return eError; + } + } + + return PVRSRV_OK; +} + + +static PVRSRV_ERROR PVRSRVFinaliseSystem_SetPowerState_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVRSRV_ERROR eError; + + eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVPowerLock call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex)); + return eError; + } + + eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex, + PVRSRV_DEV_POWER_STATE_DEFAULT); + PVRSRVPowerUnlock(KERNEL_ID); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVSetDevicePowerStateKM call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex)); + } + return eError; +} + +/*wraps the PVRSRVDevInitCompatCheck call and prints a debugging message if failed*/ +static PVRSRV_ERROR PVRSRVFinaliseSystem_CompatCheck_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + PVRSRV_ERROR eError; + eError = PVRSRVDevInitCompatCheck(psDeviceNode); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVDevInitCompatCheck call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex)); + } + return eError; +} + + +/*! +****************************************************************************** + + @Function PVRSRVFinaliseSystem + + @Description + + Final part of system initialisation. + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful) +{ +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ + SYS_DATA *psSysData; + PVRSRV_ERROR eError; + + PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVFinaliseSystem")); + + SysAcquireData(&psSysData); + + if (bInitSuccessful) + { + eError = SysFinalise(); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: SysFinalise failed (%d)", eError)); + return eError; + } + + /* Place all devices into their default power state. */ + eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList, + &PVRSRVFinaliseSystem_SetPowerState_AnyCb); + if (eError != PVRSRV_OK) + { + return eError; + } + + /* Verify microkernel compatibility for devices */ + eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList, + &PVRSRVFinaliseSystem_CompatCheck_AnyCb); + if (eError != PVRSRV_OK) + { + return eError; + } + } + + /* Some platforms call this too early in the boot phase. */ + PDUMPENDINITPHASE(); + + return PVRSRV_OK; +} + + +PVRSRV_ERROR PVRSRVDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + /* Only check devices which specify a compatibility check callback */ + if (psDeviceNode->pfnInitDeviceCompatCheck) + return psDeviceNode->pfnInitDeviceCompatCheck(psDeviceNode); + else + return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function PVRSRVAcquireDeviceDataKM + + @Description + + Matchs a device given a device type and a device index. + + @input psDeviceNode :The device node to be matched. + + @Input va : Variable argument list with: + eDeviceType : Required device type. If type is unknown use ui32DevIndex + to locate device data + + ui32DevIndex : Index to the required device obtained from the + PVRSRVEnumerateDevice function + + @Return PVRSRV_ERROR : + +******************************************************************************/ +static IMG_VOID * PVRSRVAcquireDeviceDataKM_Match_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) +{ + PVRSRV_DEVICE_TYPE eDeviceType; + IMG_UINT32 ui32DevIndex; + + eDeviceType = va_arg(va, PVRSRV_DEVICE_TYPE); + ui32DevIndex = va_arg(va, IMG_UINT32); + + if ((eDeviceType != PVRSRV_DEVICE_TYPE_UNKNOWN && + psDeviceNode->sDevId.eDeviceType == eDeviceType) || + (eDeviceType == PVRSRV_DEVICE_TYPE_UNKNOWN && + psDeviceNode->sDevId.ui32DeviceIndex == ui32DevIndex)) + { + return psDeviceNode; + } + else + { + return IMG_NULL; + } +} + +/*! +****************************************************************************** + + @Function PVRSRVAcquireDeviceDataKM + + @Description + + Returns device information + + @Input ui32DevIndex : Index to the required device obtained from the + PVRSRVEnumerateDevice function + + @Input eDeviceType : Required device type. If type is unknown use ui32DevIndex + to locate device data + + @Output *phDevCookie : Dev Cookie + + + @Return PVRSRV_ERROR : + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex, + PVRSRV_DEVICE_TYPE eDeviceType, + IMG_HANDLE *phDevCookie) +{ + PVRSRV_DEVICE_NODE *psDeviceNode; + SYS_DATA *psSysData; + + PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVAcquireDeviceDataKM")); + + SysAcquireData(&psSysData); + + /* Find device in the list */ + psDeviceNode = List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, + &PVRSRVAcquireDeviceDataKM_Match_AnyVaCb, + eDeviceType, + ui32DevIndex); + + + if (!psDeviceNode) + { + /* device can't be found in the list so it isn't in the system */ + PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireDeviceDataKM: requested device is not present")); + return PVRSRV_ERROR_INIT_FAILURE; + } + +/*FoundDevice:*/ + + PVR_ASSERT (psDeviceNode->ui32RefCount > 0); + + /* return the dev cookie? */ + if (phDevCookie) + { + *phDevCookie = (IMG_HANDLE)psDeviceNode; + } + + return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function PVRSRVDeinitialiseDevice + + @Description + + This De-inits device + + @Input ui32DevIndex : Index to the required device + + @Return PVRSRV_ERROR : + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex) +{ + PVRSRV_DEVICE_NODE *psDeviceNode; + SYS_DATA *psSysData; + PVRSRV_ERROR eError; + + SysAcquireData(&psSysData); + + psDeviceNode = (PVRSRV_DEVICE_NODE*) + List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList, + &MatchDeviceKM_AnyVaCb, + ui32DevIndex, + IMG_TRUE); + + if (!psDeviceNode) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: requested device %d is not present", ui32DevIndex)); + return PVRSRV_ERROR_DEVICEID_NOT_FOUND; + } + + eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVPowerLock call")); + return eError; + } + + /* + Power down the device if necessary. + */ + eError = PVRSRVSetDevicePowerStateKM(ui32DevIndex, + PVRSRV_DEV_POWER_STATE_OFF); + PVRSRVPowerUnlock(KERNEL_ID); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVSetDevicePowerStateKM call")); + return eError; + } + + /* + Free the dissociated device memory. + */ + eError = ResManFreeResByCriteria(psDeviceNode->hResManContext, + RESMAN_CRITERIA_RESTYPE, + RESMAN_TYPE_DEVICEMEM_ALLOCATION, + IMG_NULL, 0); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed ResManFreeResByCriteria call")); + return eError; + } + + /* + De-init the device. + */ + if(psDeviceNode->pfnDeInitDevice != IMG_NULL) + { + eError = psDeviceNode->pfnDeInitDevice(psDeviceNode); + if (eError != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed DeInitDevice call")); + return eError; + } + } + + /* + Close the device's resource manager context. + */ + PVRSRVResManDisconnect(psDeviceNode->hResManContext, IMG_TRUE); + psDeviceNode->hResManContext = IMG_NULL; + + /* remove node from list */ + List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode); + + /* deallocate id and memory */ + (IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex); + OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, + sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL); + /*not nulling pointer, out of scope*/ + + return (PVRSRV_OK); +} + + +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PollForValueKM (volatile IMG_UINT32* pui32LinMemAddr, + IMG_UINT32 ui32Value, + IMG_UINT32 ui32Mask, + IMG_UINT32 ui32Timeoutus, + IMG_UINT32 ui32PollPeriodus, + IMG_BOOL bAllowPreemption) +{ +#if defined (EMULATOR) + { + PVR_UNREFERENCED_PARAMETER(bAllowPreemption); + #if !defined(__linux__) + PVR_UNREFERENCED_PARAMETER(ui32PollPeriodus); + #endif + + /* For the Emulator we want the system to stop when a lock-up is detected so the state can be analysed. + * Also the Emulator is much slower than real silicon so timeouts are not valid. + */ + do + { + if((*pui32LinMemAddr & ui32Mask) == ui32Value) + { + return PVRSRV_OK; + } + + #if defined(__linux__) + OSWaitus(ui32PollPeriodus); + #else + OSReleaseThreadQuanta(); + #endif + + } while (ui32Timeoutus); /* Endless loop only for the Emulator */ + } +#else + { + IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU; /* Initialiser only required to prevent incorrect warning */ + + if (bAllowPreemption) + { + PVR_ASSERT(ui32PollPeriodus >= 1000); + } + + /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */ + LOOP_UNTIL_TIMEOUT(ui32Timeoutus) + { + ui32ActualValue = (*pui32LinMemAddr & ui32Mask); + if(ui32ActualValue == ui32Value) + { + return PVRSRV_OK; + } + + if (bAllowPreemption) + { + OSSleepms(ui32PollPeriodus / 1000); + } + else + { + OSWaitus(ui32PollPeriodus); + } + } END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF((PVR_DBG_ERROR,"PollForValueKM: Timeout. Expected 0x%x but found 0x%x (mask 0x%x).", + ui32Value, ui32ActualValue, ui32Mask)); + } +#endif /* #if defined (EMULATOR) */ + + return PVRSRV_ERROR_TIMEOUT; +} + + +/*Level 3 of the loop nesting*/ +static IMG_VOID PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb(BM_HEAP *psBMHeap, va_list va) +{ + IMG_CHAR **ppszStr; + IMG_UINT32 *pui32StrLen; + IMG_UINT32 ui32Mode; + PVRSRV_ERROR (*pfnGetStats)(RA_ARENA *, IMG_CHAR **, IMG_UINT32 *); + + ppszStr = va_arg(va, IMG_CHAR**); + pui32StrLen = va_arg(va, IMG_UINT32*); + ui32Mode = va_arg(va, IMG_UINT32); + + /* Would be better to pass fn pointer in the variable args list + * but MS C compiler complains with error C2066: In ANSI C, + * it is not legal to cast between a function pointer and a data pointer. + */ + switch(ui32Mode) + { + case PVRSRV_MISC_INFO_MEMSTATS_PRESENT: + pfnGetStats = &RA_GetStats; + break; + case PVRSRV_MISC_INFO_FREEMEM_PRESENT: + pfnGetStats = &RA_GetStatsFreeMem; + break; + default: + return; + } + + if(psBMHeap->pImportArena) + { + pfnGetStats(psBMHeap->pImportArena, + ppszStr, + pui32StrLen); + } + + if(psBMHeap->pVMArena) + { + pfnGetStats(psBMHeap->pVMArena, + ppszStr, + pui32StrLen); + } +} + +/*Level 2 of the loop nesting*/ +static PVRSRV_ERROR PVRSRVGetMiscInfoKM_BMContext_AnyVaCb(BM_CONTEXT *psBMContext, va_list va) +{ + + IMG_UINT32 *pui32StrLen; + IMG_INT32 *pi32Count; + IMG_CHAR **ppszStr; + IMG_UINT32 ui32Mode; + + pui32StrLen = va_arg(va, IMG_UINT32*); + pi32Count = va_arg(va, IMG_INT32*); + ppszStr = va_arg(va, IMG_CHAR**); + ui32Mode = va_arg(va, IMG_UINT32); + + CHECK_SPACE(*pui32StrLen); + *pi32Count = OSSNPrintf(*ppszStr, 100, "\nApplication Context (hDevMemContext) %p:\n", + (IMG_HANDLE)psBMContext); + UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen); + + List_BM_HEAP_ForEach_va(psBMContext->psBMHeap, + &PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb, + ppszStr, + pui32StrLen, + ui32Mode); + return PVRSRV_OK; +} + + +/*level 1 of the loop nesting*/ +static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) +{ + IMG_UINT32 *pui32StrLen; + IMG_INT32 *pi32Count; + IMG_CHAR **ppszStr; + IMG_UINT32 ui32Mode; + + pui32StrLen = va_arg(va, IMG_UINT32*); + pi32Count = va_arg(va, IMG_INT32*); + ppszStr = va_arg(va, IMG_CHAR**); + ui32Mode = va_arg(va, IMG_UINT32); + + CHECK_SPACE(*pui32StrLen); + *pi32Count = OSSNPrintf(*ppszStr, 100, "\n\nDevice Type %d:\n", psDeviceNode->sDevId.eDeviceType); + UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen); + + /* kernel context: */ + if(psDeviceNode->sDevMemoryInfo.pBMKernelContext) + { + CHECK_SPACE(*pui32StrLen); + *pi32Count = OSSNPrintf(*ppszStr, 100, "\nKernel Context:\n"); + UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen); + + List_BM_HEAP_ForEach_va(psDeviceNode->sDevMemoryInfo.pBMKernelContext->psBMHeap, + &PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb, + ppszStr, + pui32StrLen, + ui32Mode); + } + + /* double loop app contexts:heaps */ + return List_BM_CONTEXT_PVRSRV_ERROR_Any_va(psDeviceNode->sDevMemoryInfo.pBMContext, + &PVRSRVGetMiscInfoKM_BMContext_AnyVaCb, + pui32StrLen, + pi32Count, + ppszStr, + ui32Mode); +} + + +/*! +****************************************************************************** + + @Function PVRSRVGetMiscInfoKM + + @Description + Retrieves misc. info. + + @Output PVRSRV_MISC_INFO + + @Return PVRSRV_ERROR : + +******************************************************************************/ +IMG_EXPORT +#if defined (SUPPORT_SID_INTERFACE) +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO_KM *psMiscInfo) +#else +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo) +#endif +{ + SYS_DATA *psSysData; + + if(!psMiscInfo) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psMiscInfo->ui32StatePresent = 0; + + /* do a basic check for uninitialised request flag */ + if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT + |PVRSRV_MISC_INFO_CLOCKGATE_PRESENT + |PVRSRV_MISC_INFO_MEMSTATS_PRESENT + |PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT + |PVRSRV_MISC_INFO_DDKVERSION_PRESENT + |PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT + |PVRSRV_MISC_INFO_RESET_PRESENT + |PVRSRV_MISC_INFO_FREEMEM_PRESENT + |PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT + |PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT + |PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT)) + { + PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + SysAcquireData(&psSysData); + + /* return SOC Timer registers */ + if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) && + (psSysData->pvSOCTimerRegisterKM != IMG_NULL)) + { + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT; + psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM; + psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle; + } + else + { + psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL; + psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL; + } + + /* return SOC Clock Gating registers */ + if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) && + (psSysData->pvSOCClockGateRegsBase != IMG_NULL)) + { + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT; + psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase; + psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize; + } + + /* memory stats */ + if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) && + (psMiscInfo->pszMemoryStr != IMG_NULL)) + { + RA_ARENA **ppArena; +/* BM_HEAP *psBMHeap; + BM_CONTEXT *psBMContext; + PVRSRV_DEVICE_NODE *psDeviceNode;*/ + IMG_CHAR *pszStr; + IMG_UINT32 ui32StrLen; + IMG_INT32 i32Count; + + pszStr = psMiscInfo->pszMemoryStr; + ui32StrLen = psMiscInfo->ui32MemoryStrLen; + + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT; + + /* Local backing stores */ + ppArena = &psSysData->apsLocalDevMemArena[0]; + while(*ppArena) + { + CHECK_SPACE(ui32StrLen); + i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + + RA_GetStats(*ppArena, + &pszStr, + &ui32StrLen); + /* advance through the array */ + ppArena++; + } + + /* per device */ +/* psDeviceNode = psSysData->psDeviceNodeList;*/ + + /*triple loop; devices:contexts:heaps*/ + List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList, + &PVRSRVGetMiscInfoKM_Device_AnyVaCb, + &ui32StrLen, + &i32Count, + &pszStr, + PVRSRV_MISC_INFO_MEMSTATS_PRESENT); + + /* attach a new line and string terminate */ + i32Count = OSSNPrintf(pszStr, 100, "\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + /* Lean version of mem stats: only show free mem on each RA */ + if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0) + && psMiscInfo->pszMemoryStr) + { + IMG_CHAR *pszStr; + IMG_UINT32 ui32StrLen; + IMG_INT32 i32Count; + + pszStr = psMiscInfo->pszMemoryStr; + ui32StrLen = psMiscInfo->ui32MemoryStrLen; + + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT; + + /* triple loop over devices:contexts:heaps */ + List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList, + &PVRSRVGetMiscInfoKM_Device_AnyVaCb, + &ui32StrLen, + &i32Count, + &pszStr, + PVRSRV_MISC_INFO_FREEMEM_PRESENT); + + i32Count = OSSNPrintf(pszStr, 100, "\n"); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + + if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) && + (psSysData->psGlobalEventObject != IMG_NULL)) + { + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT; + psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject; + } + + /* DDK version and memstats not supported in same call to GetMiscInfo */ + + if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL) + && ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL) + && (psMiscInfo->pszMemoryStr != IMG_NULL)) + { + IMG_CHAR *pszStr; + IMG_UINT32 ui32StrLen; + IMG_UINT32 ui32LenStrPerNum = 12; /* string length per UI32: 10 digits + '.' + '\0' = 12 bytes */ + IMG_INT32 i32Count; + IMG_INT i; + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT; + + /* construct DDK string */ + psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ; + psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN; + psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BUILD_HI; + psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD_LO; + + pszStr = psMiscInfo->pszMemoryStr; + ui32StrLen = psMiscInfo->ui32MemoryStrLen; + + for (i=0; i<4; i++) + { + if (ui32StrLen < ui32LenStrPerNum) + { + return PVRSRV_ERROR_INVALID_PARAMS; + } + + i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + if (i != 3) + { + i32Count = OSSNPrintf(pszStr, 2, "."); + UPDATE_SPACE(pszStr, i32Count, ui32StrLen); + } + } + } + + if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL) + { + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT; + + if(psMiscInfo->sCacheOpCtl.bDeferOp) + { + /* For now, assume deferred ops are "full" cache ops, + * and we don't need (or expect) a meminfo. + */ + psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType; + } + else + { +#if defined (SUPPORT_SID_INTERFACE) + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo = psMiscInfo->sCacheOpCtl.psKernelMemInfo; + + if(!psMiscInfo->sCacheOpCtl.psKernelMemInfo) +#else + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + PVRSRV_PER_PROCESS_DATA *psPerProc; + + if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo) +#endif + { + PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: " + "Ignoring non-deferred cache op with no meminfo")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE) + { + PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: " + "Deferred cache op is pending. It is unlikely you want " + "to combine deferred cache ops with immediate ones")); + } + +#if defined (SUPPORT_SID_INTERFACE) + PVR_DBG_BREAK +#else + psPerProc = PVRSRVFindPerProcessData(); + + if(PVRSRVLookupHandle(psPerProc->psHandleBase, + (IMG_PVOID *)&psKernelMemInfo, + psMiscInfo->sCacheOpCtl.u.psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: " + "Can't find kernel meminfo")); + return PVRSRV_ERROR_INVALID_PARAMS; + } +#endif + + if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH) + { + if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle, + 0, + psMiscInfo->sCacheOpCtl.pvBaseVAddr, + psMiscInfo->sCacheOpCtl.ui32Length)) + { + return PVRSRV_ERROR_CACHEOP_FAILED; + } + } + else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN) + { + if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle, + 0, + psMiscInfo->sCacheOpCtl.pvBaseVAddr, + psMiscInfo->sCacheOpCtl.ui32Length)) + { + return PVRSRV_ERROR_CACHEOP_FAILED; + } + } + } + } + + if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT) != 0UL) + { +#if !defined (SUPPORT_SID_INTERFACE) + PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo; + PVRSRV_PER_PROCESS_DATA *psPerProc; +#endif + + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT; + +#if defined (SUPPORT_SID_INTERFACE) + PVR_DBG_BREAK +#else + psPerProc = PVRSRVFindPerProcessData(); + + if(PVRSRVLookupHandle(psPerProc->psHandleBase, + (IMG_PVOID *)&psKernelMemInfo, + psMiscInfo->sGetRefCountCtl.u.psKernelMemInfo, + PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: " + "Can't find kernel meminfo")); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psMiscInfo->sGetRefCountCtl.ui32RefCount = psKernelMemInfo->ui32RefCount; +#endif + } + + if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT) != 0UL) + { + psMiscInfo->ui32PageSize = HOST_PAGESIZE(); + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT; + } + +#if defined(PVRSRV_RESET_ON_HWTIMEOUT) + if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL) + { + PVR_LOG(("User requested OS reset")); + OSPanic(); + } +#endif /* #if defined(PVRSRV_RESET_ON_HWTIMEOUT) */ + + if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT) != 0UL) + { + PVRSRVSetDCState(DC_STATE_FORCE_SWAP_TO_SYSTEM); + psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT; + } + + return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function PVRSRVDeviceLISR + + @Description + OS-independent Device Low-level Interrupt Service Routine + + @Input psDeviceNode + + @Return IMG_BOOL : Whether any interrupts were serviced + +******************************************************************************/ +IMG_BOOL IMG_CALLCONV PVRSRVDeviceLISR(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + SYS_DATA *psSysData; + IMG_BOOL bStatus = IMG_FALSE; + IMG_UINT32 ui32InterruptSource; + + if(!psDeviceNode) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVDeviceLISR: Invalid params\n")); + goto out; + } + psSysData = psDeviceNode->psSysData; + + /* query the SOC/system to see whether this device was the source of the interrupt */ + ui32InterruptSource = SysGetInterruptSource(psSysData, psDeviceNode); + if(ui32InterruptSource & psDeviceNode->ui32SOCInterruptBit) + { + if(psDeviceNode->pfnDeviceISR != IMG_NULL) + { + bStatus = (*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData); + } + if(!powering_down) { + SysClearInterrupts(psSysData, psDeviceNode->ui32SOCInterruptBit); + } + } + +out: + return bStatus; +} + +static IMG_VOID PVRSRVSystemLISR_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va) +{ + + IMG_BOOL *pbStatus; + IMG_UINT32 *pui32InterruptSource; + IMG_UINT32 *pui32ClearInterrupts; + + pbStatus = va_arg(va, IMG_BOOL*); + pui32InterruptSource = va_arg(va, IMG_UINT32*); + pui32ClearInterrupts = va_arg(va, IMG_UINT32*); + + + if(psDeviceNode->pfnDeviceISR != IMG_NULL) + { + if(*pui32InterruptSource & psDeviceNode->ui32SOCInterruptBit) + { + if((*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData)) + { + /* Record if serviced any interrupts. */ + *pbStatus = IMG_TRUE; + } + /* Combine the SOC clear bits. */ + *pui32ClearInterrupts |= psDeviceNode->ui32SOCInterruptBit; + } + } +} + +/*! +****************************************************************************** + + @Function PVRSRVSystemLISR + + @Description + OS-independent System Low-level Interrupt Service Routine + + @Input pvSysData + + @Return IMG_BOOL : Whether any interrupts were serviced + +******************************************************************************/ +IMG_BOOL IMG_CALLCONV PVRSRVSystemLISR(IMG_VOID *pvSysData) +{ + SYS_DATA *psSysData = pvSysData; + IMG_BOOL bStatus = IMG_FALSE; + IMG_UINT32 ui32InterruptSource; + IMG_UINT32 ui32ClearInterrupts = 0; +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ + + if(!psSysData) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSystemLISR: Invalid params\n")); +/* goto out; */ + } + else + { + /* query SOC for source of interrupts */ + ui32InterruptSource = SysGetInterruptSource(psSysData, IMG_NULL); + + /* only proceed if PVR interrupts */ + if(ui32InterruptSource) + { + /* traverse the devices' ISR handlers */ + List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList, + &PVRSRVSystemLISR_ForEachVaCb, + &bStatus, + &ui32InterruptSource, + &ui32ClearInterrupts); + + SysClearInterrupts(psSysData, ui32ClearInterrupts); + } +/*out:*/ + } + return bStatus; +} + + +static IMG_VOID PVRSRVMISR_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + if(psDeviceNode->pfnDeviceMISR != IMG_NULL) + { + (*psDeviceNode->pfnDeviceMISR)(psDeviceNode->pvISRData); + } +} + +/*! +****************************************************************************** + + @Function PVRSRVMISR + + @Input pvSysData + + @Description + OS-independent Medium-level Interrupt Service Routine + +******************************************************************************/ +IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData) +{ + SYS_DATA *psSysData = pvSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode; */ + + if(!psSysData) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVMISR: Invalid params\n")); + return; + } + + /* Traverse the devices' MISR handlers. */ + List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, + &PVRSRVMISR_ForEachCb); + + /* Process the queues. */ + if (PVRSRVProcessQueues(IMG_FALSE) == PVRSRV_ERROR_PROCESSING_BLOCKED) + { + PVRSRVProcessQueues(IMG_FALSE); + } + + /* signal global event object */ + if (psSysData->psGlobalEventObject) + { + IMG_HANDLE hOSEventKM = psSysData->psGlobalEventObject->hOSEventKM; + if(hOSEventKM) + { + OSEventObjectSignalKM(hOSEventKM); + } + } +} + + +/*! +****************************************************************************** + + @Function PVRSRVProcessConnect + + @Description Inform services that a process has connected. + + @Input ui32PID - process ID + + @Return PVRSRV_ERROR + +******************************************************************************/ +IMG_EXPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVProcessConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) +{ + return PVRSRVPerProcessDataConnect(ui32PID, ui32Flags); +} + + +/*! +****************************************************************************** + + @Function PVRSRVProcessDisconnect + + @Description Inform services that a process has disconnected. + + @Input ui32PID - process ID + + @Return IMG_VOID + +******************************************************************************/ +IMG_EXPORT +IMG_VOID IMG_CALLCONV PVRSRVProcessDisconnect(IMG_UINT32 ui32PID) +{ + PVRSRVPerProcessDataDisconnect(ui32PID); +} + + +/*! +****************************************************************************** + + @Function PVRSRVSaveRestoreLiveSegments + + @Input pArena - the arena the segment was originally allocated from. + pbyBuffer - the system memory buffer set to null to get the size needed. + puiBufSize - size of system memory buffer. + bSave - IMG_TRUE if a save is required + + @Description + Function to save or restore Resources Live segments + +******************************************************************************/ +PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_PBYTE pbyBuffer, + IMG_SIZE_T *puiBufSize, IMG_BOOL bSave) +{ + IMG_SIZE_T uiBytesSaved = 0; + IMG_PVOID pvLocalMemCPUVAddr; + RA_SEGMENT_DETAILS sSegDetails; + + if (hArena == IMG_NULL) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + sSegDetails.uiSize = 0; + sSegDetails.sCpuPhyAddr.uiAddr = 0; + sSegDetails.hSegment = 0; + + /* walk the arena segments and write live one to the buffer */ + while (RA_GetNextLiveSegment(hArena, &sSegDetails)) + { + if (pbyBuffer == IMG_NULL) + { + /* calc buffer required */ + uiBytesSaved += sizeof(sSegDetails.uiSize) + sSegDetails.uiSize; + } + else + { + if ((uiBytesSaved + sizeof(sSegDetails.uiSize) + sSegDetails.uiSize) > *puiBufSize) + { + return (PVRSRV_ERROR_OUT_OF_MEMORY); + } + + PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVSaveRestoreLiveSegments: Base %08x size %08x", sSegDetails.sCpuPhyAddr.uiAddr, sSegDetails.uiSize)); + + /* Map the device's local memory area onto the host. */ + pvLocalMemCPUVAddr = OSMapPhysToLin(sSegDetails.sCpuPhyAddr, + sSegDetails.uiSize, + PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, + IMG_NULL); + if (pvLocalMemCPUVAddr == IMG_NULL) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSaveRestoreLiveSegments: Failed to map local memory to host")); + return (PVRSRV_ERROR_OUT_OF_MEMORY); + } + + if (bSave) + { + /* write segment size then segment data */ + OSMemCopy(pbyBuffer, &sSegDetails.uiSize, sizeof(sSegDetails.uiSize)); + pbyBuffer += sizeof(sSegDetails.uiSize); + + OSMemCopy(pbyBuffer, pvLocalMemCPUVAddr, sSegDetails.uiSize); + pbyBuffer += sSegDetails.uiSize; + } + else + { + IMG_UINT32 uiSize; + /* reag segment size and validate */ + OSMemCopy(&uiSize, pbyBuffer, sizeof(sSegDetails.uiSize)); + + if (uiSize != sSegDetails.uiSize) + { + PVR_DPF((PVR_DBG_ERROR, "PVRSRVSaveRestoreLiveSegments: Segment size error")); + } + else + { + pbyBuffer += sizeof(sSegDetails.uiSize); + + OSMemCopy(pvLocalMemCPUVAddr, pbyBuffer, sSegDetails.uiSize); + pbyBuffer += sSegDetails.uiSize; + } + } + + + uiBytesSaved += sizeof(sSegDetails.uiSize) + sSegDetails.uiSize; + + OSUnMapPhysToLin(pvLocalMemCPUVAddr, + sSegDetails.uiSize, + PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, + IMG_NULL); + } + } + + if (pbyBuffer == IMG_NULL) + { + *puiBufSize = uiBytesSaved; + } + + return (PVRSRV_OK); +} + + +/*! + ****************************************************************************** + + @Function PVRSRVGetErrorStringKM + + @Description Returns a text string relating to the PVRSRV_ERROR enum. + + @Note case statement used rather than an indexed arrary to ensure text is + synchronised with the correct enum + + @Input eError : PVRSRV_ERROR enum + + @Return const IMG_CHAR * : Text string + + @Note Must be kept in sync with servicesext.h + +******************************************************************************/ + +IMG_EXPORT +const IMG_CHAR *PVRSRVGetErrorStringKM(PVRSRV_ERROR eError) +{ +/* PRQA S 5087 1 */ /* include file required here */ +#include "pvrsrv_errors.h" +} + +static IMG_VOID PVRSRVCommandCompleteCallbacks_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode) +{ + if(psDeviceNode->pfnDeviceCommandComplete != IMG_NULL) + { + /* Call the device's callback function. */ + (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode); + } +} + +/*! +****************************************************************************** + + @Function PVRSRVScheduleDeviceCallbacks + + @Description Schedule all device callbacks + + @Return IMG_VOID + +******************************************************************************/ +IMG_VOID PVRSRVScheduleDeviceCallbacks(IMG_VOID) +{ + SYS_DATA *psSysData; +/* PVRSRV_DEVICE_NODE *psDeviceNode;*/ + + SysAcquireData(&psSysData); + + /*for all the device, invoke the callback function*/ + List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList, + &PVRSRVCommandCompleteCallbacks_ForEachCb); +} + +/*! +****************************************************************************** + + @Function PVRSRVScheduleDevices + + @Description Schedules all Services-Managed Devices to check their pending + command queues. The intention is that ScheduleDevices be called by the + 3rd party BC driver after it has finished writing new data to its output + texture. + + @Return IMG_VOID + +******************************************************************************/ +IMG_EXPORT +IMG_VOID PVRSRVScheduleDevicesKM(IMG_VOID) +{ + PVRSRVScheduleDeviceCallbacks(); +} + +/***************************************************************************** + End of file (pvrsrv.c) +*****************************************************************************/ |