blob: f54d029a632e2aea40ff521ecebaa51cdc6d0d43 [file] [log] [blame]
/*************************************************************************/ /*!
@File
@Title PVR Common Bridge Module (kernel side)
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@Description Implements core PVRSRV API, server side
@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 <stddef.h>
#include "img_defs.h"
#include "pvr_debug.h"
#include "ra.h"
#include "pvr_bridge.h"
#include "connection_server.h"
#include "device.h"
#include "htbuffer.h"
#include "pdump_km.h"
#include "srvkm.h"
#include "allocmem.h"
#include "devicemem.h"
#include "srvcore.h"
#include "rgxinit.h"
#include "pvrsrv.h"
#include "power.h"
#include "lists.h"
#include "rgxdevice.h"
#include "rgx_options.h"
#include "pvrversion.h"
#include "lock.h"
#include "osfunc.h"
#include "device_connection.h"
#include "rgxdevice.h"
#if defined(SUPPORT_GPUVIRT_VALIDATION)
#include "physmem_lma.h"
#include "services_km.h"
#endif
#include "pvrsrv_tlstreams.h"
#include "tlstream.h"
/* For the purpose of maintainability, it is intended that this file should not
* contain any OS specific #ifdefs. Please find a way to add e.g.
* an osfunc.c abstraction or override the entire function in question within
* env,*,pvr_bridge_k.c
*/
PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY g_BridgeDispatchTable[BRIDGE_DISPATCH_TABLE_ENTRY_COUNT] = { {.pfFunction = DummyBW,} ,};
#define PVR_DISPATCH_OFFSET_FIRST_FUNC 0
#define PVR_DISPATCH_OFFSET_LAST_FUNC 1
#define PVR_DISPATCH_OFFSET_ARRAY_MAX 2
#define PVR_BUFFER_POOL_MAX 10
typedef struct
{
IMG_BOOL bTaken;
void *pvBuffer;
} PVR_POOL_BUFFER;
static struct
{
POS_LOCK hLock;
IMG_UINT uiCount;
PVR_POOL_BUFFER asPool[PVR_BUFFER_POOL_MAX];
} *g_psBridgePool = NULL;
static IMG_UINT16 g_BridgeDispatchTableStartOffsets[BRIDGE_DISPATCH_TABLE_START_ENTRY_COUNT][PVR_DISPATCH_OFFSET_ARRAY_MAX];
#if defined(DEBUG_BRIDGE_KM)
/* a lock used for protecting bridge call timing calculations
* for calls which do not acquire a lock
*/
POS_LOCK g_hStatsLock;
PVRSRV_BRIDGE_GLOBAL_STATS g_BridgeGlobalStats;
#endif
void BridgeDispatchTableStartOffsetsInit(void)
{
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEFAULT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DEFAULT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEFAULT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DEFAULT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SRVCORE][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SRVCORE_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SRVCORE][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SRVCORE_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNC][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SYNC_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNC][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SYNC_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCEXPORT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SYNCEXPORT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCEXPORT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SYNCEXPORT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCSEXPORT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SYNCSEXPORT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCSEXPORT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SYNCSEXPORT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMPCTRL][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_PDUMPCTRL_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMPCTRL][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_PDUMPCTRL_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MM][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_MM_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MM][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_MM_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MMPLAT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_MMPLAT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MMPLAT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_MMPLAT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_CMM][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_CMM_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_CMM][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_CMM_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMPMM][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_PDUMPMM_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMPMM][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_PDUMPMM_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMP][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_PDUMP_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PDUMP][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_PDUMP_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DMABUF][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DMABUF_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DMABUF][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DMABUF_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DC][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DC_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DC][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DC_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_CACHE][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_CACHE_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_CACHE][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_CACHE_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SMM][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SMM_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SMM][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SMM_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PVRTL][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_PVRTL_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_PVRTL][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_PVRTL_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RI][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RI_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RI][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RI_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_VALIDATION][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_VALIDATION_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_VALIDATION][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_VALIDATION_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_TUTILS][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_TUTILS_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_TUTILS][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_TUTILS_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEVICEMEMHISTORY][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DEVICEMEMHISTORY_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEVICEMEMHISTORY][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DEVICEMEMHISTORY_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_HTBUFFER][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_HTBUFFER_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_HTBUFFER][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_HTBUFFER_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DCPLAT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DCPLAT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DCPLAT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DCPLAT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MMEXTMEM][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_MMEXTMEM_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_MMEXTMEM][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_MMEXTMEM_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCTRACKING][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_SYNCTRACKING_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_SYNCTRACKING][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_SYNCTRACKING_DISPATCH_LAST;
#if defined(SUPPORT_RGX)
/* Need a gap here to start next entry at element 128 */
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTQ][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXTQ_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTQ][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXTQ_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXCMP][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXCMP_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXCMP][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXCMP_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXINIT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXINIT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXINIT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXINIT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTA3D][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXTA3D_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTA3D][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXTA3D_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_BREAKPOINT][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_BREAKPOINT_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_BREAKPOINT][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_BREAKPOINT_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEBUGMISC][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_DEBUGMISC_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_DEBUGMISC][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_DEBUGMISC_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXPDUMP][PVR_DISPATCH_OFFSET_FIRST_FUNC]= PVRSRV_BRIDGE_RGXPDUMP_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXPDUMP][PVR_DISPATCH_OFFSET_LAST_FUNC]= PVRSRV_BRIDGE_RGXPDUMP_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXHWPERF][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXHWPERF_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXHWPERF][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXHWPERF_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXRAY][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXRAY_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXRAY][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXRAY_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_REGCONFIG][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_REGCONFIG_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_REGCONFIG][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_REGCONFIG_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_TIMERQUERY][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_TIMERQUERY_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_TIMERQUERY][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_TIMERQUERY_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXKICKSYNC][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXKICKSYNC_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXKICKSYNC][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXKICKSYNC_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXSIGNALS][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXSIGNALS_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXSIGNALS][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXSIGNALS_DISPATCH_LAST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTQ2][PVR_DISPATCH_OFFSET_FIRST_FUNC] = PVRSRV_BRIDGE_RGXTQ2_DISPATCH_FIRST;
g_BridgeDispatchTableStartOffsets[PVRSRV_BRIDGE_RGXTQ2][PVR_DISPATCH_OFFSET_LAST_FUNC] = PVRSRV_BRIDGE_RGXTQ2_DISPATCH_LAST;
#endif
}
#if defined(DEBUG_BRIDGE_KM)
PVRSRV_ERROR
CopyFromUserWrapper(CONNECTION_DATA *psConnection,
IMG_UINT32 ui32DispatchTableEntry,
void *pvDest,
void *pvSrc,
IMG_UINT32 ui32Size)
{
g_BridgeDispatchTable[ui32DispatchTableEntry].ui32CopyFromUserTotalBytes+=ui32Size;
g_BridgeGlobalStats.ui32TotalCopyFromUserBytes+=ui32Size;
return OSBridgeCopyFromUser(psConnection, pvDest, pvSrc, ui32Size);
}
PVRSRV_ERROR
CopyToUserWrapper(CONNECTION_DATA *psConnection,
IMG_UINT32 ui32DispatchTableEntry,
void *pvDest,
void *pvSrc,
IMG_UINT32 ui32Size)
{
g_BridgeDispatchTable[ui32DispatchTableEntry].ui32CopyToUserTotalBytes+=ui32Size;
g_BridgeGlobalStats.ui32TotalCopyToUserBytes+=ui32Size;
return OSBridgeCopyToUser(psConnection, pvDest, pvSrc, ui32Size);
}
#else
INLINE PVRSRV_ERROR
CopyFromUserWrapper(CONNECTION_DATA *psConnection,
IMG_UINT32 ui32DispatchTableEntry,
void *pvDest,
void *pvSrc,
IMG_UINT32 ui32Size)
{
PVR_UNREFERENCED_PARAMETER (ui32DispatchTableEntry);
return OSBridgeCopyFromUser(psConnection, pvDest, pvSrc, ui32Size);
}
INLINE PVRSRV_ERROR
CopyToUserWrapper(CONNECTION_DATA *psConnection,
IMG_UINT32 ui32DispatchTableEntry,
void *pvDest,
void *pvSrc,
IMG_UINT32 ui32Size)
{
PVR_UNREFERENCED_PARAMETER (ui32DispatchTableEntry);
return OSBridgeCopyToUser(psConnection, pvDest, pvSrc, ui32Size);
}
#endif
PVRSRV_ERROR
PVRSRVConnectKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE * psDeviceNode,
IMG_UINT32 ui32Flags,
IMG_UINT32 ui32ClientBuildOptions,
IMG_UINT32 ui32ClientDDKVersion,
IMG_UINT32 ui32ClientDDKBuild,
IMG_UINT8 *pui8KernelArch,
IMG_UINT32 *pui32CapabilityFlags,
IMG_UINT32 *ui32PVRBridges,
IMG_UINT32 *ui32RGXBridges)
{
PVRSRV_ERROR eError = PVRSRV_OK;
IMG_UINT32 ui32BuildOptions, ui32BuildOptionsMismatch;
IMG_UINT32 ui32DDKVersion, ui32DDKBuild;
PVRSRV_DATA *psSRVData = NULL;
IMG_UINT64 ui64ProcessVASpaceSize = OSGetCurrentProcessVASpaceSize();
static IMG_BOOL bIsFirstConnection=IMG_FALSE;
PVRSRV_RGXDEV_INFO *psDevInfo;
/* Clear the flags */
*pui32CapabilityFlags = 0;
psDevInfo = (PVRSRV_RGXDEV_INFO *) psDeviceNode->pvDevice;
psSRVData = PVRSRVGetPVRSRVData();
psConnection->ui32ClientFlags = ui32Flags;
/* output the available bridges */
*ui32PVRBridges = gui32PVRBridges;
*ui32RGXBridges = gui32RGXBridges;
/*Set flags to pass back to the client showing which cache coherency is available.*/
/*Is the system CPU cache coherent?*/
if (PVRSRVSystemSnoopingOfCPUCache(psDeviceNode->psDevConfig))
{
*pui32CapabilityFlags |= PVRSRV_CACHE_COHERENT_DEVICE_FLAG;
}
/*Is the system device cache coherent?*/
if (PVRSRVSystemSnoopingOfDeviceCache(psDeviceNode->psDevConfig))
{
*pui32CapabilityFlags |= PVRSRV_CACHE_COHERENT_CPU_FLAG;
}
/* Has the system device non-mappable local memory?*/
if (PVRSRVSystemHasNonMappableLocalMemory(psDeviceNode->psDevConfig))
{
*pui32CapabilityFlags |= PVRSRV_NONMAPPABLE_MEMORY_PRESENT_FLAG;
}
/* Set flags to indicate shared-virtual-memory (SVM) allocation availability */
if (! psDeviceNode->ui64GeneralSVMHeapTopVA || ! ui64ProcessVASpaceSize)
{
*pui32CapabilityFlags |= PVRSRV_DEVMEM_SVM_ALLOC_UNSUPPORTED;
}
else
{
if (ui64ProcessVASpaceSize <= psDeviceNode->ui64GeneralSVMHeapTopVA)
{
*pui32CapabilityFlags |= PVRSRV_DEVMEM_SVM_ALLOC_SUPPORTED;
}
else
{
/* This can happen when processor has more virtual address bits
than device (i.e. alloc is not always guaranteed to succeed) */
*pui32CapabilityFlags |= PVRSRV_DEVMEM_SVM_ALLOC_CANFAIL;
}
}
#if defined(SUPPORT_GPUVIRT_VALIDATION)
{
IMG_UINT32 ui32OSid = 0, ui32OSidReg = 0;
IMG_BOOL bOSidAxiProtReg = IMG_FALSE;
IMG_PID pIDCurrent = OSGetCurrentClientProcessIDKM();
ui32OSid = (ui32Flags & SRV_VIRTVAL_FLAG_OSID_MASK) >> (VIRTVAL_FLAG_OSID_SHIFT);
ui32OSidReg = (ui32Flags & SRV_VIRTVAL_FLAG_OSIDREG_MASK) >> (VIRTVAL_FLAG_OSIDREG_SHIFT);
#if defined(EMULATOR)
if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_AXI_ACELITE_BIT_MASK)
{
IMG_UINT32 ui32OSidAxiProtReg = 0, ui32OSidAxiProtTD = 0;
ui32OSidAxiProtReg = (ui32Flags & SRV_VIRTVAL_FLAG_AXIPREG_MASK) >> (VIRTVAL_FLAG_AXIPREG_SHIFT);
ui32OSidAxiProtTD = (ui32Flags & SRV_VIRTVAL_FLAG_AXIPTD_MASK) >> (VIRTVAL_FLAG_AXIPTD_SHIFT);
PVR_DPF((PVR_DBG_MESSAGE,
"[AxiProt & Virt]: Setting bOSidAxiProt of Emulator's Trusted Device for Catbase %d to %s",
ui32OSidReg,
(ui32OSidAxiProtTD == 1)?"TRUE":"FALSE"));
bOSidAxiProtReg = ui32OSidAxiProtReg == 1;
PVR_DPF((PVR_DBG_MESSAGE,
"[AxiProt & Virt]: Setting bOSidAxiProt of FW's Register for Catbase %d to %s",
ui32OSidReg,
bOSidAxiProtReg?"TRUE":"FALSE"));
SetAxiProtOSid(ui32OSidReg, ui32OSidAxiProtTD);
}
#endif
InsertPidOSidsCoupling(pIDCurrent, ui32OSid, ui32OSidReg, bOSidAxiProtReg);
PVR_DPF((PVR_DBG_MESSAGE,"[GPU Virtualization Validation]: OSIDs: %d, %d\n",ui32OSid, ui32OSidReg));
}
#endif
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* Only enable if enabled in the UM */
if(ui32Flags & SRV_WORKEST_ENABLED)
{
psDevInfo->bWorkEstEnabled = IMG_TRUE;
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVConnectKM: Workload Estimation disabled. Not enabled in UM."));
}
#endif
#if defined(SUPPORT_PDVFS)
/* Only enable if enabled in the UM */
if(ui32Flags & SRV_PDVFS_ENABLED)
{
psDevInfo->bPDVFSEnabled = IMG_TRUE;
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVConnectKM: Proactive DVFS disabled. Not enabled in UM."));
}
#endif
if (ui32Flags & SRV_FLAGS_INIT_PROCESS)
#if defined(SUPPORT_KERNEL_SRVINIT)
{
return PVRSRV_ERROR_NOT_SUPPORTED;
}
#else
{
PVR_DPF((PVR_DBG_MESSAGE, "%s: Connecting as init process", __func__));
if ((OSProcHasPrivSrvInit() == IMG_FALSE) || PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING) || PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN))
{
PVR_DPF((PVR_DBG_ERROR, "%s: Rejecting init process", __func__));
eError = PVRSRV_ERROR_SRV_CONNECT_FAILED;
goto chk_exit;
}
#if defined (__linux__) || defined(INTEGRITY_OS)
PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RUNNING, IMG_TRUE);
#endif
}
else
{
/*
* This check has to be done here (before the client against kernel check)
* while the client options have not yet been modified
*/
#if !defined(PVRSRV_GPUVIRT_GUESTDRV)
eError = RGXClientConnectCompatCheck_ClientAgainstFW(psDeviceNode, ui32ClientBuildOptions);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Initialisation failed. Mismatch between client and firmware build options.",
__FUNCTION__));
eError = PVRSRV_ERROR_BUILD_OPTIONS_MISMATCH;
goto chk_exit;
}
#endif
if(PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RAN))
{
if (!PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL))
{
PVR_DPF((PVR_DBG_ERROR, "%s: Initialisation failed. Driver unusable.",
__FUNCTION__));
eError = PVRSRV_ERROR_INIT_FAILURE;
goto chk_exit;
}
}
else
{
if(PVRSRVGetInitServerState(PVRSRV_INIT_SERVER_RUNNING))
{
PVR_DPF((PVR_DBG_ERROR, "%s: Initialisation is in progress",
__FUNCTION__));
eError = PVRSRV_ERROR_RETRY;
goto chk_exit;
}
else
{
PVR_DPF((PVR_DBG_ERROR, "%s: Driver initialisation not completed yet.",
__FUNCTION__));
eError = PVRSRV_ERROR_RETRY;
goto chk_exit;
}
}
}
#endif /* defined(SUPPORT_KERNEL_SRVINIT) */
ui32DDKVersion = PVRVERSION_PACK(PVRVERSION_MAJ, PVRVERSION_MIN);
ui32DDKBuild = PVRVERSION_BUILD;
if(IMG_FALSE == bIsFirstConnection)
{
psSRVData->sDriverInfo.sKMBuildInfo.ui32BuildOptions = (RGX_BUILD_OPTIONS_KM);
psSRVData->sDriverInfo.sUMBuildInfo.ui32BuildOptions = ui32ClientBuildOptions;
psSRVData->sDriverInfo.sKMBuildInfo.ui32BuildVersion = ui32DDKVersion;
psSRVData->sDriverInfo.sUMBuildInfo.ui32BuildVersion = ui32ClientDDKVersion;
psSRVData->sDriverInfo.sKMBuildInfo.ui32BuildRevision = ui32DDKBuild;
psSRVData->sDriverInfo.sUMBuildInfo.ui32BuildRevision = ui32ClientDDKBuild;
psSRVData->sDriverInfo.sKMBuildInfo.ui32BuildType = ((RGX_BUILD_OPTIONS_KM) & OPTIONS_DEBUG_MASK)? \
BUILD_TYPE_DEBUG:BUILD_TYPE_RELEASE;
psSRVData->sDriverInfo.sUMBuildInfo.ui32BuildType = (ui32ClientBuildOptions & OPTIONS_DEBUG_MASK)? \
BUILD_TYPE_DEBUG:BUILD_TYPE_RELEASE;
}
/* Masking out every option that is not kernel specific*/
ui32ClientBuildOptions &= RGX_BUILD_OPTIONS_MASK_KM;
/*
* Validate the build options
*/
ui32BuildOptions = (RGX_BUILD_OPTIONS_KM);
if (ui32BuildOptions != ui32ClientBuildOptions)
{
ui32BuildOptionsMismatch = ui32BuildOptions ^ ui32ClientBuildOptions;
#if !defined(PVRSRV_STRICT_COMPAT_CHECK)
/*Mask the debug flag option out as we do support combinations of debug vs release in um & km*/
ui32BuildOptionsMismatch &= ~OPTIONS_DEBUG_MASK;
#endif
if ( (ui32ClientBuildOptions & ui32BuildOptionsMismatch) != 0)
{
PVR_LOG(("(FAIL) %s: Mismatch in client-side and KM driver build options; "
"extra options present in client-side driver: (0x%x). Please check rgx_options.h",
__FUNCTION__,
ui32ClientBuildOptions & ui32BuildOptionsMismatch ));
eError = PVRSRV_ERROR_BUILD_OPTIONS_MISMATCH;
goto chk_exit;
}
if ( (ui32BuildOptions & ui32BuildOptionsMismatch) != 0)
{
PVR_LOG(("(FAIL) %s: Mismatch in client-side and KM driver build options; "
"extra options present in KM driver: (0x%x). Please check rgx_options.h",
__FUNCTION__,
ui32BuildOptions & ui32BuildOptionsMismatch ));
eError = PVRSRV_ERROR_BUILD_OPTIONS_MISMATCH;
goto chk_exit;
}
if(IMG_FALSE == bIsFirstConnection)
{
PVR_LOG(("%s: COMPAT_TEST: Client-side (0x%04x) (%s) and KM driver (0x%04x) (%s) build options differ.",
__FUNCTION__,
ui32ClientBuildOptions,
(psSRVData->sDriverInfo.sUMBuildInfo.ui32BuildType)?"release":"debug",
ui32BuildOptions,
(psSRVData->sDriverInfo.sKMBuildInfo.ui32BuildType)?"release":"debug"));
}else{
PVR_DPF((PVR_DBG_WARNING, "%s: COMPAT_TEST: Client-side (0x%04x) and KM driver (0x%04x) build options differ.",
__FUNCTION__,
ui32ClientBuildOptions,
ui32BuildOptions));
}
if(!psSRVData->sDriverInfo.bIsNoMatch)
psSRVData->sDriverInfo.bIsNoMatch = IMG_TRUE;
}
else
{
PVR_DPF((PVR_DBG_MESSAGE, "%s: COMPAT_TEST: Client-side and KM driver build options match. [ OK ]", __FUNCTION__));
}
/*
* Validate DDK version
*/
if (ui32ClientDDKVersion != ui32DDKVersion)
{
if(!psSRVData->sDriverInfo.bIsNoMatch)
psSRVData->sDriverInfo.bIsNoMatch = IMG_TRUE;
PVR_LOG(("(FAIL) %s: Incompatible driver DDK version (%u.%u) / client DDK version (%u.%u).",
__FUNCTION__,
PVRVERSION_MAJ, PVRVERSION_MIN,
PVRVERSION_UNPACK_MAJ(ui32ClientDDKVersion),
PVRVERSION_UNPACK_MIN(ui32ClientDDKVersion)));
eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH;
PVR_DBG_BREAK;
goto chk_exit;
}
else
{
PVR_DPF((PVR_DBG_MESSAGE, "%s: COMPAT_TEST: driver DDK version (%u.%u) and client DDK version (%u.%u) match. [ OK ]",
__FUNCTION__,
PVRVERSION_MAJ, PVRVERSION_MIN, PVRVERSION_MAJ, PVRVERSION_MIN));
}
/* Create stream for every connection except for the special clients
* that doesn't need it e.g.: recipients of HWPerf data. */
if (!(psConnection->ui32ClientFlags & SRV_NO_HWPERF_CLIENT_STREAM))
{
IMG_CHAR acStreamName[PRVSRVTL_MAX_STREAM_NAME_SIZE];
OSSNPrintf(acStreamName, PRVSRVTL_MAX_STREAM_NAME_SIZE,
PVRSRV_TL_HWPERF_HOST_CLIENT_STREAM_FMTSPEC,
psConnection->pid);
eError = TLStreamCreate(&psConnection->hClientTLStream, acStreamName,
131072, TL_FLAG_ALLOCATE_ON_FIRST_OPEN, NULL,
NULL, NULL, NULL);
if (eError != PVRSRV_OK && eError != PVRSRV_ERROR_ALREADY_EXISTS)
{
PVR_DPF((PVR_DBG_ERROR, "Could not create private TL stream (%s)",
PVRSRVGetErrorStringKM(eError)));
psConnection->hClientTLStream = NULL;
}
/* Reset error status. We don't want to propagate any errors from here. */
eError = PVRSRV_OK;
PVR_DPF((PVR_DBG_MESSAGE, "Created stream \"%s\".", acStreamName));
}
/*
* Validate DDK build
*/
if (ui32ClientDDKBuild != ui32DDKBuild)
{
if(!psSRVData->sDriverInfo.bIsNoMatch)
psSRVData->sDriverInfo.bIsNoMatch = IMG_TRUE;
PVR_DPF((PVR_DBG_WARNING, "%s: Mismatch in driver DDK revision (%d) / client DDK revision (%d).",
__FUNCTION__, ui32DDKBuild, ui32ClientDDKBuild));
#if defined(PVRSRV_STRICT_COMPAT_CHECK)
eError = PVRSRV_ERROR_DDK_BUILD_MISMATCH;
PVR_DBG_BREAK;
goto chk_exit;
#endif
}
else
{
PVR_DPF((PVR_DBG_MESSAGE, "%s: COMPAT_TEST: driver DDK revision (%d) and client DDK revision (%d) match. [ OK ]",
__FUNCTION__, ui32DDKBuild, ui32ClientDDKBuild));
}
/* Success so far so is it the PDump client that is connecting? */
if (ui32Flags & SRV_FLAGS_PDUMPCTRL)
{
PDumpConnectionNotify();
}
PVR_ASSERT(pui8KernelArch != NULL);
/* Can't use __SIZEOF_POINTER__ here as it is not defined on Windows */
if (sizeof(void *) == 8)
{
*pui8KernelArch = 64;
}
else
{
*pui8KernelArch = 32;
}
bIsFirstConnection = IMG_TRUE;
#if defined(DEBUG_BRIDGE_KM)
{
int ii;
/* dump dispatch table offset lookup table */
PVR_DPF((PVR_DBG_MESSAGE, "%s: g_BridgeDispatchTableStartOffsets[0-%lu] entries:", __FUNCTION__, BRIDGE_DISPATCH_TABLE_START_ENTRY_COUNT - 1));
for (ii=0; ii < BRIDGE_DISPATCH_TABLE_START_ENTRY_COUNT; ii++)
{
PVR_DPF((PVR_DBG_MESSAGE, "g_BridgeDispatchTableStartOffsets[%d]: %u", ii, g_BridgeDispatchTableStartOffsets[ii][PVR_DISPATCH_OFFSET_FIRST_FUNC]));
}
}
#endif
if (ui32Flags & SRV_FLAGS_INIT_PROCESS)
{
#if defined(SUPPORT_KERNEL_SRVINIT)
eError = PVRSRV_ERROR_INVALID_PARAMS;
#endif
}
chk_exit:
return eError;
}
PVRSRV_ERROR
PVRSRVDisconnectKM(void)
{
/* just return OK, per-process data is cleaned up by resmgr */
return PVRSRV_OK;
}
/**************************************************************************/ /*!
@Function PVRSRVAcquireGlobalEventObjectKM
@Description Acquire the global event object.
@Output phGlobalEventObject On success, points to the global event
object handle
@Return PVRSRV_ERROR PVRSRV_OK on success or an error
otherwise
*/ /***************************************************************************/
PVRSRV_ERROR
PVRSRVAcquireGlobalEventObjectKM(IMG_HANDLE *phGlobalEventObject)
{
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
*phGlobalEventObject = psPVRSRVData->hGlobalEventObject;
return PVRSRV_OK;
}
/**************************************************************************/ /*!
@Function PVRSRVReleaseGlobalEventObjectKM
@Description Release the global event object.
@Output hGlobalEventObject Global event object handle
@Return PVRSRV_ERROR PVRSRV_OK on success or an error otherwise
*/ /***************************************************************************/
PVRSRV_ERROR
PVRSRVReleaseGlobalEventObjectKM(IMG_HANDLE hGlobalEventObject)
{
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
PVR_ASSERT(psPVRSRVData->hGlobalEventObject == hGlobalEventObject);
return PVRSRV_OK;
}
/*
PVRSRVDumpDebugInfoKM
*/
PVRSRV_ERROR
PVRSRVDumpDebugInfoKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 ui32VerbLevel)
{
if (ui32VerbLevel > DEBUG_REQUEST_VERBOSITY_MAX)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
PVR_LOG(("User requested PVR debug info"));
PVRSRVDebugRequest(psDeviceNode, ui32VerbLevel, NULL, NULL);
return PVRSRV_OK;
}
/*
PVRSRVGetDevClockSpeedKM
*/
PVRSRV_ERROR
PVRSRVGetDevClockSpeedKM(CONNECTION_DATA * psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_PUINT32 pui32RGXClockSpeed)
{
PVRSRV_ERROR eError = PVRSRV_OK;
PVR_ASSERT(psDeviceNode->pfnDeviceClockSpeed != NULL);
PVR_UNREFERENCED_PARAMETER(psConnection);
eError = psDeviceNode->pfnDeviceClockSpeed(psDeviceNode, pui32RGXClockSpeed);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetDevClockSpeedKM: "
"Could not get device clock speed (%d)!",
eError));
}
return eError;
}
/*
PVRSRVHWOpTimeoutKM
*/
PVRSRV_ERROR
PVRSRVHWOpTimeoutKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode)
{
#if defined(PVRSRV_RESET_ON_HWTIMEOUT)
PVR_LOG(("User requested OS reset"));
OSPanic();
#endif
PVR_LOG(("HW operation timeout, dump server info"));
PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MEDIUM, NULL, NULL);
return PVRSRV_OK;
}
IMG_INT
DummyBW(IMG_UINT32 ui32DispatchTableEntry,
void *psBridgeIn,
void *psBridgeOut,
CONNECTION_DATA *psConnection)
{
PVR_UNREFERENCED_PARAMETER(psBridgeIn);
PVR_UNREFERENCED_PARAMETER(psBridgeOut);
PVR_UNREFERENCED_PARAMETER(psConnection);
#if defined(DEBUG_BRIDGE_KM)
PVR_DPF((PVR_DBG_ERROR, "%s: BRIDGE ERROR: ui32DispatchTableEntry %u (%s) mapped to "
"Dummy Wrapper (probably not what you want!)",
__FUNCTION__, ui32DispatchTableEntry, g_BridgeDispatchTable[ui32DispatchTableEntry].pszIOCName));
#else
PVR_DPF((PVR_DBG_ERROR, "%s: BRIDGE ERROR: ui32DispatchTableEntry %u mapped to "
"Dummy Wrapper (probably not what you want!)",
__FUNCTION__, ui32DispatchTableEntry));
#endif
return PVRSRV_ERROR_BRIDGE_ENOTTY;
}
#if defined(SUPPORT_KERNEL_SRVINIT)
PVRSRV_ERROR PVRSRVAlignmentCheckKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 ui32AlignChecksSize,
IMG_UINT32 aui32AlignChecks[])
{
PVR_UNREFERENCED_PARAMETER(psConnection);
#if !defined(NO_HARDWARE) && defined(RGXFW_ALIGNCHECKS)
PVR_ASSERT(psDeviceNode->pfnAlignmentCheck != NULL);
return psDeviceNode->pfnAlignmentCheck(psDeviceNode, ui32AlignChecksSize,
aui32AlignChecks);
#else
PVR_UNREFERENCED_PARAMETER(psDeviceNode);
PVR_UNREFERENCED_PARAMETER(ui32AlignChecksSize);
PVR_UNREFERENCED_PARAMETER(aui32AlignChecks);
return PVRSRV_OK;
#endif /* !defined(NO_HARDWARE) */
}
#endif /* defined(SUPPORT_KERNEL_SRVINIT) */
PVRSRV_ERROR PVRSRVGetDeviceStatusKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 *pui32DeviceStatus)
{
PVR_UNREFERENCED_PARAMETER(psConnection);
/* First try to update the status. */
if (psDeviceNode->pfnUpdateHealthStatus != NULL)
{
PVRSRV_ERROR eError = psDeviceNode->pfnUpdateHealthStatus(psDeviceNode,
IMG_FALSE);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetDeviceStatusKM: Failed to"
"check for device status (%d)", eError));
/* Return unknown status and error because we don't know what
* happened and if the status is valid. */
*pui32DeviceStatus = PVRSRV_DEVICE_STATUS_UNKNOWN;
return eError;
}
}
switch (OSAtomicRead(&psDeviceNode->eHealthStatus))
{
case PVRSRV_DEVICE_HEALTH_STATUS_OK:
*pui32DeviceStatus = PVRSRV_DEVICE_STATUS_OK;
return PVRSRV_OK;
case PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING:
*pui32DeviceStatus = PVRSRV_DEVICE_STATUS_NOT_RESPONDING;
return PVRSRV_OK;
case PVRSRV_DEVICE_HEALTH_STATUS_DEAD:
*pui32DeviceStatus = PVRSRV_DEVICE_STATUS_DEVICE_ERROR;
return PVRSRV_OK;
default:
*pui32DeviceStatus = PVRSRV_DEVICE_STATUS_UNKNOWN;
return PVRSRV_ERROR_INTERNAL_ERROR;
}
}
/*!
* *****************************************************************************
* @brief A wrapper for filling in the g_BridgeDispatchTable array that does
* error checking.
*
* @param ui32Index
* @param pszIOCName
* @param pfFunction
* @param pszFunctionName
*
* @return
********************************************************************************/
void
_SetDispatchTableEntry(IMG_UINT32 ui32BridgeGroup,
IMG_UINT32 ui32Index,
const IMG_CHAR *pszIOCName,
BridgeWrapperFunction pfFunction,
const IMG_CHAR *pszFunctionName,
POS_LOCK hBridgeLock,
const IMG_CHAR *pszBridgeLockName,
IMG_BOOL bUseLock)
{
static IMG_UINT32 ui32PrevIndex = IMG_UINT32_MAX; /* -1 */
#if !defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE) && !defined(DEBUG_BRIDGE_KM)
PVR_UNREFERENCED_PARAMETER(pszFunctionName);
PVR_UNREFERENCED_PARAMETER(pszBridgeLockName);
#endif
ui32Index += g_BridgeDispatchTableStartOffsets[ui32BridgeGroup][PVR_DISPATCH_OFFSET_FIRST_FUNC];
#if defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE)
/* Enable this to dump out the dispatch table entries */
PVR_DPF((PVR_DBG_WARNING, "%s: g_BridgeDispatchTableStartOffsets[%d]=%d", __FUNCTION__, ui32BridgeGroup, g_BridgeDispatchTableStartOffsets[ui32BridgeGroup][PVR_DISPATCH_OFFSET_FIRST_FUNC]));
PVR_DPF((PVR_DBG_WARNING, "%s: %d %s %s %s", __FUNCTION__, ui32Index, pszIOCName, pszFunctionName, pszBridgeLockName));
#endif
/* Any gaps are sub-optimal in-terms of memory usage, but we are mainly
* interested in spotting any large gap of wasted memory that could be
* accidentally introduced.
*
* This will currently flag up any gaps > 5 entries.
*
* NOTE: This shouldn't be debug only since switching from debug->release
* etc is likely to modify the available ioctls and thus be a point where
* mistakes are exposed. This isn't run at a performance critical time.
*/
if((ui32PrevIndex != IMG_UINT32_MAX) &&
((ui32Index >= ui32PrevIndex + DISPATCH_TABLE_GAP_THRESHOLD) ||
(ui32Index <= ui32PrevIndex)))
{
#if defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE)
PVR_DPF((PVR_DBG_WARNING,
"%s: There is a gap in the dispatch table between indices %u (%s) and %u (%s)",
__FUNCTION__, ui32PrevIndex, g_BridgeDispatchTable[ui32PrevIndex].pszIOCName,
ui32Index, pszIOCName));
#else
PVR_DPF((PVR_DBG_MESSAGE,
"%s: There is a gap in the dispatch table between indices %u and %u (%s)",
__FUNCTION__, (IMG_UINT)ui32PrevIndex, (IMG_UINT)ui32Index, pszIOCName));
#endif
}
if (ui32Index >= BRIDGE_DISPATCH_TABLE_ENTRY_COUNT)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Index %u (%s) out of range",
__FUNCTION__, (IMG_UINT)ui32Index, pszIOCName));
#if defined(DEBUG_BRIDGE_KM)
PVR_DPF((PVR_DBG_ERROR, "%s: BRIDGE_DISPATCH_TABLE_ENTRY_COUNT = %lu",
__FUNCTION__, BRIDGE_DISPATCH_TABLE_ENTRY_COUNT));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_TIMERQUERY_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_TIMERQUERY_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_REGCONFIG_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_REGCONFIG_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXRAY_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXRAY_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXHWPERF_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXHWPERF_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXPDUMP_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXPDUMP_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_DEBUGMISC_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_DEBUGMISC_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_BREAKPOINT_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_BREAKPOINT_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXTA3D_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXTA3D_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXINIT_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXINIT_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXCMP_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGXCMP_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGXTQ_DISPATCH_LAST = %lu\n",
__FUNCTION__, PVRSRV_BRIDGE_RGXTQ_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGX_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGX_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_RGX_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_RGX_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_DEVICEMEMHISTORY_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_DEVICEMEMHISTORY_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_TUTILS_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_TUTILS_DISPATCH_LAST));
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRV_BRIDGE_VALIDATION_DISPATCH_LAST = %lu",
__FUNCTION__, PVRSRV_BRIDGE_VALIDATION_DISPATCH_LAST));
#endif
OSPanic();
}
/* Panic if the previous entry has been overwritten as this is not allowed!
* NOTE: This shouldn't be debug only since switching from debug->release
* etc is likely to modify the available ioctls and thus be a point where
* mistakes are exposed. This isn't run at a performance critical time.
*/
if(g_BridgeDispatchTable[ui32Index].pfFunction)
{
if(g_BridgeDispatchTable[ui32Index].pfFunction != pfFunction)
{
#if defined(DEBUG_BRIDGE_KM_DISPATCH_TABLE)
PVR_DPF((PVR_DBG_ERROR,
"%s: Adding dispatch table entry for %s clobbers an existing entry for %s (current pfn=<%p>, new pfn=<%p>)",
__FUNCTION__, pszIOCName, g_BridgeDispatchTable[ui32Index].pszIOCName),
(void*)g_BridgeDispatchTable[ui32Index].pfFunction, (void*)pfFunction));
#else
PVR_DPF((PVR_DBG_ERROR,
"%s: Adding dispatch table entry for %s clobbers an existing entry (index=%u). (current pfn=<%p>, new pfn=<%p>)",
__FUNCTION__, pszIOCName, ui32Index,
(void*)g_BridgeDispatchTable[ui32Index].pfFunction, (void*)pfFunction));
PVR_DPF((PVR_DBG_WARNING, "NOTE: Enabling DEBUG_BRIDGE_KM_DISPATCH_TABLE may help debug this issue."));
#endif
OSPanic();
}
}
else
{
g_BridgeDispatchTable[ui32Index].pfFunction = pfFunction;
g_BridgeDispatchTable[ui32Index].hBridgeLock = hBridgeLock;
g_BridgeDispatchTable[ui32Index].bUseLock = bUseLock;
#if defined(DEBUG_BRIDGE_KM)
g_BridgeDispatchTable[ui32Index].pszIOCName = pszIOCName;
g_BridgeDispatchTable[ui32Index].pszFunctionName = pszFunctionName;
g_BridgeDispatchTable[ui32Index].pszBridgeLockName = pszBridgeLockName;
g_BridgeDispatchTable[ui32Index].ui32CallCount = 0;
g_BridgeDispatchTable[ui32Index].ui32CopyFromUserTotalBytes = 0;
g_BridgeDispatchTable[ui32Index].ui64TotalTimeNS = 0;
g_BridgeDispatchTable[ui32Index].ui64MaxTimeNS = 0;
#endif
}
ui32PrevIndex = ui32Index;
}
PVRSRV_ERROR
PVRSRVInitSrvDisconnectKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE * psDeviceNode,
IMG_BOOL bInitSuccesful,
IMG_UINT32 ui32ClientBuildOptions)
{
PVRSRV_ERROR eError;
#if defined(SUPPORT_KERNEL_SRVINIT)
if (psConnection)
{
/* Assume this is being called by a user space process */
return PVRSRV_ERROR_NOT_SUPPORTED;
}
#else
if (!(psConnection->ui32ClientFlags & SRV_FLAGS_INIT_PROCESS))
{
return PVRSRV_ERROR_SRV_DISCONNECT_FAILED;
}
PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RUNNING, IMG_FALSE);
PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_RAN, IMG_TRUE);
#endif
eError = PVRSRVDeviceFinalise(psDeviceNode, bInitSuccesful);
#if !defined(SUPPORT_KERNEL_SRVINIT)
PVRSRVSetInitServerState(PVRSRV_INIT_SERVER_SUCCESSFUL,
(eError == PVRSRV_OK) && bInitSuccesful);
#endif
return eError;
}
static PVRSRV_ERROR _BridgeBufferPoolCreate(void)
{
PVRSRV_ERROR eError;
PVR_DPF((PVR_DBG_VERBOSE, "BridgePoolCreate: Creating bridge buffer pool."));
g_psBridgePool = OSAllocZMemNoStats(sizeof(*g_psBridgePool));
if (g_psBridgePool == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "BridgePoolCreate: Failed to allocate memory "
"for the bridge buffer pool."));
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
eError = OSLockCreate(&g_psBridgePool->hLock, LOCK_TYPE_PASSIVE);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "BridgePoolCreate: Failed to create lock "
"for the bridge buffer pool."));
OSFreeMemNoStats(g_psBridgePool);
return eError;
}
return PVRSRV_OK;
}
static void _BridgeBufferPoolDestroy(void)
{
IMG_UINT i;
PVR_DPF((PVR_DBG_VERBOSE, "Destroying bridge buffer pool."));
for (i = 0; i < g_psBridgePool->uiCount; i++)
OSFreeMem(g_psBridgePool->asPool[i].pvBuffer);
OSLockDestroy(g_psBridgePool->hLock);
OSFreeMemNoStats(g_psBridgePool);
}
PVRSRV_ERROR BridgeInit(void)
{
PVRSRV_ERROR eError;
eError = _BridgeBufferPoolCreate();
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "Failed to create bridge buffer pool"));
return eError;
}
#if defined(DEBUG_BRIDGE_KM)
eError = OSLockCreate(&g_hStatsLock, LOCK_TYPE_PASSIVE);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "Failed to create bridge stats lock"));
return eError;
}
#endif
return PVRSRV_OK;
}
void BridgeDeinit(void)
{
#if defined(DEBUG_BRIDGE_KM)
if(g_hStatsLock)
{
OSLockDestroy(g_hStatsLock);
g_hStatsLock = NULL;
}
#endif
_BridgeBufferPoolDestroy();
}
static PVR_POOL_BUFFER *_BridgePoolAcquireBuffer(void **ppvBridgeIn,
void **ppvBridgeOut)
{
PVR_POOL_BUFFER *psPoolBuffer = NULL;
IMG_UINT i;
PVR_ASSERT(g_psBridgePool != NULL);
PVR_ASSERT(ppvBridgeIn != NULL && ppvBridgeOut != NULL);
OSLockAcquire(g_psBridgePool->hLock);
for (i = 0; i < PVR_BUFFER_POOL_MAX; i++)
{
PVR_POOL_BUFFER *psBuffer = &g_psBridgePool->asPool[i];
if (psBuffer->pvBuffer != NULL)
{
if (psBuffer->bTaken)
continue;
PVR_DPF((PVR_DBG_VERBOSE, "_BridgePoolAcquireBuffer: "
"Reusing buffer %p.", psBuffer->pvBuffer));
psBuffer->bTaken = IMG_TRUE;
*ppvBridgeIn = psBuffer->pvBuffer;
*ppvBridgeOut = ((IMG_BYTE *) psBuffer->pvBuffer) +
PVRSRV_MAX_BRIDGE_IN_SIZE;
psPoolBuffer = psBuffer;
goto return_;
}
else
{
PVR_DPF((PVR_DBG_VERBOSE, "_BridgePoolAcquireBuffer: "
"Allocating new bridge buffer."));
psBuffer->pvBuffer = OSAllocZMemNoStats(PVRSRV_MAX_BRIDGE_IN_SIZE +
PVRSRV_MAX_BRIDGE_OUT_SIZE);
if (psBuffer->pvBuffer == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "_BridgePoolAcquireBuffer: "
"Out of memory! Could not allocate new buffer."));
goto return_;
}
*ppvBridgeIn = psBuffer->pvBuffer;
*ppvBridgeOut = ((IMG_BYTE *) psBuffer->pvBuffer) +
PVRSRV_MAX_BRIDGE_IN_SIZE;
g_psBridgePool->uiCount++;
psPoolBuffer = psBuffer;
goto return_;
}
}
PVR_DPF((PVR_DBG_ERROR, "_BridgePoolAcquireBuffer: "
"Not enough buffers in the pool."));
return_:
OSLockRelease(g_psBridgePool->hLock);
return psPoolBuffer;
}
static void _BridgePoolReleaseBuffers(PVR_POOL_BUFFER *psBuffer)
{
PVR_ASSERT(g_psBridgePool != NULL);
if (psBuffer == NULL)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Called release on NULL buffer",
__FUNCTION__));
return;
}
OSLockAcquire(g_psBridgePool->hLock);
PVR_DPF((PVR_DBG_VERBOSE, "_BridgePoolReleaseBuffers: "
"Releasing buffer %p.", psBuffer->pvBuffer));
psBuffer->bTaken = IMG_FALSE;
OSLockRelease(g_psBridgePool->hLock);
}
PVRSRV_ERROR BridgedDispatchKM(CONNECTION_DATA * psConnection,
PVRSRV_BRIDGE_PACKAGE * psBridgePackageKM)
{
void * psBridgeIn=NULL;
void * psBridgeOut=NULL;
BridgeWrapperFunction pfBridgeHandler;
IMG_UINT32 ui32DispatchTableEntry, ui32GroupBoundary;
PVRSRV_ERROR err = PVRSRV_OK;
PVR_POOL_BUFFER *psPoolBuffer = NULL;
IMG_UINT32 ui32Timestamp = OSClockus();
#if defined(DEBUG_BRIDGE_KM)
IMG_UINT64 ui64TimeStart;
IMG_UINT64 ui64TimeEnd;
IMG_UINT64 ui64TimeDiff;
#endif
#if defined(DEBUG_BRIDGE_KM_STOP_AT_DISPATCH)
PVR_DBG_BREAK;
#endif
if(BRIDGE_DISPATCH_TABLE_START_ENTRY_COUNT <= psBridgePackageKM->ui32BridgeID)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Out of range dispatch table group ID: %d",
__FUNCTION__, psBridgePackageKM->ui32BridgeID));
err = PVRSRV_ERROR_BRIDGE_EINVAL;
goto return_error;
}
ui32DispatchTableEntry = g_BridgeDispatchTableStartOffsets[psBridgePackageKM->ui32BridgeID][PVR_DISPATCH_OFFSET_FIRST_FUNC];
ui32GroupBoundary = g_BridgeDispatchTableStartOffsets[psBridgePackageKM->ui32BridgeID][PVR_DISPATCH_OFFSET_LAST_FUNC];
/* bridge function is not implemented in this build */
if(0 == ui32DispatchTableEntry)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Dispatch table entry=%d, boundary = %d, (bridge module %d, function %d)",
__FUNCTION__,
ui32DispatchTableEntry,ui32GroupBoundary, psBridgePackageKM->ui32BridgeID, psBridgePackageKM->ui32FunctionID));
/* this points to DummyBW() which returns PVRSRV_ERROR_ENOTTY */
err = g_BridgeDispatchTable[ui32DispatchTableEntry].pfFunction(ui32DispatchTableEntry,
psBridgeIn,
psBridgeOut,
psConnection);
goto return_error;
}
else
{
ui32DispatchTableEntry += psBridgePackageKM->ui32FunctionID;
}
if(ui32DispatchTableEntry > ui32GroupBoundary)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Dispatch table entry=%d, boundary = %d, (bridge module %d, function %d)",
__FUNCTION__,
ui32DispatchTableEntry,ui32GroupBoundary, psBridgePackageKM->ui32BridgeID, psBridgePackageKM->ui32FunctionID));
err = PVRSRV_ERROR_BRIDGE_EINVAL;
goto return_error;
}
if(BRIDGE_DISPATCH_TABLE_ENTRY_COUNT <= ui32DispatchTableEntry)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Dispatch table entry=%d, entry count = %lu,"
" (bridge module %d, function %d)", __FUNCTION__,
ui32DispatchTableEntry, BRIDGE_DISPATCH_TABLE_ENTRY_COUNT,
psBridgePackageKM->ui32BridgeID,
psBridgePackageKM->ui32FunctionID));
err = PVRSRV_ERROR_BRIDGE_EINVAL;
goto return_error;
}
#if defined(DEBUG_BRIDGE_KM)
PVR_DPF((PVR_DBG_MESSAGE, "%s: Dispatch table entry=%d, (bridge module %d, function %d)",
__FUNCTION__,
ui32DispatchTableEntry, psBridgePackageKM->ui32BridgeID, psBridgePackageKM->ui32FunctionID));
PVR_DPF((PVR_DBG_MESSAGE, "%s: %s",
__FUNCTION__,
g_BridgeDispatchTable[ui32DispatchTableEntry].pszIOCName));
g_BridgeDispatchTable[ui32DispatchTableEntry].ui32CallCount++;
g_BridgeGlobalStats.ui32IOCTLCount++;
#endif
if (g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock == NULL &&
g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
/* Acquire default global bridge lock if calling module has no independent lock */
OSAcquireBridgeLock();
/* Request for global bridge buffers */
OSGetGlobalBridgeBuffers(&psBridgeIn,
&psBridgeOut);
}
else
{
if (g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock != NULL &&
g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
OSLockAcquire(g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock);
}
psPoolBuffer = _BridgePoolAcquireBuffer(&psBridgeIn,
&psBridgeOut);
if (psPoolBuffer == NULL)
{
err = PVRSRV_ERROR_BRIDGE_ENOMEM;
goto unlock_and_return_error;
}
}
#if defined(DEBUG_BRIDGE_KM)
ui64TimeStart = OSClockns64();
#endif
if (psBridgePackageKM->ui32InBufferSize > PVRSRV_MAX_BRIDGE_IN_SIZE)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Bridge input buffer too small "
"(data size %u, buffer size %u)!", __FUNCTION__,
psBridgePackageKM->ui32InBufferSize, PVRSRV_MAX_BRIDGE_IN_SIZE));
err = PVRSRV_ERROR_BRIDGE_ERANGE;
goto unlock_and_return_error;
}
#if !defined(INTEGRITY_OS)
if (psBridgePackageKM->ui32OutBufferSize > PVRSRV_MAX_BRIDGE_OUT_SIZE)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Bridge output buffer too small "
"(data size %u, buffer size %u)!", __FUNCTION__,
psBridgePackageKM->ui32OutBufferSize, PVRSRV_MAX_BRIDGE_OUT_SIZE));
err = PVRSRV_ERROR_BRIDGE_ERANGE;
goto unlock_and_return_error;
}
if((CopyFromUserWrapper (psConnection,
ui32DispatchTableEntry,
psBridgeIn,
psBridgePackageKM->pvParamIn,
psBridgePackageKM->ui32InBufferSize) != PVRSRV_OK)
#if defined __QNXNTO__
/* For Neutrino, the output bridge buffer acts as an input as well */
|| (CopyFromUserWrapper(psConnection,
ui32DispatchTableEntry,
psBridgeOut,
(void *)((IMG_UINT32)psBridgePackageKM->pvParamIn + psBridgePackageKM->ui32InBufferSize),
psBridgePackageKM->ui32OutBufferSize) != PVRSRV_OK)
#endif
) /* end of if-condition */
{
PVR_DPF((PVR_DBG_ERROR, "%s: CopyFromUserWrapper returned an error!", __FUNCTION__));
err = PVRSRV_ERROR_BRIDGE_EFAULT;
goto unlock_and_return_error;
}
#else
psBridgeIn = psBridgePackageKM->pvParamIn;
psBridgeOut = psBridgePackageKM->pvParamOut;
#endif
pfBridgeHandler =
(BridgeWrapperFunction)g_BridgeDispatchTable[ui32DispatchTableEntry].pfFunction;
if (pfBridgeHandler == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "%s: ui32DispatchTableEntry = %d is not a registered function!",
__FUNCTION__, ui32DispatchTableEntry));
err = PVRSRV_ERROR_BRIDGE_EFAULT;
goto unlock_and_return_error;
}
/* pfBridgeHandler functions do not fail and return an IMG_INT.
* The value returned is either 0 or PVRSRV_OK (0).
* In the event this changes an error may be +ve or -ve,
* so try to return something consistent here.
*/
if (0 != pfBridgeHandler(ui32DispatchTableEntry,
psBridgeIn,
psBridgeOut,
psConnection)
)
{
PVR_DPF((PVR_DBG_ERROR, "%s: pfBridgeHandler returned an error", __FUNCTION__));
err = PVRSRV_ERROR_BRIDGE_EPERM;
goto unlock_and_return_error;
}
/*
This should always be true as a.t.m. all bridge calls have to
return an error message, but this could change so we do this
check to be safe.
*/
if (psBridgePackageKM->ui32OutBufferSize > 0)
{
#if !defined(INTEGRITY_OS)
if (CopyToUserWrapper (psConnection,
ui32DispatchTableEntry,
psBridgePackageKM->pvParamOut,
psBridgeOut,
psBridgePackageKM->ui32OutBufferSize) != PVRSRV_OK)
{
err = PVRSRV_ERROR_BRIDGE_EFAULT;
goto unlock_and_return_error;
}
#endif
}
#if defined(DEBUG_BRIDGE_KM)
ui64TimeEnd = OSClockns64();
ui64TimeDiff = ui64TimeEnd - ui64TimeStart;
/* if there is no lock held then acquire the stats lock to
* ensure the calculations are done safely
*/
if(!g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
OSLockAcquire(g_hStatsLock);
}
g_BridgeDispatchTable[ui32DispatchTableEntry].ui64TotalTimeNS += ui64TimeDiff;
if(ui64TimeDiff > g_BridgeDispatchTable[ui32DispatchTableEntry].ui64MaxTimeNS)
{
g_BridgeDispatchTable[ui32DispatchTableEntry].ui64MaxTimeNS = ui64TimeDiff;
}
if(!g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
OSLockRelease(g_hStatsLock);
}
#endif
unlock_and_return_error:
if (g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock == NULL &&
g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
OSReleaseBridgeLock();
}
else
{
if (g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock != NULL &&
g_BridgeDispatchTable[ui32DispatchTableEntry].bUseLock)
{
OSLockRelease(g_BridgeDispatchTable[ui32DispatchTableEntry].hBridgeLock);
}
_BridgePoolReleaseBuffers(psPoolBuffer);
}
return_error:
if (err)
{
PVR_DPF((PVR_DBG_ERROR, "%s: returning (err = %d)", __FUNCTION__, err));
}
/* ignore transport layer bridge to avoid HTB flooding */
if (psBridgePackageKM->ui32BridgeID != PVRSRV_BRIDGE_PVRTL)
{
if (err)
{
HTBLOGK(HTB_SF_BRG_BRIDGE_CALL_ERR, ui32Timestamp,
psBridgePackageKM->ui32BridgeID,
psBridgePackageKM->ui32FunctionID, err);
}
else
{
HTBLOGK(HTB_SF_BRG_BRIDGE_CALL, ui32Timestamp,
psBridgePackageKM->ui32BridgeID,
psBridgePackageKM->ui32FunctionID);
}
}
return err;
}