blob: 1b730f5b2e0bdb2a2206af8ed30170509e75a2f5 [file] [log] [blame]
/**********************************************************************
*
* Copyright (C) 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.
* 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. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#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(TTRACE)
#include "ttrace.h"
#endif
#include "perfkm.h"
#include "pvrversion.h"
#include "lists.h"
IMG_UINT32 g_ui32InitFlags;
#define INIT_DATA_ENABLE_PDUMPINIT 0x1U
#define INIT_DATA_ENABLE_TTARCE 0x2U
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;
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!"));
PVR_ASSERT(psDeviceWalker < psDeviceEnd);
return PVRSRV_ERROR_NO_FREE_DEVICEIDS_AVALIABLE;
}
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;
while (psDeviceWalker < psDeviceEnd)
{
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!"));
PVR_ASSERT(psDeviceWalker < psDeviceEnd);
return PVRSRV_ERROR_INVALID_DEVICEID;
}
#ifndef ReadHWReg
IMG_EXPORT
IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset)
{
return *(volatile IMG_UINT32*)((IMG_UINTPTR_T)pvLinRegBaseAddr+ui32Offset);
}
#endif
#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
#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
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)++;
}
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices,
PVRSRV_DEVICE_IDENTIFIER *psDevIdList)
{
SYS_DATA *psSysData;
IMG_UINT32 i;
if (!pui32NumDevices || !psDevIdList)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumerateDevicesKM: Invalid params"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
for (i=0; i<PVRSRV_MAX_DEVICES; i++)
{
psDevIdList[i].eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN;
}
*pui32NumDevices = 0;
List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
&PVRSRVEnumerateDevicesKM_ForEachVaCb,
pui32NumDevices,
&psDevIdList);
return PVRSRV_OK;
}
PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData)
{
PVRSRV_ERROR eError;
eError = ResManInit();
if (eError != PVRSRV_OK)
{
goto Error;
}
eError = PVRSRVPerProcessDataInit();
if(eError != PVRSRV_OK)
{
goto Error;
}
eError = PVRSRVHandleInit();
if(eError != PVRSRV_OK)
{
goto Error;
}
eError = OSCreateResource(&psSysData->sPowerStateChangeResource);
if (eError != PVRSRV_OK)
{
goto Error;
}
psSysData->eCurrentPowerState = PVRSRV_SYS_POWER_STATE_D0;
psSysData->eFailedPowerState = PVRSRV_SYS_POWER_STATE_Unspecified;
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;
}
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
PDUMPINIT();
g_ui32InitFlags |= INIT_DATA_ENABLE_PDUMPINIT;
PERFINIT();
return eError;
Error:
PVRSRVDeInit(psSysData);
return eError;
}
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)
if ((g_ui32InitFlags & INIT_DATA_ENABLE_TTARCE) > 0)
{
PVRSRVTimeTraceDeinit();
}
#endif
if( (g_ui32InitFlags & INIT_DATA_ENABLE_PDUMPINIT) > 0)
{
PDUMPDEINIT();
}
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();
}
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;
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);
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to register device"));
return (PVRSRV_ERROR_DEVICE_REGISTER_FAILED);
}
psDeviceNode->ui32RefCount = 1;
psDeviceNode->psSysData = psSysData;
psDeviceNode->ui32SOCInterruptBit = ui32SOCInterruptBit;
AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex);
List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode);
*pui32DeviceIndex = psDeviceNode->sDevId.ui32DeviceIndex;
return PVRSRV_OK;
}
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);
psDeviceNode = (PVRSRV_DEVICE_NODE*)
List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&MatchDeviceKM_AnyVaCb,
ui32DevIndex,
IMG_TRUE);
if(!psDeviceNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: requested device is not present"));
return PVRSRV_ERROR_INIT_FAILURE;
}
PVR_ASSERT (psDeviceNode->ui32RefCount > 0);
eError = PVRSRVResManConnect(IMG_NULL, &psDeviceNode->hResManContext);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: Failed PVRSRVResManConnect call"));
return eError;
}
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 = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex,
PVRSRV_DEV_POWER_STATE_DEFAULT,
KERNEL_ID, IMG_FALSE);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVSetDevicePowerStateKM call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex));
}
return eError;
}
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;
}
PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful)
{
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;
}
eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList,
&PVRSRVFinaliseSystem_SetPowerState_AnyCb);
if (eError != PVRSRV_OK)
{
return eError;
}
eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList,
&PVRSRVFinaliseSystem_CompatCheck_AnyCb);
if (eError != PVRSRV_OK)
{
return eError;
}
}
PDUMPENDINITPHASE();
return PVRSRV_OK;
}
PVRSRV_ERROR PVRSRVDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode)
{
if (psDeviceNode->pfnInitDeviceCompatCheck)
return psDeviceNode->pfnInitDeviceCompatCheck(psDeviceNode);
else
return PVRSRV_OK;
}
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;
}
}
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);
psDeviceNode = List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
&PVRSRVAcquireDeviceDataKM_Match_AnyVaCb,
eDeviceType,
ui32DevIndex);
if (!psDeviceNode)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireDeviceDataKM: requested device is not present"));
return PVRSRV_ERROR_INIT_FAILURE;
}
PVR_ASSERT (psDeviceNode->ui32RefCount > 0);
if (phDevCookie)
{
*phDevCookie = (IMG_HANDLE)psDeviceNode;
}
return PVRSRV_OK;
}
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 = PVRSRVSetDevicePowerStateKM(ui32DevIndex,
PVRSRV_DEV_POWER_STATE_OFF,
KERNEL_ID,
IMG_FALSE);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVSetDevicePowerStateKM call"));
return eError;
}
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;
}
if(psDeviceNode->pfnDeInitDevice != IMG_NULL)
{
eError = psDeviceNode->pfnDeInitDevice(psDeviceNode);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed DeInitDevice call"));
return eError;
}
}
PVRSRVResManDisconnect(psDeviceNode->hResManContext, IMG_TRUE);
psDeviceNode->hResManContext = IMG_NULL;
List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode);
(IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex);
OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL);
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
do
{
if((*pui32LinMemAddr & ui32Mask) == ui32Value)
{
return PVRSRV_OK;
}
#if defined(__linux__)
OSWaitus(ui32PollPeriodus);
#else
OSReleaseThreadQuanta();
#endif
} while (ui32Timeoutus);
}
#else
{
IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU;
if (bAllowPreemption)
{
PVR_ASSERT(ui32PollPeriodus >= 1000);
}
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
return PVRSRV_ERROR_TIMEOUT;
}
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);
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);
}
}
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;
}
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);
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);
}
return List_BM_CONTEXT_PVRSRV_ERROR_Any_va(psDeviceNode->sDevMemoryInfo.pBMContext,
&PVRSRVGetMiscInfoKM_BMContext_AnyVaCb,
pui32StrLen,
pi32Count,
ppszStr,
ui32Mode);
}
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;
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))
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
SysAcquireData(&psSysData);
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;
}
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;
}
if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
(psMiscInfo->pszMemoryStr != IMG_NULL))
{
RA_ARENA **ppArena;
IMG_CHAR *pszStr;
IMG_UINT32 ui32StrLen;
IMG_INT32 i32Count;
pszStr = psMiscInfo->pszMemoryStr;
ui32StrLen = psMiscInfo->ui32MemoryStrLen;
psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;
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);
ppArena++;
}
List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
&PVRSRVGetMiscInfoKM_Device_AnyVaCb,
&ui32StrLen,
&i32Count,
&pszStr,
PVRSRV_MISC_INFO_MEMSTATS_PRESENT);
i32Count = OSSNPrintf(pszStr, 100, "\n");
UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
}
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;
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;
}
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;
IMG_INT32 i32Count;
IMG_INT i;
psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;
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)
{
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,
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,
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 defined(PVRSRV_RESET_ON_HWTIMEOUT)
if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
{
PVR_LOG(("User requested OS reset"));
OSPanic();
}
#endif
return PVRSRV_OK;
}
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;
ui32InterruptSource = SysGetInterruptSource(psSysData, psDeviceNode);
if(ui32InterruptSource & psDeviceNode->ui32SOCInterruptBit)
{
if(psDeviceNode->pfnDeviceISR != IMG_NULL)
{
bStatus = (*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData);
}
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))
{
*pbStatus = IMG_TRUE;
}
*pui32ClearInterrupts |= psDeviceNode->ui32SOCInterruptBit;
}
}
}
IMG_BOOL IMG_CALLCONV PVRSRVSystemLISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = pvSysData;
IMG_BOOL bStatus = IMG_FALSE;
IMG_UINT32 ui32InterruptSource;
IMG_UINT32 ui32ClearInterrupts = 0;
if(!psSysData)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVSystemLISR: Invalid params\n"));
}
else
{
ui32InterruptSource = SysGetInterruptSource(psSysData, IMG_NULL);
if(ui32InterruptSource)
{
List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
&PVRSRVSystemLISR_ForEachVaCb,
&bStatus,
&ui32InterruptSource,
&ui32ClearInterrupts);
SysClearInterrupts(psSysData, ui32ClearInterrupts);
}
}
return bStatus;
}
static IMG_VOID PVRSRVMISR_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
{
if(psDeviceNode->pfnDeviceMISR != IMG_NULL)
{
(*psDeviceNode->pfnDeviceMISR)(psDeviceNode->pvISRData);
}
}
IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData)
{
SYS_DATA *psSysData = pvSysData;
if(!psSysData)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVMISR: Invalid params\n"));
return;
}
List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
&PVRSRVMISR_ForEachCb);
if (PVRSRVProcessQueues(IMG_FALSE) == PVRSRV_ERROR_PROCESSING_BLOCKED)
{
PVRSRVProcessQueues(IMG_FALSE);
}
if (psSysData->psGlobalEventObject)
{
IMG_HANDLE hOSEventKM = psSysData->psGlobalEventObject->hOSEventKM;
if(hOSEventKM)
{
OSEventObjectSignalKM(hOSEventKM);
}
}
}
IMG_EXPORT
PVRSRV_ERROR IMG_CALLCONV PVRSRVProcessConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags)
{
return PVRSRVPerProcessDataConnect(ui32PID, ui32Flags);
}
IMG_EXPORT
IMG_VOID IMG_CALLCONV PVRSRVProcessDisconnect(IMG_UINT32 ui32PID)
{
PVRSRVPerProcessDataDisconnect(ui32PID);
}
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;
while (RA_GetNextLiveSegment(hArena, &sSegDetails))
{
if (pbyBuffer == IMG_NULL)
{
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));
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)
{
OSMemCopy(pbyBuffer, &sSegDetails.uiSize, sizeof(sSegDetails.uiSize));
pbyBuffer += sizeof(sSegDetails.uiSize);
OSMemCopy(pbyBuffer, pvLocalMemCPUVAddr, sSegDetails.uiSize);
pbyBuffer += sSegDetails.uiSize;
}
else
{
IMG_UINT32 uiSize;
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);
}
IMG_EXPORT
const IMG_CHAR *PVRSRVGetErrorStringKM(PVRSRV_ERROR eError)
{
#include "pvrsrv_errors.h"
}
static IMG_VOID PVRSRVCommandCompleteCallbacks_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
{
if(psDeviceNode->pfnDeviceCommandComplete != IMG_NULL)
{
(*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode);
}
}
IMG_VOID PVRSRVScheduleDeviceCallbacks(IMG_VOID)
{
SYS_DATA *psSysData;
SysAcquireData(&psSysData);
List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
&PVRSRVCommandCompleteCallbacks_ForEachCb);
}
IMG_EXPORT
IMG_VOID PVRSRVScheduleDevicesKM(IMG_VOID)
{
PVRSRVScheduleDeviceCallbacks();
}