/*************************************************************************/ /*!
|
@File
|
@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 "rgxdebug.h"
|
#include "handle.h"
|
#include "connection_server.h"
|
#include "pdump_km.h"
|
#include "ra.h"
|
#include "allocmem.h"
|
#include "pmr.h"
|
#include "pvrsrv.h"
|
#include "srvcore.h"
|
#if defined(SUPPORT_PVRSRV_GPUVIRT)
|
#include "pvrsrv_vz.h"
|
#endif
|
#include "services_km.h"
|
#include "pvrsrv_device.h"
|
#include "pvr_debug.h"
|
#include "pvr_notifier.h"
|
#include "sync.h"
|
#include "sync_server.h"
|
#include "devicemem.h"
|
#include "cache_km.h"
|
|
#include "log2.h"
|
|
#include "lists.h"
|
#include "dllist.h"
|
#include "syscommon.h"
|
#include "sysvalidation.h"
|
|
#include "physmem_lma.h"
|
#include "physmem_osmem.h"
|
|
#include "tlintern.h"
|
#include "htbserver.h"
|
|
#if defined (SUPPORT_RGX)
|
#include "rgxinit.h"
|
#include "rgxfwutils.h"
|
#endif
|
|
#if defined(PVR_RI_DEBUG)
|
#include "ri_server.h"
|
#endif
|
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
#include "process_stats.h"
|
#endif
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
#if !defined(GPUVIRT_SIZEOF_ARENA0)
|
#define GPUVIRT_SIZEOF_ARENA0 64 * 1024 * 1024 //Giving 64 megs of LMA memory to arena 0 for firmware and other allocations
|
#endif
|
#endif
|
|
#if defined(SUPPORT_PAGE_FAULT_DEBUG)
|
#include "devicemem_history_server.h"
|
#endif
|
|
#if defined(PVR_DVFS)
|
#include "pvr_dvfs_device.h"
|
#endif
|
|
#if defined(SUPPORT_DISPLAY_CLASS)
|
#include "dc_server.h"
|
#endif
|
|
#if defined(SUPPORT_KERNEL_SRVINIT)
|
#include "rgx_options.h"
|
#include "srvinit.h"
|
#include "rgxutils.h"
|
#endif
|
|
#include "oskm_apphint.h"
|
#include "pvrsrv_apphint.h"
|
|
#include "rgx_bvnc_defs_km.h"
|
|
/*! Wait 100ms before retrying deferred clean-up again */
|
#define CLEANUP_THREAD_WAIT_RETRY_TIMEOUT 100000ULL
|
|
/*! Wait 8hrs when no deferred clean-up required. Allows a poll several times
|
* a day to check for any missed clean-up. */
|
#define CLEANUP_THREAD_WAIT_SLEEP_TIMEOUT 28800000000ULL
|
|
|
#define PVRSRV_PROC_HANDLE_BASE_INIT 10
|
|
static PVRSRV_DATA *gpsPVRSRVData = NULL;
|
static IMG_UINT32 g_ui32InitFlags;
|
|
/* mark which parts of Services were initialised */
|
#define INIT_DATA_ENABLE_PDUMPINIT 0x1U
|
|
static IMG_UINT32 g_aui32DebugOrderTable[] = {
|
DEBUG_REQUEST_SYS,
|
DEBUG_REQUEST_APPHINT,
|
DEBUG_REQUEST_HTB,
|
DEBUG_REQUEST_DC,
|
DEBUG_REQUEST_SYNCCHECKPOINT,
|
DEBUG_REQUEST_SERVERSYNC,
|
DEBUG_REQUEST_ANDROIDSYNC,
|
DEBUG_REQUEST_LINUXFENCE
|
};
|
|
/* Add work to the cleanup thread work list.
|
* The work item will be executed by the cleanup thread
|
*/
|
void PVRSRVCleanupThreadAddWork(PVRSRV_CLEANUP_THREAD_WORK *psData)
|
{
|
PVRSRV_DATA *psPVRSRVData;
|
PVRSRV_ERROR eError;
|
|
psPVRSRVData = PVRSRVGetPVRSRVData();
|
|
PVR_ASSERT(psData != NULL);
|
#if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
|
if(psPVRSRVData->eServicesState != PVRSRV_SERVICES_STATE_OK || psPVRSRVData->bUnload)
|
#else
|
if(psPVRSRVData->bUnload)
|
#endif
|
{
|
CLEANUP_THREAD_FN pfnFree = psData->pfnFree;
|
|
PVR_DPF((PVR_DBG_MESSAGE, "Cleanup thread has already quit: doing work immediately"));
|
|
eError = pfnFree(psData->pvData);
|
|
if(eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "Failed to free resource "
|
"(callback " IMG_PFN_FMTSPEC "). "
|
"Immediate free will not be retried.",
|
pfnFree));
|
}
|
}
|
else
|
{
|
/* add this work item to the list */
|
OSLockAcquire(psPVRSRVData->hCleanupThreadWorkListLock);
|
dllist_add_to_tail(&psPVRSRVData->sCleanupThreadWorkList, &psData->sNode);
|
OSLockRelease(psPVRSRVData->hCleanupThreadWorkListLock);
|
|
/* signal the cleanup thread to ensure this item gets processed */
|
eError = OSEventObjectSignal(psPVRSRVData->hCleanupEventObject);
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectSignal");
|
}
|
}
|
|
/* Pop an item from the head of the cleanup thread work list */
|
static INLINE DLLIST_NODE *_CleanupThreadWorkListPop(PVRSRV_DATA *psPVRSRVData)
|
{
|
DLLIST_NODE *psNode;
|
|
OSLockAcquire(psPVRSRVData->hCleanupThreadWorkListLock);
|
psNode = dllist_get_next_node(&psPVRSRVData->sCleanupThreadWorkList);
|
if(psNode != NULL)
|
{
|
dllist_remove_node(psNode);
|
}
|
OSLockRelease(psPVRSRVData->hCleanupThreadWorkListLock);
|
|
return psNode;
|
}
|
|
/* Process the cleanup thread work list */
|
static IMG_BOOL _CleanupThreadProcessWorkList(PVRSRV_DATA *psPVRSRVData,
|
IMG_BOOL *pbUseGlobalEO)
|
{
|
DLLIST_NODE *psNodeIter, *psNodeLast;
|
PVRSRV_ERROR eError;
|
IMG_BOOL bNeedRetry = IMG_FALSE;
|
|
/* any callback functions which return error will be
|
* moved to the back of the list, and additional items can be added
|
* to the list at any time so we ensure we only iterate from the
|
* head of the list to the current tail (since the tail may always
|
* be changing)
|
*/
|
|
OSLockAcquire(psPVRSRVData->hCleanupThreadWorkListLock);
|
psNodeLast = psPVRSRVData->sCleanupThreadWorkList.psPrevNode;
|
OSLockRelease(psPVRSRVData->hCleanupThreadWorkListLock);
|
|
do
|
{
|
PVRSRV_CLEANUP_THREAD_WORK *psData;
|
|
psNodeIter = _CleanupThreadWorkListPop(psPVRSRVData);
|
|
if(psNodeIter != NULL)
|
{
|
CLEANUP_THREAD_FN pfnFree;
|
|
psData = IMG_CONTAINER_OF(psNodeIter, PVRSRV_CLEANUP_THREAD_WORK, sNode);
|
|
/* get the function pointer address here so we have access to it
|
* in order to report the error in case of failure, without having
|
* to depend on psData not having been freed
|
*/
|
pfnFree = psData->pfnFree;
|
|
*pbUseGlobalEO = psData->bDependsOnHW;
|
eError = pfnFree(psData->pvData);
|
|
if(eError != PVRSRV_OK)
|
{
|
/* move to back of the list, if this item's
|
* retry count hasn't hit zero.
|
*/
|
if(psData->ui32RetryCount-- > 0)
|
{
|
OSLockAcquire(psPVRSRVData->hCleanupThreadWorkListLock);
|
dllist_add_to_tail(&psPVRSRVData->sCleanupThreadWorkList, psNodeIter);
|
OSLockRelease(psPVRSRVData->hCleanupThreadWorkListLock);
|
bNeedRetry = IMG_TRUE;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_ERROR, "Failed to free resource "
|
"(callback " IMG_PFN_FMTSPEC "). "
|
"Retry limit reached",
|
pfnFree));
|
}
|
}
|
}
|
} while((psNodeIter != NULL) && (psNodeIter != psNodeLast));
|
|
return bNeedRetry;
|
}
|
|
// #define CLEANUP_DPFL PVR_DBG_WARNING
|
#define CLEANUP_DPFL PVR_DBG_MESSAGE
|
|
/* Create/initialise data required by the cleanup thread,
|
* before the cleanup thread is started
|
*/
|
static PVRSRV_ERROR _CleanupThreadPrepare(PVRSRV_DATA *psPVRSRVData)
|
{
|
PVRSRV_ERROR eError;
|
|
/* Create the clean up event object */
|
|
eError = OSEventObjectCreate("PVRSRV_CLEANUP_EVENTOBJECT", &gpsPVRSRVData->hCleanupEventObject);
|
PVR_LOGG_IF_ERROR(eError, "OSEventObjectCreate", Exit);
|
|
/* initialise the mutex and linked list required for the cleanup thread work list */
|
|
eError = OSLockCreate(&psPVRSRVData->hCleanupThreadWorkListLock, LOCK_TYPE_PASSIVE);
|
PVR_LOGG_IF_ERROR(eError, "OSLockCreate", Exit);
|
|
dllist_init(&psPVRSRVData->sCleanupThreadWorkList);
|
|
Exit:
|
return eError;
|
}
|
|
static void CleanupThread(void *pvData)
|
{
|
PVRSRV_DATA *psPVRSRVData = pvData;
|
IMG_BOOL bRetryWorkList = IMG_FALSE;
|
IMG_HANDLE hGlobalEvent;
|
IMG_HANDLE hOSEvent;
|
PVRSRV_ERROR eRc;
|
IMG_BOOL bUseGlobalEO = IMG_FALSE;
|
|
/* Store the process id (pid) of the clean-up thread */
|
psPVRSRVData->cleanupThreadPid = OSGetCurrentProcessID();
|
|
PVR_DPF((CLEANUP_DPFL, "CleanupThread: thread starting... "));
|
|
/* Open an event on the clean up event object so we can listen on it,
|
* abort the clean up thread and driver if this fails.
|
*/
|
eRc = OSEventObjectOpen(psPVRSRVData->hCleanupEventObject, &hOSEvent);
|
PVR_ASSERT(eRc == PVRSRV_OK);
|
|
eRc = OSEventObjectOpen(psPVRSRVData->hGlobalEventObject, &hGlobalEvent);
|
PVR_ASSERT(eRc == PVRSRV_OK);
|
|
/* While the driver is in a good state and is not being unloaded
|
* try to free any deferred items when signalled
|
*/
|
while ((psPVRSRVData->eServicesState == PVRSRV_SERVICES_STATE_OK) &&
|
(!psPVRSRVData->bUnload))
|
{
|
IMG_HANDLE hEvent;
|
|
/* Wait until signalled for deferred clean up OR wait for a
|
* short period if the previous deferred clean up was not able
|
* to release all the resources before trying again.
|
* Bridge lock re-acquired on our behalf before the wait call returns.
|
*/
|
|
if(bRetryWorkList && bUseGlobalEO)
|
{
|
hEvent = hGlobalEvent;
|
}
|
else
|
{
|
hEvent = hOSEvent;
|
}
|
|
eRc = OSEventObjectWaitTimeout(hEvent,
|
bRetryWorkList ?
|
CLEANUP_THREAD_WAIT_RETRY_TIMEOUT :
|
CLEANUP_THREAD_WAIT_SLEEP_TIMEOUT);
|
if (eRc == PVRSRV_ERROR_TIMEOUT)
|
{
|
PVR_DPF((CLEANUP_DPFL, "CleanupThread: wait timeout"));
|
}
|
else if (eRc == PVRSRV_OK)
|
{
|
PVR_DPF((CLEANUP_DPFL, "CleanupThread: wait OK, signal received"));
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_ERROR, "CleanupThread: wait error %d", eRc));
|
}
|
|
bRetryWorkList = _CleanupThreadProcessWorkList(psPVRSRVData, &bUseGlobalEO);
|
}
|
|
OSLockDestroy(psPVRSRVData->hCleanupThreadWorkListLock);
|
|
eRc = OSEventObjectClose(hOSEvent);
|
PVR_LOG_IF_ERROR(eRc, "OSEventObjectClose");
|
|
eRc = OSEventObjectClose(hGlobalEvent);
|
PVR_LOG_IF_ERROR(eRc, "OSEventObjectClose");
|
|
PVR_DPF((CLEANUP_DPFL, "CleanupThread: thread ending... "));
|
}
|
|
static IMG_BOOL DevicesWatchdogThread_Powered_Any(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
PVRSRV_DEV_POWER_STATE ePowerState = PVRSRV_DEV_POWER_STATE_ON;
|
PVRSRV_ERROR eError;
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
if (eError == PVRSRV_ERROR_RETRY)
|
{
|
/* Power lock cannot be acquired at this time (sys power is off) */
|
return IMG_FALSE;
|
}
|
|
/* Any other error is unexpected so we assume the device is on */
|
PVR_DPF((PVR_DBG_ERROR,
|
"DevicesWatchdogThread: Failed to acquire power lock for device %p (%s)",
|
psDeviceNode, PVRSRVGetErrorStringKM(eError)));
|
return IMG_TRUE;
|
}
|
|
(void) PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
return (ePowerState == PVRSRV_DEV_POWER_STATE_ON) ? IMG_TRUE : IMG_FALSE;
|
}
|
|
static void DevicesWatchdogThread_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode,
|
va_list va)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo = (PVRSRV_RGXDEV_INFO *) psDeviceNode->pvDevice;
|
PVRSRV_DEVICE_HEALTH_STATUS *pePreviousHealthStatus, eHealthStatus;
|
PVRSRV_ERROR eError;
|
|
pePreviousHealthStatus = va_arg(va, PVRSRV_DEVICE_HEALTH_STATUS *);
|
|
if (psDeviceNode->pfnUpdateHealthStatus != NULL)
|
{
|
eError = psDeviceNode->pfnUpdateHealthStatus(psDeviceNode, IMG_TRUE);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_WARNING, "DevicesWatchdogThread: "
|
"Could not check for fatal error (%d)!",
|
eError));
|
}
|
}
|
eHealthStatus = OSAtomicRead(&psDeviceNode->eHealthStatus);
|
|
if (eHealthStatus != PVRSRV_DEVICE_HEALTH_STATUS_OK)
|
{
|
if (eHealthStatus != *pePreviousHealthStatus)
|
{
|
if (!(psDevInfo->ui32DeviceFlags &
|
RGXKM_DEVICE_STATE_DISABLE_DW_LOGGING_EN))
|
{
|
PVR_DPF((PVR_DBG_ERROR, "DevicesWatchdogThread: "
|
"Device not responding!!!"));
|
PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX,
|
NULL, NULL);
|
}
|
}
|
}
|
|
*pePreviousHealthStatus = eHealthStatus;
|
}
|
|
static void DevicesWatchdogThread(void *pvData)
|
{
|
PVRSRV_DATA *psPVRSRVData = pvData;
|
PVRSRV_DEVICE_HEALTH_STATUS ePreviousHealthStatus = PVRSRV_DEVICE_HEALTH_STATUS_OK;
|
IMG_HANDLE hOSEvent;
|
PVRSRV_ERROR eError;
|
IMG_UINT32 ui32Timeout = DEVICES_WATCHDOG_POWER_ON_SLEEP_TIMEOUT;
|
|
PVR_DPF((PVR_DBG_MESSAGE, "DevicesWatchdogThread: Power off sleep time: %d.",
|
DEVICES_WATCHDOG_POWER_OFF_SLEEP_TIMEOUT));
|
|
/* Open an event on the devices watchdog event object so we can listen on it
|
and abort the devices watchdog thread. */
|
eError = OSEventObjectOpen(psPVRSRVData->hDevicesWatchdogEvObj, &hOSEvent);
|
PVR_LOGRN_IF_ERROR(eError, "OSEventObjectOpen");
|
|
/* Loop continuously checking the device status every few seconds. */
|
#if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
|
while ((psPVRSRVData->eServicesState == PVRSRV_SERVICES_STATE_OK) &&
|
!psPVRSRVData->bUnload)
|
#else
|
while (!psPVRSRVData->bUnload)
|
#endif
|
{
|
IMG_BOOL bPwrIsOn = IMG_FALSE;
|
|
/* Wait time between polls (done at the start of the loop to allow devices
|
to initialise) or for the event signal (shutdown or power on). */
|
eError = OSEventObjectWaitTimeout(hOSEvent, (IMG_UINT64)ui32Timeout * 1000);
|
|
#ifdef PVR_TESTING_UTILS
|
psPVRSRVData->ui32DevicesWdWakeupCounter++;
|
#endif
|
if (eError == PVRSRV_OK)
|
{
|
if (psPVRSRVData->bUnload)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "DevicesWatchdogThread: Shutdown event received."));
|
break;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "DevicesWatchdogThread: Power state change event received."));
|
}
|
}
|
else if (eError != PVRSRV_ERROR_TIMEOUT)
|
{
|
/* If timeout do nothing otherwise print warning message. */
|
PVR_DPF((PVR_DBG_ERROR, "DevicesWatchdogThread: "
|
"Error (%d) when waiting for event!", eError));
|
}
|
|
bPwrIsOn = List_PVRSRV_DEVICE_NODE_IMG_BOOL_Any(psPVRSRVData->psDeviceNodeList,
|
DevicesWatchdogThread_Powered_Any);
|
if (bPwrIsOn || psPVRSRVData->ui32DevicesWatchdogPwrTrans)
|
{
|
psPVRSRVData->ui32DevicesWatchdogPwrTrans = 0;
|
ui32Timeout = psPVRSRVData->ui32DevicesWatchdogTimeout = DEVICES_WATCHDOG_POWER_ON_SLEEP_TIMEOUT;
|
}
|
else
|
{
|
ui32Timeout = psPVRSRVData->ui32DevicesWatchdogTimeout = DEVICES_WATCHDOG_POWER_OFF_SLEEP_TIMEOUT;
|
}
|
|
List_PVRSRV_DEVICE_NODE_ForEach_va(psPVRSRVData->psDeviceNodeList,
|
DevicesWatchdogThread_ForEachVaCb,
|
&ePreviousHealthStatus);
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION) && defined(EMULATOR)
|
SysPrintAndResetFaultStatusRegister();
|
#endif
|
}
|
|
eError = OSEventObjectClose(hOSEvent);
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectClose");
|
}
|
|
|
PVRSRV_DATA *PVRSRVGetPVRSRVData()
|
{
|
return gpsPVRSRVData;
|
}
|
|
PVRSRV_ERROR IMG_CALLCONV
|
PVRSRVDriverInit(void)
|
{
|
PVRSRV_ERROR eError;
|
PVRSRV_DATA *psPVRSRVData = NULL;
|
|
IMG_UINT32 ui32AppHintCleanupThreadPriority;
|
IMG_UINT32 ui32AppHintCleanupThreadWeight;
|
IMG_UINT32 ui32AppHintWatchdogThreadPriority;
|
IMG_UINT32 ui32AppHintWatchdogThreadWeight;
|
|
void *pvAppHintState = NULL;
|
IMG_UINT32 ui32AppHintDefault;
|
|
/*
|
* As this function performs one time driver initialisation, use the
|
* Services global device-independent data to determine whether or not
|
* this function has already been called.
|
*/
|
if (gpsPVRSRVData)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Driver already initialised", __func__));
|
return PVRSRV_ERROR_ALREADY_EXISTS;
|
}
|
|
eError = PhysHeapInit();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
/*
|
* Allocate the device-independent data
|
*/
|
psPVRSRVData = OSAllocZMem(sizeof(*gpsPVRSRVData));
|
if (psPVRSRVData == NULL)
|
{
|
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
|
goto Error;
|
}
|
|
/* Now it is set up, point gpsPVRSRVData to the actual data */
|
gpsPVRSRVData = psPVRSRVData;
|
|
/* Init any OS specific's */
|
eError = OSInitEnvData();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
#if defined(PVR_RI_DEBUG)
|
RIInitKM();
|
#endif
|
|
#if defined(SUPPORT_PAGE_FAULT_DEBUG)
|
eError = DevicememHistoryInitKM();
|
|
if(eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to initialise DevicememHistoryInitKM", __func__));
|
goto Error;
|
}
|
#endif
|
|
eError = BridgeInit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to initialise bridge",
|
__func__));
|
goto Error;
|
}
|
|
eError = PMRInit();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
eError = CacheOpInit();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
#if defined(SUPPORT_DISPLAY_CLASS)
|
eError = DCInit();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
#endif
|
|
/* Initialise overall system state */
|
gpsPVRSRVData->eServicesState = PVRSRV_SERVICES_STATE_OK;
|
|
/* Create an event object */
|
eError = OSEventObjectCreate("PVRSRV_GLOBAL_EVENTOBJECT", &gpsPVRSRVData->hGlobalEventObject);
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
gpsPVRSRVData->ui32GEOConsecutiveTimeouts = 0;
|
|
eError = PVRSRVCmdCompleteInit();
|
if (eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
/* Initialise pdump */
|
eError = PDUMPINIT();
|
if(eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
g_ui32InitFlags |= INIT_DATA_ENABLE_PDUMPINIT;
|
|
eError = PVRSRVHandleInit();
|
if(eError != PVRSRV_OK)
|
{
|
goto Error;
|
}
|
|
eError = _CleanupThreadPrepare(gpsPVRSRVData);
|
PVR_LOGG_IF_ERROR(eError, "_CleanupThreadPrepare", Error);
|
|
/* Create a thread which is used to do the deferred cleanup */
|
eError = OSThreadCreatePriority(&gpsPVRSRVData->hCleanupThread,
|
"pvr_defer_free",
|
CleanupThread,
|
gpsPVRSRVData,
|
OS_THREAD_LOWEST_PRIORITY);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to create deferred cleanup thread",
|
__func__));
|
goto Error;
|
}
|
|
OSCreateKMAppHintState(&pvAppHintState);
|
ui32AppHintDefault = PVRSRV_APPHINT_CLEANUPTHREADPRIORITY;
|
OSGetKMAppHintUINT32(pvAppHintState, CleanupThreadPriority,
|
&ui32AppHintDefault, &ui32AppHintCleanupThreadPriority);
|
ui32AppHintDefault = PVRSRV_APPHINT_CLEANUPTHREADWEIGHT;
|
OSGetKMAppHintUINT32(pvAppHintState, CleanupThreadWeight,
|
&ui32AppHintDefault, &ui32AppHintCleanupThreadWeight);
|
ui32AppHintDefault = PVRSRV_APPHINT_WATCHDOGTHREADPRIORITY;
|
OSGetKMAppHintUINT32(pvAppHintState, WatchdogThreadPriority,
|
&ui32AppHintDefault, &ui32AppHintWatchdogThreadPriority);
|
ui32AppHintDefault = PVRSRV_APPHINT_WATCHDOGTHREADWEIGHT;
|
OSGetKMAppHintUINT32(pvAppHintState, WatchdogThreadWeight,
|
&ui32AppHintDefault, &ui32AppHintWatchdogThreadWeight);
|
OSFreeKMAppHintState(pvAppHintState);
|
pvAppHintState = NULL;
|
|
eError = OSSetThreadPriority(gpsPVRSRVData->hCleanupThread,
|
ui32AppHintCleanupThreadPriority,
|
ui32AppHintCleanupThreadWeight);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to set thread priority of deferred cleanup thread.",
|
__func__));
|
goto Error;
|
}
|
|
/* Create the devices watchdog event object */
|
eError = OSEventObjectCreate("PVRSRV_DEVICESWATCHDOG_EVENTOBJECT", &gpsPVRSRVData->hDevicesWatchdogEvObj);
|
PVR_LOGG_IF_ERROR(eError, "OSEventObjectCreate", Error);
|
|
/* Create a thread which is used to detect fatal errors */
|
eError = OSThreadCreate(&gpsPVRSRVData->hDevicesWatchdogThread,
|
"pvr_device_wdg",
|
DevicesWatchdogThread,
|
gpsPVRSRVData);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to create devices watchdog thread",
|
__func__));
|
goto Error;
|
}
|
|
eError = OSSetThreadPriority(gpsPVRSRVData->hDevicesWatchdogThread,
|
ui32AppHintWatchdogThreadPriority,
|
ui32AppHintWatchdogThreadWeight);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to set thread priority of the watchdog thread.",
|
__func__));
|
goto Error;
|
}
|
|
gpsPVRSRVData->psProcessHandleBase_Table = HASH_Create(PVRSRV_PROC_HANDLE_BASE_INIT);
|
|
if (gpsPVRSRVData->psProcessHandleBase_Table == NULL)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to create hash table for process handle base.",
|
__func__));
|
eError = PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE;
|
goto Error;
|
}
|
|
eError = OSLockCreate(&gpsPVRSRVData->hProcessHandleBase_Lock, LOCK_TYPE_PASSIVE);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to create lock for process handle base.",
|
__func__));
|
goto Error;
|
}
|
|
return 0;
|
|
Error:
|
PVRSRVDriverDeInit();
|
return eError;
|
}
|
|
void IMG_CALLCONV
|
PVRSRVDriverDeInit(void)
|
{
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
if (gpsPVRSRVData == NULL)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: missing device-independent data",
|
__func__));
|
return;
|
}
|
|
gpsPVRSRVData->bUnload = IMG_TRUE;
|
|
if (gpsPVRSRVData->hProcessHandleBase_Lock)
|
{
|
OSLockDestroy(gpsPVRSRVData->hProcessHandleBase_Lock);
|
gpsPVRSRVData->hProcessHandleBase_Lock = NULL;
|
}
|
|
if (gpsPVRSRVData->psProcessHandleBase_Table)
|
{
|
HASH_Delete(gpsPVRSRVData->psProcessHandleBase_Table);
|
gpsPVRSRVData->psProcessHandleBase_Table = NULL;
|
}
|
|
if (gpsPVRSRVData->hGlobalEventObject)
|
{
|
OSEventObjectSignal(gpsPVRSRVData->hGlobalEventObject);
|
}
|
|
/* Stop and cleanup the devices watchdog thread */
|
if (gpsPVRSRVData->hDevicesWatchdogThread)
|
{
|
if (gpsPVRSRVData->hDevicesWatchdogEvObj)
|
{
|
eError = OSEventObjectSignal(gpsPVRSRVData->hDevicesWatchdogEvObj);
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectSignal");
|
}
|
LOOP_UNTIL_TIMEOUT(OS_THREAD_DESTROY_TIMEOUT_US)
|
{
|
eError = OSThreadDestroy(gpsPVRSRVData->hDevicesWatchdogThread);
|
if (PVRSRV_OK == eError)
|
{
|
gpsPVRSRVData->hDevicesWatchdogThread = NULL;
|
break;
|
}
|
OSWaitus(OS_THREAD_DESTROY_TIMEOUT_US/OS_THREAD_DESTROY_RETRY_COUNT);
|
} END_LOOP_UNTIL_TIMEOUT();
|
PVR_LOG_IF_ERROR(eError, "OSThreadDestroy");
|
}
|
|
if (gpsPVRSRVData->hDevicesWatchdogEvObj)
|
{
|
eError = OSEventObjectDestroy(gpsPVRSRVData->hDevicesWatchdogEvObj);
|
gpsPVRSRVData->hDevicesWatchdogEvObj = NULL;
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectDestroy");
|
}
|
|
/* Stop and cleanup the deferred clean up thread, event object and
|
* deferred context list.
|
*/
|
if (gpsPVRSRVData->hCleanupThread)
|
{
|
if (gpsPVRSRVData->hCleanupEventObject)
|
{
|
eError = OSEventObjectSignal(gpsPVRSRVData->hCleanupEventObject);
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectSignal");
|
}
|
LOOP_UNTIL_TIMEOUT(OS_THREAD_DESTROY_TIMEOUT_US)
|
{
|
eError = OSThreadDestroy(gpsPVRSRVData->hCleanupThread);
|
if (PVRSRV_OK == eError)
|
{
|
gpsPVRSRVData->hCleanupThread = NULL;
|
break;
|
}
|
OSWaitus(OS_THREAD_DESTROY_TIMEOUT_US/OS_THREAD_DESTROY_RETRY_COUNT);
|
} END_LOOP_UNTIL_TIMEOUT();
|
PVR_LOG_IF_ERROR(eError, "OSThreadDestroy");
|
}
|
|
if (gpsPVRSRVData->hCleanupEventObject)
|
{
|
eError = OSEventObjectDestroy(gpsPVRSRVData->hCleanupEventObject);
|
gpsPVRSRVData->hCleanupEventObject = NULL;
|
PVR_LOG_IF_ERROR(eError, "OSEventObjectDestroy");
|
}
|
|
/* Tear down the HTB before PVRSRVHandleDeInit() removes its TL handle */
|
/* HTB De-init happens in device de-registration currently */
|
eError = HTBDeInit();
|
PVR_LOG_IF_ERROR(eError, "HTBDeInit");
|
|
eError = PVRSRVHandleDeInit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: PVRSRVHandleDeInit failed", __func__));
|
}
|
|
/* deinitialise pdump */
|
if ((g_ui32InitFlags & INIT_DATA_ENABLE_PDUMPINIT) > 0)
|
{
|
PDUMPDEINIT();
|
}
|
|
/* destroy event object */
|
if (gpsPVRSRVData->hGlobalEventObject)
|
{
|
OSEventObjectDestroy(gpsPVRSRVData->hGlobalEventObject);
|
gpsPVRSRVData->hGlobalEventObject = NULL;
|
}
|
|
PVRSRVCmdCompleteDeinit();
|
|
#if defined(SUPPORT_DISPLAY_CLASS)
|
eError = DCDeInit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: DCDeInit failed", __func__));
|
}
|
#endif
|
|
eError = CacheOpDeInit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: CacheOpDeInit failed", __func__));
|
}
|
|
eError = PMRDeInit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: PMRDeInit failed", __func__));
|
}
|
|
BridgeDeinit();
|
|
#if defined(PVR_RI_DEBUG)
|
RIDeInitKM();
|
#endif
|
|
#if defined(SUPPORT_PAGE_FAULT_DEBUG)
|
DevicememHistoryDeInitKM();
|
#endif
|
|
OSDeInitEnvData();
|
|
eError = PhysHeapDeinit();
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: PhysHeapDeinit failed", __func__));
|
}
|
|
OSFreeMem(gpsPVRSRVData);
|
gpsPVRSRVData = NULL;
|
}
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
static PVRSRV_ERROR CreateLMASubArenas(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
IMG_UINT uiCounter=0;
|
|
for (uiCounter = 0; uiCounter < GPUVIRT_VALIDATION_NUM_OS; uiCounter++)
|
{
|
psDeviceNode->psOSidSubArena[uiCounter] =
|
RA_Create(psDeviceNode->apszRANames[0],
|
OSGetPageShift(), /* Use host page size, keeps things simple */
|
RA_LOCKCLASS_0, /* This arena doesn't use any other arenas. */
|
NULL, /* No Import */
|
NULL, /* No free import */
|
NULL, /* No import handle */
|
IMG_FALSE);
|
|
if (psDeviceNode->psOSidSubArena[uiCounter] == NULL)
|
{
|
return PVRSRV_ERROR_OUT_OF_MEMORY;
|
}
|
}
|
|
PVR_DPF((PVR_DBG_MESSAGE,"\n(GPU Virtualization Validation): Calling RA_Add with base %u and size %u \n",0, GPUVIRT_SIZEOF_ARENA0));
|
|
/* Arena creation takes place earlier than when the client side reads the apphints and transfers them over the bridge. Since we don't
|
* know how the memory is going to be partitioned and since we already need some memory for all the initial allocations that take place,
|
* we populate the first sub-arena (0) with a span of 64 megabytes. This has been shown to be enough even for cases where EWS is allocated
|
* memory in this sub arena and then a multi app example is executed. This pre-allocation also means that consistency must be maintained
|
* between apphints and reality. That's why in the Apphints, the OSid0 region must start from 0 and end at 3FFFFFF. */
|
|
if (!RA_Add(psDeviceNode->psOSidSubArena[0], 0, GPUVIRT_SIZEOF_ARENA0, 0 , NULL ))
|
{
|
RA_Delete(psDeviceNode->psOSidSubArena[0]);
|
return PVRSRV_ERROR_OUT_OF_MEMORY;
|
}
|
|
psDeviceNode->apsLocalDevMemArenas[0] = psDeviceNode->psOSidSubArena[0];
|
|
return PVRSRV_OK;
|
}
|
|
void PopulateLMASubArenas(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 aui32OSidMin[GPUVIRT_VALIDATION_NUM_OS][GPUVIRT_VALIDATION_NUM_REGIONS], IMG_UINT32 aui32OSidMax[GPUVIRT_VALIDATION_NUM_OS][GPUVIRT_VALIDATION_NUM_REGIONS])
|
{
|
IMG_UINT uiCounter;
|
|
/* Since Sub Arena[0] has been populated already, now we populate the rest starting from 1*/
|
|
for (uiCounter = 1; uiCounter < GPUVIRT_VALIDATION_NUM_OS; uiCounter++)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE,"\n[GPU Virtualization Validation]: Calling RA_Add with base %u and size %u \n",aui32OSidMin[uiCounter][0], aui32OSidMax[uiCounter][0]-aui32OSidMin[uiCounter][0]+1));
|
|
if (!RA_Add(psDeviceNode->psOSidSubArena[uiCounter], aui32OSidMin[uiCounter][0], aui32OSidMax[uiCounter][0]-aui32OSidMin[uiCounter][0]+1, 0, NULL))
|
{
|
goto error;
|
}
|
}
|
|
#if defined(EMULATOR)
|
{
|
SysSetOSidRegisters(aui32OSidMin, aui32OSidMax);
|
}
|
#endif
|
|
return ;
|
|
error:
|
for (uiCounter = 0; uiCounter < GPUVIRT_VALIDATION_NUM_OS; uiCounter++)
|
{
|
RA_Delete(psDeviceNode->psOSidSubArena[uiCounter]);
|
}
|
|
return ;
|
}
|
|
#endif
|
|
static void _SysDebugRequestNotify(PVRSRV_DBGREQ_HANDLE hDebugRequestHandle,
|
IMG_UINT32 ui32VerbLevel,
|
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
void *pvDumpDebugFile)
|
{
|
/* Only dump info once */
|
if (ui32VerbLevel == DEBUG_REQUEST_VERBOSITY_LOW)
|
{
|
PVRSRV_DEVICE_NODE *psDeviceNode =
|
(PVRSRV_DEVICE_NODE *) hDebugRequestHandle;
|
|
switch (psDeviceNode->eCurrentSysPowerState)
|
{
|
case PVRSRV_SYS_POWER_STATE_OFF:
|
PVR_DUMPDEBUG_LOG("Device System Power State: OFF");
|
break;
|
case PVRSRV_SYS_POWER_STATE_ON:
|
PVR_DUMPDEBUG_LOG("Device System Power State: ON");
|
break;
|
default:
|
PVR_DUMPDEBUG_LOG("Device System Power State: UNKNOWN (%d)",
|
psDeviceNode->eCurrentSysPowerState);
|
break;
|
}
|
|
SysDebugInfo(psDeviceNode->psDevConfig, pfnDumpDebugPrintf, pvDumpDebugFile);
|
}
|
}
|
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVDeviceCreate(void *pvOSDevice,
|
PVRSRV_DEVICE_NODE **ppsDeviceNode)
|
{
|
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
PVRSRV_ERROR eError;
|
PVRSRV_DEVICE_CONFIG *psDevConfig;
|
PVRSRV_DEVICE_NODE *psDeviceNode;
|
PVRSRV_DEVICE_PHYS_HEAP physHeapIndex;
|
IMG_UINT32 i;
|
|
#if !defined(SUPPORT_KERNEL_SRVINIT)
|
if (0 != psPVRSRVData->ui32RegisteredDevices)
|
{
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
}
|
#endif
|
psDeviceNode = OSAllocZMem(sizeof(*psDeviceNode));
|
if (!psDeviceNode)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to allocate device node",
|
__func__));
|
return PVRSRV_ERROR_OUT_OF_MEMORY;
|
}
|
|
eError = SysDevInit(pvOSDevice, &psDevConfig);
|
if (eError)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to get device config (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto e0;
|
}
|
|
PVR_ASSERT(psDevConfig);
|
PVR_ASSERT(psDevConfig->pvOSDevice == pvOSDevice);
|
PVR_ASSERT(!psDevConfig->psDevNode);
|
|
/* Store the device node in the device config for the system layer to use */
|
psDevConfig->psDevNode = psDeviceNode;
|
|
psDeviceNode->eDevState = PVRSRV_DEVICE_STATE_INIT;
|
psDeviceNode->psDevConfig = psDevConfig;
|
psDeviceNode->eCurrentSysPowerState = PVRSRV_SYS_POWER_STATE_ON;
|
|
eError = PVRSRVRegisterDbgTable(psDeviceNode,
|
g_aui32DebugOrderTable,
|
IMG_ARR_NUM_ELEMS(g_aui32DebugOrderTable));
|
if (eError != PVRSRV_OK)
|
{
|
goto e1;
|
}
|
|
eError = OSLockCreate(&psDeviceNode->hPowerLock, LOCK_TYPE_PASSIVE);
|
if (eError != PVRSRV_OK)
|
{
|
goto e2;
|
}
|
|
/* Register the physical memory heaps */
|
psDeviceNode->papsRegisteredPhysHeaps =
|
OSAllocZMem(sizeof(*psDeviceNode->papsRegisteredPhysHeaps) *
|
psDevConfig->ui32PhysHeapCount);
|
if (!psDeviceNode->papsRegisteredPhysHeaps)
|
{
|
goto e3;
|
}
|
|
for (i = 0; i < psDevConfig->ui32PhysHeapCount; i++)
|
{
|
eError = PhysHeapRegister(&psDevConfig->pasPhysHeaps[i],
|
&psDeviceNode->papsRegisteredPhysHeaps[i]);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to register physical heap %d (%s)",
|
__func__, psDevConfig->pasPhysHeaps[i].ui32PhysHeapID,
|
PVRSRVGetErrorStringKM(eError)));
|
goto e4;
|
}
|
|
psDeviceNode->ui32RegisteredPhysHeaps++;
|
}
|
|
/*
|
* The physical backing storage for the following physical heaps
|
* [CPU,GPU,FW] may or may not come from the same underlying source
|
*/
|
eError = PhysHeapAcquire(psDevConfig->aui32PhysHeapID[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL],
|
&psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL]);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to acquire PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL physical memory heap",
|
__func__));
|
goto e4;
|
}
|
|
eError = PhysHeapAcquire(psDevConfig->aui32PhysHeapID[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL],
|
&psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL]);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to acquire PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL physical memory heap",
|
__func__));
|
goto e5;
|
}
|
|
eError = PhysHeapAcquire(psDevConfig->aui32PhysHeapID[PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL],
|
&psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL]);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to acquire PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL physical memory heap",
|
__func__));
|
goto e5;
|
}
|
|
/* Do we have card memory? If so create RAs to manage it */
|
if (PhysHeapGetType(psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL]) == PHYS_HEAP_TYPE_LMA)
|
{
|
RA_BASE_T uBase;
|
RA_LENGTH_T uSize;
|
IMG_UINT64 ui64Size;
|
IMG_CPU_PHYADDR sCpuPAddr;
|
IMG_DEV_PHYADDR sDevPAddr;
|
|
IMG_UINT32 ui32NumOfLMARegions;
|
IMG_UINT32 ui32RegionId;
|
PHYS_HEAP* psLMAHeap;
|
|
psLMAHeap = psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL];
|
ui32NumOfLMARegions = PhysHeapNumberOfRegions(psLMAHeap);
|
|
if (ui32NumOfLMARegions == 0)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: LMA heap has no memory regions defined.", __func__));
|
eError = PVRSRV_ERROR_DEVICEMEM_INVALID_LMA_HEAP;
|
goto e5;
|
}
|
|
/* Allocate memory for RA pointers and name strings */
|
psDeviceNode->apsLocalDevMemArenas = OSAllocMem(sizeof(RA_ARENA*) * ui32NumOfLMARegions);
|
psDeviceNode->ui32NumOfLocalMemArenas = ui32NumOfLMARegions;
|
psDeviceNode->apszRANames = OSAllocMem(ui32NumOfLMARegions * sizeof(IMG_PCHAR));
|
|
for (ui32RegionId = 0; ui32RegionId < ui32NumOfLMARegions; ui32RegionId++)
|
{
|
eError = PhysHeapRegionGetSize(psLMAHeap, ui32RegionId, &ui64Size);
|
if (eError != PVRSRV_OK)
|
{
|
/* We can only get here if there is a bug in this module */
|
PVR_ASSERT(IMG_FALSE);
|
return eError;
|
}
|
|
eError = PhysHeapRegionGetCpuPAddr(psLMAHeap, ui32RegionId, &sCpuPAddr);
|
if (eError != PVRSRV_OK)
|
{
|
/* We can only get here if there is a bug in this module */
|
PVR_ASSERT(IMG_FALSE);
|
return eError;
|
}
|
|
eError = PhysHeapRegionGetDevPAddr(psLMAHeap, ui32RegionId, &sDevPAddr);
|
if (eError != PVRSRV_OK)
|
{
|
/* We can only get here if there is a bug in this module */
|
PVR_ASSERT(IMG_FALSE);
|
return eError;
|
}
|
|
PVR_DPF((PVR_DBG_MESSAGE,
|
"Creating RA for card memory - region %d - 0x%016llx-0x%016llx",
|
ui32RegionId, (IMG_UINT64) sCpuPAddr.uiAddr,
|
sCpuPAddr.uiAddr + ui64Size));
|
|
psDeviceNode->apszRANames[ui32RegionId] =
|
OSAllocMem(PVRSRV_MAX_RA_NAME_LENGTH);
|
OSSNPrintf(psDeviceNode->apszRANames[ui32RegionId],
|
PVRSRV_MAX_RA_NAME_LENGTH,
|
"%s card mem",
|
psDevConfig->pszName);
|
|
uBase = sDevPAddr.uiAddr;
|
uSize = (RA_LENGTH_T) ui64Size;
|
PVR_ASSERT(uSize == ui64Size);
|
|
/* Use host page size, keeps things simple */
|
psDeviceNode->apsLocalDevMemArenas[ui32RegionId] =
|
RA_Create(psDeviceNode->apszRANames[ui32RegionId],
|
OSGetPageShift(), RA_LOCKCLASS_0, NULL, NULL, NULL,
|
IMG_FALSE);
|
|
if (psDeviceNode->apsLocalDevMemArenas[ui32RegionId] == NULL)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to create LMA memory arena",
|
__func__));
|
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
|
goto e6;
|
}
|
|
if (!RA_Add(psDeviceNode->apsLocalDevMemArenas[ui32RegionId],
|
uBase, uSize, 0, NULL))
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to add memory to LMA memory arena",
|
__func__));
|
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
|
goto e6;
|
}
|
}
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
eError = CreateLMASubArenas(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to create LMA memory sub-arenas", __func__));
|
goto e6;
|
}
|
#endif
|
|
/* If additional psDeviceNode->pfnDevPx* callbacks are added,
|
update the corresponding virtualization-specific override
|
in pvrsrv_vz.c:PVRSRVVzDeviceCreate() */
|
psDeviceNode->pfnDevPxAlloc = LMA_PhyContigPagesAlloc;
|
psDeviceNode->pfnDevPxFree = LMA_PhyContigPagesFree;
|
psDeviceNode->pfnDevPxMap = LMA_PhyContigPagesMap;
|
psDeviceNode->pfnDevPxUnMap = LMA_PhyContigPagesUnmap;
|
psDeviceNode->pfnDevPxClean = LMA_PhyContigPagesClean;
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL] = PhysmemNewLocalRamBackedPMR;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "===== OS System memory only, no local card memory"));
|
|
/* else we only have OS system memory */
|
psDeviceNode->pfnDevPxAlloc = OSPhyContigPagesAlloc;
|
psDeviceNode->pfnDevPxFree = OSPhyContigPagesFree;
|
psDeviceNode->pfnDevPxMap = OSPhyContigPagesMap;
|
psDeviceNode->pfnDevPxUnMap = OSPhyContigPagesUnmap;
|
psDeviceNode->pfnDevPxClean = OSPhyContigPagesClean;
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL] = PhysmemNewOSRamBackedPMR;
|
}
|
|
if (PhysHeapGetType(psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL]) == PHYS_HEAP_TYPE_LMA)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "===== Local card memory only, no OS system memory"));
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL] = PhysmemNewLocalRamBackedPMR;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "===== OS System memory, 2nd phys heap"));
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_CPU_LOCAL] = PhysmemNewOSRamBackedPMR;
|
}
|
|
if (PhysHeapGetType(psDeviceNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL]) == PHYS_HEAP_TYPE_LMA)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "===== Local card memory only, no OS system memory"));
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL] = PhysmemNewLocalRamBackedPMR;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "===== OS System memory, 3rd phys heap"));
|
psDeviceNode->pfnCreateRamBackedPMR[PVRSRV_DEVICE_PHYS_HEAP_FW_LOCAL] = PhysmemNewOSRamBackedPMR;
|
}
|
|
psDeviceNode->uiMMUPxLog2AllocGran = OSGetPageShift();
|
|
eError = ServerSyncInit(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
goto e6;
|
}
|
|
#if defined(SUPPORT_PVRSRV_GPUVIRT)
|
/* Perform virtualization device creation */
|
PVRSRVVzDeviceCreate(psDeviceNode);
|
#endif
|
|
/*
|
* This is registered before doing device specific initialisation to ensure
|
* generic device information is dumped first during a debug request.
|
*/
|
eError = PVRSRVRegisterDbgRequestNotify(&psDeviceNode->hDbgReqNotify,
|
psDeviceNode,
|
_SysDebugRequestNotify,
|
DEBUG_REQUEST_SYS,
|
psDeviceNode);
|
PVR_LOG_IF_ERROR(eError, "PVRSRVRegisterDbgRequestNotify");
|
|
eError = HTBDeviceCreate(psDeviceNode);
|
PVR_LOG_IF_ERROR(eError, "HTBDeviceCreate");
|
|
psPVRSRVData->ui32RegisteredDevices++;
|
|
#if defined(SUPPORT_RGX)
|
eError = RGXRegisterDevice(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to register device", __func__));
|
eError = PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
|
goto e7;
|
}
|
#endif
|
|
#if defined(PVR_DVFS)
|
eError = InitDVFS(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to start DVFS", __func__));
|
#if defined(SUPPORT_RGX)
|
DevDeInitRGX(psDeviceNode);
|
#endif
|
goto e7;
|
}
|
#endif
|
|
#if defined(PVR_TESTING_UTILS)
|
TUtilsInit(psDeviceNode);
|
#endif
|
|
dllist_init(&psDeviceNode->sMemoryContextPageFaultNotifyListHead);
|
|
/*
|
* Initialise the Transport Layer.
|
* Need to remember the RGX device node for use in the Transport Layer
|
* when allocating stream buffers that are shared with clients.
|
* Note however when the device is an LMA device our buffers will not
|
* be in host memory but card memory.
|
*/
|
eError = TLInit(psDeviceNode);
|
PVR_LOG_IF_ERROR(eError, "TLInit");
|
|
PVR_DPF((PVR_DBG_MESSAGE, "Registered device %p", psDeviceNode));
|
PVR_DPF((PVR_DBG_MESSAGE, "Register bank address = 0x%08lx",
|
(unsigned long)psDevConfig->sRegsCpuPBase.uiAddr));
|
PVR_DPF((PVR_DBG_MESSAGE, "IRQ = %d", psDevConfig->ui32IRQ));
|
|
/* Finally insert the device into the dev-list and set it as active */
|
List_PVRSRV_DEVICE_NODE_InsertTail(&psPVRSRVData->psDeviceNodeList,
|
psDeviceNode);
|
|
*ppsDeviceNode = psDeviceNode;
|
|
return PVRSRV_OK;
|
|
#if defined(SUPPORT_RGX) || defined(PVR_DVFS)
|
e7:
|
psPVRSRVData->ui32RegisteredDevices--;
|
|
if (psDeviceNode->hDbgReqNotify)
|
{
|
PVRSRVUnregisterDbgRequestNotify(psDeviceNode->hDbgReqNotify);
|
}
|
|
#if defined(SUPPORT_PVRSRV_GPUVIRT)
|
/* Perform virtualization device destruction */
|
PVRSRVVzDeviceDestroy(psDeviceNode);
|
#endif
|
ServerSyncDeinit(psDeviceNode);
|
#endif
|
e6:
|
{
|
IMG_UINT32 ui32RegionId;
|
|
for (ui32RegionId = 0;
|
ui32RegionId < psDeviceNode->ui32NumOfLocalMemArenas;
|
ui32RegionId++)
|
{
|
if (psDeviceNode->apsLocalDevMemArenas[ui32RegionId])
|
{
|
RA_Delete(psDeviceNode->apsLocalDevMemArenas[ui32RegionId]);
|
}
|
}
|
}
|
|
e5:
|
for (physHeapIndex = 0;
|
physHeapIndex < IMG_ARR_NUM_ELEMS(psDeviceNode->apsPhysHeap);
|
physHeapIndex++)
|
{
|
if (psDeviceNode->apsPhysHeap[physHeapIndex])
|
{
|
PhysHeapRelease(psDeviceNode->apsPhysHeap[physHeapIndex]);
|
}
|
}
|
e4:
|
for (i = 0; i < psDeviceNode->ui32RegisteredPhysHeaps; i++)
|
{
|
PhysHeapUnregister(psDeviceNode->papsRegisteredPhysHeaps[i]);
|
}
|
|
OSFreeMem(psDeviceNode->papsRegisteredPhysHeaps);
|
e3:
|
OSLockDestroy(psDeviceNode->hPowerLock);
|
e2:
|
PVRSRVUnregisterDbgTable(psDeviceNode);
|
e1:
|
psDevConfig->psDevNode = NULL;
|
SysDevDeInit(psDevConfig);
|
e0:
|
OSFreeMem(psDeviceNode);
|
return eError;
|
}
|
|
#if defined(SUPPORT_KERNEL_SRVINIT)
|
static PVRSRV_ERROR _SetDeviceFlag(const PVRSRV_DEVICE_NODE *psDevice,
|
const void *psPrivate, IMG_BOOL bValue)
|
{
|
PVRSRV_ERROR eResult = PVRSRV_OK;
|
IMG_UINT32 ui32Flag = (IMG_UINT32)((uintptr_t)psPrivate);
|
|
if (!ui32Flag)
|
{
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
eResult = RGXSetDeviceFlags((PVRSRV_RGXDEV_INFO *)psDevice->pvDevice,
|
ui32Flag, bValue);
|
|
return eResult;
|
}
|
|
static PVRSRV_ERROR _ReadDeviceFlag(const PVRSRV_DEVICE_NODE *psDevice,
|
const void *psPrivate, IMG_BOOL *pbValue)
|
{
|
PVRSRV_ERROR eResult = PVRSRV_OK;
|
IMG_UINT32 ui32Flag = (IMG_UINT32)((uintptr_t)psPrivate);
|
IMG_UINT32 ui32State;
|
|
if (!ui32Flag)
|
{
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
eResult = RGXGetDeviceFlags((PVRSRV_RGXDEV_INFO *)psDevice->pvDevice,
|
&ui32State);
|
|
if (PVRSRV_OK == eResult)
|
{
|
*pbValue = (ui32State & ui32Flag)? IMG_TRUE: IMG_FALSE;
|
}
|
|
return eResult;
|
}
|
static PVRSRV_ERROR _SetStateFlag(const PVRSRV_DEVICE_NODE *psDevice,
|
const void *psPrivate, IMG_BOOL bValue)
|
{
|
PVRSRV_ERROR eResult = PVRSRV_OK;
|
IMG_UINT32 ui32Flag = (IMG_UINT32)((uintptr_t)psPrivate);
|
|
if (!ui32Flag)
|
{
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
/* EnableHWR is a special case
|
* only possible to disable after FW is running
|
*/
|
if (bValue && RGXFWIF_INICFG_HWR_EN == ui32Flag)
|
{
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
}
|
|
eResult = RGXStateFlagCtrl((PVRSRV_RGXDEV_INFO *)psDevice->pvDevice,
|
ui32Flag, NULL, bValue);
|
|
return eResult;
|
}
|
|
static PVRSRV_ERROR _ReadStateFlag(const PVRSRV_DEVICE_NODE *psDevice,
|
const void *psPrivate, IMG_BOOL *pbValue)
|
{
|
PVRSRV_ERROR eResult = PVRSRV_OK;
|
IMG_UINT32 ui32Flag = (IMG_UINT32)((uintptr_t)psPrivate);
|
IMG_UINT32 ui32State;
|
|
if (!ui32Flag)
|
{
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
eResult = RGXStateFlagCtrl((PVRSRV_RGXDEV_INFO *)psDevice->pvDevice,
|
0, &ui32State, IMG_FALSE);
|
|
if (PVRSRV_OK == eResult)
|
{
|
*pbValue = (ui32State & ui32Flag)? IMG_TRUE: IMG_FALSE;
|
}
|
|
return eResult;
|
}
|
|
PVRSRV_ERROR PVRSRVDeviceInitialise(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
IMG_BOOL bInitSuccesful = IMG_FALSE;
|
PVRSRV_ERROR eError;
|
|
if (psDeviceNode->eDevState != PVRSRV_DEVICE_STATE_INIT)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Device already initialised", __func__));
|
return PVRSRV_ERROR_INIT_FAILURE;
|
}
|
|
#if defined(SUPPORT_RGX)
|
eError = RGXInit(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Initialisation of Rogue device failed (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto Exit;
|
}
|
#endif
|
|
bInitSuccesful = IMG_TRUE;
|
|
#if defined(SUPPORT_RGX)
|
Exit:
|
#endif
|
eError = PVRSRVDeviceFinalise(psDeviceNode, bInitSuccesful);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Services failed to finalise the device (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
}
|
|
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_DisableClockGating,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_DISABLE_CLKGATING_EN));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_DisableDMOverlap,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_DISABLE_DM_OVERLAP));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_AssertOnHWRTrigger,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_ASSERT_ON_HWR_TRIGGER));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_AssertOutOfMemory,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_ASSERT_ON_OUTOFMEMORY));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_CheckMList,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_CHECK_MLIST_EN));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_EnableHWR,
|
_ReadStateFlag, _SetStateFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXFWIF_INICFG_HWR_EN));
|
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_DisableFEDLogging,
|
_ReadDeviceFlag, _SetDeviceFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXKMIF_DEVICE_STATE_DISABLE_DW_LOGGING_EN));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_ZeroFreelist,
|
_ReadDeviceFlag, _SetDeviceFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXKMIF_DEVICE_STATE_ZERO_FREELIST));
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_DustRequestInject,
|
_ReadDeviceFlag, _SetDeviceFlag,
|
psDeviceNode,
|
(void*)((uintptr_t)RGXKMIF_DEVICE_STATE_DUST_REQUEST_INJECT_EN));
|
|
PVRSRVAppHintRegisterHandlersBOOL(APPHINT_ID_DisablePDumpPanic,
|
RGXQueryPdumpPanicEnable, RGXSetPdumpPanicEnable,
|
psDeviceNode,
|
NULL);
|
return eError;
|
}
|
#endif /* defined(SUPPORT_KERNEL_SRVINIT) */
|
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVDeviceDestroy(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
PVRSRV_DEVICE_PHYS_HEAP ePhysHeapIdx;
|
IMG_UINT32 ui32RegionIdx;
|
IMG_UINT32 i;
|
PVRSRV_ERROR eError;
|
#if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
|
IMG_BOOL bForceUnload = IMG_FALSE;
|
|
if (PVRSRVGetPVRSRVData()->eServicesState != PVRSRV_SERVICES_STATE_OK)
|
{
|
bForceUnload = IMG_TRUE;
|
}
|
#endif
|
|
psPVRSRVData->ui32RegisteredDevices--;
|
|
psDeviceNode->eDevState = PVRSRV_DEVICE_STATE_DEINIT;
|
|
#if defined(PVR_TESTING_UTILS)
|
TUtilsDeinit(psDeviceNode);
|
#endif
|
|
/* Counter part to what gets done in PVRSRVDeviceFinalise */
|
if (psDeviceNode->hSyncPrimContext)
|
{
|
if (psDeviceNode->psSyncPrim)
|
{
|
/* Free general pupose sync primitive */
|
SyncPrimFree(psDeviceNode->psSyncPrim);
|
psDeviceNode->psSyncPrim = NULL;
|
}
|
|
if (psDeviceNode->psMMUCacheSyncPrim)
|
{
|
PVRSRV_CLIENT_SYNC_PRIM *psSync = psDeviceNode->psMMUCacheSyncPrim;
|
|
/* Important to set the device node pointer to NULL
|
* before we free the sync-prim to make sure we don't
|
* defer the freeing of the sync-prim's page tables itself.
|
* The sync is used to defer the MMU page table
|
* freeing. */
|
psDeviceNode->psMMUCacheSyncPrim = NULL;
|
|
/* Free general pupose sync primitive */
|
SyncPrimFree(psSync);
|
|
}
|
|
SyncPrimContextDestroy(psDeviceNode->hSyncPrimContext);
|
psDeviceNode->hSyncPrimContext = NULL;
|
}
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to acquire power lock", __func__));
|
return eError;
|
}
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
{
|
#if defined(PVRSRV_FORCE_UNLOAD_IF_BAD_STATE)
|
if (bForceUnload)
|
{
|
/*
|
* Firmware probably not responding but we still want to unload the
|
* driver.
|
*/
|
break;
|
}
|
#endif
|
/* Force idle device */
|
eError = PVRSRVDeviceIdleRequestKM(psDeviceNode, NULL, IMG_TRUE);
|
if (eError == PVRSRV_OK)
|
{
|
break;
|
}
|
else if (eError == PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED)
|
{
|
PVRSRV_ERROR eError2;
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
eError2 = PVRSRVPowerLock(psDeviceNode);
|
if (eError2 != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to acquire power lock",
|
__func__));
|
return eError2;
|
}
|
}
|
else
|
{
|
PVRSRVPowerUnlock(psDeviceNode);
|
return eError;
|
}
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
/* Power down the device if necessary */
|
eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
|
PVRSRV_DEV_POWER_STATE_OFF,
|
IMG_TRUE);
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed PVRSRVSetDevicePowerStateKM call (%s). Dump debug.",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
|
PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL);
|
|
/*
|
* If the driver is okay then return the error, otherwise we can ignore
|
* this error.
|
*/
|
if (PVRSRVGetPVRSRVData()->eServicesState == PVRSRV_SERVICES_STATE_OK)
|
{
|
return eError;
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_MESSAGE,
|
"%s: Will continue to unregister as driver status is not OK",
|
__func__));
|
}
|
}
|
|
#if defined(SUPPORT_RGX)
|
DevDeInitRGX(psDeviceNode);
|
#endif
|
|
HTBDeviceDestroy(psDeviceNode);
|
|
if (psDeviceNode->hDbgReqNotify)
|
{
|
PVRSRVUnregisterDbgRequestNotify(psDeviceNode->hDbgReqNotify);
|
}
|
|
#if defined(SUPPORT_PVRSRV_GPUVIRT)
|
/* Perform virtualization device destruction */
|
PVRSRVVzDeviceDestroy(psDeviceNode);
|
#endif
|
|
ServerSyncDeinit(psDeviceNode);
|
|
/* Remove RAs and RA names for local card memory */
|
for (ui32RegionIdx = 0;
|
ui32RegionIdx < psDeviceNode->ui32NumOfLocalMemArenas;
|
ui32RegionIdx++)
|
{
|
if (psDeviceNode->apsLocalDevMemArenas[ui32RegionIdx])
|
{
|
RA_Delete(psDeviceNode->apsLocalDevMemArenas[ui32RegionIdx]);
|
}
|
|
if (psDeviceNode->apszRANames[ui32RegionIdx])
|
{
|
OSFreeMem(psDeviceNode->apszRANames[ui32RegionIdx]);
|
}
|
}
|
|
OSFreeMem(psDeviceNode->apsLocalDevMemArenas);
|
OSFreeMem(psDeviceNode->apszRANames);
|
|
List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode);
|
|
for (ePhysHeapIdx = 0;
|
ePhysHeapIdx < IMG_ARR_NUM_ELEMS(psDeviceNode->apsPhysHeap);
|
ePhysHeapIdx++)
|
{
|
if (psDeviceNode->apsPhysHeap[ePhysHeapIdx])
|
{
|
PhysHeapRelease(psDeviceNode->apsPhysHeap[ePhysHeapIdx]);
|
}
|
}
|
|
for (i = 0; i < psDeviceNode->ui32RegisteredPhysHeaps; i++)
|
{
|
PhysHeapUnregister(psDeviceNode->papsRegisteredPhysHeaps[i]);
|
}
|
|
OSFreeMem(psDeviceNode->papsRegisteredPhysHeaps);
|
|
#if defined(PVR_DVFS)
|
DeinitDVFS(psDeviceNode);
|
#endif
|
|
OSLockDestroy(psDeviceNode->hPowerLock);
|
|
PVRSRVUnregisterDbgTable(psDeviceNode);
|
|
psDeviceNode->psDevConfig->psDevNode = NULL;
|
SysDevDeInit(psDeviceNode->psDevConfig);
|
|
/*
|
* Clean up Transport Layer resources that remain. Done after RGX node clean
|
* up as HWPerf stream is destroyed during this.
|
*/
|
TLDeInit(psDeviceNode);
|
|
OSFreeMem(psDeviceNode);
|
|
return PVRSRV_OK;
|
}
|
|
PVRSRV_ERROR LMA_PhyContigPagesAlloc(PVRSRV_DEVICE_NODE *psDevNode, size_t uiSize,
|
PG_HANDLE *psMemHandle, IMG_DEV_PHYADDR *psDevPAddr)
|
{
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
IMG_UINT32 ui32OSid = 0;
|
#endif
|
RA_BASE_T uiCardAddr;
|
RA_LENGTH_T uiActualSize;
|
PVRSRV_ERROR eError;
|
|
RA_ARENA *pArena=psDevNode->apsLocalDevMemArenas[0];
|
IMG_UINT32 ui32Log2NumPages = 0;
|
|
PVR_ASSERT(uiSize != 0);
|
ui32Log2NumPages = OSGetOrder(uiSize);
|
uiSize = (1 << ui32Log2NumPages) * OSGetPageSize();
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
{
|
IMG_UINT32 ui32OSidReg = 0;
|
IMG_BOOL bOSidAxiProt;
|
|
IMG_PID pId = OSGetCurrentClientProcessIDKM();
|
|
RetrieveOSidsfromPidList(pId, &ui32OSid, &ui32OSidReg, &bOSidAxiProt);
|
|
pArena = psDevNode->psOSidSubArena[ui32OSid];
|
}
|
#endif
|
|
eError = RA_Alloc(pArena,
|
uiSize,
|
RA_NO_IMPORT_MULTIPLIER,
|
0, /* No flags */
|
OSGetPageSize(),
|
"LMA_PhyContigPagesAlloc",
|
&uiCardAddr,
|
&uiActualSize,
|
NULL); /* No private handle */
|
|
PVR_ASSERT(uiSize == uiActualSize);
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE,"(GPU Virtualization Validation): LMA_PhyContigPagesAlloc: Address:%llu, size:%llu", uiCardAddr,uiActualSize));
|
}
|
#endif
|
|
psMemHandle->u.ui64Handle = uiCardAddr;
|
psDevPAddr->uiAddr = (IMG_UINT64) uiCardAddr;
|
|
if (PVRSRV_OK == eError)
|
{
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
|
PVRSRVStatsIncrMemAllocStatAndTrack(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA,
|
uiSize,
|
(IMG_UINT64)(uintptr_t) psMemHandle);
|
#else
|
IMG_CPU_PHYADDR sCpuPAddr;
|
sCpuPAddr.uiAddr = psDevPAddr->uiAddr;
|
|
PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA,
|
NULL,
|
sCpuPAddr,
|
uiSize,
|
NULL);
|
#endif
|
#endif
|
psMemHandle->ui32Order = ui32Log2NumPages;
|
}
|
|
return eError;
|
}
|
|
void LMA_PhyContigPagesFree(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle)
|
{
|
RA_BASE_T uiCardAddr = (RA_BASE_T) psMemHandle->u.ui64Handle;
|
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
|
PVRSRVStatsDecrMemAllocStatAndUntrack(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA,
|
(IMG_UINT64)(uintptr_t) psMemHandle);
|
#else
|
PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_PAGES_PT_LMA, (IMG_UINT64)uiCardAddr);
|
#endif
|
#endif
|
RA_Free(psDevNode->apsLocalDevMemArenas[0], uiCardAddr);
|
psMemHandle->ui32Order = 0;
|
}
|
|
PVRSRV_ERROR LMA_PhyContigPagesMap(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle,
|
size_t uiSize, IMG_DEV_PHYADDR *psDevPAddr,
|
void **pvPtr)
|
{
|
IMG_CPU_PHYADDR sCpuPAddr;
|
IMG_UINT32 ui32NumPages = (1 << psMemHandle->ui32Order);
|
PVR_UNREFERENCED_PARAMETER(psMemHandle);
|
PVR_UNREFERENCED_PARAMETER(uiSize);
|
|
PhysHeapDevPAddrToCpuPAddr(psDevNode->apsPhysHeap[PVRSRV_DEVICE_PHYS_HEAP_GPU_LOCAL], 1, &sCpuPAddr, psDevPAddr);
|
*pvPtr = OSMapPhysToLin(sCpuPAddr,
|
ui32NumPages * OSGetPageSize(),
|
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE);
|
if (*pvPtr == NULL)
|
{
|
return PVRSRV_ERROR_OUT_OF_MEMORY;
|
}
|
else
|
{
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
|
PVRSRVStatsIncrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA, ui32NumPages * OSGetPageSize());
|
#else
|
{
|
PVRSRVStatsAddMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA,
|
*pvPtr,
|
sCpuPAddr,
|
ui32NumPages * OSGetPageSize(),
|
NULL);
|
}
|
#endif
|
#endif
|
return PVRSRV_OK;
|
}
|
}
|
|
void LMA_PhyContigPagesUnmap(PVRSRV_DEVICE_NODE *psDevNode, PG_HANDLE *psMemHandle,
|
void *pvPtr)
|
{
|
IMG_UINT32 ui32NumPages = (1 << psMemHandle->ui32Order);
|
PVR_UNREFERENCED_PARAMETER(psMemHandle);
|
PVR_UNREFERENCED_PARAMETER(psDevNode);
|
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
|
PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA, ui32NumPages * OSGetPageSize());
|
#else
|
PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_IOREMAP_PT_LMA, (IMG_UINT64)(uintptr_t)pvPtr);
|
#endif
|
#endif
|
|
OSUnMapPhysToLin(pvPtr, ui32NumPages * OSGetPageSize(),
|
PVRSRV_MEMALLOCFLAG_CPU_UNCACHED);
|
}
|
|
PVRSRV_ERROR LMA_PhyContigPagesClean(PVRSRV_DEVICE_NODE *psDevNode,
|
PG_HANDLE *psMemHandle,
|
IMG_UINT32 uiOffset,
|
IMG_UINT32 uiLength)
|
{
|
/* No need to flush because we map as uncached */
|
PVR_UNREFERENCED_PARAMETER(psDevNode);
|
PVR_UNREFERENCED_PARAMETER(psMemHandle);
|
PVR_UNREFERENCED_PARAMETER(uiOffset);
|
PVR_UNREFERENCED_PARAMETER(uiLength);
|
|
return PVRSRV_OK;
|
}
|
|
/**************************************************************************/ /*!
|
@Function PVRSRVDeviceFinalise
|
@Description Performs the final parts of device initialisation.
|
@Input psDeviceNode Device node of the device to finish
|
initialising
|
@Input bInitSuccessful Whether or not device specific
|
initialisation was successful
|
@Return PVRSRV_ERROR PVRSRV_OK on success and an error otherwise
|
*/ /***************************************************************************/
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVDeviceFinalise(PVRSRV_DEVICE_NODE *psDeviceNode,
|
IMG_BOOL bInitSuccessful)
|
{
|
PVRSRV_ERROR eError;
|
|
if (bInitSuccessful)
|
{
|
eError = SyncPrimContextCreate(psDeviceNode,
|
&psDeviceNode->hSyncPrimContext);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to create sync prim context (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
|
/* Allocate general purpose sync primitive */
|
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
|
&psDeviceNode->psSyncPrim,
|
"pvrsrv dev general");
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to allocate sync primitive with error (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
|
/* Allocate MMU cache invalidate sync */
|
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
|
&psDeviceNode->psMMUCacheSyncPrim,
|
"pvrsrv dev MMU cache");
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to allocate sync primitive with error (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
|
/* Next update value will be 1 since sync prim starts with 0 */
|
psDeviceNode->ui32NextMMUInvalidateUpdate = 1;
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to acquire power lock (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
|
/*
|
* Always ensure a single power on command appears in the pdump. This
|
* should be the only power related call outside of PDUMPPOWCMDSTART
|
* and PDUMPPOWCMDEND.
|
*/
|
eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
|
PVRSRV_DEV_POWER_STATE_ON, IMG_TRUE);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to set device %p power state to 'on' (%s)",
|
__func__, psDeviceNode, PVRSRVGetErrorStringKM(eError)));
|
PVRSRVPowerUnlock(psDeviceNode);
|
goto ErrorExit;
|
}
|
|
/* Verify firmware compatibility for device */
|
eError = PVRSRVDevInitCompatCheck(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed compatibility check for device %p (%s)",
|
__func__, psDeviceNode, PVRSRVGetErrorStringKM(eError)));
|
PVRSRVPowerUnlock(psDeviceNode);
|
PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL);
|
goto ErrorExit;
|
}
|
|
PDUMPPOWCMDSTART();
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
{
|
/* Force the device to idle if its default power state is off */
|
eError = PVRSRVDeviceIdleRequestKM(psDeviceNode,
|
&PVRSRVDeviceIsDefaultStateOFF,
|
IMG_TRUE);
|
if (eError == PVRSRV_OK)
|
{
|
break;
|
}
|
else if (eError == PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED)
|
{
|
PVRSRVPowerUnlock(psDeviceNode);
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to acquire power lock (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
}
|
else
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to idle device %p (%s)",
|
__func__, psDeviceNode,
|
PVRSRVGetErrorStringKM(eError)));
|
PVRSRVPowerUnlock(psDeviceNode);
|
goto ErrorExit;
|
}
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
/* Place device into its default power state. */
|
eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
|
PVRSRV_DEV_POWER_STATE_DEFAULT,
|
IMG_TRUE);
|
PDUMPPOWCMDEND();
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to set device %p into its default power state (%s)",
|
__func__, psDeviceNode, PVRSRVGetErrorStringKM(eError)));
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
goto ErrorExit;
|
}
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
/*
|
* If PDUMP is enabled and RGX device is supported, then initialise the
|
* performance counters that can be further modified in PDUMP. Then,
|
* before ending the init phase of the pdump, drain the commands put in
|
* the kCCB during the init phase.
|
*/
|
#if defined(SUPPORT_RGX) && defined(PDUMP)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo =
|
(PVRSRV_RGXDEV_INFO *)(psDeviceNode->pvDevice);
|
|
eError = PVRSRVRGXInitHWPerfCountersKM(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to init hwperf counters (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
|
eError = RGXPdumpDrainKCCB(psDevInfo,
|
psDevInfo->psKernelCCBCtl->ui32WriteOffset);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Problem draining kCCB (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
goto ErrorExit;
|
}
|
}
|
#endif
|
|
/* Now that the device(s) are fully initialised set them as active */
|
psDeviceNode->eDevState = PVRSRV_DEVICE_STATE_ACTIVE;
|
|
#if defined(SUPPORT_RGX) && defined(PVRSRV_GPUVIRT_GUESTDRV)
|
eError = RGXFWOSConfig((PVRSRV_RGXDEV_INFO *)(psDeviceNode->pvDevice));
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: Cannot kick initialization configuration to the Device (%s)",
|
__func__, PVRSRVGetErrorStringKM(eError)));
|
|
goto ErrorExit;
|
}
|
#endif
|
}
|
else
|
{
|
/* Initialisation failed so set the device(s) into a bad state */
|
psDeviceNode->eDevState = PVRSRV_DEVICE_STATE_BAD;
|
eError = PVRSRV_ERROR_NOT_INITIALISED;
|
}
|
|
/* Give PDump control a chance to end the init phase, depends on OS */
|
PDumpStopInitPhase(IMG_FALSE, IMG_TRUE);
|
|
return eError;
|
|
ErrorExit:
|
/* Initialisation failed so set the device(s) into a bad state */
|
psDeviceNode->eDevState = PVRSRV_DEVICE_STATE_BAD;
|
|
return eError;
|
}
|
|
PVRSRV_ERROR IMG_CALLCONV 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;
|
}
|
|
/*
|
PollForValueKM
|
*/
|
static
|
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(NO_HARDWARE)
|
PVR_UNREFERENCED_PARAMETER(pui32LinMemAddr);
|
PVR_UNREFERENCED_PARAMETER(ui32Value);
|
PVR_UNREFERENCED_PARAMETER(ui32Mask);
|
PVR_UNREFERENCED_PARAMETER(ui32Timeoutus);
|
PVR_UNREFERENCED_PARAMETER(ui32PollPeriodus);
|
PVR_UNREFERENCED_PARAMETER(bAllowPreemption);
|
return PVRSRV_OK;
|
#else
|
IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU; /* Initialiser only required to prevent incorrect warning */
|
|
if (bAllowPreemption)
|
{
|
PVR_ASSERT(ui32PollPeriodus >= 1000);
|
}
|
|
LOOP_UNTIL_TIMEOUT(ui32Timeoutus)
|
{
|
ui32ActualValue = OSReadHWReg32((void *)pui32LinMemAddr, 0) & ui32Mask;
|
|
if(ui32ActualValue == ui32Value)
|
{
|
return PVRSRV_OK;
|
}
|
|
if (gpsPVRSRVData->eServicesState != PVRSRV_SERVICES_STATE_OK)
|
{
|
return PVRSRV_ERROR_TIMEOUT;
|
}
|
|
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));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
#endif /* NO_HARDWARE */
|
}
|
|
|
/*
|
PVRSRVPollForValueKM
|
*/
|
IMG_EXPORT
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVPollForValueKM (volatile IMG_UINT32 *pui32LinMemAddr,
|
IMG_UINT32 ui32Value,
|
IMG_UINT32 ui32Mask)
|
{
|
return PollForValueKM(pui32LinMemAddr, ui32Value, ui32Mask,
|
MAX_HW_TIME_US,
|
MAX_HW_TIME_US/WAIT_TRY_COUNT,
|
IMG_FALSE);
|
}
|
|
static
|
PVRSRV_ERROR IMG_CALLCONV WaitForValueKM(volatile IMG_UINT32 *pui32LinMemAddr,
|
IMG_UINT32 ui32Value,
|
IMG_UINT32 ui32Mask,
|
IMG_BOOL bHoldBridgeLock)
|
{
|
#if defined(NO_HARDWARE)
|
PVR_UNREFERENCED_PARAMETER(pui32LinMemAddr);
|
PVR_UNREFERENCED_PARAMETER(ui32Value);
|
PVR_UNREFERENCED_PARAMETER(ui32Mask);
|
return PVRSRV_OK;
|
#else
|
|
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
IMG_HANDLE hOSEvent;
|
PVRSRV_ERROR eError;
|
PVRSRV_ERROR eErrorWait;
|
IMG_UINT32 ui32ActualValue;
|
|
eError = OSEventObjectOpen(psPVRSRVData->hGlobalEventObject, &hOSEvent);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"PVRSRVWaitForValueKM: Failed to setup EventObject with error (%d)", eError));
|
goto EventObjectOpenError;
|
}
|
|
eError = PVRSRV_ERROR_TIMEOUT;
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
{
|
ui32ActualValue = (*pui32LinMemAddr & ui32Mask);
|
|
if (ui32ActualValue == ui32Value)
|
{
|
/* Expected value has been found */
|
eError = PVRSRV_OK;
|
break;
|
}
|
else if (psPVRSRVData->eServicesState != PVRSRV_SERVICES_STATE_OK)
|
{
|
/* Services in bad state, don't wait any more */
|
eError = PVRSRV_ERROR_NOT_READY;
|
break;
|
}
|
else
|
{
|
/* wait for event and retry */
|
eErrorWait = bHoldBridgeLock ? OSEventObjectWaitAndHoldBridgeLock(hOSEvent) : OSEventObjectWait(hOSEvent);
|
if (eErrorWait != PVRSRV_OK && eErrorWait != PVRSRV_ERROR_TIMEOUT)
|
{
|
PVR_DPF((PVR_DBG_WARNING,"PVRSRVWaitForValueKM: Waiting for value failed with error %d. Expected 0x%x but found 0x%x (Mask 0x%08x). Retrying",
|
eErrorWait,
|
ui32Value,
|
ui32ActualValue,
|
ui32Mask));
|
}
|
}
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
OSEventObjectClose(hOSEvent);
|
|
/* One last check incase the object wait ended after the loop timeout... */
|
if (eError != PVRSRV_OK && (*pui32LinMemAddr & ui32Mask) == ui32Value)
|
{
|
eError = PVRSRV_OK;
|
}
|
|
/* Provide event timeout information to aid the Device Watchdog Thread... */
|
if (eError == PVRSRV_OK)
|
{
|
psPVRSRVData->ui32GEOConsecutiveTimeouts = 0;
|
}
|
else if (eError == PVRSRV_ERROR_TIMEOUT)
|
{
|
psPVRSRVData->ui32GEOConsecutiveTimeouts++;
|
}
|
|
EventObjectOpenError:
|
|
return eError;
|
|
#endif /* NO_HARDWARE */
|
}
|
|
/*
|
PVRSRVWaitForValueKM
|
*/
|
IMG_EXPORT
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVWaitForValueKM (volatile IMG_UINT32 *pui32LinMemAddr,
|
IMG_UINT32 ui32Value,
|
IMG_UINT32 ui32Mask)
|
{
|
/* In this case we are NOT retaining bridge lock while waiting
|
for bridge lock. */
|
return WaitForValueKM(pui32LinMemAddr, ui32Value, ui32Mask, IMG_FALSE);
|
}
|
|
/*
|
PVRSRVWaitForValueKMAndHoldBridgeLock
|
*/
|
PVRSRV_ERROR IMG_CALLCONV PVRSRVWaitForValueKMAndHoldBridgeLockKM(volatile IMG_UINT32 *pui32LinMemAddr,
|
IMG_UINT32 ui32Value,
|
IMG_UINT32 ui32Mask)
|
{
|
return WaitForValueKM(pui32LinMemAddr, ui32Value, ui32Mask, IMG_TRUE);
|
}
|
|
int PVRSRVGetDriverStatus(void)
|
{
|
return PVRSRVGetPVRSRVData()->eServicesState;
|
}
|
|
/*!
|
******************************************************************************
|
|
@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)
|
{
|
switch(eError)
|
{
|
case PVRSRV_OK:
|
return "PVRSRV_OK";
|
#define PVRE(x) \
|
case x: \
|
return #x;
|
#include "pvrsrv_errors.h"
|
#undef PVRE
|
default:
|
return "Unknown PVRSRV error number";
|
}
|
}
|
|
/*
|
PVRSRVSystemHasCacheSnooping
|
*/
|
IMG_BOOL PVRSRVSystemHasCacheSnooping(PVRSRV_DEVICE_CONFIG *psDevConfig)
|
{
|
if (psDevConfig->eCacheSnoopingMode != PVRSRV_DEVICE_SNOOP_NONE)
|
{
|
return IMG_TRUE;
|
}
|
return IMG_FALSE;
|
}
|
|
IMG_BOOL PVRSRVSystemSnoopingOfCPUCache(PVRSRV_DEVICE_CONFIG *psDevConfig)
|
{
|
if ((psDevConfig->eCacheSnoopingMode == PVRSRV_DEVICE_SNOOP_CPU_ONLY) ||
|
(psDevConfig->eCacheSnoopingMode == PVRSRV_DEVICE_SNOOP_CROSS))
|
{
|
return IMG_TRUE;
|
}
|
return IMG_FALSE;
|
}
|
|
IMG_BOOL PVRSRVSystemSnoopingOfDeviceCache(PVRSRV_DEVICE_CONFIG *psDevConfig)
|
{
|
if ((psDevConfig->eCacheSnoopingMode == PVRSRV_DEVICE_SNOOP_DEVICE_ONLY) ||
|
(psDevConfig->eCacheSnoopingMode == PVRSRV_DEVICE_SNOOP_CROSS))
|
{
|
return IMG_TRUE;
|
}
|
return IMG_FALSE;
|
}
|
|
IMG_BOOL PVRSRVSystemHasNonMappableLocalMemory(PVRSRV_DEVICE_CONFIG *psDevConfig)
|
{
|
return psDevConfig->bHasNonMappableLocalMemory;
|
}
|
|
/*
|
PVRSRVSystemWaitCycles
|
*/
|
void PVRSRVSystemWaitCycles(PVRSRV_DEVICE_CONFIG *psDevConfig, IMG_UINT32 ui32Cycles)
|
{
|
/* Delay in us */
|
IMG_UINT32 ui32Delayus = 1;
|
|
/* obtain the device freq */
|
if (psDevConfig->pfnClockFreqGet != NULL)
|
{
|
IMG_UINT32 ui32DeviceFreq;
|
|
ui32DeviceFreq = psDevConfig->pfnClockFreqGet(psDevConfig->hSysData);
|
|
ui32Delayus = (ui32Cycles*1000000)/ui32DeviceFreq;
|
|
if (ui32Delayus == 0)
|
{
|
ui32Delayus = 1;
|
}
|
}
|
|
OSWaitus(ui32Delayus);
|
}
|
|
static void *
|
PVRSRVSystemInstallDeviceLISR_Match_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode,
|
va_list va)
|
{
|
void *pvOSDevice = va_arg(va, void *);
|
|
if (psDeviceNode->psDevConfig->pvOSDevice == pvOSDevice)
|
{
|
return psDeviceNode;
|
}
|
|
return NULL;
|
}
|
|
PVRSRV_ERROR PVRSRVSystemInstallDeviceLISR(void *pvOSDevice,
|
IMG_UINT32 ui32IRQ,
|
const IMG_CHAR *pszName,
|
PFN_LISR pfnLISR,
|
void *pvData,
|
IMG_HANDLE *phLISRData)
|
{
|
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
PVRSRV_DEVICE_NODE *psDeviceNode;
|
|
psDeviceNode =
|
List_PVRSRV_DEVICE_NODE_Any_va(psPVRSRVData->psDeviceNodeList,
|
&PVRSRVSystemInstallDeviceLISR_Match_AnyVaCb,
|
pvOSDevice);
|
if (!psDeviceNode)
|
{
|
/* Device can't be found in the list so it isn't in the system */
|
PVR_DPF((PVR_DBG_ERROR, "%s: device %p with irq %d is not present",
|
__func__, pvOSDevice, ui32IRQ));
|
return PVRSRV_ERROR_INVALID_DEVICE;
|
}
|
|
return SysInstallDeviceLISR(psDeviceNode->psDevConfig->hSysData, ui32IRQ,
|
pszName, pfnLISR, pvData, phLISRData);
|
}
|
|
PVRSRV_ERROR PVRSRVSystemUninstallDeviceLISR(IMG_HANDLE hLISRData)
|
{
|
return SysUninstallDeviceLISR(hLISRData);
|
}
|
|
PVRSRV_ERROR
|
PVRSRVSystemBIFTilingHeapGetXStride(PVRSRV_DEVICE_CONFIG *psDevConfig,
|
IMG_UINT32 uiHeapNum,
|
IMG_UINT32 *puiXStride)
|
{
|
PVR_ASSERT(puiXStride != NULL);
|
|
if (uiHeapNum < 1 || uiHeapNum > psDevConfig->ui32BIFTilingHeapCount)
|
{
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
*puiXStride = psDevConfig->pui32BIFTilingHeapConfigs[uiHeapNum - 1];
|
|
return PVRSRV_OK;
|
}
|
|
PVRSRV_ERROR
|
PVRSRVSystemBIFTilingGetConfig(PVRSRV_DEVICE_CONFIG *psDevConfig,
|
RGXFWIF_BIFTILINGMODE *peBifTilingMode,
|
IMG_UINT32 *puiNumHeaps)
|
{
|
*peBifTilingMode = psDevConfig->eBIFTilingMode;
|
*puiNumHeaps = psDevConfig->ui32BIFTilingHeapCount;
|
return PVRSRV_OK;
|
}
|
|
#if defined(SUPPORT_GPUVIRT_VALIDATION) && defined(EMULATOR)
|
void SetAxiProtOSid(IMG_UINT32 ui32OSid, IMG_BOOL bState)
|
{
|
SysSetAxiProtOSid(ui32OSid, bState);
|
return ;
|
}
|
|
void SetTrustedDeviceAceEnabled(void)
|
{
|
SysSetTrustedDeviceAceEnabled();
|
|
return ;
|
}
|
#endif
|
|
/*****************************************************************************
|
End of file (pvrsrv.c)
|
*****************************************************************************/
|