mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-09-16 20:32:19 +02:00
7826 lines
257 KiB
C
7826 lines
257 KiB
C
/*************************************************************************/ /*!
|
|
@File
|
|
@Title Rogue firmware utility routines
|
|
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
|
|
@Description Rogue firmware utility routines
|
|
@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.
|
|
*/ /**************************************************************************/
|
|
|
|
#if defined(__linux__)
|
|
#include <linux/stddef.h>
|
|
#else
|
|
#include <stddef.h>
|
|
#endif
|
|
|
|
#include "img_defs.h"
|
|
|
|
#include "rgxdefs_km.h"
|
|
#include "rgx_fwif_km.h"
|
|
#include "pdump_km.h"
|
|
#include "osfunc.h"
|
|
#include "oskm_apphint.h"
|
|
#include "cache_km.h"
|
|
#include "allocmem.h"
|
|
#include "physheap.h"
|
|
#include "devicemem.h"
|
|
#include "devicemem_pdump.h"
|
|
#include "devicemem_server.h"
|
|
|
|
#include "pvr_debug.h"
|
|
#include "pvr_notifier.h"
|
|
#include "rgxfwutils.h"
|
|
#include "rgx_options.h"
|
|
#include "rgx_fwif_alignchecks.h"
|
|
#include "rgx_fwif_resetframework.h"
|
|
#include "rgx_pdump_panics.h"
|
|
#include "fwtrace_string.h"
|
|
#include "rgxheapconfig.h"
|
|
#include "pvrsrv.h"
|
|
#include "rgxdebug.h"
|
|
#include "rgxhwperf.h"
|
|
#include "rgxccb.h"
|
|
#include "rgxcompute.h"
|
|
#include "rgxtransfer.h"
|
|
#include "rgxpower.h"
|
|
#include "rgxtdmtransfer.h"
|
|
#if defined(SUPPORT_DISPLAY_CLASS)
|
|
#include "dc_server.h"
|
|
#endif
|
|
#include "rgxmem.h"
|
|
#include "rgxmmudefs_km.h"
|
|
#include "rgxmipsmmuinit.h"
|
|
#include "rgxta3d.h"
|
|
#include "rgxkicksync.h"
|
|
#include "rgxutils.h"
|
|
#include "rgxtimecorr.h"
|
|
#include "sync_internal.h"
|
|
#include "sync.h"
|
|
#include "sync_checkpoint.h"
|
|
#include "sync_checkpoint_external.h"
|
|
#include "tlstream.h"
|
|
#include "devicemem_server_utils.h"
|
|
#include "htbuffer.h"
|
|
#include "rgx_bvnc_defs_km.h"
|
|
#include "info_page.h"
|
|
|
|
#include "physmem_lma.h"
|
|
#include "physmem_osmem.h"
|
|
|
|
#ifdef __linux__
|
|
#include <linux/kernel.h> /* sprintf */
|
|
#include "rogue_trace_events.h"
|
|
#else
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#endif
|
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
|
#include "process_stats.h"
|
|
#endif
|
|
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
#include "rgxworkest.h"
|
|
#endif
|
|
|
|
#if defined(SUPPORT_PDVFS)
|
|
#include "rgxpdvfs.h"
|
|
#endif
|
|
|
|
#if defined(SUPPORT_VALIDATION) && defined(SUPPORT_SOC_TIMER)
|
|
#include "rgxsoctimer.h"
|
|
#endif
|
|
|
|
#include "vz_vmm_pvz.h"
|
|
#include "rgx_heaps.h"
|
|
|
|
/*!
|
|
******************************************************************************
|
|
* HWPERF
|
|
*****************************************************************************/
|
|
/* Size of the Firmware L1 HWPERF buffer in bytes (2MB). Accessed by the
|
|
* Firmware and host driver. */
|
|
#define RGXFW_HWPERF_L1_SIZE_MIN (16U)
|
|
#define RGXFW_HWPERF_L1_SIZE_DEFAULT PVRSRV_APPHINT_HWPERFFWBUFSIZEINKB
|
|
#define RGXFW_HWPERF_L1_SIZE_MAX (12288U)
|
|
|
|
/* Firmware CCB length */
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
#define RGXFWIF_FWCCB_NUMCMDS_LOG2 (10)
|
|
#elif defined(SUPPORT_PDVFS)
|
|
#define RGXFWIF_FWCCB_NUMCMDS_LOG2 (8)
|
|
#else
|
|
#define RGXFWIF_FWCCB_NUMCMDS_LOG2 (5)
|
|
#endif
|
|
|
|
#if defined(RGX_FW_IRQ_OS_COUNTERS)
|
|
const IMG_UINT32 gaui32FwOsIrqCntRegAddr[RGXFW_MAX_NUM_OS] = {IRQ_COUNTER_STORAGE_REGS};
|
|
#endif
|
|
|
|
/*
|
|
* Maximum length of time a DM can run for before the DM will be marked
|
|
* as out-of-time. CDM has an increased value due to longer running kernels.
|
|
*
|
|
* These deadlines are increased on FPGA, EMU and VP due to the slower
|
|
* execution time of these platforms. PDUMPS are also included since they
|
|
* are often run on EMU, FPGA or in CSim.
|
|
*/
|
|
#if defined(FPGA) || defined(EMULATOR) || defined(VIRTUAL_PLATFORM) || defined(PDUMP)
|
|
#define RGXFWIF_MAX_WORKLOAD_DEADLINE_MS (480000)
|
|
#define RGXFWIF_MAX_CDM_WORKLOAD_DEADLINE_MS (1000000)
|
|
#else
|
|
#define RGXFWIF_MAX_WORKLOAD_DEADLINE_MS (40000)
|
|
#define RGXFWIF_MAX_CDM_WORKLOAD_DEADLINE_MS (90000)
|
|
#endif
|
|
|
|
/* Workload Estimation Firmware CCB length */
|
|
#define RGXFWIF_WORKEST_FWCCB_NUMCMDS_LOG2 (7)
|
|
|
|
/* Size of memory buffer for firmware gcov data
|
|
* The actual data size is several hundred kilobytes. The buffer is an order of magnitude larger. */
|
|
#define RGXFWIF_FIRMWARE_GCOV_BUFFER_SIZE (4*1024*1024)
|
|
|
|
typedef struct
|
|
{
|
|
RGXFWIF_KCCB_CMD sKCCBcmd;
|
|
DLLIST_NODE sListNode;
|
|
PDUMP_FLAGS_T uiPDumpFlags;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
} RGX_DEFERRED_KCCB_CMD;
|
|
|
|
#if defined(PDUMP)
|
|
/* ensure PIDs are 32-bit because a 32-bit PDump load is generated for the
|
|
* PID filter example entries
|
|
*/
|
|
static_assert(sizeof(IMG_PID) == sizeof(IMG_UINT32),
|
|
"FW PID filtering assumes the IMG_PID type is 32-bits wide as it "
|
|
"generates WRW commands for loading the PID values");
|
|
#endif
|
|
|
|
static void RGXFreeFwOsData(PVRSRV_RGXDEV_INFO *psDevInfo);
|
|
static void RGXFreeFwSysData(PVRSRV_RGXDEV_INFO *psDevInfo);
|
|
|
|
#if defined(RGX_FEATURE_SLC_VIVT_BIT_MASK)
|
|
static PVRSRV_ERROR _AllocateSLC3Fence(PVRSRV_RGXDEV_INFO* psDevInfo, RGXFWIF_SYSINIT* psFwSysInit)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
DEVMEM_MEMDESC** ppsSLC3FenceMemDesc = &psDevInfo->psSLC3FenceMemDesc;
|
|
IMG_UINT32 ui32CacheLineSize = GET_ROGUE_CACHE_LINE_SIZE(
|
|
RGX_GET_FEATURE_VALUE(psDevInfo, SLC_CACHE_LINE_SIZE_BITS));
|
|
|
|
PVR_DPF_ENTERED;
|
|
|
|
eError = DevmemAllocate(psDevInfo->psFirmwareMainHeap,
|
|
1,
|
|
ui32CacheLineSize,
|
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
|
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
|
PVRSRV_MEMALLOCFLAG_GPU_UNCACHED |
|
|
PVRSRV_MEMALLOCFLAG_PHYS_HEAP_HINT(FW_MAIN),
|
|
"FwSLC3FenceWA",
|
|
ppsSLC3FenceMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF_RETURN_RC(eError);
|
|
}
|
|
|
|
/* We need to map it so the heap for this allocation is set */
|
|
eError = DevmemMapToDevice(*ppsSLC3FenceMemDesc,
|
|
psDevInfo->psFirmwareMainHeap,
|
|
&psFwSysInit->sSLC3FenceDevVAddr);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
DevmemFree(*ppsSLC3FenceMemDesc);
|
|
*ppsSLC3FenceMemDesc = NULL;
|
|
}
|
|
|
|
PVR_DPF_RETURN_RC1(eError, *ppsSLC3FenceMemDesc);
|
|
}
|
|
|
|
static void _FreeSLC3Fence(PVRSRV_RGXDEV_INFO* psDevInfo)
|
|
{
|
|
DEVMEM_MEMDESC* psSLC3FenceMemDesc = psDevInfo->psSLC3FenceMemDesc;
|
|
|
|
if (psSLC3FenceMemDesc)
|
|
{
|
|
DevmemReleaseDevVirtAddr(psSLC3FenceMemDesc);
|
|
DevmemFree(psSLC3FenceMemDesc);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void __MTSScheduleWrite(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Value)
|
|
{
|
|
/* ensure memory is flushed before kicking MTS */
|
|
OSWriteMemoryBarrier(NULL);
|
|
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_MTS_SCHEDULE, ui32Value);
|
|
|
|
/* ensure the MTS kick goes through before continuing */
|
|
#if !defined(NO_HARDWARE) && !defined(INTEGRITY_OS)
|
|
OSWriteMemoryBarrier((IMG_BYTE*) psDevInfo->pvRegsBaseKM + RGX_CR_MTS_SCHEDULE);
|
|
#else
|
|
OSWriteMemoryBarrier(NULL);
|
|
#endif
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXSetupFwAllocation
|
|
|
|
@Description Sets a pointer in a firmware data structure.
|
|
|
|
@Input psDevInfo Device Info struct
|
|
@Input uiAllocFlags Flags determining type of memory allocation
|
|
@Input ui32Size Size of memory allocation
|
|
@Input pszName Allocation label
|
|
@Input ppsMemDesc pointer to the allocation's memory descriptor
|
|
@Input psFwPtr Address of the firmware pointer to set
|
|
@Input ppvCpuPtr Address of the cpu pointer to set
|
|
@Input ui32DevVAFlags Any combination of RFW_FWADDR_*_FLAG
|
|
|
|
@Return PVRSRV_ERROR
|
|
*/ /**************************************************************************/
|
|
PVRSRV_ERROR RGXSetupFwAllocation(PVRSRV_RGXDEV_INFO* psDevInfo,
|
|
PVRSRV_MEMALLOCFLAGS_T uiAllocFlags,
|
|
IMG_UINT32 ui32Size,
|
|
const IMG_CHAR *pszName,
|
|
DEVMEM_MEMDESC **ppsMemDesc,
|
|
RGXFWIF_DEV_VIRTADDR *psFwPtr,
|
|
void **ppvCpuPtr,
|
|
IMG_UINT32 ui32DevVAFlags)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
IMG_BOOL bClearByMemset;
|
|
if (PVRSRV_CHECK_ZERO_ON_ALLOC(uiAllocFlags))
|
|
{
|
|
/* Under AutoVz the ZERO_ON_ALLOC flag is avoided as it causes the memory to
|
|
* be allocated from a different PMR than an allocation without the flag.
|
|
* When the content of an allocation needs to be recovered from physical memory
|
|
* on a later driver reboot, the memory then cannot be zeroed but the allocation
|
|
* addresses must still match.
|
|
* If the memory requires clearing, perform a memset after the allocation. */
|
|
uiAllocFlags &= ~PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC;
|
|
bClearByMemset = IMG_TRUE;
|
|
}
|
|
else
|
|
{
|
|
bClearByMemset = IMG_FALSE;
|
|
}
|
|
#endif
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Allocate %s", pszName);
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
ui32Size,
|
|
uiAllocFlags,
|
|
pszName,
|
|
ppsMemDesc);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to allocate %u bytes for %s (%u)",
|
|
__func__,
|
|
ui32Size,
|
|
pszName,
|
|
eError));
|
|
goto fail_alloc;
|
|
}
|
|
|
|
if (psFwPtr)
|
|
{
|
|
eError = RGXSetFirmwareAddress(psFwPtr, *ppsMemDesc, 0, ui32DevVAFlags);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to acquire firmware virtual address for %s (%u)",
|
|
__func__,
|
|
pszName,
|
|
eError));
|
|
goto fail_fwaddr;
|
|
}
|
|
}
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
if ((bClearByMemset) || (ppvCpuPtr))
|
|
#else
|
|
if (ppvCpuPtr)
|
|
#endif
|
|
{
|
|
void *pvTempCpuPtr;
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(*ppsMemDesc, &pvTempCpuPtr);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to acquire CPU virtual address for %s (%u)",
|
|
__func__,
|
|
pszName,
|
|
eError));
|
|
goto fail_cpuva;
|
|
}
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
if (bClearByMemset)
|
|
{
|
|
if (PVRSRV_CHECK_CPU_WRITE_COMBINE(uiAllocFlags))
|
|
{
|
|
OSCachedMemSetWMB(pvTempCpuPtr, 0, ui32Size);
|
|
}
|
|
else
|
|
{
|
|
OSDeviceMemSet(pvTempCpuPtr, 0, ui32Size);
|
|
}
|
|
}
|
|
if (ppvCpuPtr)
|
|
#endif
|
|
{
|
|
*ppvCpuPtr = pvTempCpuPtr;
|
|
}
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
else
|
|
{
|
|
DevmemReleaseCpuVirtAddr(*ppsMemDesc);
|
|
pvTempCpuPtr = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: %s set up at Fw VA 0x%x and CPU VA 0x%p with alloc flags 0x%" IMG_UINT64_FMTSPECX,
|
|
__func__, pszName,
|
|
(psFwPtr) ? (psFwPtr->ui32Addr) : (0),
|
|
(ppvCpuPtr) ? (*ppvCpuPtr) : (NULL),
|
|
uiAllocFlags));
|
|
|
|
return eError;
|
|
|
|
fail_cpuva:
|
|
if (psFwPtr)
|
|
{
|
|
RGXUnsetFirmwareAddress(*ppsMemDesc);
|
|
}
|
|
fail_fwaddr:
|
|
DevmemFree(*ppsMemDesc);
|
|
fail_alloc:
|
|
return eError;
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function GetHwPerfBufferSize
|
|
|
|
@Description Computes the effective size of the HW Perf Buffer
|
|
@Input ui32HWPerfFWBufSizeKB Device Info struct
|
|
@Return HwPerfBufferSize
|
|
*/ /**************************************************************************/
|
|
static IMG_UINT32 GetHwPerfBufferSize(IMG_UINT32 ui32HWPerfFWBufSizeKB)
|
|
{
|
|
IMG_UINT32 HwPerfBufferSize;
|
|
|
|
/* HWPerf: Determine the size of the FW buffer */
|
|
if (ui32HWPerfFWBufSizeKB == 0 ||
|
|
ui32HWPerfFWBufSizeKB == RGXFW_HWPERF_L1_SIZE_DEFAULT)
|
|
{
|
|
/* Under pvrsrvctl 0 size implies AppHint not set or is set to zero,
|
|
* use default size from driver constant. Set it to the default
|
|
* size, no logging.
|
|
*/
|
|
HwPerfBufferSize = RGXFW_HWPERF_L1_SIZE_DEFAULT<<10;
|
|
}
|
|
else if (ui32HWPerfFWBufSizeKB > (RGXFW_HWPERF_L1_SIZE_MAX))
|
|
{
|
|
/* Size specified as a AppHint but it is too big */
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: HWPerfFWBufSizeInKB value (%u) too big, using maximum (%u)",
|
|
__func__,
|
|
ui32HWPerfFWBufSizeKB, RGXFW_HWPERF_L1_SIZE_MAX));
|
|
HwPerfBufferSize = RGXFW_HWPERF_L1_SIZE_MAX<<10;
|
|
}
|
|
else if (ui32HWPerfFWBufSizeKB > (RGXFW_HWPERF_L1_SIZE_MIN))
|
|
{
|
|
/* Size specified as in AppHint HWPerfFWBufSizeInKB */
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: Using HWPerf FW buffer size of %u KB",
|
|
__func__,
|
|
ui32HWPerfFWBufSizeKB));
|
|
HwPerfBufferSize = ui32HWPerfFWBufSizeKB<<10;
|
|
}
|
|
else
|
|
{
|
|
/* Size specified as a AppHint but it is too small */
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: HWPerfFWBufSizeInKB value (%u) too small, using minimum (%u)",
|
|
__func__,
|
|
ui32HWPerfFWBufSizeKB, RGXFW_HWPERF_L1_SIZE_MIN));
|
|
HwPerfBufferSize = RGXFW_HWPERF_L1_SIZE_MIN<<10;
|
|
}
|
|
|
|
return HwPerfBufferSize;
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFWSetupSignatureChecks
|
|
@Description
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXFWSetupSignatureChecks(PVRSRV_RGXDEV_INFO* psDevInfo,
|
|
DEVMEM_MEMDESC** ppsSigChecksMemDesc,
|
|
IMG_UINT32 ui32SigChecksBufSize,
|
|
RGXFWIF_SIGBUF_CTL* psSigBufCtl)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
/* Allocate memory for the checks */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS,
|
|
ui32SigChecksBufSize,
|
|
"FwSignatureChecks",
|
|
ppsSigChecksMemDesc,
|
|
&psSigBufCtl->sBuffer,
|
|
NULL,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
DevmemPDumpLoadMem( *ppsSigChecksMemDesc,
|
|
0,
|
|
ui32SigChecksBufSize,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
psSigBufCtl->ui32LeftSizeInRegs = ui32SigChecksBufSize / sizeof(IMG_UINT32);
|
|
fail:
|
|
return eError;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(SUPPORT_FIRMWARE_GCOV)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFWSetupFirmwareGcovBuffer
|
|
@Description
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXFWSetupFirmwareGcovBuffer(PVRSRV_RGXDEV_INFO* psDevInfo,
|
|
DEVMEM_MEMDESC** ppsBufferMemDesc,
|
|
IMG_UINT32 ui32FirmwareGcovBufferSize,
|
|
RGXFWIF_FIRMWARE_GCOV_CTL* psFirmwareGcovCtl,
|
|
const IMG_CHAR* pszBufferName)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
/* Allocate memory for gcov */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
(RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED)),
|
|
ui32FirmwareGcovBufferSize,
|
|
pszBufferName,
|
|
ppsBufferMemDesc,
|
|
&psFirmwareGcovCtl->sBuffer,
|
|
NULL,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "RGXSetupFwAllocation");
|
|
|
|
psFirmwareGcovCtl->ui32Size = ui32FirmwareGcovBufferSize;
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_POWER_SAMPLING_VIA_DEBUGFS)
|
|
/*!
|
|
******************************************************************************
|
|
@Function RGXFWSetupCounterBuffer
|
|
@Description
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
*****************************************************************************/
|
|
static PVRSRV_ERROR RGXFWSetupCounterBuffer(PVRSRV_RGXDEV_INFO* psDevInfo,
|
|
DEVMEM_MEMDESC** ppsBufferMemDesc,
|
|
IMG_UINT32 ui32CounterDataBufferSize,
|
|
RGXFWIF_COUNTER_DUMP_CTL* psCounterDumpCtl,
|
|
const IMG_CHAR* pszBufferName)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
(RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED)),
|
|
ui32CounterDataBufferSize,
|
|
"FwCounterBuffer",
|
|
ppsBufferMemDesc,
|
|
&psCounterDumpCtl->sBuffer,
|
|
NULL,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "RGXSetupFwAllocation");
|
|
|
|
psCounterDumpCtl->ui32SizeInDwords = ui32CounterDataBufferSize >> 2;
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
******************************************************************************
|
|
@Function RGXFWSetupAlignChecks
|
|
@Description This functions allocates and fills memory needed for the
|
|
aligns checks of the UM and KM structures shared with the
|
|
firmware. The format of the data in the memory is as follows:
|
|
<number of elements in the KM array>
|
|
<array of KM structures' sizes and members' offsets>
|
|
<number of elements in the UM array>
|
|
<array of UM structures' sizes and members' offsets>
|
|
The UM array is passed from the user side. Now the firmware is
|
|
is responsible for filling this part of the memory. If that
|
|
happens the check of the UM structures will be performed
|
|
by the host driver on client's connect.
|
|
If the macro is not defined the client driver fills the memory
|
|
and the firmware checks for the alignment of all structures.
|
|
@Input psDeviceNode
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXFWSetupAlignChecks(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
RGXFWIF_DEV_VIRTADDR *psAlignChecksDevFW)
|
|
{
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
IMG_UINT32 aui32RGXFWAlignChecksKM[] = { RGXFW_ALIGN_CHECKS_INIT_KM };
|
|
IMG_UINT32 ui32RGXFWAlignChecksTotal;
|
|
IMG_UINT32* paui32AlignChecks;
|
|
PVRSRV_ERROR eError;
|
|
|
|
/* In this case we don't know the number of elements in UM array.
|
|
* We have to assume something so we assume RGXFW_ALIGN_CHECKS_UM_MAX.
|
|
*/
|
|
ui32RGXFWAlignChecksTotal = sizeof(aui32RGXFWAlignChecksKM)
|
|
+ RGXFW_ALIGN_CHECKS_UM_MAX * sizeof(IMG_UINT32)
|
|
+ 2 * sizeof(IMG_UINT32);
|
|
|
|
/* Allocate memory for the checks */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
ui32RGXFWAlignChecksTotal,
|
|
"FwAlignmentChecks",
|
|
&psDevInfo->psRGXFWAlignChecksMemDesc,
|
|
psAlignChecksDevFW,
|
|
(void**) &paui32AlignChecks,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
if (!psDeviceNode->bAutoVzFwIsUp)
|
|
{
|
|
/* Copy the values */
|
|
*paui32AlignChecks++ = ARRAY_SIZE(aui32RGXFWAlignChecksKM);
|
|
OSCachedMemCopy(paui32AlignChecks, &aui32RGXFWAlignChecksKM[0],
|
|
sizeof(aui32RGXFWAlignChecksKM));
|
|
paui32AlignChecks += ARRAY_SIZE(aui32RGXFWAlignChecksKM);
|
|
|
|
*paui32AlignChecks = 0;
|
|
}
|
|
|
|
OSWriteMemoryBarrier(paui32AlignChecks);
|
|
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWAlignChecksMemDesc,
|
|
0,
|
|
ui32RGXFWAlignChecksTotal,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail:
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
return eError;
|
|
}
|
|
|
|
static void RGXFWFreeAlignChecks(PVRSRV_RGXDEV_INFO* psDevInfo)
|
|
{
|
|
if (psDevInfo->psRGXFWAlignChecksMemDesc != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWAlignChecksMemDesc);
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWAlignChecksMemDesc);
|
|
psDevInfo->psRGXFWAlignChecksMemDesc = NULL;
|
|
}
|
|
}
|
|
|
|
PVRSRV_ERROR RGXSetFirmwareAddress(RGXFWIF_DEV_VIRTADDR *ppDest,
|
|
DEVMEM_MEMDESC *psSrc,
|
|
IMG_UINT32 uiExtraOffset,
|
|
IMG_UINT32 ui32Flags)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
IMG_DEV_VIRTADDR psDevVirtAddr;
|
|
PVRSRV_DEVICE_NODE *psDeviceNode;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
|
|
psDeviceNode = (PVRSRV_DEVICE_NODE *) DevmemGetConnection(psSrc);
|
|
psDevInfo = (PVRSRV_RGXDEV_INFO *)psDeviceNode->pvDevice;
|
|
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META))
|
|
{
|
|
IMG_UINT32 ui32Offset;
|
|
IMG_BOOL bCachedInMETA;
|
|
PVRSRV_MEMALLOCFLAGS_T uiDevFlags;
|
|
IMG_UINT32 uiGPUCacheMode;
|
|
|
|
eError = DevmemAcquireDevVirtAddr(psSrc, &psDevVirtAddr);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "DevmemAcquireDevVirtAddr", failDevVAAcquire);
|
|
|
|
/* Convert to an address in META memmap */
|
|
ui32Offset = psDevVirtAddr.uiAddr + uiExtraOffset - RGX_FIRMWARE_RAW_HEAP_BASE;
|
|
|
|
/* Check in the devmem flags whether this memory is cached/uncached */
|
|
DevmemGetFlags(psSrc, &uiDevFlags);
|
|
|
|
/* Honour the META cache flags */
|
|
bCachedInMETA = (PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) & uiDevFlags) != 0;
|
|
|
|
/* Honour the SLC cache flags */
|
|
eError = DevmemDeviceCacheMode(psDeviceNode, uiDevFlags, &uiGPUCacheMode);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "DevmemDeviceCacheMode", failDevCacheMode);
|
|
|
|
ui32Offset += RGXFW_SEGMMU_DATA_BASE_ADDRESS;
|
|
|
|
if (bCachedInMETA)
|
|
{
|
|
ui32Offset |= RGXFW_SEGMMU_DATA_META_CACHED;
|
|
}
|
|
else
|
|
{
|
|
ui32Offset |= RGXFW_SEGMMU_DATA_META_UNCACHED;
|
|
}
|
|
|
|
if (PVRSRV_CHECK_GPU_CACHED(uiGPUCacheMode))
|
|
{
|
|
ui32Offset |= RGXFW_SEGMMU_DATA_VIVT_SLC_CACHED;
|
|
}
|
|
else
|
|
{
|
|
ui32Offset |= RGXFW_SEGMMU_DATA_VIVT_SLC_UNCACHED;
|
|
}
|
|
ppDest->ui32Addr = ui32Offset;
|
|
}
|
|
else
|
|
#endif
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS))
|
|
{
|
|
eError = DevmemAcquireDevVirtAddr(psSrc, &psDevVirtAddr);
|
|
PVR_GOTO_IF_ERROR(eError, failDevVAAcquire);
|
|
|
|
ppDest->ui32Addr = (IMG_UINT32)((psDevVirtAddr.uiAddr + uiExtraOffset) & 0xFFFFFFFF);
|
|
}
|
|
else
|
|
{
|
|
IMG_UINT32 ui32Offset;
|
|
IMG_BOOL bCachedInRISCV;
|
|
PVRSRV_MEMALLOCFLAGS_T uiDevFlags;
|
|
|
|
eError = DevmemAcquireDevVirtAddr(psSrc, &psDevVirtAddr);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "DevmemAcquireDevVirtAddr", failDevVAAcquire);
|
|
|
|
/* Convert to an address in RISCV memmap */
|
|
ui32Offset = psDevVirtAddr.uiAddr + uiExtraOffset - RGX_FIRMWARE_RAW_HEAP_BASE;
|
|
|
|
/* Check in the devmem flags whether this memory is cached/uncached */
|
|
DevmemGetFlags(psSrc, &uiDevFlags);
|
|
|
|
/* Honour the RISCV cache flags */
|
|
bCachedInRISCV = (PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) & uiDevFlags) != 0;
|
|
|
|
if (bCachedInRISCV)
|
|
{
|
|
ui32Offset |= RGXRISCVFW_SHARED_CACHED_DATA_BASE;
|
|
}
|
|
else
|
|
{
|
|
ui32Offset |= RGXRISCVFW_SHARED_UNCACHED_DATA_BASE;
|
|
}
|
|
|
|
ppDest->ui32Addr = ui32Offset;
|
|
}
|
|
|
|
if ((ppDest->ui32Addr & 0x3U) != 0)
|
|
{
|
|
IMG_CHAR *pszAnnotation;
|
|
/* It is expected that the annotation returned by DevmemGetAnnotation() is always valid */
|
|
DevmemGetAnnotation(psSrc, &pszAnnotation);
|
|
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: %s @ 0x%x is not aligned to 32 bit",
|
|
__func__, pszAnnotation, ppDest->ui32Addr));
|
|
|
|
return PVRSRV_ERROR_INVALID_ALIGNMENT;
|
|
}
|
|
|
|
if (ui32Flags & RFW_FWADDR_NOREF_FLAG)
|
|
{
|
|
DevmemReleaseDevVirtAddr(psSrc);
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
failDevCacheMode:
|
|
DevmemReleaseDevVirtAddr(psSrc);
|
|
#endif
|
|
failDevVAAcquire:
|
|
return eError;
|
|
}
|
|
|
|
void RGXSetMetaDMAAddress(RGXFWIF_DMA_ADDR *psDest,
|
|
DEVMEM_MEMDESC *psSrcMemDesc,
|
|
RGXFWIF_DEV_VIRTADDR *psSrcFWDevVAddr,
|
|
IMG_UINT32 uiOffset)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
IMG_DEV_VIRTADDR sDevVirtAddr;
|
|
|
|
eError = DevmemAcquireDevVirtAddr(psSrcMemDesc, &sDevVirtAddr);
|
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
|
|
psDest->psDevVirtAddr.uiAddr = sDevVirtAddr.uiAddr;
|
|
psDest->psDevVirtAddr.uiAddr += uiOffset;
|
|
psDest->pbyFWAddr.ui32Addr = psSrcFWDevVAddr->ui32Addr;
|
|
|
|
DevmemReleaseDevVirtAddr(psSrcMemDesc);
|
|
}
|
|
|
|
|
|
void RGXUnsetFirmwareAddress(DEVMEM_MEMDESC *psSrc)
|
|
{
|
|
DevmemReleaseDevVirtAddr(psSrc);
|
|
}
|
|
|
|
struct _RGX_SERVER_COMMON_CONTEXT_ {
|
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
DEVMEM_MEMDESC *psFWCommonContextMemDesc;
|
|
PRGXFWIF_FWCOMMONCONTEXT sFWCommonContextFWAddr;
|
|
SERVER_MMU_CONTEXT *psServerMMUContext;
|
|
DEVMEM_MEMDESC *psFWMemContextMemDesc;
|
|
DEVMEM_MEMDESC *psFWFrameworkMemDesc;
|
|
DEVMEM_MEMDESC *psContextStateMemDesc;
|
|
RGX_CLIENT_CCB *psClientCCB;
|
|
DEVMEM_MEMDESC *psClientCCBMemDesc;
|
|
DEVMEM_MEMDESC *psClientCCBCtrlMemDesc;
|
|
IMG_BOOL bCommonContextMemProvided;
|
|
IMG_UINT32 ui32ContextID;
|
|
DLLIST_NODE sListNode;
|
|
RGX_CONTEXT_RESET_REASON eLastResetReason;
|
|
IMG_UINT32 ui32LastResetJobRef;
|
|
IMG_INT32 i32Priority;
|
|
RGX_CCB_REQUESTOR_TYPE eRequestor;
|
|
};
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function _CheckPriority
|
|
@Description Check if priority is allowed for requestor type
|
|
@Input psDevInfo pointer to DevInfo struct
|
|
@Input i32Priority Requested priority
|
|
@Input eRequestor Requestor type specifying data master
|
|
@Return PVRSRV_ERROR PVRSRV_OK on success
|
|
*/ /**************************************************************************/
|
|
static PVRSRV_ERROR _CheckPriority(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_INT32 i32Priority,
|
|
RGX_CCB_REQUESTOR_TYPE eRequestor)
|
|
{
|
|
/* Only one context allowed with real time priority (highest priority) */
|
|
if (i32Priority == RGX_CTX_PRIORITY_REALTIME)
|
|
{
|
|
DLLIST_NODE *psNode, *psNext;
|
|
|
|
dllist_foreach_node(&psDevInfo->sCommonCtxtListHead, psNode, psNext)
|
|
{
|
|
RGX_SERVER_COMMON_CONTEXT *psThisContext =
|
|
IMG_CONTAINER_OF(psNode, RGX_SERVER_COMMON_CONTEXT, sListNode);
|
|
|
|
if (psThisContext->i32Priority == RGX_CTX_PRIORITY_REALTIME &&
|
|
psThisContext->eRequestor == eRequestor)
|
|
{
|
|
PVR_LOG(("Only one context with real time priority allowed"));
|
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
|
}
|
|
}
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
PVRSRV_ERROR FWCommonContextAllocate(CONNECTION_DATA *psConnection,
|
|
PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
RGX_CCB_REQUESTOR_TYPE eRGXCCBRequestor,
|
|
RGXFWIF_DM eDM,
|
|
SERVER_MMU_CONTEXT *psServerMMUContext,
|
|
DEVMEM_MEMDESC *psAllocatedMemDesc,
|
|
IMG_UINT32 ui32AllocatedOffset,
|
|
DEVMEM_MEMDESC *psFWMemContextMemDesc,
|
|
DEVMEM_MEMDESC *psContextStateMemDesc,
|
|
IMG_UINT32 ui32CCBAllocSizeLog2,
|
|
IMG_UINT32 ui32CCBMaxAllocSizeLog2,
|
|
IMG_UINT32 ui32ContextFlags,
|
|
IMG_UINT32 ui32Priority,
|
|
IMG_UINT32 ui32MaxDeadlineMS,
|
|
IMG_UINT64 ui64RobustnessAddress,
|
|
RGX_COMMON_CONTEXT_INFO *psInfo,
|
|
RGX_SERVER_COMMON_CONTEXT **ppsServerCommonContext)
|
|
{
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext;
|
|
RGXFWIF_FWCOMMONCONTEXT *psFWCommonContext;
|
|
IMG_UINT32 ui32FWCommonContextOffset;
|
|
IMG_UINT8 *pui8Ptr;
|
|
IMG_INT32 i32Priority = (IMG_INT32)ui32Priority;
|
|
PVRSRV_ERROR eError;
|
|
|
|
/*
|
|
* Allocate all the resources that are required
|
|
*/
|
|
psServerCommonContext = OSAllocMem(sizeof(*psServerCommonContext));
|
|
if (psServerCommonContext == NULL)
|
|
{
|
|
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
|
|
goto fail_alloc;
|
|
}
|
|
|
|
psServerCommonContext->psDevInfo = psDevInfo;
|
|
psServerCommonContext->psServerMMUContext = psServerMMUContext;
|
|
|
|
if (psAllocatedMemDesc)
|
|
{
|
|
PDUMPCOMMENT(psDeviceNode,
|
|
"Using existing MemDesc for Rogue firmware %s context (offset = %d)",
|
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
|
ui32AllocatedOffset);
|
|
ui32FWCommonContextOffset = ui32AllocatedOffset;
|
|
psServerCommonContext->psFWCommonContextMemDesc = psAllocatedMemDesc;
|
|
psServerCommonContext->bCommonContextMemProvided = IMG_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Allocate device memory for the firmware context */
|
|
PDUMPCOMMENT(psDeviceNode,
|
|
"Allocate Rogue firmware %s context", aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT]);
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
sizeof(*psFWCommonContext),
|
|
RGX_FWCOMCTX_ALLOCFLAGS,
|
|
"FwContext",
|
|
&psServerCommonContext->psFWCommonContextMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to allocate firmware %s context (%s)",
|
|
__func__,
|
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
|
PVRSRVGetErrorString(eError)));
|
|
goto fail_contextalloc;
|
|
}
|
|
ui32FWCommonContextOffset = 0;
|
|
psServerCommonContext->bCommonContextMemProvided = IMG_FALSE;
|
|
}
|
|
|
|
/* Record this context so we can refer to it if the FW needs to tell us it was reset. */
|
|
psServerCommonContext->eLastResetReason = RGX_CONTEXT_RESET_REASON_NONE;
|
|
psServerCommonContext->ui32LastResetJobRef = 0;
|
|
psServerCommonContext->ui32ContextID = psDevInfo->ui32CommonCtxtCurrentID++;
|
|
|
|
/*
|
|
* Temporarily map the firmware context to the kernel and initialise it
|
|
*/
|
|
eError = DevmemAcquireCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc,
|
|
(void **)&pui8Ptr);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map firmware %s context to CPU (%s)",
|
|
__func__,
|
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
|
PVRSRVGetErrorString(eError)));
|
|
goto fail_cpuvirtacquire;
|
|
}
|
|
|
|
/* Allocate the client CCB */
|
|
eError = RGXCreateCCB(psDevInfo,
|
|
ui32CCBAllocSizeLog2,
|
|
ui32CCBMaxAllocSizeLog2,
|
|
ui32ContextFlags,
|
|
psConnection,
|
|
eRGXCCBRequestor,
|
|
psServerCommonContext,
|
|
&psServerCommonContext->psClientCCB,
|
|
&psServerCommonContext->psClientCCBMemDesc,
|
|
&psServerCommonContext->psClientCCBCtrlMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: failed to create CCB for %s context (%s)",
|
|
__func__,
|
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
|
PVRSRVGetErrorString(eError)));
|
|
goto fail_allocateccb;
|
|
}
|
|
|
|
psFWCommonContext = (RGXFWIF_FWCOMMONCONTEXT *) (pui8Ptr + ui32FWCommonContextOffset);
|
|
psFWCommonContext->eDM = eDM;
|
|
|
|
/* Set the firmware CCB device addresses in the firmware common context */
|
|
eError = RGXSetFirmwareAddress(&psFWCommonContext->psCCB,
|
|
psServerCommonContext->psClientCCBMemDesc,
|
|
0, RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:1", fail_cccbfwaddr);
|
|
|
|
eError = RGXSetFirmwareAddress(&psFWCommonContext->psCCBCtl,
|
|
psServerCommonContext->psClientCCBCtrlMemDesc,
|
|
0, RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:2", fail_cccbctrlfwaddr);
|
|
|
|
#if defined(RGX_FEATURE_META_DMA_CHANNEL_COUNT_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, META_DMA))
|
|
{
|
|
RGXSetMetaDMAAddress(&psFWCommonContext->sCCBMetaDMAAddr,
|
|
psServerCommonContext->psClientCCBMemDesc,
|
|
&psFWCommonContext->psCCB,
|
|
0);
|
|
}
|
|
#endif
|
|
|
|
/* Set the memory context device address */
|
|
psServerCommonContext->psFWMemContextMemDesc = psFWMemContextMemDesc;
|
|
eError = RGXSetFirmwareAddress(&psFWCommonContext->psFWMemContext,
|
|
psFWMemContextMemDesc,
|
|
0, RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:3", fail_fwmemctxfwaddr);
|
|
|
|
/* Set the framework register updates address */
|
|
psServerCommonContext->psFWFrameworkMemDesc = psInfo->psFWFrameworkMemDesc;
|
|
if (psInfo->psFWFrameworkMemDesc != NULL)
|
|
{
|
|
eError = RGXSetFirmwareAddress(&psFWCommonContext->psRFCmd,
|
|
psInfo->psFWFrameworkMemDesc,
|
|
0, RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:4", fail_fwframeworkfwaddr);
|
|
}
|
|
else
|
|
{
|
|
/* This should never be touched in this contexts without a framework
|
|
* memdesc, but ensure it is zero so we see crashes if it is.
|
|
*/
|
|
psFWCommonContext->psRFCmd.ui32Addr = 0;
|
|
}
|
|
|
|
eError = _CheckPriority(psDevInfo, i32Priority, eRGXCCBRequestor);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "_CheckPriority", fail_checkpriority);
|
|
|
|
psServerCommonContext->i32Priority = i32Priority;
|
|
psServerCommonContext->eRequestor = eRGXCCBRequestor;
|
|
|
|
psFWCommonContext->i32Priority = i32Priority;
|
|
psFWCommonContext->ui32PrioritySeqNum = 0;
|
|
psFWCommonContext->ui32MaxDeadlineMS = MIN(ui32MaxDeadlineMS,
|
|
(eDM == RGXFWIF_DM_CDM ?
|
|
RGXFWIF_MAX_CDM_WORKLOAD_DEADLINE_MS :
|
|
RGXFWIF_MAX_WORKLOAD_DEADLINE_MS));
|
|
psFWCommonContext->ui64RobustnessAddress = ui64RobustnessAddress;
|
|
|
|
/* Store a references to Server Common Context and PID for notifications back from the FW. */
|
|
psFWCommonContext->ui32ServerCommonContextID = psServerCommonContext->ui32ContextID;
|
|
psFWCommonContext->ui32PID = OSGetCurrentClientProcessIDKM();
|
|
|
|
/* Set the firmware GPU context state buffer */
|
|
psServerCommonContext->psContextStateMemDesc = psContextStateMemDesc;
|
|
if (psContextStateMemDesc)
|
|
{
|
|
eError = RGXSetFirmwareAddress(&psFWCommonContext->psContextState,
|
|
psContextStateMemDesc,
|
|
0,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:5", fail_ctxstatefwaddr);
|
|
}
|
|
|
|
/*
|
|
* Dump the created context
|
|
*/
|
|
PDUMPCOMMENT(psDeviceNode,
|
|
"Dump %s context", aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT]);
|
|
DevmemPDumpLoadMem(psServerCommonContext->psFWCommonContextMemDesc,
|
|
ui32FWCommonContextOffset,
|
|
sizeof(*psFWCommonContext),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* We've finished the setup so release the CPU mapping */
|
|
DevmemReleaseCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc);
|
|
|
|
/* Map this allocation into the FW */
|
|
eError = RGXSetFirmwareAddress(&psServerCommonContext->sFWCommonContextFWAddr,
|
|
psServerCommonContext->psFWCommonContextMemDesc,
|
|
ui32FWCommonContextOffset,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:6", fail_fwcommonctxfwaddr);
|
|
|
|
#if defined(__linux__)
|
|
{
|
|
IMG_UINT32 ui32FWAddr;
|
|
switch (eDM) {
|
|
case RGXFWIF_DM_GEOM:
|
|
ui32FWAddr = (IMG_UINT32) ((uintptr_t) IMG_CONTAINER_OF((void *) ((uintptr_t)
|
|
psServerCommonContext->sFWCommonContextFWAddr.ui32Addr), RGXFWIF_FWRENDERCONTEXT, sTAContext));
|
|
break;
|
|
case RGXFWIF_DM_3D:
|
|
ui32FWAddr = (IMG_UINT32) ((uintptr_t) IMG_CONTAINER_OF((void *) ((uintptr_t)
|
|
psServerCommonContext->sFWCommonContextFWAddr.ui32Addr), RGXFWIF_FWRENDERCONTEXT, s3DContext));
|
|
break;
|
|
default:
|
|
ui32FWAddr = psServerCommonContext->sFWCommonContextFWAddr.ui32Addr;
|
|
break;
|
|
}
|
|
|
|
trace_rogue_create_fw_context(OSGetCurrentClientProcessNameKM(),
|
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
|
ui32FWAddr);
|
|
}
|
|
#endif
|
|
/*Add the node to the list when finalised */
|
|
OSWRLockAcquireWrite(psDevInfo->hCommonCtxtListLock);
|
|
dllist_add_to_tail(&(psDevInfo->sCommonCtxtListHead), &(psServerCommonContext->sListNode));
|
|
OSWRLockReleaseWrite(psDevInfo->hCommonCtxtListLock);
|
|
|
|
*ppsServerCommonContext = psServerCommonContext;
|
|
return PVRSRV_OK;
|
|
|
|
fail_fwcommonctxfwaddr:
|
|
if (psContextStateMemDesc)
|
|
{
|
|
RGXUnsetFirmwareAddress(psContextStateMemDesc);
|
|
}
|
|
fail_ctxstatefwaddr:
|
|
fail_checkpriority:
|
|
if (psInfo->psFWFrameworkMemDesc != NULL)
|
|
{
|
|
RGXUnsetFirmwareAddress(psInfo->psFWFrameworkMemDesc);
|
|
}
|
|
fail_fwframeworkfwaddr:
|
|
RGXUnsetFirmwareAddress(psFWMemContextMemDesc);
|
|
fail_fwmemctxfwaddr:
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBCtrlMemDesc);
|
|
fail_cccbctrlfwaddr:
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBMemDesc);
|
|
fail_cccbfwaddr:
|
|
RGXDestroyCCB(psDevInfo, psServerCommonContext->psClientCCB);
|
|
fail_allocateccb:
|
|
DevmemReleaseCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc);
|
|
fail_cpuvirtacquire:
|
|
if (!psServerCommonContext->bCommonContextMemProvided)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psServerCommonContext->psFWCommonContextMemDesc);
|
|
psServerCommonContext->psFWCommonContextMemDesc = NULL;
|
|
}
|
|
fail_contextalloc:
|
|
OSFreeMem(psServerCommonContext);
|
|
fail_alloc:
|
|
return eError;
|
|
}
|
|
|
|
void FWCommonContextFree(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext)
|
|
{
|
|
|
|
OSWRLockAcquireWrite(psServerCommonContext->psDevInfo->hCommonCtxtListLock);
|
|
/* Remove the context from the list of all contexts. */
|
|
dllist_remove_node(&psServerCommonContext->sListNode);
|
|
OSWRLockReleaseWrite(psServerCommonContext->psDevInfo->hCommonCtxtListLock);
|
|
|
|
/*
|
|
Unmap the context itself and then all its resources
|
|
*/
|
|
|
|
/* Unmap the FW common context */
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psFWCommonContextMemDesc);
|
|
/* Umap context state buffer (if there was one) */
|
|
if (psServerCommonContext->psContextStateMemDesc)
|
|
{
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psContextStateMemDesc);
|
|
}
|
|
/* Unmap the framework buffer */
|
|
if (psServerCommonContext->psFWFrameworkMemDesc)
|
|
{
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psFWFrameworkMemDesc);
|
|
}
|
|
/* Unmap client CCB and CCB control */
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBCtrlMemDesc);
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBMemDesc);
|
|
/* Unmap the memory context */
|
|
RGXUnsetFirmwareAddress(psServerCommonContext->psFWMemContextMemDesc);
|
|
|
|
/* Destroy the client CCB */
|
|
RGXDestroyCCB(psServerCommonContext->psDevInfo, psServerCommonContext->psClientCCB);
|
|
|
|
|
|
/* Free the FW common context (if there was one) */
|
|
if (!psServerCommonContext->bCommonContextMemProvided)
|
|
{
|
|
DevmemFwUnmapAndFree(psServerCommonContext->psDevInfo,
|
|
psServerCommonContext->psFWCommonContextMemDesc);
|
|
psServerCommonContext->psFWCommonContextMemDesc = NULL;
|
|
}
|
|
/* Free the hosts representation of the common context */
|
|
OSFreeMem(psServerCommonContext);
|
|
}
|
|
|
|
PRGXFWIF_FWCOMMONCONTEXT FWCommonContextGetFWAddress(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext)
|
|
{
|
|
return psServerCommonContext->sFWCommonContextFWAddr;
|
|
}
|
|
|
|
RGX_CLIENT_CCB *FWCommonContextGetClientCCB(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext)
|
|
{
|
|
return psServerCommonContext->psClientCCB;
|
|
}
|
|
|
|
RGX_CONTEXT_RESET_REASON FWCommonContextGetLastResetReason(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext,
|
|
IMG_UINT32 *pui32LastResetJobRef)
|
|
{
|
|
RGX_CONTEXT_RESET_REASON eLastResetReason;
|
|
|
|
PVR_ASSERT(psServerCommonContext != NULL);
|
|
PVR_ASSERT(pui32LastResetJobRef != NULL);
|
|
|
|
/* Take the most recent reason & job ref and reset for next time... */
|
|
eLastResetReason = psServerCommonContext->eLastResetReason;
|
|
*pui32LastResetJobRef = psServerCommonContext->ui32LastResetJobRef;
|
|
psServerCommonContext->eLastResetReason = RGX_CONTEXT_RESET_REASON_NONE;
|
|
psServerCommonContext->ui32LastResetJobRef = 0;
|
|
|
|
if (eLastResetReason == RGX_CONTEXT_RESET_REASON_HARD_CONTEXT_SWITCH)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"A Hard Context Switch was triggered on the GPU to ensure Quality of Service."));
|
|
}
|
|
|
|
return eLastResetReason;
|
|
}
|
|
|
|
PVRSRV_RGXDEV_INFO* FWCommonContextGetRGXDevInfo(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext)
|
|
{
|
|
return psServerCommonContext->psDevInfo;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXGetFWCommonContextAddrFromServerMMUCtx(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
SERVER_MMU_CONTEXT *psServerMMUContext,
|
|
PRGXFWIF_FWCOMMONCONTEXT *psFWCommonContextFWAddr)
|
|
{
|
|
DLLIST_NODE *psNode, *psNext;
|
|
dllist_foreach_node(&psDevInfo->sCommonCtxtListHead, psNode, psNext)
|
|
{
|
|
RGX_SERVER_COMMON_CONTEXT *psThisContext =
|
|
IMG_CONTAINER_OF(psNode, RGX_SERVER_COMMON_CONTEXT, sListNode);
|
|
|
|
if (psThisContext->psServerMMUContext == psServerMMUContext)
|
|
{
|
|
psFWCommonContextFWAddr->ui32Addr = psThisContext->sFWCommonContextFWAddr.ui32Addr;
|
|
return PVRSRV_OK;
|
|
}
|
|
}
|
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
|
}
|
|
|
|
PVRSRV_ERROR FWCommonContextSetFlags(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext,
|
|
IMG_UINT32 ui32ContextFlags)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
|
|
if (BITMASK_ANY(ui32ContextFlags, ~RGX_CONTEXT_FLAGS_WRITEABLE_MASK))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Context flag(s) invalid or not writeable (%d)",
|
|
__func__, ui32ContextFlags));
|
|
eError = PVRSRV_ERROR_INVALID_PARAMS;
|
|
}
|
|
else
|
|
{
|
|
RGXSetCCBFlags(psServerCommonContext->psClientCCB,
|
|
ui32ContextFlags);
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFreeCCB
|
|
@Description Free the kernel or firmware CCB
|
|
@Input psDevInfo
|
|
@Input ppsCCBCtl
|
|
@Input ppsCCBCtlMemDesc
|
|
@Input ppsCCBMemDesc
|
|
@Input psCCBCtlFWAddr
|
|
******************************************************************************/
|
|
static void RGXFreeCCB(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_CCB_CTL **ppsCCBCtl,
|
|
DEVMEM_MEMDESC **ppsCCBCtlMemDesc,
|
|
IMG_UINT8 **ppui8CCB,
|
|
DEVMEM_MEMDESC **ppsCCBMemDesc)
|
|
{
|
|
if (*ppsCCBMemDesc != NULL)
|
|
{
|
|
if (*ppui8CCB != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(*ppsCCBMemDesc);
|
|
*ppui8CCB = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, *ppsCCBMemDesc);
|
|
*ppsCCBMemDesc = NULL;
|
|
}
|
|
if (*ppsCCBCtlMemDesc != NULL)
|
|
{
|
|
if (*ppsCCBCtl != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(*ppsCCBCtlMemDesc);
|
|
*ppsCCBCtl = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, *ppsCCBCtlMemDesc);
|
|
*ppsCCBCtlMemDesc = NULL;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFreeCCBReturnSlots
|
|
@Description Free the kernel CCB's return slot array and associated mappings
|
|
@Input psDevInfo Device Info struct
|
|
@Input ppui32CCBRtnSlots CPU mapping of slot array
|
|
@Input ppsCCBRtnSlotsMemDesc Slot array's device memdesc
|
|
******************************************************************************/
|
|
static void RGXFreeCCBReturnSlots(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 **ppui32CCBRtnSlots,
|
|
DEVMEM_MEMDESC **ppsCCBRtnSlotsMemDesc)
|
|
{
|
|
/* Free the return slot array if allocated */
|
|
if (*ppsCCBRtnSlotsMemDesc != NULL)
|
|
{
|
|
/* Before freeing, ensure the CPU mapping as well is released */
|
|
if (*ppui32CCBRtnSlots != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(*ppsCCBRtnSlotsMemDesc);
|
|
*ppui32CCBRtnSlots = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, *ppsCCBRtnSlotsMemDesc);
|
|
*ppsCCBRtnSlotsMemDesc = NULL;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXSetupCCB
|
|
@Description Allocate and initialise a circular command buffer
|
|
@Input psDevInfo
|
|
@Input ppsCCBCtl
|
|
@Input ppsCCBCtlMemDesc
|
|
@Input ppui8CCB
|
|
@Input ppsCCBMemDesc
|
|
@Input psCCBCtlFWAddr
|
|
@Input ui32NumCmdsLog2
|
|
@Input ui32CmdSize
|
|
@Input uiCCBMemAllocFlags
|
|
@Input pszName
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXSetupCCB(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_CCB_CTL **ppsCCBCtl,
|
|
DEVMEM_MEMDESC **ppsCCBCtlMemDesc,
|
|
IMG_UINT8 **ppui8CCB,
|
|
DEVMEM_MEMDESC **ppsCCBMemDesc,
|
|
PRGXFWIF_CCB_CTL *psCCBCtlFWAddr,
|
|
PRGXFWIF_CCB *psCCBFWAddr,
|
|
IMG_UINT32 ui32NumCmdsLog2,
|
|
IMG_UINT32 ui32CmdSize,
|
|
PVRSRV_MEMALLOCFLAGS_T uiCCBMemAllocFlags,
|
|
const IMG_CHAR *pszName)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_CCB_CTL *psCCBCtl;
|
|
IMG_UINT32 ui32CCBSize = (1U << ui32NumCmdsLog2);
|
|
IMG_CHAR szCCBCtlName[DEVMEM_ANNOTATION_MAX_LEN];
|
|
IMG_INT32 iStrLen;
|
|
|
|
/* Append "Control" to the name for the control struct. */
|
|
iStrLen = OSSNPrintf(szCCBCtlName, sizeof(szCCBCtlName), "%sControl", pszName);
|
|
PVR_ASSERT(iStrLen < sizeof(szCCBCtlName));
|
|
|
|
if (unlikely(iStrLen < 0))
|
|
{
|
|
OSStringLCopy(szCCBCtlName, "FwCCBControl", DEVMEM_ANNOTATION_MAX_LEN);
|
|
}
|
|
|
|
/* Allocate memory for the CCB control.*/
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
|
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
|
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
|
PVRSRV_MEMALLOCFLAG_GPU_UNCACHED |
|
|
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
|
|
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
|
|
PVRSRV_MEMALLOCFLAG_CPU_UNCACHED |
|
|
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE |
|
|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
|
|
PVRSRV_MEMALLOCFLAG_PHYS_HEAP_HINT(FW_MAIN),
|
|
sizeof(RGXFWIF_CCB_CTL),
|
|
szCCBCtlName,
|
|
ppsCCBCtlMemDesc,
|
|
psCCBCtlFWAddr,
|
|
(void**) ppsCCBCtl,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
/*
|
|
* Allocate memory for the CCB.
|
|
* (this will reference further command data in non-shared CCBs)
|
|
*/
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
uiCCBMemAllocFlags,
|
|
ui32CCBSize * ui32CmdSize,
|
|
pszName,
|
|
ppsCCBMemDesc,
|
|
psCCBFWAddr,
|
|
(void**) ppui8CCB,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
/*
|
|
* Initialise the CCB control.
|
|
*/
|
|
psCCBCtl = *ppsCCBCtl;
|
|
psCCBCtl->ui32WriteOffset = 0;
|
|
psCCBCtl->ui32ReadOffset = 0;
|
|
psCCBCtl->ui32WrapMask = ui32CCBSize - 1;
|
|
psCCBCtl->ui32CmdSize = ui32CmdSize;
|
|
|
|
/* Pdump the CCB control */
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Initialise %s", szCCBCtlName);
|
|
DevmemPDumpLoadMem(*ppsCCBCtlMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_CCB_CTL),
|
|
0);
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail:
|
|
RGXFreeCCB(psDevInfo,
|
|
ppsCCBCtl,
|
|
ppsCCBCtlMemDesc,
|
|
ppui8CCB,
|
|
ppsCCBMemDesc);
|
|
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
return eError;
|
|
}
|
|
|
|
static void RGXSetupFaultReadRegisterRollback(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
PMR *psPMR;
|
|
|
|
if (psDevInfo->psRGXFaultAddressMemDesc)
|
|
{
|
|
if (DevmemServerGetImportHandle(psDevInfo->psRGXFaultAddressMemDesc, (void **)&psPMR) == PVRSRV_OK)
|
|
{
|
|
PMRUnlockSysPhysAddresses(psPMR);
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFaultAddressMemDesc);
|
|
psDevInfo->psRGXFaultAddressMemDesc = NULL;
|
|
}
|
|
}
|
|
|
|
static PVRSRV_ERROR RGXSetupFaultReadRegister(PVRSRV_DEVICE_NODE *psDeviceNode, RGXFWIF_SYSINIT *psFwSysInit)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
IMG_UINT32 *pui32MemoryVirtAddr;
|
|
IMG_UINT32 i;
|
|
size_t ui32PageSize = OSGetPageSize();
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
PMR *psPMR;
|
|
|
|
/* Allocate page of memory to use for page faults on non-blocking memory transactions.
|
|
* Doesn't need to be cleared as it is initialised with the 0xDEADBEE0 pattern below. */
|
|
psDevInfo->psRGXFaultAddressMemDesc = NULL;
|
|
eError = DevmemFwAllocateExportable(psDeviceNode,
|
|
ui32PageSize,
|
|
ui32PageSize,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS & ~PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC,
|
|
"FwExFaultAddress",
|
|
&psDevInfo->psRGXFaultAddressMemDesc);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to allocate mem for fault address (%u)",
|
|
__func__, eError));
|
|
goto failFaultAddressDescAlloc;
|
|
}
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFaultAddressMemDesc,
|
|
(void **)&pui32MemoryVirtAddr);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to acquire mem for fault address (%u)",
|
|
__func__, eError));
|
|
goto failFaultAddressDescAqCpuVirt;
|
|
}
|
|
|
|
if (!psDeviceNode->bAutoVzFwIsUp)
|
|
{
|
|
/* fill the page with a known pattern when booting the firmware */
|
|
for (i = 0; i < ui32PageSize/sizeof(IMG_UINT32); i++)
|
|
{
|
|
*(pui32MemoryVirtAddr + i) = 0xDEADBEE0;
|
|
}
|
|
}
|
|
|
|
OSWriteMemoryBarrier(pui32MemoryVirtAddr);
|
|
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFaultAddressMemDesc);
|
|
|
|
eError = DevmemServerGetImportHandle(psDevInfo->psRGXFaultAddressMemDesc, (void **)&psPMR);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Error getting PMR for fault address (%u)",
|
|
__func__, eError));
|
|
|
|
goto failFaultAddressDescGetPMR;
|
|
}
|
|
else
|
|
{
|
|
IMG_BOOL bValid;
|
|
IMG_UINT32 ui32Log2PageSize = OSGetPageShift();
|
|
|
|
eError = PMRLockSysPhysAddresses(psPMR);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Error locking physical address for fault address MemDesc (%u)",
|
|
__func__, eError));
|
|
|
|
goto failFaultAddressDescLockPhys;
|
|
}
|
|
|
|
eError = PMR_DevPhysAddr(psPMR,ui32Log2PageSize, 1, 0, &(psFwSysInit->sFaultPhysAddr), &bValid);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Error getting physical address for fault address MemDesc (%u)",
|
|
__func__, eError));
|
|
|
|
goto failFaultAddressDescGetPhys;
|
|
}
|
|
|
|
if (!bValid)
|
|
{
|
|
psFwSysInit->sFaultPhysAddr.uiAddr = 0;
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed getting physical address for fault address MemDesc - invalid page (0x%" IMG_UINT64_FMTSPECX ")",
|
|
__func__, psFwSysInit->sFaultPhysAddr.uiAddr));
|
|
|
|
goto failFaultAddressDescGetPhys;
|
|
}
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
|
|
failFaultAddressDescGetPhys:
|
|
PMRUnlockSysPhysAddresses(psPMR);
|
|
|
|
failFaultAddressDescLockPhys:
|
|
failFaultAddressDescGetPMR:
|
|
failFaultAddressDescAqCpuVirt:
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFaultAddressMemDesc);
|
|
psDevInfo->psRGXFaultAddressMemDesc = NULL;
|
|
|
|
failFaultAddressDescAlloc:
|
|
|
|
return eError;
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
/* Replace the DevPhy address with the one Pdump allocates at pdump_player run time */
|
|
static PVRSRV_ERROR RGXPDumpFaultReadRegister(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PMR *psFWInitPMR, *psFaultAddrPMR;
|
|
IMG_UINT32 ui32Dstoffset;
|
|
|
|
psFWInitPMR = (PMR *)(psDevInfo->psRGXFWIfSysInitMemDesc->psImport->hPMR);
|
|
ui32Dstoffset = psDevInfo->psRGXFWIfSysInitMemDesc->uiOffset + offsetof(RGXFWIF_SYSINIT, sFaultPhysAddr.uiAddr);
|
|
|
|
psFaultAddrPMR = (PMR *)(psDevInfo->psRGXFaultAddressMemDesc->psImport->hPMR);
|
|
|
|
eError = PDumpMemLabelToMem64(psFaultAddrPMR,
|
|
psFWInitPMR,
|
|
0,
|
|
ui32Dstoffset,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Dump of Fault Page Phys address failed(%u)", __func__, eError));
|
|
}
|
|
return eError;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_TBI_INTERFACE)
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTBIBufferIsInitRequired
|
|
|
|
@Description Returns true if the firmware tbi buffer is not allocated and
|
|
might be required by the firmware soon. TBI buffer allocated
|
|
on-demand to reduce RAM footprint on systems not needing
|
|
tbi.
|
|
|
|
@Input psDevInfo RGX device info
|
|
|
|
@Return IMG_BOOL Whether on-demand allocation(s) is/are needed
|
|
or not
|
|
*/ /**************************************************************************/
|
|
INLINE IMG_BOOL RGXTBIBufferIsInitRequired(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBufCtl;
|
|
|
|
/* The firmware expects a tbi buffer only when:
|
|
* - Logtype is "tbi"
|
|
*/
|
|
if ((psDevInfo->psRGXFWIfTBIBufferMemDesc == NULL)
|
|
&& (psTraceBufCtl->ui32LogType & ~RGXFWIF_LOG_TYPE_TRACE)
|
|
&& (psTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_GROUP_MASK))
|
|
{
|
|
return IMG_TRUE;
|
|
}
|
|
|
|
return IMG_FALSE;
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTBIBufferDeinit
|
|
|
|
@Description Deinitialises all the allocations and references that are made
|
|
for the FW tbi buffer
|
|
|
|
@Input ppsDevInfo RGX device info
|
|
@Return void
|
|
*/ /**************************************************************************/
|
|
static void RGXTBIBufferDeinit(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfTBIBufferMemDesc);
|
|
psDevInfo->psRGXFWIfTBIBufferMemDesc = NULL;
|
|
psDevInfo->ui32RGXFWIfHWPerfBufSize = 0;
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTBIBufferInitOnDemandResources
|
|
|
|
@Description Allocates the firmware TBI buffer required for reading SFs
|
|
strings and initialize it with SFs.
|
|
|
|
@Input psDevInfo RGX device info
|
|
|
|
@Return PVRSRV_OK If all went good, PVRSRV_ERROR otherwise.
|
|
*/ /**************************************************************************/
|
|
PVRSRV_ERROR RGXTBIBufferInitOnDemandResources(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
IMG_UINT32 i, ui32Len;
|
|
const IMG_UINT32 ui32FWTBIBufsize = g_ui32SFsCount * sizeof(RGXFW_STID_FMT);
|
|
RGXFW_STID_FMT *psFW_SFs = NULL;
|
|
|
|
/* Firmware address should not be already set */
|
|
if (psDevInfo->sRGXFWIfTBIBuffer.ui32Addr)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: FW address for FWTBI is already set. Resetting it with newly allocated one",
|
|
__func__));
|
|
}
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_GPU_RO_ALLOCFLAGS,
|
|
ui32FWTBIBufsize,
|
|
"FwTBIBuffer",
|
|
&psDevInfo->psRGXFWIfTBIBufferMemDesc,
|
|
&psDevInfo->sRGXFWIfTBIBuffer,
|
|
(void**)&psFW_SFs,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
/* Copy SFs entries to FW buffer */
|
|
for (i = 0; i < g_ui32SFsCount; i++)
|
|
{
|
|
OSCachedMemCopy(&psFW_SFs[i].ui32Id, &SFs[i].ui32Id, sizeof(SFs[i].ui32Id));
|
|
ui32Len = OSStringLength(SFs[i].psName);
|
|
OSCachedMemCopy(psFW_SFs[i].sName, SFs[i].psName, MIN(ui32Len, IMG_SF_STRING_MAX_SIZE - 1));
|
|
}
|
|
|
|
/* flush write buffers for psFW_SFs */
|
|
OSWriteMemoryBarrier(psFW_SFs);
|
|
|
|
/* Set size of TBI buffer */
|
|
psDevInfo->ui32FWIfTBIBufferSize = ui32FWTBIBufsize;
|
|
|
|
/* release CPU mapping */
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfTBIBufferMemDesc);
|
|
|
|
return PVRSRV_OK;
|
|
fail:
|
|
RGXTBIBufferDeinit(psDevInfo);
|
|
return eError;
|
|
}
|
|
#endif
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTraceBufferIsInitRequired
|
|
|
|
@Description Returns true if the firmware trace buffer is not allocated and
|
|
might be required by the firmware soon. Trace buffer allocated
|
|
on-demand to reduce RAM footprint on systems not needing
|
|
firmware trace.
|
|
|
|
@Input psDevInfo RGX device info
|
|
|
|
@Return IMG_BOOL Whether on-demand allocation(s) is/are needed
|
|
or not
|
|
*/ /**************************************************************************/
|
|
INLINE IMG_BOOL RGXTraceBufferIsInitRequired(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBufCtl;
|
|
|
|
/* The firmware expects a trace buffer only when:
|
|
* - Logtype is "trace" AND
|
|
* - at least one LogGroup is configured
|
|
* - the Driver Mode is not Guest
|
|
*/
|
|
if ((psDevInfo->psRGXFWIfTraceBufferMemDesc[0] == NULL)
|
|
&& (psTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_TRACE)
|
|
&& (psTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_GROUP_MASK)
|
|
&& !PVRSRV_VZ_MODE_IS(GUEST))
|
|
{
|
|
return IMG_TRUE;
|
|
}
|
|
|
|
return IMG_FALSE;
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTraceBufferDeinit
|
|
|
|
@Description Deinitialises all the allocations and references that are made
|
|
for the FW trace buffer(s)
|
|
|
|
@Input ppsDevInfo RGX device info
|
|
@Return void
|
|
*/ /**************************************************************************/
|
|
static void RGXTraceBufferDeinit(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBufCtl;
|
|
IMG_UINT32 i;
|
|
|
|
for (i = 0; i < RGXFW_THREAD_NUM; i++)
|
|
{
|
|
if (psDevInfo->psRGXFWIfTraceBufferMemDesc[i])
|
|
{
|
|
if (psTraceBufCtl->sTraceBuf[i].pui32TraceBuffer != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufferMemDesc[i]);
|
|
psTraceBufCtl->sTraceBuf[i].pui32TraceBuffer = NULL;
|
|
}
|
|
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfTraceBufferMemDesc[i]);
|
|
psDevInfo->psRGXFWIfTraceBufferMemDesc[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/ /*!
|
|
@Function RGXTraceBufferInitOnDemandResources
|
|
|
|
@Description Allocates the firmware trace buffer required for dumping trace
|
|
info from the firmware.
|
|
|
|
@Input psDevInfo RGX device info
|
|
|
|
@Return PVRSRV_OK If all went good, PVRSRV_ERROR otherwise.
|
|
*/ /**************************************************************************/
|
|
PVRSRV_ERROR RGXTraceBufferInitOnDemandResources(PVRSRV_RGXDEV_INFO* psDevInfo,
|
|
PVRSRV_MEMALLOCFLAGS_T uiAllocFlags)
|
|
{
|
|
RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBufCtl;
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
IMG_UINT32 ui32FwThreadNum;
|
|
IMG_UINT32 ui32DefaultTraceBufSize;
|
|
IMG_DEVMEM_SIZE_T uiTraceBufSizeInBytes;
|
|
void *pvAppHintState = NULL;
|
|
IMG_CHAR pszBufferName[] = "FwTraceBuffer_Thread0";
|
|
|
|
/* Check AppHint value for module-param FWTraceBufSizeInDWords */
|
|
OSCreateKMAppHintState(&pvAppHintState);
|
|
ui32DefaultTraceBufSize = RGXFW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS;
|
|
OSGetKMAppHintUINT32(APPHINT_NO_DEVICE,
|
|
pvAppHintState,
|
|
FWTraceBufSizeInDWords,
|
|
&ui32DefaultTraceBufSize,
|
|
&psTraceBufCtl->ui32TraceBufSizeInDWords);
|
|
OSFreeKMAppHintState(pvAppHintState);
|
|
pvAppHintState = NULL;
|
|
|
|
uiTraceBufSizeInBytes = psTraceBufCtl->ui32TraceBufSizeInDWords * sizeof(IMG_UINT32);
|
|
|
|
for (ui32FwThreadNum = 0; ui32FwThreadNum < RGXFW_THREAD_NUM; ui32FwThreadNum++)
|
|
{
|
|
#if !defined(SUPPORT_AUTOVZ)
|
|
/* Ensure allocation API is only called when not already allocated */
|
|
PVR_ASSERT(psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum] == NULL);
|
|
/* Firmware address should not be already set */
|
|
PVR_ASSERT(psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32RGXFWIfTraceBuffer.ui32Addr == 0x0);
|
|
#endif
|
|
|
|
/* update the firmware thread number in the Trace Buffer's name */
|
|
pszBufferName[sizeof(pszBufferName) - 2] += ui32FwThreadNum;
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
uiAllocFlags,
|
|
uiTraceBufSizeInBytes,
|
|
pszBufferName,
|
|
&psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum],
|
|
&psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32RGXFWIfTraceBuffer,
|
|
(void**)&psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32TraceBuffer,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail:
|
|
RGXTraceBufferDeinit(psDevInfo);
|
|
return eError;
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
/*************************************************************************/ /*!
|
|
@Function RGXPDumpLoadFWInitData
|
|
|
|
@Description Allocates the firmware trace buffer required for dumping trace
|
|
info from the firmware.
|
|
|
|
@Input psDevInfo RGX device info
|
|
*/ /*************************************************************************/
|
|
static void RGXPDumpLoadFWInitData(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32HWPerfCountersDataSize,
|
|
IMG_BOOL bEnableSignatureChecks)
|
|
{
|
|
IMG_UINT32 ui32ConfigFlags = psDevInfo->psRGXFWIfFwSysData->ui32ConfigFlags;
|
|
IMG_UINT32 ui32FwOsCfgFlags = psDevInfo->psRGXFWIfFwOsData->ui32FwOsConfigFlags;
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Dump RGXFW Init data");
|
|
if (!bEnableSignatureChecks)
|
|
{
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(to enable rgxfw signatures place the following line after the RTCONF line)");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
offsetof(RGXFWIF_SYSINIT, asSigBufCtl),
|
|
sizeof(RGXFWIF_SIGBUF_CTL)*(RGXFWIF_DM_MAX),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
}
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump initial state of FW runtime configuration");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_RUNTIME_CFG),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgxfw hwperfctl structure");
|
|
DevmemPDumpLoadZeroMem(psDevInfo->psRGXFWIfHWPerfCountersMemDesc,
|
|
0,
|
|
ui32HWPerfCountersDataSize,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgxfw trace control structure");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfTraceBufCtlMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_TRACEBUF),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump firmware system data structure");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfFwSysDataMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_SYSDATA),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump firmware OS data structure");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfFwOsDataMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_OSDATA),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
#if defined(SUPPORT_TBI_INTERFACE)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgx TBI buffer");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfTBIBufferMemDesc,
|
|
0,
|
|
psDevInfo->ui32FWIfTBIBufferSize,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif /* defined(SUPPORT_TBI_INTERFACE) */
|
|
|
|
#if defined(SUPPORT_USER_REGISTER_CONFIGURATION)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgxfw register configuration buffer");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_REG_CFG),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif /* defined(SUPPORT_USER_REGISTER_CONFIGURATION) */
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgxfw system init structure");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_SYSINIT),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Dump rgxfw os init structure");
|
|
DevmemPDumpLoadMem(psDevInfo->psRGXFWIfOsInitMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_OSINIT),
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* RGXFW Init structure needs to be loaded before we overwrite FaultPhysAddr, else this address patching won't have any effect */
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Overwrite FaultPhysAddr of FwSysInit in pdump with actual physical address");
|
|
RGXPDumpFaultReadRegister(psDevInfo);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"RTCONF: run-time configuration");
|
|
|
|
|
|
/* Dump the config options so they can be edited.
|
|
*
|
|
*/
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(Set the FW system config options here)");
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch Rand mode: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_MODE_RAND);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch Soft Reset Enable: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_SRESET_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable HWPerf: 0x%08x)", RGXFWIF_INICFG_HWPERF_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable generic DM Killing Rand mode: 0x%08x)", RGXFWIF_INICFG_DM_KILL_MODE_RAND_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Rascal+Dust Power Island: 0x%08x)", RGXFWIF_INICFG_POW_RASCALDUST);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( FBCDC Version 3.1 Enable: 0x%08x)", RGXFWIF_INICFG_FBCDC_V3_1_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Check MList: 0x%08x)", RGXFWIF_INICFG_CHECK_MLIST_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Disable Auto Clock Gating: 0x%08x)", RGXFWIF_INICFG_DISABLE_CLKGATING_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable register configuration: 0x%08x)", RGXFWIF_INICFG_REGCONFIG_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Assert on TA Out-of-Memory: 0x%08x)", RGXFWIF_INICFG_ASSERT_ON_OUTOFMEMORY);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Disable HWPerf custom counter filter: 0x%08x)", RGXFWIF_INICFG_HWP_DISABLE_FILTER);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable Ctx Switch profile mode: 0x%08x (none=b'000, fast=b'001, medium=b'010, slow=b'011, nodelay=b'100))", RGXFWIF_INICFG_CTXSWITCH_PROFILE_MASK);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Disable DM overlap (except TA during SPM): 0x%08x)", RGXFWIF_INICFG_DISABLE_DM_OVERLAP);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Assert on HWR trigger (page fault, lockup, overrun or poll failure): 0x%08x)", RGXFWIF_INICFG_ASSERT_ON_HWR_TRIGGER);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable coherent memory accesses: 0x%08x)", RGXFWIF_INICFG_FABRIC_COHERENCY_ENABLED);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable IRQ validation: 0x%08x)", RGXFWIF_INICFG_VALIDATE_IRQ);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( SPU power state mask change Enable: 0x%08x)", RGXFWIF_INICFG_SPU_POWER_STATE_MASK_CHANGE_EN);
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable Workload Estimation: 0x%08x)", RGXFWIF_INICFG_WORKEST);
|
|
#if defined(SUPPORT_PDVFS)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Enable Proactive DVFS: 0x%08x)", RGXFWIF_INICFG_PDVFS);
|
|
#endif /* defined(SUPPORT_PDVFS) */
|
|
#endif /* defined(SUPPORT_WORKLOAD_ESTIMATION) */
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( CDM Arbitration Mode (task demand=b'01, round robin=b'10): 0x%08x)", RGXFWIF_INICFG_CDM_ARBITRATION_MASK);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( ISP Scheduling Mode (v1=b'01, v2=b'10): 0x%08x)", RGXFWIF_INICFG_ISPSCHEDMODE_MASK);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Validate SOC & USC timers: 0x%08x)", RGXFWIF_INICFG_VALIDATE_SOCUSC_TIMER);
|
|
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfFwSysDataMemDesc,
|
|
offsetof(RGXFWIF_SYSDATA, ui32ConfigFlags),
|
|
ui32ConfigFlags,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Extended FW system config options not used.)");
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(Set the FW OS config options here)");
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch TDM Enable: 0x%08x)", RGXFWIF_INICFG_OS_CTXSWITCH_TDM_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch TA Enable: 0x%08x)", RGXFWIF_INICFG_OS_CTXSWITCH_GEOM_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch 3D Enable: 0x%08x)", RGXFWIF_INICFG_OS_CTXSWITCH_3D_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Ctx Switch CDM Enable: 0x%08x)", RGXFWIF_INICFG_OS_CTXSWITCH_CDM_EN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Lower Priority Ctx Switch 2D Enable: 0x%08x)", RGXFWIF_INICFG_OS_LOW_PRIO_CS_TDM);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Lower Priority Ctx Switch TA Enable: 0x%08x)", RGXFWIF_INICFG_OS_LOW_PRIO_CS_GEOM);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Lower Priority Ctx Switch 3D Enable: 0x%08x)", RGXFWIF_INICFG_OS_LOW_PRIO_CS_3D);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Lower Priority Ctx Switch CDM Enable: 0x%08x)", RGXFWIF_INICFG_OS_LOW_PRIO_CS_CDM);
|
|
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfFwOsDataMemDesc,
|
|
offsetof(RGXFWIF_OSDATA, ui32FwOsConfigFlags),
|
|
ui32FwOsCfgFlags,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
|
|
#if defined(SUPPORT_SECURITY_VALIDATION)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(Select one or more security tests here)");
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Read/write FW private data from non-FW contexts: 0x%08x)", RGXFWIF_SECURE_ACCESS_TEST_READ_WRITE_FW_DATA);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Read/write FW code from non-FW contexts: 0x%08x)", RGXFWIF_SECURE_ACCESS_TEST_READ_WRITE_FW_CODE);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Execute FW code from non-secure memory: 0x%08x)", RGXFWIF_SECURE_ACCESS_TEST_RUN_FROM_NONSECURE);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Execute FW code from secure (non-FW) memory: 0x%08x)", RGXFWIF_SECURE_ACCESS_TEST_RUN_FROM_SECURE);
|
|
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
offsetof(RGXFWIF_SYSINIT, ui32SecurityTestFlags),
|
|
psDevInfo->psRGXFWIfSysInit->ui32SecurityTestFlags,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( PID filter type: %X=INCLUDE_ALL_EXCEPT, %X=EXCLUDE_ALL_EXCEPT)",
|
|
RGXFW_PID_FILTER_INCLUDE_ALL_EXCEPT,
|
|
RGXFW_PID_FILTER_EXCLUDE_ALL_EXCEPT);
|
|
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
offsetof(RGXFWIF_SYSINIT, sPIDFilter.eMode),
|
|
psDevInfo->psRGXFWIfSysInit->sPIDFilter.eMode,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( PID filter PID/OSID list (Up to %u entries. Terminate with a zero PID))",
|
|
RGXFWIF_PID_FILTER_MAX_NUM_PIDS);
|
|
{
|
|
IMG_UINT32 i;
|
|
|
|
/* generate a few WRWs in the pdump stream as an example */
|
|
for (i = 0; i < MIN(RGXFWIF_PID_FILTER_MAX_NUM_PIDS, 8); i++)
|
|
{
|
|
/*
|
|
* Some compilers cannot cope with the uses of offsetof() below - the specific problem being the use of
|
|
* a non-const variable in the expression, which it needs to be const. Typical compiler output is
|
|
* "expression must have a constant value".
|
|
*/
|
|
const IMG_DEVMEM_OFFSET_T uiPIDOff
|
|
= (IMG_DEVMEM_OFFSET_T)(uintptr_t)&(((RGXFWIF_SYSINIT *)0)->sPIDFilter.asItems[i].uiPID);
|
|
|
|
const IMG_DEVMEM_OFFSET_T uiOSIDOff
|
|
= (IMG_DEVMEM_OFFSET_T)(uintptr_t)&(((RGXFWIF_SYSINIT *)0)->sPIDFilter.asItems[i].ui32OSID);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(PID and OSID pair %u)", i);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "(PID)");
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
uiPIDOff,
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "(OSID)");
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
uiOSIDOff,
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Dump the log config so it can be edited.
|
|
*/
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(Set the log config here)");
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( Log Type: set bit 0 for TRACE, reset for TBI)");
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( MAIN Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_MAIN);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( MTS Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_MTS);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( CLEANUP Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_CLEANUP);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( CSW Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_CSW);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( BIF Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_BIF);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( PM Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_PM);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( RTD Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_RTD);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( SPM Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_SPM);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( POW Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_POW);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( HWR Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_HWR);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( HWP Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_HWP);
|
|
|
|
#if defined(RGX_FEATURE_META_DMA_CHANNEL_COUNT_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, META_DMA))
|
|
{
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( DMA Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_DMA);
|
|
}
|
|
#endif
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( MISC Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_MISC);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"( DEBUG Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_DEBUG);
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfTraceBufCtlMemDesc,
|
|
offsetof(RGXFWIF_TRACEBUF, ui32LogType),
|
|
psDevInfo->psRGXFWIfTraceBufCtl->ui32LogType,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Set the HWPerf Filter config here, see \"hwperfbin2jsont -h\"");
|
|
DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
offsetof(RGXFWIF_SYSINIT, ui64HWPerfFilter),
|
|
psDevInfo->psRGXFWIfSysInit->ui64HWPerfFilter,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
#if defined(SUPPORT_USER_REGISTER_CONFIGURATION)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"(Number of registers configurations for types(byte index): pow on(%d), dust change(%d), ta(%d), 3d(%d), cdm(%d), tla(%d), TDM(%d))",
|
|
RGXFWIF_REG_CFG_TYPE_PWR_ON,
|
|
RGXFWIF_REG_CFG_TYPE_DUST_CHANGE,
|
|
RGXFWIF_REG_CFG_TYPE_TA,
|
|
RGXFWIF_REG_CFG_TYPE_3D,
|
|
RGXFWIF_REG_CFG_TYPE_CDM,
|
|
RGXFWIF_REG_CFG_TYPE_TLA,
|
|
RGXFWIF_REG_CFG_TYPE_TDM);
|
|
|
|
{
|
|
IMG_UINT32 i;
|
|
|
|
/* Write 32 bits in each iteration as required by PDUMP WRW command */
|
|
for (i = 0; i < RGXFWIF_REG_CFG_TYPE_ALL; i += sizeof(IMG_UINT32))
|
|
{
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[i]),
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
}
|
|
}
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "(Set registers here: address, mask, value)");
|
|
DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Addr),
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Mask),
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Value),
|
|
0,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif /* SUPPORT_USER_REGISTER_CONFIGURATION */
|
|
}
|
|
#endif /* defined(PDUMP) */
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXSetupFwGuardPage
|
|
|
|
@Description Allocate a Guard Page at the start of a Guest's Main Heap
|
|
|
|
@Input psDevceNode
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXSetupFwGuardPage(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
(RGX_FWSHAREDMEM_GPU_ONLY_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_PHYS_HEAP_HINT(FW_MAIN)),
|
|
OSGetPageSize(),
|
|
"FwGuardPage",
|
|
&psDevInfo->psRGXFWHeapGuardPageReserveMemDesc,
|
|
NULL,
|
|
NULL,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXSetupFwSysData
|
|
|
|
@Description Sets up all system-wide firmware related data
|
|
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXSetupFwSysData(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
IMG_BOOL bEnableSignatureChecks,
|
|
IMG_UINT32 ui32SignatureChecksBufSize,
|
|
IMG_UINT32 ui32HWPerfFWBufSizeKB,
|
|
IMG_UINT64 ui64HWPerfFilter,
|
|
IMG_UINT32 ui32ConfigFlags,
|
|
IMG_UINT32 ui32ConfigFlagsExt,
|
|
IMG_UINT32 ui32LogType,
|
|
IMG_UINT32 ui32FilterFlags,
|
|
IMG_UINT32 ui32JonesDisableMask,
|
|
IMG_UINT32 ui32HWPerfCountersDataSize,
|
|
IMG_UINT32 *pui32TPUTrilinearFracMask,
|
|
RGX_RD_POWER_ISLAND_CONF eRGXRDPowerIslandConf,
|
|
FW_PERF_CONF eFirmwarePerf)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
RGXFWIF_SYSINIT *psFwSysInitScratch = NULL;
|
|
|
|
psFwSysInitScratch = OSAllocZMem(sizeof(*psFwSysInitScratch));
|
|
PVR_LOG_GOTO_IF_NOMEM(psFwSysInitScratch, eError, fail);
|
|
|
|
/* Sys Fw init data */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
(RGX_FWSHAREDMEM_CONFIG_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED)) &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_SYSINIT),
|
|
"FwSysInitStructure",
|
|
&psDevInfo->psRGXFWIfSysInitMemDesc,
|
|
NULL,
|
|
(void**) &psDevInfo->psRGXFWIfSysInit,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware Sys Init structure allocation", fail);
|
|
|
|
/* Setup Fault read register */
|
|
eError = RGXSetupFaultReadRegister(psDeviceNode, psFwSysInitScratch);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Fault read register setup", fail);
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
psFwSysInitScratch->ui32VzWdgPeriod = PVR_AUTOVZ_WDG_PERIOD_MS;
|
|
#endif
|
|
|
|
/* RD Power Island */
|
|
{
|
|
RGX_DATA *psRGXData = (RGX_DATA*) psDeviceNode->psDevConfig->hDevData;
|
|
IMG_BOOL bSysEnableRDPowIsland = psRGXData->psRGXTimingInfo->bEnableRDPowIsland;
|
|
IMG_BOOL bEnableRDPowIsland = ((eRGXRDPowerIslandConf == RGX_RD_POWER_ISLAND_DEFAULT) && bSysEnableRDPowIsland) ||
|
|
(eRGXRDPowerIslandConf == RGX_RD_POWER_ISLAND_FORCE_ON);
|
|
|
|
ui32ConfigFlags |= bEnableRDPowIsland? RGXFWIF_INICFG_POW_RASCALDUST : 0;
|
|
}
|
|
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
ui32ConfigFlags |= RGXFWIF_INICFG_WORKEST;
|
|
#if defined(SUPPORT_PDVFS)
|
|
{
|
|
RGXFWIF_PDVFS_OPP *psPDVFSOPPInfo;
|
|
IMG_DVFS_DEVICE_CFG *psDVFSDeviceCfg;
|
|
|
|
/* Pro-active DVFS depends on Workload Estimation */
|
|
psPDVFSOPPInfo = &psFwSysInitScratch->sPDVFSOPPInfo;
|
|
psDVFSDeviceCfg = &psDeviceNode->psDevConfig->sDVFS.sDVFSDeviceCfg;
|
|
PVR_LOG_IF_FALSE(psDVFSDeviceCfg->pasOPPTable, "RGXSetupFwSysData: Missing OPP Table");
|
|
|
|
if (psDVFSDeviceCfg->pasOPPTable != NULL)
|
|
{
|
|
if (psDVFSDeviceCfg->ui32OPPTableSize > ARRAY_SIZE(psPDVFSOPPInfo->asOPPValues))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: OPP Table too large: Size = %u, Maximum size = %lu",
|
|
__func__,
|
|
psDVFSDeviceCfg->ui32OPPTableSize,
|
|
(unsigned long)(ARRAY_SIZE(psPDVFSOPPInfo->asOPPValues))));
|
|
eError = PVRSRV_ERROR_INVALID_PARAMS;
|
|
goto fail;
|
|
}
|
|
|
|
OSDeviceMemCopy(psPDVFSOPPInfo->asOPPValues,
|
|
psDVFSDeviceCfg->pasOPPTable,
|
|
sizeof(psPDVFSOPPInfo->asOPPValues));
|
|
|
|
psPDVFSOPPInfo->ui32MaxOPPPoint = psDVFSDeviceCfg->ui32OPPTableSize - 1;
|
|
|
|
ui32ConfigFlags |= RGXFWIF_INICFG_PDVFS;
|
|
}
|
|
}
|
|
#endif /* defined(SUPPORT_PDVFS) */
|
|
#endif /* defined(SUPPORT_WORKLOAD_ESTIMATION) */
|
|
|
|
/* FW trace control structure */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_TRACEBUF),
|
|
"FwTraceCtlStruct",
|
|
&psDevInfo->psRGXFWIfTraceBufCtlMemDesc,
|
|
&psFwSysInitScratch->sTraceBufCtl,
|
|
(void**) &psDevInfo->psRGXFWIfTraceBufCtl,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
if (!psDeviceNode->bAutoVzFwIsUp)
|
|
{
|
|
/* Set initial firmware log type/group(s) */
|
|
if (ui32LogType & ~RGXFWIF_LOG_TYPE_MASK)
|
|
{
|
|
eError = PVRSRV_ERROR_INVALID_PARAMS;
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Invalid initial log type (0x%X)",
|
|
__func__, ui32LogType));
|
|
goto fail;
|
|
}
|
|
psDevInfo->psRGXFWIfTraceBufCtl->ui32LogType = ui32LogType;
|
|
}
|
|
|
|
/* When PDUMP is enabled, ALWAYS allocate on-demand trace buffer resource
|
|
* (irrespective of loggroup(s) enabled), given that logtype/loggroups can
|
|
* be set during PDump playback in logconfig, at any point of time,
|
|
* Otherwise, allocate only if required. */
|
|
#if !defined(PDUMP)
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
/* always allocate trace buffer for AutoVz Host drivers to allow
|
|
* deterministic addresses of all SysData structures */
|
|
if ((PVRSRV_VZ_MODE_IS(HOST)) || (RGXTraceBufferIsInitRequired(psDevInfo)))
|
|
#else
|
|
if (RGXTraceBufferIsInitRequired(psDevInfo))
|
|
#endif
|
|
#endif
|
|
{
|
|
eError = RGXTraceBufferInitOnDemandResources(psDevInfo,
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp));
|
|
}
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXTraceBufferInitOnDemandResources", fail);
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_SYSDATA),
|
|
"FwSysData",
|
|
&psDevInfo->psRGXFWIfFwSysDataMemDesc,
|
|
&psFwSysInitScratch->sFwSysData,
|
|
(void**) &psDevInfo->psRGXFWIfFwSysData,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
/* GPIO validation setup */
|
|
psFwSysInitScratch->eGPIOValidationMode = RGXFWIF_GPIO_VAL_OFF;
|
|
#if defined(SUPPORT_VALIDATION)
|
|
{
|
|
IMG_INT32 ui32AppHintDefault;
|
|
IMG_INT32 ui32GPIOValidationMode;
|
|
void *pvAppHintState = NULL;
|
|
|
|
/* Check AppHint for GPIO validation mode */
|
|
OSCreateKMAppHintState(&pvAppHintState);
|
|
ui32AppHintDefault = PVRSRV_APPHINT_GPIOVALIDATIONMODE;
|
|
OSGetKMAppHintUINT32(APPHINT_NO_DEVICE,
|
|
pvAppHintState,
|
|
GPIOValidationMode,
|
|
&ui32AppHintDefault,
|
|
&ui32GPIOValidationMode);
|
|
OSFreeKMAppHintState(pvAppHintState);
|
|
pvAppHintState = NULL;
|
|
|
|
if (ui32GPIOValidationMode >= RGXFWIF_GPIO_VAL_LAST)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Invalid GPIO validation mode: %d, only valid if smaller than %d. Disabling GPIO validation.",
|
|
__func__,
|
|
ui32GPIOValidationMode,
|
|
RGXFWIF_GPIO_VAL_LAST));
|
|
}
|
|
else
|
|
{
|
|
psFwSysInitScratch->eGPIOValidationMode = (RGXFWIF_GPIO_VAL_MODE) ui32GPIOValidationMode;
|
|
}
|
|
|
|
psFwSysInitScratch->eGPIOValidationMode = ui32GPIOValidationMode;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_POWER_SAMPLING_VIA_DEBUGFS)
|
|
eError = RGXFWSetupCounterBuffer(psDevInfo,
|
|
&psDevInfo->psCounterBufferMemDesc,
|
|
PAGE_SIZE,
|
|
&psFwSysInitScratch->sCounterDumpCtl,
|
|
"CounterBuffer");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Counter Buffer allocation", fail);
|
|
#endif /* defined(SUPPORT_POWER_SAMPLING_VIA_DEBUGFS) */
|
|
|
|
#if defined(SUPPORT_VALIDATION)
|
|
{
|
|
IMG_UINT32 ui32EnablePollOnChecksumErrorStatus;
|
|
IMG_UINT32 ui32ApphintDefault = 0;
|
|
void *pvAppHintState = NULL;
|
|
|
|
/* Check AppHint for polling on GPU Checksum status */
|
|
OSCreateKMAppHintState(&pvAppHintState);
|
|
OSGetKMAppHintUINT32(APPHINT_NO_DEVICE,
|
|
pvAppHintState,
|
|
EnablePollOnChecksumErrorStatus,
|
|
&ui32ApphintDefault,
|
|
&ui32EnablePollOnChecksumErrorStatus);
|
|
OSFreeKMAppHintState(pvAppHintState);
|
|
pvAppHintState = NULL;
|
|
|
|
switch (ui32EnablePollOnChecksumErrorStatus)
|
|
{
|
|
case 0: /* no checking */ break;
|
|
case 3: psDevInfo->ui32ValidationFlags |= RGX_VAL_KZ_SIG_CHECK_NOERR_EN; break;
|
|
case 4: psDevInfo->ui32ValidationFlags |= RGX_VAL_KZ_SIG_CHECK_ERR_EN; break;
|
|
default:
|
|
PVR_DPF((PVR_DBG_WARNING, "Unsupported value in EnablePollOnChecksumErrorStatus (%d)", ui32EnablePollOnChecksumErrorStatus));
|
|
break;
|
|
}
|
|
}
|
|
#endif /* defined(SUPPORT_VALIDATION) */
|
|
|
|
#if defined(SUPPORT_FIRMWARE_GCOV)
|
|
eError = RGXFWSetupFirmwareGcovBuffer(psDevInfo,
|
|
&psDevInfo->psFirmwareGcovBufferMemDesc,
|
|
RGXFWIF_FIRMWARE_GCOV_BUFFER_SIZE,
|
|
&psFwSysInitScratch->sFirmwareGcovCtl,
|
|
"FirmwareGcovBuffer");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware GCOV buffer allocation", fail);
|
|
psDevInfo->ui32FirmwareGcovSize = RGXFWIF_FIRMWARE_GCOV_BUFFER_SIZE;
|
|
#endif /* defined(SUPPORT_FIRMWARE_GCOV) */
|
|
|
|
#if defined(PDUMP)
|
|
/* Require a minimum amount of memory for the signature buffers */
|
|
if (ui32SignatureChecksBufSize < RGXFW_SIG_BUFFER_SIZE_MIN)
|
|
{
|
|
ui32SignatureChecksBufSize = RGXFW_SIG_BUFFER_SIZE_MIN;
|
|
}
|
|
|
|
/* Setup Signature and Checksum Buffers for TDM, GEOM and 3D */
|
|
eError = RGXFWSetupSignatureChecks(psDevInfo,
|
|
&psDevInfo->psRGXFWSigTAChecksMemDesc,
|
|
ui32SignatureChecksBufSize,
|
|
&psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_GEOM]);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "TA Signature check setup", fail);
|
|
psDevInfo->ui32SigTAChecksSize = ui32SignatureChecksBufSize;
|
|
|
|
eError = RGXFWSetupSignatureChecks(psDevInfo,
|
|
&psDevInfo->psRGXFWSig3DChecksMemDesc,
|
|
ui32SignatureChecksBufSize,
|
|
&psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_3D]);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "3D Signature check setup", fail);
|
|
psDevInfo->ui32Sig3DChecksSize = ui32SignatureChecksBufSize;
|
|
|
|
psDevInfo->psRGXFWSigTDM2DChecksMemDesc = NULL;
|
|
psDevInfo->ui32SigTDM2DChecksSize = 0;
|
|
|
|
#if defined(RGX_FEATURE_TDM_PDS_CHECKSUM_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, TDM_PDS_CHECKSUM))
|
|
{
|
|
/* Buffer allocated only when feature present because, all known TDM
|
|
* signature registers are dependent on this feature being present */
|
|
eError = RGXFWSetupSignatureChecks(psDevInfo,
|
|
&psDevInfo->psRGXFWSigTDM2DChecksMemDesc,
|
|
ui32SignatureChecksBufSize,
|
|
&psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_TDM]);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "TDM Signature check setup", fail);
|
|
psDevInfo->ui32SigTDM2DChecksSize = ui32SignatureChecksBufSize;
|
|
}
|
|
#endif
|
|
|
|
if (!bEnableSignatureChecks)
|
|
{
|
|
psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_TDM].sBuffer.ui32Addr = 0x0;
|
|
psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_GEOM].sBuffer.ui32Addr = 0x0;
|
|
psFwSysInitScratch->asSigBufCtl[RGXFWIF_DM_3D].sBuffer.ui32Addr = 0x0;
|
|
}
|
|
#endif /* defined(PDUMP) */
|
|
|
|
eError = RGXFWSetupAlignChecks(psDeviceNode,
|
|
&psFwSysInitScratch->sAlignChecks);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Alignment checks setup", fail);
|
|
|
|
psFwSysInitScratch->ui32FilterFlags = ui32FilterFlags;
|
|
|
|
/* Fill the remaining bits of fw the init data */
|
|
psFwSysInitScratch->sPDSExecBase.uiAddr = RGX_PDSCODEDATA_HEAP_BASE;
|
|
psFwSysInitScratch->sUSCExecBase.uiAddr = RGX_USCCODE_HEAP_BASE;
|
|
psFwSysInitScratch->sFBCDCStateTableBase.uiAddr = RGX_FBCDC_HEAP_BASE;
|
|
psFwSysInitScratch->sFBCDCLargeStateTableBase.uiAddr = RGX_FBCDC_LARGE_HEAP_BASE;
|
|
psFwSysInitScratch->sTextureHeapBase.uiAddr = RGX_TEXTURE_STATE_HEAP_BASE;
|
|
|
|
#if defined(FIX_HW_BRN_65273_BIT_MASK)
|
|
if (RGX_IS_BRN_SUPPORTED(psDevInfo, 65273))
|
|
{
|
|
/* Fill the remaining bits of fw the init data */
|
|
psFwSysInitScratch->sPDSExecBase.uiAddr = RGX_PDSCODEDATA_BRN_65273_HEAP_BASE;
|
|
psFwSysInitScratch->sUSCExecBase.uiAddr = RGX_USCCODE_BRN_65273_HEAP_BASE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE))
|
|
{
|
|
psFwSysInitScratch->ui32JonesDisableMask = ui32JonesDisableMask;
|
|
}
|
|
#endif
|
|
#if defined(RGX_FEATURE_SLC_VIVT_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, SLC_VIVT))
|
|
{
|
|
eError = _AllocateSLC3Fence(psDevInfo, psFwSysInitScratch);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "SLC3Fence memory allocation", fail);
|
|
}
|
|
#endif
|
|
#if defined(SUPPORT_PDVFS)
|
|
/* Core clock rate */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(IMG_UINT32),
|
|
"FwPDVFSCoreClkRate",
|
|
&psDevInfo->psRGXFWIFCoreClkRateMemDesc,
|
|
&psFwSysInitScratch->sCoreClockRate,
|
|
(void**) &psDevInfo->pui32RGXFWIFCoreClkRate,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "PDVFS core clock rate memory setup", fail);
|
|
#endif
|
|
{
|
|
/* Timestamps */
|
|
PVRSRV_MEMALLOCFLAGS_T uiMemAllocFlags =
|
|
PVRSRV_MEMALLOCFLAG_PHYS_HEAP_HINT(FW_MAIN) |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
|
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE | /* XXX ?? */
|
|
PVRSRV_MEMALLOCFLAG_GPU_UNCACHED |
|
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
|
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
|
|
PVRSRV_MEMALLOCFLAG_CPU_UNCACHED_WC |
|
|
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE |
|
|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC;
|
|
|
|
/*
|
|
the timer query arrays
|
|
*/
|
|
PDUMPCOMMENT(psDeviceNode, "Allocate timer query arrays (FW)");
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
sizeof(IMG_UINT64) * RGX_MAX_TIMER_QUERIES,
|
|
uiMemAllocFlags |
|
|
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE,
|
|
"FwStartTimesArray",
|
|
&psDevInfo->psStartTimeMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map start times array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psStartTimeMemDesc,
|
|
(void **)& psDevInfo->pui64StartTimeById);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map start times array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
sizeof(IMG_UINT64) * RGX_MAX_TIMER_QUERIES,
|
|
uiMemAllocFlags |
|
|
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE,
|
|
"FwEndTimesArray",
|
|
& psDevInfo->psEndTimeMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map end times array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psEndTimeMemDesc,
|
|
(void **)& psDevInfo->pui64EndTimeById);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map end times array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
sizeof(IMG_UINT32) * RGX_MAX_TIMER_QUERIES,
|
|
uiMemAllocFlags,
|
|
"FwCompletedOpsArray",
|
|
& psDevInfo->psCompletedMemDesc);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to completed ops array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psCompletedMemDesc,
|
|
(void **)& psDevInfo->pui32CompletedById);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map completed ops array",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
}
|
|
#if !defined(PVRSRV_USE_BRIDGE_LOCK)
|
|
eError = OSLockCreate(&psDevInfo->hTimerQueryLock);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to allocate log for timer query",
|
|
__func__));
|
|
goto fail;
|
|
}
|
|
#endif
|
|
#if defined(SUPPORT_TBI_INTERFACE)
|
|
#if !defined(PDUMP)
|
|
/* allocate only if required */
|
|
if (RGXTBIBufferIsInitRequired(psDevInfo))
|
|
#endif /* !defined(PDUMP) */
|
|
{
|
|
/* When PDUMP is enabled, ALWAYS allocate on-demand TBI buffer resource
|
|
* (irrespective of loggroup(s) enabled), given that logtype/loggroups
|
|
* can be set during PDump playback in logconfig, at any point of time
|
|
*/
|
|
eError = RGXTBIBufferInitOnDemandResources(psDevInfo);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXTBIBufferInitOnDemandResources", fail);
|
|
}
|
|
|
|
psFwSysInitScratch->sTBIBuf = psDevInfo->sRGXFWIfTBIBuffer;
|
|
#endif /* defined(SUPPORT_TBI_INTERFACE) */
|
|
|
|
/* Allocate shared buffer for GPU utilisation */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_GPU_UTIL_FWCB),
|
|
"FwGPUUtilisationBuffer",
|
|
&psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc,
|
|
&psFwSysInitScratch->sGpuUtilFWCbCtl,
|
|
(void**) &psDevInfo->psRGXFWIfGpuUtilFWCb,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "GPU Utilisation Buffer ctl allocation", fail);
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_GPU_RO_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_RUNTIME_CFG),
|
|
"FwRuntimeCfg",
|
|
&psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
&psFwSysInitScratch->sRuntimeCfg,
|
|
(void**) &psDevInfo->psRGXFWIfRuntimeCfg,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware runtime configuration memory allocation", fail);
|
|
|
|
#if defined(SUPPORT_USER_REGISTER_CONFIGURATION)
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
sizeof(RGXFWIF_REG_CFG),
|
|
"FwRegisterConfigStructure",
|
|
&psDevInfo->psRGXFWIfRegCfgMemDesc,
|
|
&psFwSysInitScratch->sRegCfg,
|
|
NULL,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware register user configuration structure allocation", fail);
|
|
#endif
|
|
|
|
psDevInfo->ui32RGXFWIfHWPerfBufSize = GetHwPerfBufferSize(ui32HWPerfFWBufSizeKB);
|
|
/* Second stage initialisation or HWPerf, hHWPerfLock created in first
|
|
* stage. See RGXRegisterDevice() call to RGXHWPerfInit(). */
|
|
if (psDevInfo->ui64HWPerfFilter == 0)
|
|
{
|
|
psDevInfo->ui64HWPerfFilter = ui64HWPerfFilter;
|
|
psFwSysInitScratch->ui64HWPerfFilter = ui64HWPerfFilter;
|
|
}
|
|
else
|
|
{
|
|
/* The filter has already been modified. This can happen if
|
|
* pvr/apphint/EnableFTraceGPU was enabled. */
|
|
psFwSysInitScratch->ui64HWPerfFilter = psDevInfo->ui64HWPerfFilter;
|
|
}
|
|
|
|
#if !defined(PDUMP)
|
|
/* Allocate if HWPerf filter has already been set. This is possible either
|
|
* by setting a proper AppHint or enabling GPU ftrace events. */
|
|
if (psDevInfo->ui64HWPerfFilter != 0)
|
|
#endif
|
|
{
|
|
/* When PDUMP is enabled, ALWAYS allocate on-demand HWPerf resources
|
|
* (irrespective of HWPerf enabled or not), given that HWPerf can be
|
|
* enabled during PDump playback via RTCONF at any point of time. */
|
|
eError = RGXHWPerfInitOnDemandResources(psDevInfo);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXHWPerfInitOnDemandResources", fail);
|
|
}
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS &
|
|
RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp),
|
|
ui32HWPerfCountersDataSize,
|
|
"FwHWPerfControlStructure",
|
|
&psDevInfo->psRGXFWIfHWPerfCountersMemDesc,
|
|
&psFwSysInitScratch->sHWPerfCtl,
|
|
NULL,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware HW Perf control struct allocation", fail);
|
|
|
|
psDevInfo->bPDPEnabled = (ui32ConfigFlags & RGXFWIF_INICFG_DISABLE_PDP_EN)
|
|
? IMG_FALSE : IMG_TRUE;
|
|
|
|
psFwSysInitScratch->eFirmwarePerf = eFirmwarePerf;
|
|
|
|
#if defined(PDUMP)
|
|
/* default: no filter */
|
|
psFwSysInitScratch->sPIDFilter.eMode = RGXFW_PID_FILTER_INCLUDE_ALL_EXCEPT;
|
|
psFwSysInitScratch->sPIDFilter.asItems[0].uiPID = 0;
|
|
#endif
|
|
|
|
#if defined(SUPPORT_VALIDATION)
|
|
{
|
|
IMG_UINT32 dm;
|
|
|
|
/* TPU trilinear rounding mask override */
|
|
for (dm = 0; dm < RGXFWIF_TPU_DM_LAST; dm++)
|
|
{
|
|
psFwSysInitScratch->aui32TPUTrilinearFracMask[dm] = pui32TPUTrilinearFracMask[dm];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_SECURITY_VALIDATION)
|
|
{
|
|
PVRSRV_MEMALLOCFLAGS_T uiFlags = RGX_FWSHAREDMEM_GPU_ONLY_ALLOCFLAGS;
|
|
PVRSRV_SET_PHYS_HEAP_HINT(GPU_SECURE, uiFlags);
|
|
|
|
PDUMPCOMMENT(psDeviceNode, "Allocate non-secure buffer for security validation test");
|
|
eError = DevmemFwAllocateExportable(psDeviceNode,
|
|
OSGetPageSize(),
|
|
OSGetPageSize(),
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS,
|
|
"FwExNonSecureBuffer",
|
|
&psDevInfo->psRGXFWIfNonSecureBufMemDesc);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Non-secure buffer allocation", fail);
|
|
|
|
eError = RGXSetFirmwareAddress(&psFwSysInitScratch->pbNonSecureBuffer,
|
|
psDevInfo->psRGXFWIfNonSecureBufMemDesc,
|
|
0, RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:1", fail);
|
|
|
|
PDUMPCOMMENT(psDeviceNode, "Allocate secure buffer for security validation test");
|
|
eError = DevmemFwAllocateExportable(psDeviceNode,
|
|
OSGetPageSize(),
|
|
OSGetPageSize(),
|
|
uiFlags,
|
|
"FwExSecureBuffer",
|
|
&psDevInfo->psRGXFWIfSecureBufMemDesc);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Secure buffer allocation", fail);
|
|
|
|
eError = RGXSetFirmwareAddress(&psFwSysInitScratch->pbSecureBuffer,
|
|
psDevInfo->psRGXFWIfSecureBufMemDesc,
|
|
0, RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetFirmwareAddress:2", fail);
|
|
}
|
|
#endif /* SUPPORT_SECURITY_VALIDATION */
|
|
|
|
#if defined(RGX_FEATURE_TFBC_LOSSY_37_PERCENT_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, TFBC_LOSSY_37_PERCENT) || RGX_IS_FEATURE_SUPPORTED(psDevInfo, TFBC_DELTA_CORRELATION))
|
|
{
|
|
psFwSysInitScratch->ui32TFBCCompressionControl =
|
|
(ui32ConfigFlagsExt & RGXFWIF_INICFG_EXT_TFBC_CONTROL_MASK) >> RGXFWIF_INICFG_EXT_TFBC_CONTROL_SHIFT;
|
|
}
|
|
#endif
|
|
|
|
/* Initialize FW started flag */
|
|
psFwSysInitScratch->bFirmwareStarted = IMG_FALSE;
|
|
psFwSysInitScratch->ui32MarkerVal = 1;
|
|
|
|
if (!psDeviceNode->bAutoVzFwIsUp)
|
|
{
|
|
IMG_UINT32 ui32OSIndex;
|
|
|
|
RGX_DATA *psRGXData = (RGX_DATA*) psDeviceNode->psDevConfig->hDevData;
|
|
RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
|
|
|
|
/* Required info by FW to calculate the ActivePM idle timer latency */
|
|
psFwSysInitScratch->ui32InitialCoreClockSpeed = psRGXData->psRGXTimingInfo->ui32CoreClockSpeed;
|
|
psFwSysInitScratch->ui32InitialActivePMLatencyms = psRGXData->psRGXTimingInfo->ui32ActivePMLatencyms;
|
|
|
|
/* Initialise variable runtime configuration to the system defaults */
|
|
psRuntimeCfg->ui32CoreClockSpeed = psFwSysInitScratch->ui32InitialCoreClockSpeed;
|
|
psRuntimeCfg->ui32ActivePMLatencyms = psFwSysInitScratch->ui32InitialActivePMLatencyms;
|
|
psRuntimeCfg->bActivePMLatencyPersistant = IMG_TRUE;
|
|
psRuntimeCfg->ui32WdgPeriodUs = RGXFW_SAFETY_WATCHDOG_PERIOD_IN_US;
|
|
psRuntimeCfg->ui32HCSDeadlineMS = RGX_HCS_DEFAULT_DEADLINE_MS;
|
|
|
|
if (PVRSRV_VZ_MODE_IS(NATIVE))
|
|
{
|
|
psRuntimeCfg->aui32OSidPriority[RGXFW_HOST_OS] = 0;
|
|
}
|
|
else
|
|
{
|
|
for (ui32OSIndex = 0; ui32OSIndex < RGX_NUM_OS_SUPPORTED; ui32OSIndex++)
|
|
{
|
|
const IMG_INT32 ai32DefaultOsPriority[RGXFW_MAX_NUM_OS] =
|
|
{RGX_OSID_0_DEFAULT_PRIORITY, RGX_OSID_1_DEFAULT_PRIORITY, RGX_OSID_2_DEFAULT_PRIORITY, RGX_OSID_3_DEFAULT_PRIORITY,
|
|
RGX_OSID_4_DEFAULT_PRIORITY, RGX_OSID_5_DEFAULT_PRIORITY, RGX_OSID_6_DEFAULT_PRIORITY, RGX_OSID_7_DEFAULT_PRIORITY};
|
|
|
|
/* Set up initial priorities between different OSes */
|
|
psRuntimeCfg->aui32OSidPriority[ui32OSIndex] = (IMG_UINT32)ai32DefaultOsPriority[ui32OSIndex];
|
|
}
|
|
}
|
|
|
|
#if defined(PVR_ENABLE_PHR) && defined(PDUMP)
|
|
psRuntimeCfg->ui32PHRMode = RGXFWIF_PHR_MODE_RD_RESET;
|
|
#else
|
|
psRuntimeCfg->ui32PHRMode = 0;
|
|
#endif
|
|
|
|
/* Initialize the DefaultDustsNumInit Field to Max Dusts */
|
|
psRuntimeCfg->ui32DefaultDustsNumInit = psDevInfo->sDevFeatureCfg.ui32MAXDustCount;
|
|
|
|
/* flush write buffers for psDevInfo->psRGXFWIfRuntimeCfg */
|
|
OSWriteMemoryBarrier(psDevInfo->psRGXFWIfRuntimeCfg);
|
|
|
|
/* Setup FW coremem data */
|
|
if (psDevInfo->psRGXFWIfCorememDataStoreMemDesc)
|
|
{
|
|
psFwSysInitScratch->sCorememDataStore.pbyFWAddr = psDevInfo->sFWCorememDataStoreFWAddr;
|
|
|
|
#if defined(RGX_FEATURE_META_DMA_CHANNEL_COUNT_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, META_DMA))
|
|
{
|
|
RGXSetMetaDMAAddress(&psFwSysInitScratch->sCorememDataStore,
|
|
psDevInfo->psRGXFWIfCorememDataStoreMemDesc,
|
|
&psFwSysInitScratch->sCorememDataStore.pbyFWAddr,
|
|
0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
psDevInfo->psRGXFWIfFwSysData->ui32ConfigFlags = ui32ConfigFlags & RGXFWIF_INICFG_ALL;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32ConfigFlagsExt = ui32ConfigFlagsExt & RGXFWIF_INICFG_EXT_ALL;
|
|
|
|
/* Initialise GPU utilisation buffer */
|
|
psDevInfo->psRGXFWIfGpuUtilFWCb->ui64LastWord =
|
|
RGXFWIF_GPU_UTIL_MAKE_WORD(OSClockns64(),RGXFWIF_GPU_UTIL_STATE_IDLE);
|
|
|
|
/* init HWPERF data */
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfRIdx = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfWIdx = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfWrapCount = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfSize = psDevInfo->ui32RGXFWIfHWPerfBufSize;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfUt = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWPerfDropCount = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32FirstDropOrdinal = 0;
|
|
psDevInfo->psRGXFWIfFwSysData->ui32LastDropOrdinal = 0;
|
|
|
|
/*Send through the BVNC Feature Flags*/
|
|
eError = RGXServerFeatureFlagsToHWPerfFlags(psDevInfo, &psFwSysInitScratch->sBvncKmFeatureFlags);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXServerFeatureFlagsToHWPerfFlags", fail);
|
|
|
|
/* populate the real FwOsInit structure with the values stored in the scratch copy */
|
|
OSCachedMemCopyWMB(psDevInfo->psRGXFWIfSysInit, psFwSysInitScratch, sizeof(RGXFWIF_SYSINIT));
|
|
}
|
|
|
|
OSFreeMem(psFwSysInitScratch);
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail:
|
|
if (psFwSysInitScratch)
|
|
{
|
|
OSFreeMem(psFwSysInitScratch);
|
|
}
|
|
|
|
RGXFreeFwSysData(psDevInfo);
|
|
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXSetupFwOsData
|
|
|
|
@Description Sets up all os-specific firmware related data
|
|
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXSetupFwOsData(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
IMG_UINT32 ui32KCCBSizeLog2,
|
|
IMG_UINT32 ui32HWRDebugDumpLimit,
|
|
IMG_UINT32 ui32FwOsCfgFlags)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_OSINIT sFwOsInitScratch;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
|
|
OSCachedMemSet(&sFwOsInitScratch, 0, sizeof(RGXFWIF_OSINIT));
|
|
|
|
if (PVRSRV_VZ_MODE_IS(GUEST))
|
|
{
|
|
eError = RGXSetupFwGuardPage(psDevInfo);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Setting up firmware heap guard pages", fail);
|
|
}
|
|
|
|
/* Memory tracking the connection state should be non-volatile and
|
|
* is not cleared on allocation to prevent loss of pre-reset information */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_CONFIG_ALLOCFLAGS &
|
|
~PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC,
|
|
sizeof(RGXFWIF_CONNECTION_CTL),
|
|
"FwConnectionCtl",
|
|
&psDevInfo->psRGXFWIfConnectionCtlMemDesc,
|
|
NULL,
|
|
(void**) &psDevInfo->psRGXFWIfConnectionCtl,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware Connection Control structure allocation", fail);
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_CONFIG_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED),
|
|
sizeof(RGXFWIF_OSINIT),
|
|
"FwOsInitStructure",
|
|
&psDevInfo->psRGXFWIfOsInitMemDesc,
|
|
NULL,
|
|
(void**) &psDevInfo->psRGXFWIfOsInit,
|
|
RFW_FWADDR_FLAG_NONE);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware Os Init structure allocation", fail);
|
|
|
|
/* init HWR frame info */
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS,
|
|
sizeof(RGXFWIF_HWRINFOBUF),
|
|
"FwHWRInfoBuffer",
|
|
&psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc,
|
|
&sFwOsInitScratch.sRGXFWIfHWRInfoBufCtl,
|
|
(void**) &psDevInfo->psRGXFWIfHWRInfoBufCtl,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "HWR Info Buffer allocation", fail);
|
|
|
|
/* Might be uncached. Be conservative and use a DeviceMemSet */
|
|
OSDeviceMemSet(psDevInfo->psRGXFWIfHWRInfoBufCtl, 0, sizeof(RGXFWIF_HWRINFOBUF));
|
|
|
|
/* Allocate a sync for power management */
|
|
eError = SyncPrimContextCreate(psDevInfo->psDeviceNode,
|
|
&psDevInfo->hSyncPrimContext);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Sync primitive context allocation", fail);
|
|
|
|
eError = SyncPrimAlloc(psDevInfo->hSyncPrimContext, &psDevInfo->psPowSyncPrim, "fw power ack");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Sync primitive allocation", fail);
|
|
|
|
/* Set up kernel CCB */
|
|
eError = RGXSetupCCB(psDevInfo,
|
|
&psDevInfo->psKernelCCBCtl,
|
|
&psDevInfo->psKernelCCBCtlMemDesc,
|
|
&psDevInfo->psKernelCCB,
|
|
&psDevInfo->psKernelCCBMemDesc,
|
|
&sFwOsInitScratch.psKernelCCBCtl,
|
|
&sFwOsInitScratch.psKernelCCB,
|
|
ui32KCCBSizeLog2,
|
|
sizeof(RGXFWIF_KCCB_CMD),
|
|
(RGX_FWSHAREDMEM_GPU_RO_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED)),
|
|
"FwKernelCCB");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Kernel CCB allocation", fail);
|
|
|
|
/* KCCB additionally uses a return slot array for FW to be able to send back
|
|
* return codes for each required command
|
|
*/
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS,
|
|
(1U << ui32KCCBSizeLog2) * sizeof(IMG_UINT32),
|
|
"FwKernelCCBRtnSlots",
|
|
&psDevInfo->psKernelCCBRtnSlotsMemDesc,
|
|
&sFwOsInitScratch.psKernelCCBRtnSlots,
|
|
(void**) &psDevInfo->pui32KernelCCBRtnSlots,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Kernel CCB return slot array allocation", fail);
|
|
|
|
/* Set up firmware CCB */
|
|
eError = RGXSetupCCB(psDevInfo,
|
|
&psDevInfo->psFirmwareCCBCtl,
|
|
&psDevInfo->psFirmwareCCBCtlMemDesc,
|
|
&psDevInfo->psFirmwareCCB,
|
|
&psDevInfo->psFirmwareCCBMemDesc,
|
|
&sFwOsInitScratch.psFirmwareCCBCtl,
|
|
&sFwOsInitScratch.psFirmwareCCB,
|
|
RGXFWIF_FWCCB_NUMCMDS_LOG2,
|
|
sizeof(RGXFWIF_FWCCB_CMD),
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS,
|
|
"FwCCB");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Firmware CCB allocation", fail);
|
|
|
|
eError = RGXSetupFwAllocation(psDevInfo,
|
|
RGX_FWSHAREDMEM_MAIN_ALLOCFLAGS,
|
|
sizeof(RGXFWIF_OSDATA),
|
|
"FwOsData",
|
|
&psDevInfo->psRGXFWIfFwOsDataMemDesc,
|
|
&sFwOsInitScratch.sFwOsData,
|
|
(void**) &psDevInfo->psRGXFWIfFwOsData,
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSetupFwAllocation", fail);
|
|
|
|
psDevInfo->psRGXFWIfFwOsData->ui32FwOsConfigFlags = ui32FwOsCfgFlags & RGXFWIF_INICFG_OS_ALL;
|
|
|
|
eError = SyncPrimGetFirmwareAddr(psDevInfo->psPowSyncPrim, &psDevInfo->psRGXFWIfFwOsData->sPowerSync.ui32Addr);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Get Sync Prim FW address", fail);
|
|
|
|
/* flush write buffers for psRGXFWIfFwOsData */
|
|
OSWriteMemoryBarrier(psDevInfo->psRGXFWIfFwOsData);
|
|
|
|
sFwOsInitScratch.ui32HWRDebugDumpLimit = ui32HWRDebugDumpLimit;
|
|
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
/* Set up Workload Estimation firmware CCB */
|
|
eError = RGXSetupCCB(psDevInfo,
|
|
&psDevInfo->psWorkEstFirmwareCCBCtl,
|
|
&psDevInfo->psWorkEstFirmwareCCBCtlMemDesc,
|
|
&psDevInfo->psWorkEstFirmwareCCB,
|
|
&psDevInfo->psWorkEstFirmwareCCBMemDesc,
|
|
&sFwOsInitScratch.psWorkEstFirmwareCCBCtl,
|
|
&sFwOsInitScratch.psWorkEstFirmwareCCB,
|
|
RGXFWIF_WORKEST_FWCCB_NUMCMDS_LOG2,
|
|
sizeof(RGXFWIF_WORKEST_FWCCB_CMD),
|
|
RGX_FWSHAREDMEM_CPU_RO_ALLOCFLAGS,
|
|
"FwWEstCCB");
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Workload Estimation Firmware CCB allocation", fail);
|
|
#endif /* defined(SUPPORT_WORKLOAD_ESTIMATION) */
|
|
|
|
/* Initialise the compatibility check data */
|
|
RGXFWIF_COMPCHECKS_BVNC_INIT(sFwOsInitScratch.sRGXCompChecks.sFWBVNC);
|
|
RGXFWIF_COMPCHECKS_BVNC_INIT(sFwOsInitScratch.sRGXCompChecks.sHWBVNC);
|
|
|
|
/* populate the real FwOsInit structure with the values stored in the scratch copy */
|
|
OSCachedMemCopyWMB(psDevInfo->psRGXFWIfOsInit, &sFwOsInitScratch, sizeof(RGXFWIF_OSINIT));
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail:
|
|
RGXFreeFwOsData(psDevInfo);
|
|
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXSetupFirmware
|
|
|
|
@Description Sets up all firmware related data
|
|
|
|
@Input psDevInfo
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXSetupFirmware(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
IMG_BOOL bEnableSignatureChecks,
|
|
IMG_UINT32 ui32SignatureChecksBufSize,
|
|
IMG_UINT32 ui32HWPerfFWBufSizeKB,
|
|
IMG_UINT64 ui64HWPerfFilter,
|
|
IMG_UINT32 ui32ConfigFlags,
|
|
IMG_UINT32 ui32ConfigFlagsExt,
|
|
IMG_UINT32 ui32FwOsCfgFlags,
|
|
IMG_UINT32 ui32LogType,
|
|
IMG_UINT32 ui32FilterFlags,
|
|
IMG_UINT32 ui32JonesDisableMask,
|
|
IMG_UINT32 ui32HWRDebugDumpLimit,
|
|
IMG_UINT32 ui32HWPerfCountersDataSize,
|
|
IMG_UINT32 *pui32TPUTrilinearFracMask,
|
|
RGX_RD_POWER_ISLAND_CONF eRGXRDPowerIslandConf,
|
|
FW_PERF_CONF eFirmwarePerf,
|
|
IMG_UINT32 ui32KCCBSizeLog2)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
|
|
eError = RGXSetupFwOsData(psDeviceNode,
|
|
ui32KCCBSizeLog2,
|
|
ui32HWRDebugDumpLimit,
|
|
ui32FwOsCfgFlags);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Setting up firmware os data", fail);
|
|
|
|
if (PVRSRV_VZ_MODE_IS(GUEST))
|
|
{
|
|
/* Guest drivers do not configure system-wide firmware data */
|
|
psDevInfo->psRGXFWIfSysInit = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Native and Host drivers must initialise the firmware's system data */
|
|
eError = RGXSetupFwSysData(psDeviceNode,
|
|
bEnableSignatureChecks,
|
|
ui32SignatureChecksBufSize,
|
|
ui32HWPerfFWBufSizeKB,
|
|
ui64HWPerfFilter,
|
|
ui32ConfigFlags,
|
|
ui32ConfigFlagsExt,
|
|
ui32LogType,
|
|
ui32FilterFlags,
|
|
ui32JonesDisableMask,
|
|
ui32HWPerfCountersDataSize,
|
|
pui32TPUTrilinearFracMask,
|
|
eRGXRDPowerIslandConf,
|
|
eFirmwarePerf);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "Setting up firmware system data", fail);
|
|
}
|
|
|
|
psDevInfo->bFirmwareInitialised = IMG_TRUE;
|
|
|
|
#if defined(PDUMP)
|
|
RGXPDumpLoadFWInitData(psDevInfo,
|
|
ui32HWPerfCountersDataSize,
|
|
bEnableSignatureChecks);
|
|
#endif /* PDUMP */
|
|
|
|
fail:
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFreeFwSysData
|
|
|
|
@Description Frees all system-wide firmware related data
|
|
|
|
@Input psDevInfo
|
|
******************************************************************************/
|
|
static void RGXFreeFwSysData(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
psDevInfo->bFirmwareInitialised = IMG_FALSE;
|
|
|
|
if (psDevInfo->psRGXFWAlignChecksMemDesc)
|
|
{
|
|
RGXFWFreeAlignChecks(psDevInfo);
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
#if defined(RGX_FEATURE_TDM_PDS_CHECKSUM_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, TDM_PDS_CHECKSUM) &&
|
|
psDevInfo->psRGXFWSigTDM2DChecksMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWSigTDM2DChecksMemDesc);
|
|
psDevInfo->psRGXFWSigTDM2DChecksMemDesc = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (psDevInfo->psRGXFWSigTAChecksMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWSigTAChecksMemDesc);
|
|
psDevInfo->psRGXFWSigTAChecksMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWSig3DChecksMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWSig3DChecksMemDesc);
|
|
psDevInfo->psRGXFWSig3DChecksMemDesc = NULL;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_POWER_SAMPLING_VIA_DEBUGFS)
|
|
if (psDevInfo->psCounterBufferMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psCounterBufferMemDesc);
|
|
psDevInfo->psCounterBufferMemDesc = NULL;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_FIRMWARE_GCOV)
|
|
if (psDevInfo->psFirmwareGcovBufferMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psFirmwareGcovBufferMemDesc);
|
|
psDevInfo->psFirmwareGcovBufferMemDesc = NULL;
|
|
}
|
|
#endif
|
|
|
|
RGXSetupFaultReadRegisterRollback(psDevInfo);
|
|
|
|
if (psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfGpuUtilFWCb != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc);
|
|
psDevInfo->psRGXFWIfGpuUtilFWCb = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc);
|
|
psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfRuntimeCfgMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfRuntimeCfg != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfRuntimeCfgMemDesc);
|
|
psDevInfo->psRGXFWIfRuntimeCfg = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfRuntimeCfgMemDesc);
|
|
psDevInfo->psRGXFWIfRuntimeCfgMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfCorememDataStoreMemDesc)
|
|
{
|
|
psDevInfo->psRGXFWIfCorememDataStoreMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfTraceBufCtlMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfTraceBufCtl != NULL)
|
|
{
|
|
/* first deinit/free the tracebuffer allocation */
|
|
RGXTraceBufferDeinit(psDevInfo);
|
|
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufCtlMemDesc);
|
|
psDevInfo->psRGXFWIfTraceBufCtl = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfTraceBufCtlMemDesc);
|
|
psDevInfo->psRGXFWIfTraceBufCtlMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfFwSysDataMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfFwSysData != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfFwSysDataMemDesc);
|
|
psDevInfo->psRGXFWIfFwSysData = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfFwSysDataMemDesc);
|
|
psDevInfo->psRGXFWIfFwSysDataMemDesc = NULL;
|
|
}
|
|
|
|
#if defined(SUPPORT_TBI_INTERFACE)
|
|
if (psDevInfo->psRGXFWIfTBIBufferMemDesc)
|
|
{
|
|
RGXTBIBufferDeinit(psDevInfo);
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_USER_REGISTER_CONFIGURATION)
|
|
if (psDevInfo->psRGXFWIfRegCfgMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfRegCfgMemDesc);
|
|
psDevInfo->psRGXFWIfRegCfgMemDesc = NULL;
|
|
}
|
|
#endif
|
|
if (psDevInfo->psRGXFWIfHWPerfCountersMemDesc)
|
|
{
|
|
RGXUnsetFirmwareAddress(psDevInfo->psRGXFWIfHWPerfCountersMemDesc);
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfHWPerfCountersMemDesc);
|
|
psDevInfo->psRGXFWIfHWPerfCountersMemDesc = NULL;
|
|
}
|
|
|
|
#if defined(SUPPORT_SECURITY_VALIDATION)
|
|
if (psDevInfo->psRGXFWIfNonSecureBufMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfNonSecureBufMemDesc);
|
|
psDevInfo->psRGXFWIfNonSecureBufMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfSecureBufMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfSecureBufMemDesc);
|
|
psDevInfo->psRGXFWIfSecureBufMemDesc = NULL;
|
|
}
|
|
#endif
|
|
|
|
#if defined(RGX_FEATURE_SLC_VIVT_BIT_MASK)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, SLC_VIVT))
|
|
{
|
|
_FreeSLC3Fence(psDevInfo);
|
|
}
|
|
#endif
|
|
#if defined(SUPPORT_PDVFS)
|
|
if (psDevInfo->psRGXFWIFCoreClkRateMemDesc)
|
|
{
|
|
if (psDevInfo->pui32RGXFWIFCoreClkRate != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIFCoreClkRateMemDesc);
|
|
psDevInfo->pui32RGXFWIFCoreClkRate = NULL;
|
|
}
|
|
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIFCoreClkRateMemDesc);
|
|
psDevInfo->psRGXFWIFCoreClkRateMemDesc = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFreeFwOsData
|
|
|
|
@Description Frees all os-specific firmware related data
|
|
|
|
@Input psDevInfo
|
|
******************************************************************************/
|
|
static void RGXFreeFwOsData(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFreeCCBReturnSlots(psDevInfo,
|
|
&psDevInfo->pui32KernelCCBRtnSlots,
|
|
&psDevInfo->psKernelCCBRtnSlotsMemDesc);
|
|
RGXFreeCCB(psDevInfo,
|
|
&psDevInfo->psKernelCCBCtl,
|
|
&psDevInfo->psKernelCCBCtlMemDesc,
|
|
&psDevInfo->psKernelCCB,
|
|
&psDevInfo->psKernelCCBMemDesc);
|
|
|
|
RGXFreeCCB(psDevInfo,
|
|
&psDevInfo->psFirmwareCCBCtl,
|
|
&psDevInfo->psFirmwareCCBCtlMemDesc,
|
|
&psDevInfo->psFirmwareCCB,
|
|
&psDevInfo->psFirmwareCCBMemDesc);
|
|
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
RGXFreeCCB(psDevInfo,
|
|
&psDevInfo->psWorkEstFirmwareCCBCtl,
|
|
&psDevInfo->psWorkEstFirmwareCCBCtlMemDesc,
|
|
&psDevInfo->psWorkEstFirmwareCCB,
|
|
&psDevInfo->psWorkEstFirmwareCCBMemDesc);
|
|
#endif
|
|
|
|
if (psDevInfo->psPowSyncPrim != NULL)
|
|
{
|
|
SyncPrimFree(psDevInfo->psPowSyncPrim);
|
|
psDevInfo->psPowSyncPrim = NULL;
|
|
}
|
|
|
|
if (psDevInfo->hSyncPrimContext != (IMG_HANDLE) NULL)
|
|
{
|
|
SyncPrimContextDestroy(psDevInfo->hSyncPrimContext);
|
|
psDevInfo->hSyncPrimContext = (IMG_HANDLE) NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfHWRInfoBufCtl != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc);
|
|
psDevInfo->psRGXFWIfHWRInfoBufCtl = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc);
|
|
psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfFwOsDataMemDesc)
|
|
{
|
|
if (psDevInfo->psRGXFWIfFwOsData != NULL)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfFwOsDataMemDesc);
|
|
psDevInfo->psRGXFWIfFwOsData = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfFwOsDataMemDesc);
|
|
psDevInfo->psRGXFWIfFwOsDataMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psCompletedMemDesc)
|
|
{
|
|
if (psDevInfo->pui32CompletedById)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psCompletedMemDesc);
|
|
psDevInfo->pui32CompletedById = NULL;
|
|
}
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psCompletedMemDesc);
|
|
psDevInfo->psCompletedMemDesc = NULL;
|
|
}
|
|
if (psDevInfo->psEndTimeMemDesc)
|
|
{
|
|
if (psDevInfo->pui64EndTimeById)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psEndTimeMemDesc);
|
|
psDevInfo->pui64EndTimeById = NULL;
|
|
}
|
|
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psEndTimeMemDesc);
|
|
psDevInfo->psEndTimeMemDesc = NULL;
|
|
}
|
|
if (psDevInfo->psStartTimeMemDesc)
|
|
{
|
|
if (psDevInfo->pui64StartTimeById)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psStartTimeMemDesc);
|
|
psDevInfo->pui64StartTimeById = NULL;
|
|
}
|
|
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psStartTimeMemDesc);
|
|
psDevInfo->psStartTimeMemDesc = NULL;
|
|
}
|
|
#if !defined(PVRSRV_USE_BRIDGE_LOCK)
|
|
if (psDevInfo->hTimerQueryLock)
|
|
{
|
|
OSLockDestroy(psDevInfo->hTimerQueryLock);
|
|
psDevInfo->hTimerQueryLock = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (psDevInfo->psRGXFWHeapGuardPageReserveMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWHeapGuardPageReserveMemDesc);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXFreeFirmware
|
|
|
|
@Description Frees all the firmware-related allocations
|
|
|
|
@Input psDevInfo
|
|
******************************************************************************/
|
|
void RGXFreeFirmware(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFreeFwOsData(psDevInfo);
|
|
|
|
if (psDevInfo->psRGXFWIfConnectionCtl)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfConnectionCtlMemDesc);
|
|
psDevInfo->psRGXFWIfConnectionCtl = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfConnectionCtlMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfConnectionCtlMemDesc);
|
|
psDevInfo->psRGXFWIfConnectionCtlMemDesc = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfOsInit)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfOsInitMemDesc);
|
|
psDevInfo->psRGXFWIfOsInit = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfOsInitMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfOsInitMemDesc);
|
|
psDevInfo->psRGXFWIfOsInitMemDesc = NULL;
|
|
}
|
|
|
|
RGXFreeFwSysData(psDevInfo);
|
|
if (psDevInfo->psRGXFWIfSysInit)
|
|
{
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfSysInitMemDesc);
|
|
psDevInfo->psRGXFWIfSysInit = NULL;
|
|
}
|
|
|
|
if (psDevInfo->psRGXFWIfSysInitMemDesc)
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psRGXFWIfSysInitMemDesc);
|
|
psDevInfo->psRGXFWIfSysInitMemDesc = NULL;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : RGXAcquireKernelCCBSlot
|
|
|
|
PURPOSE : Attempts to obtain a slot in the Kernel CCB
|
|
|
|
PARAMETERS : psCCB - the CCB
|
|
: Address of space if available, NULL otherwise
|
|
|
|
RETURNS : PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXAcquireKernelCCBSlot(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
const RGXFWIF_CCB_CTL *psKCCBCtl,
|
|
IMG_UINT32 *pui32Offset)
|
|
{
|
|
IMG_UINT32 ui32OldWriteOffset, ui32NextWriteOffset;
|
|
#if defined(PDUMP)
|
|
const DEVMEM_MEMDESC *psKCCBCtrlMemDesc = psDevInfo->psKernelCCBCtlMemDesc;
|
|
#endif
|
|
|
|
ui32OldWriteOffset = psKCCBCtl->ui32WriteOffset;
|
|
ui32NextWriteOffset = (ui32OldWriteOffset + 1) & psKCCBCtl->ui32WrapMask;
|
|
|
|
#if defined(PDUMP)
|
|
/* Wait for sufficient CCB space to become available */
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, 0,
|
|
"Wait for kCCB woff=%u", ui32NextWriteOffset);
|
|
DevmemPDumpCBP(psKCCBCtrlMemDesc,
|
|
offsetof(RGXFWIF_CCB_CTL, ui32ReadOffset),
|
|
ui32NextWriteOffset,
|
|
1,
|
|
(psKCCBCtl->ui32WrapMask + 1));
|
|
#endif
|
|
|
|
if (ui32NextWriteOffset == psKCCBCtl->ui32ReadOffset)
|
|
{
|
|
return PVRSRV_ERROR_KERNEL_CCB_FULL;
|
|
}
|
|
*pui32Offset = ui32NextWriteOffset;
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : RGXPollKernelCCBSlot
|
|
|
|
PURPOSE : Poll for space in Kernel CCB
|
|
|
|
PARAMETERS : psCCB - the CCB
|
|
: Address of space if available, NULL otherwise
|
|
|
|
RETURNS : PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXPollKernelCCBSlot(const DEVMEM_MEMDESC *psKCCBCtrlMemDesc,
|
|
const RGXFWIF_CCB_CTL *psKCCBCtl)
|
|
{
|
|
IMG_UINT32 ui32OldWriteOffset, ui32NextWriteOffset;
|
|
|
|
ui32OldWriteOffset = psKCCBCtl->ui32WriteOffset;
|
|
ui32NextWriteOffset = (ui32OldWriteOffset + 1) & psKCCBCtl->ui32WrapMask;
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
|
|
if (ui32NextWriteOffset != psKCCBCtl->ui32ReadOffset)
|
|
{
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*
|
|
* The following check doesn't impact performance, since the
|
|
* CPU has to wait for the GPU anyway (full kernel CCB).
|
|
*/
|
|
if (PVRSRVGetPVRSRVData()->eServicesState != PVRSRV_SERVICES_STATE_OK)
|
|
{
|
|
return PVRSRV_ERROR_KERNEL_CCB_FULL;
|
|
}
|
|
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
return PVRSRV_ERROR_KERNEL_CCB_FULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : RGXGetCmdMemCopySize
|
|
|
|
PURPOSE : Calculates actual size of KCCB command getting used
|
|
|
|
PARAMETERS : eCmdType Type of KCCB command
|
|
|
|
RETURNS : Returns actual size of KCCB command on success else zero
|
|
******************************************************************************/
|
|
static IMG_UINT32 RGXGetCmdMemCopySize(RGXFWIF_KCCB_CMD_TYPE eCmdType)
|
|
{
|
|
/* First get offset of uCmdData inside the struct RGXFWIF_KCCB_CMD
|
|
* This will account alignment requirement of uCmdData union
|
|
*
|
|
* Then add command-data size depending on command type to calculate actual
|
|
* command size required to do mem copy
|
|
*
|
|
* NOTE: Make sure that uCmdData is the last member of RGXFWIF_KCCB_CMD struct.
|
|
*/
|
|
switch (eCmdType)
|
|
{
|
|
case RGXFWIF_KCCB_CMD_KICK:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_KCCB_CMD_KICK_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_COMBINED_TA_3D_KICK:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_KCCB_CMD_COMBINED_TA_3D_KICK_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_MMUCACHE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_MMUCACHEDATA);
|
|
}
|
|
#if defined(SUPPORT_USC_BREAKPOINT)
|
|
case RGXFWIF_KCCB_CMD_BP:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_BPDATA);
|
|
}
|
|
#endif
|
|
case RGXFWIF_KCCB_CMD_SLCFLUSHINVAL:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_SLCFLUSHINVALDATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_CLEANUP:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_CLEANUP_REQUEST);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_POW:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_POWER_REQUEST);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_ZSBUFFER_BACKING_UPDATE:
|
|
case RGXFWIF_KCCB_CMD_ZSBUFFER_UNBACKING_UPDATE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_ZSBUFFER_BACKING_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_FREELIST_GROW_UPDATE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_FREELIST_GS_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_FREELISTS_RECONSTRUCTION_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_NOTIFY_WRITE_OFFSET_UPDATE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_WRITE_OFFSET_UPDATE_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_FORCE_UPDATE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_KCCB_CMD_FORCE_UPDATE_DATA);
|
|
}
|
|
#if defined(SUPPORT_USER_REGISTER_CONFIGURATION)
|
|
case RGXFWIF_KCCB_CMD_REGCONFIG:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_REGCONFIG_DATA);
|
|
}
|
|
#endif
|
|
case RGXFWIF_KCCB_CMD_HWPERF_SELECT_CUSTOM_CNTRS:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_HWPERF_SELECT_CUSTOM_CNTRS);
|
|
}
|
|
#if defined(SUPPORT_PDVFS)
|
|
case RGXFWIF_KCCB_CMD_PDVFS_LIMIT_MAX_FREQ:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_PDVFS_MAX_FREQ_DATA);
|
|
}
|
|
#endif
|
|
case RGXFWIF_KCCB_CMD_OS_ONLINE_STATE_CONFIGURE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_OS_STATE_CHANGE_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_COUNTER_DUMP:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_COUNTER_DUMP_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_HWPERF_UPDATE_CONFIG:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_HWPERF_CTRL);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_HWPERF_CONFIG_ENABLE_BLKS:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_HWPERF_CONFIG_ENABLE_BLKS);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_HWPERF_CONFIG_BLKS:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_HWPERF_CONFIG_DA_BLKS);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_HWPERF_CTRL_BLKS:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_HWPERF_CTRL_BLKS);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_CORECLKSPEEDCHANGE:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_CORECLKSPEEDCHANGE_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_OSID_PRIORITY_CHANGE:
|
|
case RGXFWIF_KCCB_CMD_WDG_CFG:
|
|
case RGXFWIF_KCCB_CMD_PHR_CFG:
|
|
case RGXFWIF_KCCB_CMD_HEALTH_CHECK:
|
|
case RGXFWIF_KCCB_CMD_LOGTYPE_UPDATE:
|
|
case RGXFWIF_KCCB_CMD_STATEFLAGS_CTRL:
|
|
{
|
|
/* No command specific data */
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData);
|
|
}
|
|
#if defined(SUPPORT_VALIDATION)
|
|
case RGXFWIF_KCCB_CMD_RGXREG:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_RGXREG_DATA);
|
|
}
|
|
case RGXFWIF_KCCB_CMD_GPUMAP:
|
|
{
|
|
return offsetof(RGXFWIF_KCCB_CMD, uCmdData) + sizeof(RGXFWIF_GPUMAP_DATA);
|
|
}
|
|
#endif
|
|
default:
|
|
{
|
|
/* Invalid (OR) Unused (OR) Newly added command type */
|
|
return 0; /* Error */
|
|
}
|
|
}
|
|
}
|
|
|
|
PVRSRV_ERROR RGXWaitForKCCBSlotUpdate(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32SlotNum,
|
|
IMG_UINT32 ui32PDumpFlags)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
eError = PVRSRVWaitForValueKM(
|
|
(IMG_UINT32 __iomem *)&psDevInfo->pui32KernelCCBRtnSlots[ui32SlotNum],
|
|
RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED,
|
|
RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "PVRSRVWaitForValueKM");
|
|
|
|
#if defined(PDUMP)
|
|
/* PDumping conditions same as RGXSendCommandRaw for the actual command and poll command to go in harmony */
|
|
if (PDumpCheckFlagsWrite(psDevInfo->psDeviceNode, ui32PDumpFlags))
|
|
{
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Poll on KCCB slot %u for value %u (mask: 0x%x)", ui32SlotNum,
|
|
RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED, RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED);
|
|
|
|
eError = DevmemPDumpDevmemPol32(psDevInfo->psKernelCCBRtnSlotsMemDesc,
|
|
ui32SlotNum * sizeof(IMG_UINT32),
|
|
RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED,
|
|
RGXFWIF_KCCB_RTN_SLOT_CMD_EXECUTED,
|
|
PDUMP_POLL_OPERATOR_EQUAL,
|
|
ui32PDumpFlags);
|
|
PVR_LOG_IF_ERROR(eError, "DevmemPDumpDevmemPol32");
|
|
}
|
|
#else
|
|
PVR_UNREFERENCED_PARAMETER(ui32PDumpFlags);
|
|
#endif
|
|
|
|
return eError;
|
|
}
|
|
|
|
static PVRSRV_ERROR RGXSendCommandRaw(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
IMG_UINT32 uiPDumpFlags,
|
|
IMG_UINT32 *pui32CmdKCCBSlot)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode;
|
|
RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl;
|
|
IMG_UINT8 *pui8KCCB = psDevInfo->psKernelCCB;
|
|
IMG_UINT32 ui32NewWriteOffset;
|
|
IMG_UINT32 ui32OldWriteOffset = psKCCBCtl->ui32WriteOffset;
|
|
IMG_UINT32 ui32CmdMemCopySize;
|
|
|
|
#if !defined(PDUMP)
|
|
PVR_UNREFERENCED_PARAMETER(uiPDumpFlags);
|
|
#else
|
|
IMG_BOOL bContCaptureOn = PDumpCheckFlagsWrite(psDeviceNode, PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_POWER); /* client connected or in pdump init phase */
|
|
IMG_BOOL bPDumpEnabled = PDumpCheckFlagsWrite(psDeviceNode, uiPDumpFlags); /* Are we in capture range or continuous and not in a power transition */
|
|
|
|
if (bContCaptureOn)
|
|
{
|
|
/* in capture range */
|
|
if (bPDumpEnabled)
|
|
{
|
|
if (!psDevInfo->bDumpedKCCBCtlAlready)
|
|
{
|
|
/* entering capture range */
|
|
psDevInfo->bDumpedKCCBCtlAlready = IMG_TRUE;
|
|
|
|
/* Wait for the live FW to catch up */
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: waiting on fw to catch-up, roff: %d, woff: %d",
|
|
__func__,
|
|
psKCCBCtl->ui32ReadOffset, ui32OldWriteOffset));
|
|
PVRSRVPollForValueKM(psDeviceNode,
|
|
(IMG_UINT32 __iomem *)&psKCCBCtl->ui32ReadOffset,
|
|
ui32OldWriteOffset, 0xFFFFFFFF,
|
|
POLL_FLAG_LOG_ERROR | POLL_FLAG_DEBUG_DUMP);
|
|
|
|
/* Dump Init state of Kernel CCB control (read and write offset) */
|
|
PDUMPCOMMENTWITHFLAGS(psDeviceNode, uiPDumpFlags,
|
|
"Initial state of kernel CCB Control, roff: %d, woff: %d",
|
|
psKCCBCtl->ui32ReadOffset, psKCCBCtl->ui32WriteOffset);
|
|
|
|
DevmemPDumpLoadMem(psDevInfo->psKernelCCBCtlMemDesc,
|
|
0,
|
|
sizeof(RGXFWIF_CCB_CTL),
|
|
uiPDumpFlags);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
if (!((KM_FW_CONNECTION_IS(READY, psDevInfo) && KM_OS_CONNECTION_IS(READY, psDevInfo)) ||
|
|
(KM_FW_CONNECTION_IS(ACTIVE, psDevInfo) && KM_OS_CONNECTION_IS(ACTIVE, psDevInfo))) &&
|
|
!PVRSRV_VZ_MODE_IS(NATIVE))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: The firmware-driver connection is invalid:"
|
|
"driver state = %u / firmware state = %u;"
|
|
"expected READY (%u/%u) or ACTIVE (%u/%u);",
|
|
__func__, KM_GET_OS_CONNECTION(psDevInfo), KM_GET_FW_CONNECTION(psDevInfo),
|
|
RGXFW_CONNECTION_OS_READY, RGXFW_CONNECTION_FW_READY,
|
|
RGXFW_CONNECTION_OS_ACTIVE, RGXFW_CONNECTION_FW_ACTIVE));
|
|
eError = PVRSRV_ERROR_PVZ_OSID_IS_OFFLINE;
|
|
goto _RGXSendCommandRaw_Exit;
|
|
}
|
|
#endif
|
|
|
|
PVR_ASSERT(sizeof(RGXFWIF_KCCB_CMD) == psKCCBCtl->ui32CmdSize);
|
|
if (!OSLockIsLocked(psDeviceNode->hPowerLock))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s called without power lock held!",
|
|
__func__));
|
|
PVR_ASSERT(OSLockIsLocked(psDeviceNode->hPowerLock));
|
|
}
|
|
|
|
/* Acquire a slot in the CCB */
|
|
eError = RGXAcquireKernelCCBSlot(psDevInfo, psKCCBCtl, &ui32NewWriteOffset);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
goto _RGXSendCommandRaw_Exit;
|
|
}
|
|
|
|
/* Calculate actual size of command to optimize device mem copy */
|
|
ui32CmdMemCopySize = RGXGetCmdMemCopySize(psKCCBCmd->eCmdType);
|
|
PVR_LOG_RETURN_IF_FALSE(ui32CmdMemCopySize !=0, "RGXGetCmdMemCopySize failed", PVRSRV_ERROR_INVALID_CCB_COMMAND);
|
|
|
|
/* Copy the command into the CCB */
|
|
OSCachedMemCopyWMB(&pui8KCCB[ui32OldWriteOffset * psKCCBCtl->ui32CmdSize],
|
|
psKCCBCmd, ui32CmdMemCopySize);
|
|
|
|
/* If non-NULL pui32CmdKCCBSlot passed-in, return the kCCB slot in which the command was enqueued */
|
|
if (pui32CmdKCCBSlot)
|
|
{
|
|
*pui32CmdKCCBSlot = ui32OldWriteOffset;
|
|
|
|
/* Each such command enqueue needs to reset the slot value first. This is so that a caller
|
|
* doesn't get to see stale/false value in allotted slot */
|
|
OSWriteDeviceMem32WithWMB(&psDevInfo->pui32KernelCCBRtnSlots[ui32OldWriteOffset],
|
|
RGXFWIF_KCCB_RTN_SLOT_NO_RESPONSE);
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDeviceNode, uiPDumpFlags,
|
|
"Reset kCCB slot number %u", ui32OldWriteOffset);
|
|
DevmemPDumpLoadMem(psDevInfo->psKernelCCBRtnSlotsMemDesc,
|
|
ui32OldWriteOffset * sizeof(IMG_UINT32),
|
|
sizeof(IMG_UINT32),
|
|
uiPDumpFlags);
|
|
#endif
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: Device (%p) KCCB slot %u reset with value %u for command type %x",
|
|
__func__, psDevInfo, ui32OldWriteOffset, RGXFWIF_KCCB_RTN_SLOT_NO_RESPONSE, psKCCBCmd->eCmdType));
|
|
}
|
|
|
|
/* Move past the current command */
|
|
psKCCBCtl->ui32WriteOffset = ui32NewWriteOffset;
|
|
|
|
OSWriteMemoryBarrier(&psKCCBCtl->ui32WriteOffset);
|
|
|
|
#if defined(PDUMP)
|
|
if (bContCaptureOn)
|
|
{
|
|
/* in capture range */
|
|
if (bPDumpEnabled)
|
|
{
|
|
/* Dump new Kernel CCB content */
|
|
PDUMPCOMMENTWITHFLAGS(psDeviceNode,
|
|
uiPDumpFlags, "Dump kCCB cmd woff = %d",
|
|
ui32OldWriteOffset);
|
|
DevmemPDumpLoadMem(psDevInfo->psKernelCCBMemDesc,
|
|
ui32OldWriteOffset * psKCCBCtl->ui32CmdSize,
|
|
ui32CmdMemCopySize,
|
|
uiPDumpFlags);
|
|
|
|
/* Dump new kernel CCB write offset */
|
|
PDUMPCOMMENTWITHFLAGS(psDeviceNode,
|
|
uiPDumpFlags, "Dump kCCBCtl woff: %d",
|
|
ui32NewWriteOffset);
|
|
DevmemPDumpLoadMem(psDevInfo->psKernelCCBCtlMemDesc,
|
|
offsetof(RGXFWIF_CCB_CTL, ui32WriteOffset),
|
|
sizeof(IMG_UINT32),
|
|
uiPDumpFlags);
|
|
|
|
/* mimic the read-back of the write from above */
|
|
DevmemPDumpDevmemPol32(psDevInfo->psKernelCCBCtlMemDesc,
|
|
offsetof(RGXFWIF_CCB_CTL, ui32WriteOffset),
|
|
ui32NewWriteOffset,
|
|
0xFFFFFFFF,
|
|
PDUMP_POLL_OPERATOR_EQUAL,
|
|
uiPDumpFlags);
|
|
}
|
|
/* out of capture range */
|
|
else
|
|
{
|
|
eError = RGXPdumpDrainKCCB(psDevInfo, ui32OldWriteOffset);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXPdumpDrainKCCB", _RGXSendCommandRaw_Exit);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
PDUMPCOMMENTWITHFLAGS(psDeviceNode, uiPDumpFlags, "MTS kick for kernel CCB");
|
|
/*
|
|
* Kick the MTS to schedule the firmware.
|
|
*/
|
|
__MTSScheduleWrite(psDevInfo, RGXFWIF_DM_GP & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK);
|
|
|
|
PDUMPREG32(psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_MTS_SCHEDULE,
|
|
RGXFWIF_DM_GP & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK, uiPDumpFlags);
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
RGXUpdateAutoVzWdgToken(psDevInfo);
|
|
#endif
|
|
|
|
#if defined(NO_HARDWARE)
|
|
/* keep the roff updated because fw isn't there to update it */
|
|
psKCCBCtl->ui32ReadOffset = psKCCBCtl->ui32WriteOffset;
|
|
#endif
|
|
|
|
_RGXSendCommandRaw_Exit:
|
|
return eError;
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : _AllocDeferredCommand
|
|
|
|
PURPOSE : Allocate a KCCB command and add it to KCCB deferred list
|
|
|
|
PARAMETERS : psDevInfo RGX device info
|
|
: eKCCBType Firmware Command type
|
|
: psKCCBCmd Firmware Command
|
|
: uiPDumpFlags Pdump flags
|
|
|
|
RETURNS : PVRSRV_OK If all went good, PVRSRV_ERROR_RETRY otherwise.
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR _AllocDeferredCommand(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
IMG_UINT32 uiPDumpFlags)
|
|
{
|
|
RGX_DEFERRED_KCCB_CMD *psDeferredCommand;
|
|
OS_SPINLOCK_FLAGS uiFlags;
|
|
|
|
psDeferredCommand = OSAllocMem(sizeof(*psDeferredCommand));
|
|
|
|
if (!psDeferredCommand)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"Deferring a KCCB command failed: allocation failure: requesting retry"));
|
|
return PVRSRV_ERROR_RETRY;
|
|
}
|
|
|
|
psDeferredCommand->sKCCBcmd = *psKCCBCmd;
|
|
psDeferredCommand->uiPDumpFlags = uiPDumpFlags;
|
|
psDeferredCommand->psDevInfo = psDevInfo;
|
|
|
|
OSSpinLockAcquire(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
dllist_add_to_tail(&(psDevInfo->sKCCBDeferredCommandsListHead), &(psDeferredCommand->sListNode));
|
|
psDevInfo->ui32KCCBDeferredCommandsCount++;
|
|
OSSpinLockRelease(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : _FreeDeferredCommand
|
|
|
|
PURPOSE : Remove from the deferred list the sent deferred KCCB command
|
|
|
|
PARAMETERS : psNode Node in deferred list
|
|
: psDeferredKCCBCmd KCCB Command to free
|
|
|
|
RETURNS : None
|
|
******************************************************************************/
|
|
static void _FreeDeferredCommand(DLLIST_NODE *psNode, RGX_DEFERRED_KCCB_CMD *psDeferredKCCBCmd)
|
|
{
|
|
dllist_remove_node(psNode);
|
|
psDeferredKCCBCmd->psDevInfo->ui32KCCBDeferredCommandsCount--;
|
|
OSFreeMem(psDeferredKCCBCmd);
|
|
}
|
|
|
|
/******************************************************************************
|
|
FUNCTION : RGXSendCommandsFromDeferredList
|
|
|
|
PURPOSE : Try send KCCB commands in deferred list to KCCB
|
|
Should be called by holding PowerLock
|
|
|
|
PARAMETERS : psDevInfo RGX device info
|
|
: bPoll Poll for space in KCCB
|
|
|
|
RETURNS : PVRSRV_OK If all commands in deferred list are sent to KCCB,
|
|
PVRSRV_ERROR_KERNEL_CCB_FULL otherwise.
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXSendCommandsFromDeferredList(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_BOOL bPoll)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
DLLIST_NODE *psNode, *psNext;
|
|
RGX_DEFERRED_KCCB_CMD *psTempDeferredKCCBCmd;
|
|
DLLIST_NODE sCommandList;
|
|
OS_SPINLOCK_FLAGS uiFlags;
|
|
|
|
PVR_ASSERT(PVRSRVPwrLockIsLockedByMe(psDevInfo->psDeviceNode));
|
|
|
|
/* !!! Important !!!
|
|
*
|
|
* The idea of moving the whole list hLockKCCBDeferredCommandsList below
|
|
* to the temporary list is only valid under the principle that all of the
|
|
* operations are also protected by the power lock. It must be held
|
|
* so that the order of the commands doesn't get messed up while we're
|
|
* performing the operations on the local list.
|
|
*
|
|
* The necessity of releasing the hLockKCCBDeferredCommandsList comes from
|
|
* the fact that _FreeDeferredCommand() is allocating memory and it can't
|
|
* be done in atomic context (inside section protected by a spin lock).
|
|
*
|
|
* We're using spin lock here instead of mutex to quickly perform a check
|
|
* if the list is empty in MISR without a risk that the MISR is going
|
|
* to sleep due to a lock.
|
|
*/
|
|
|
|
/* move the whole list to a local list so it can be processed without lock */
|
|
OSSpinLockAcquire(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
dllist_replace_head(&psDevInfo->sKCCBDeferredCommandsListHead, &sCommandList);
|
|
OSSpinLockRelease(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
if (dllist_is_empty(&sCommandList))
|
|
{
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/* For every deferred KCCB command, try to send it*/
|
|
dllist_foreach_node(&sCommandList, psNode, psNext)
|
|
{
|
|
psTempDeferredKCCBCmd = IMG_CONTAINER_OF(psNode, RGX_DEFERRED_KCCB_CMD, sListNode);
|
|
eError = RGXSendCommandRaw(psTempDeferredKCCBCmd->psDevInfo,
|
|
&psTempDeferredKCCBCmd->sKCCBcmd,
|
|
psTempDeferredKCCBCmd->uiPDumpFlags,
|
|
NULL /* We surely aren't interested in kCCB slot number of deferred command */);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
if (!bPoll)
|
|
{
|
|
eError = PVRSRV_ERROR_KERNEL_CCB_FULL;
|
|
goto cleanup_;
|
|
}
|
|
break;
|
|
}
|
|
|
|
_FreeDeferredCommand(psNode, psTempDeferredKCCBCmd);
|
|
}
|
|
|
|
if (bPoll)
|
|
{
|
|
PVRSRV_ERROR eErrPollForKCCBSlot;
|
|
|
|
/* Don't overwrite eError because if RGXPollKernelCCBSlot returns OK and the
|
|
* outer loop times-out, we'll still want to return KCCB_FULL to caller
|
|
*/
|
|
eErrPollForKCCBSlot = RGXPollKernelCCBSlot(psDevInfo->psKernelCCBCtlMemDesc,
|
|
psDevInfo->psKernelCCBCtl);
|
|
if (eErrPollForKCCBSlot == PVRSRV_ERROR_KERNEL_CCB_FULL)
|
|
{
|
|
eError = PVRSRV_ERROR_KERNEL_CCB_FULL;
|
|
goto cleanup_;
|
|
}
|
|
}
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
cleanup_:
|
|
/* if the local list is not empty put it back to the deferred list head
|
|
* so that the old order of commands is retained */
|
|
OSSpinLockAcquire(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
dllist_insert_list_at_head(&psDevInfo->sKCCBDeferredCommandsListHead, &sCommandList);
|
|
OSSpinLockRelease(psDevInfo->hLockKCCBDeferredCommandsList, uiFlags);
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXSendCommandAndGetKCCBSlot(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
IMG_UINT32 uiPDumpFlags,
|
|
IMG_UINT32 *pui32CmdKCCBSlot)
|
|
{
|
|
IMG_BOOL bPoll = (pui32CmdKCCBSlot != NULL);
|
|
PVRSRV_ERROR eError;
|
|
|
|
/*
|
|
* First try to Flush all the cmds in deferred list.
|
|
*
|
|
* We cannot defer an incoming command if the caller is interested in
|
|
* knowing the command's kCCB slot: it plans to poll/wait for a
|
|
* response from the FW just after the command is enqueued, so we must
|
|
* poll for space to be available.
|
|
*/
|
|
eError = RGXSendCommandsFromDeferredList(psDevInfo, bPoll);
|
|
if (eError == PVRSRV_OK)
|
|
{
|
|
eError = RGXSendCommandRaw(psDevInfo,
|
|
psKCCBCmd,
|
|
uiPDumpFlags,
|
|
pui32CmdKCCBSlot);
|
|
}
|
|
|
|
/*
|
|
* If we don't manage to enqueue one of the deferred commands or the command
|
|
* passed as argument because the KCCB is full, insert the latter into the deferred commands list.
|
|
* The deferred commands will also be flushed eventually by:
|
|
* - one more KCCB command sent for any DM
|
|
* - RGX_MISRHandler_CheckFWActivePowerState
|
|
*/
|
|
if (eError == PVRSRV_ERROR_KERNEL_CCB_FULL)
|
|
{
|
|
if (pui32CmdKCCBSlot == NULL)
|
|
{
|
|
eError = _AllocDeferredCommand(psDevInfo, psKCCBCmd, uiPDumpFlags);
|
|
}
|
|
else
|
|
{
|
|
/* Let the caller retry. Otherwise if we deferred the command and returned OK,
|
|
* the caller can end up looking in a stale CCB slot.
|
|
*/
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Couldn't flush the deferred queue for a command (Type:%d) "
|
|
"- will be retried", __func__, psKCCBCmd->eCmdType));
|
|
}
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXSendCommandWithPowLockAndGetKCCBSlot(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
IMG_UINT32 ui32PDumpFlags,
|
|
IMG_UINT32 *pui32CmdKCCBSlot)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode;
|
|
|
|
/* Ensure Rogue is powered up before kicking MTS */
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: failed to acquire powerlock (%s)",
|
|
__func__,
|
|
PVRSRVGetErrorString(eError)));
|
|
|
|
goto _PVRSRVPowerLock_Exit;
|
|
}
|
|
|
|
PDUMPPOWCMDSTART(psDeviceNode);
|
|
eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
|
|
PVRSRV_DEV_POWER_STATE_ON,
|
|
PVRSRV_POWER_FLAGS_NONE);
|
|
PDUMPPOWCMDEND(psDeviceNode);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: failed to transition Rogue to ON (%s)",
|
|
__func__,
|
|
PVRSRVGetErrorString(eError)));
|
|
|
|
goto _PVRSRVSetDevicePowerStateKM_Exit;
|
|
}
|
|
|
|
eError = RGXSendCommandAndGetKCCBSlot(psDevInfo,
|
|
psKCCBCmd,
|
|
ui32PDumpFlags,
|
|
pui32CmdKCCBSlot);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: failed to schedule command (%s)",
|
|
__func__,
|
|
PVRSRVGetErrorString(eError)));
|
|
#if defined(DEBUG)
|
|
/* PVRSRVDebugRequest must be called without powerlock */
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL);
|
|
goto _PVRSRVPowerLock_Exit;
|
|
#endif
|
|
}
|
|
|
|
_PVRSRVSetDevicePowerStateKM_Exit:
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
|
|
_PVRSRVPowerLock_Exit:
|
|
return eError;
|
|
}
|
|
|
|
void RGXScheduleProcessQueuesKM(PVRSRV_CMDCOMP_HANDLE hCmdCompHandle)
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE*) hCmdCompHandle;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
|
|
OSScheduleMISR(psDevInfo->hProcessQueuesMISR);
|
|
}
|
|
|
|
#if defined(SUPPORT_VALIDATION)
|
|
PVRSRV_ERROR RGXScheduleRgxRegCommand(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT64 ui64RegVal,
|
|
IMG_UINT64 ui64Size,
|
|
IMG_UINT32 ui32Offset,
|
|
IMG_BOOL bWriteOp)
|
|
{
|
|
RGXFWIF_KCCB_CMD sRgxRegsCmd = {0};
|
|
IMG_UINT32 ui32kCCBCommandSlot;
|
|
PVRSRV_ERROR eError;
|
|
|
|
sRgxRegsCmd.eCmdType = RGXFWIF_KCCB_CMD_RGXREG;
|
|
sRgxRegsCmd.uCmdData.sFwRgxData.ui64RegVal = ui64RegVal;
|
|
sRgxRegsCmd.uCmdData.sFwRgxData.ui32RegWidth = ui64Size;
|
|
sRgxRegsCmd.uCmdData.sFwRgxData.ui32RegAddr = ui32Offset;
|
|
sRgxRegsCmd.uCmdData.sFwRgxData.bWriteOp = bWriteOp;
|
|
|
|
eError = RGXScheduleCommandAndGetKCCBSlot(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sRgxRegsCmd,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
&ui32kCCBCommandSlot);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "RGXScheduleCommandAndGetKCCBSlot");
|
|
|
|
if (bWriteOp)
|
|
{
|
|
eError = RGXWaitForKCCBSlotUpdate(psDevInfo,
|
|
ui32kCCBCommandSlot,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "RGXWaitForKCCBSlotUpdate");
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
|
|
@Function RGX_MISRHandler_ScheduleProcessQueues
|
|
|
|
@Description - Sends uncounted kick to all the DMs (the FW will process all
|
|
the queue for all the DMs)
|
|
******************************************************************************/
|
|
static void RGX_MISRHandler_ScheduleProcessQueues(void *pvData)
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDeviceNode = pvData;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_DEV_POWER_STATE ePowerState;
|
|
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: failed to acquire powerlock (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
return;
|
|
}
|
|
|
|
/* Check whether it's worth waking up the GPU */
|
|
eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
|
|
|
|
if (!PVRSRV_VZ_MODE_IS(GUEST) &&
|
|
(eError == PVRSRV_OK) && (ePowerState == PVRSRV_DEV_POWER_STATE_OFF))
|
|
{
|
|
/* For now, guest drivers will always wake-up the GPU */
|
|
RGXFWIF_GPU_UTIL_FWCB *psUtilFWCb = psDevInfo->psRGXFWIfGpuUtilFWCb;
|
|
IMG_BOOL bGPUHasWorkWaiting;
|
|
|
|
bGPUHasWorkWaiting =
|
|
(RGXFWIF_GPU_UTIL_GET_STATE(psUtilFWCb->ui64LastWord) == RGXFWIF_GPU_UTIL_STATE_BLOCKED);
|
|
|
|
if (!bGPUHasWorkWaiting)
|
|
{
|
|
/* all queues are empty, don't wake up the GPU */
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
return;
|
|
}
|
|
}
|
|
|
|
PDUMPPOWCMDSTART(psDeviceNode);
|
|
/* wake up the GPU */
|
|
eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
|
|
PVRSRV_DEV_POWER_STATE_ON,
|
|
PVRSRV_POWER_FLAGS_NONE);
|
|
PDUMPPOWCMDEND(psDeviceNode);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: failed to transition Rogue to ON (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
return;
|
|
}
|
|
|
|
/* uncounted kick to the FW */
|
|
HTBLOGK(HTB_SF_MAIN_KICK_UNCOUNTED);
|
|
__MTSScheduleWrite(psDevInfo, (RGXFWIF_DM_GP & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK) | RGX_CR_MTS_SCHEDULE_TASK_NON_COUNTED);
|
|
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
}
|
|
|
|
PVRSRV_ERROR RGXInstallProcessQueuesMISR(IMG_HANDLE *phMISR, PVRSRV_DEVICE_NODE *psDeviceNode)
|
|
{
|
|
return OSInstallMISR(phMISR,
|
|
RGX_MISRHandler_ScheduleProcessQueues,
|
|
psDeviceNode,
|
|
"RGX_ScheduleProcessQueues");
|
|
}
|
|
|
|
PVRSRV_ERROR RGXScheduleCommandAndGetKCCBSlot(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_DM eKCCBType,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
IMG_UINT32 ui32PDumpFlags,
|
|
IMG_UINT32 *pui32CmdKCCBSlot)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
IMG_UINT32 uiMMUSyncUpdate;
|
|
|
|
/* Don't send the command/power up request if the device is de-initialising.
|
|
* The de-init thread could destroy the device whilst the power up
|
|
* sequence below is accessing the HW registers.
|
|
*/
|
|
if (unlikely((psDevInfo == NULL) ||
|
|
(psDevInfo->psDeviceNode == NULL) ||
|
|
(psDevInfo->psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_DEINIT)))
|
|
{
|
|
return PVRSRV_ERROR_INVALID_DEVICE;
|
|
}
|
|
|
|
#if defined(SUPPORT_VALIDATION)
|
|
/* For validation, force the core to different dust count states with each kick */
|
|
if ((eKCCBType == RGXFWIF_DM_GEOM) || (eKCCBType == RGXFWIF_DM_CDM))
|
|
{
|
|
if (psDevInfo->ui32DeviceFlags & RGXKM_DEVICE_STATE_GPU_UNITS_POWER_CHANGE_EN)
|
|
{
|
|
IMG_UINT32 ui32NumDusts = RGXGetNextDustCount(&psDevInfo->sDustReqState, psDevInfo->sDevFeatureCfg.ui32MAXDustCount);
|
|
PVRSRVDeviceGPUUnitsPowerChange(psDevInfo->psDeviceNode, ui32NumDusts);
|
|
}
|
|
}
|
|
|
|
if (psDevInfo->ui32ECCRAMErrInjModule != RGXKM_ECC_ERR_INJ_DISABLE)
|
|
{
|
|
if (psDevInfo->ui32ECCRAMErrInjInterval > 0U)
|
|
{
|
|
--psDevInfo->ui32ECCRAMErrInjInterval;
|
|
}
|
|
else
|
|
{
|
|
IMG_UINT64 ui64ECCRegVal = 0U;
|
|
|
|
psDevInfo->ui32ECCRAMErrInjInterval = RGXKM_ECC_ERR_INJ_INTERVAL;
|
|
|
|
if (psDevInfo->ui32ECCRAMErrInjModule == RGXKM_ECC_ERR_INJ_SLC)
|
|
{
|
|
PVR_LOG(("ECC RAM Error Inject SLC"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_EN;
|
|
}
|
|
else if (psDevInfo->ui32ECCRAMErrInjModule == RGXKM_ECC_ERR_INJ_USC)
|
|
{
|
|
PVR_LOG(("ECC RAM Error Inject USC"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_USC_EN;
|
|
}
|
|
else if (psDevInfo->ui32ECCRAMErrInjModule == RGXKM_ECC_ERR_INJ_TPU)
|
|
{
|
|
#if defined(RGX_FEATURE_MAX_TPU_PER_SPU)
|
|
PVR_LOG(("ECC RAM Error Inject Swift TPU"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_SWIFT_EN;
|
|
#else
|
|
PVR_LOG(("ECC RAM Error Inject TPU MCU L0"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_EN;
|
|
#endif
|
|
}
|
|
else if (psDevInfo->ui32ECCRAMErrInjModule == RGXKM_ECC_ERR_INJ_RASCAL)
|
|
{
|
|
#if defined(RGX_CR_ECC_RAM_ERR_INJ_RASCAL_EN)
|
|
PVR_LOG(("ECC RAM Error Inject RASCAL"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_RASCAL_EN;
|
|
#else
|
|
PVR_LOG(("ECC RAM Error Inject USC"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_USC_EN;
|
|
#endif
|
|
}
|
|
else if (psDevInfo->ui32ECCRAMErrInjModule == RGXKM_ECC_ERR_INJ_MARS)
|
|
{
|
|
PVR_LOG(("ECC RAM Error Inject MARS"));
|
|
ui64ECCRegVal = RGX_CR_ECC_RAM_ERR_INJ_MARS_EN;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
OSWriteMemoryBarrier(NULL);
|
|
OSWriteHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_ECC_RAM_ERR_INJ, ui64ECCRegVal);
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Write reg ECC_RAM_ERR_INJ");
|
|
PDUMPREG64(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_ECC_RAM_ERR_INJ, ui64ECCRegVal, PDUMP_FLAGS_CONTINUOUS);
|
|
OSWriteMemoryBarrier(NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* PVRSRVPowerLock guarantees atomicity between commands. This is helpful
|
|
in a scenario with several applications allocating resources. */
|
|
eError = PVRSRVPowerLock(psDevInfo->psDeviceNode);
|
|
if (unlikely(eError != PVRSRV_OK))
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: failed to acquire powerlock (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
|
|
/* If system is found powered OFF, Retry scheduling the command */
|
|
if (likely(eError == PVRSRV_ERROR_SYSTEM_STATE_POWERED_OFF))
|
|
{
|
|
eError = PVRSRV_ERROR_RETRY;
|
|
}
|
|
|
|
goto RGXScheduleCommand_exit;
|
|
}
|
|
|
|
if (unlikely(psDevInfo->psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_DEINIT))
|
|
{
|
|
/* If we have the power lock the device is valid but the deinit
|
|
* thread could be waiting for the lock. */
|
|
PVRSRVPowerUnlock(psDevInfo->psDeviceNode);
|
|
return PVRSRV_ERROR_INVALID_DEVICE;
|
|
}
|
|
|
|
/* Ensure device is powered up before sending any commands */
|
|
PDUMPPOWCMDSTART(psDevInfo->psDeviceNode);
|
|
eError = PVRSRVSetDevicePowerStateKM(psDevInfo->psDeviceNode,
|
|
PVRSRV_DEV_POWER_STATE_ON,
|
|
PVRSRV_POWER_FLAGS_NONE);
|
|
PDUMPPOWCMDEND(psDevInfo->psDeviceNode);
|
|
if (unlikely(eError != PVRSRV_OK))
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: failed to transition RGX to ON (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
goto _PVRSRVSetDevicePowerStateKM_Exit;
|
|
}
|
|
|
|
eError = RGXPreKickCacheCommand(psDevInfo, eKCCBType, &uiMMUSyncUpdate);
|
|
if (unlikely(eError != PVRSRV_OK)) goto _PVRSRVSetDevicePowerStateKM_Exit;
|
|
|
|
eError = RGXSendCommandAndGetKCCBSlot(psDevInfo, psKCCBCmd, ui32PDumpFlags, pui32CmdKCCBSlot);
|
|
if (unlikely(eError != PVRSRV_OK)) goto _PVRSRVSetDevicePowerStateKM_Exit;
|
|
|
|
_PVRSRVSetDevicePowerStateKM_Exit:
|
|
PVRSRVPowerUnlock(psDevInfo->psDeviceNode);
|
|
|
|
RGXScheduleCommand_exit:
|
|
return eError;
|
|
}
|
|
|
|
/*
|
|
* RGXCheckFirmwareCCB
|
|
*/
|
|
void RGXCheckFirmwareCCB(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFWIF_CCB_CTL *psFWCCBCtl = psDevInfo->psFirmwareCCBCtl;
|
|
IMG_UINT8 *psFWCCB = psDevInfo->psFirmwareCCB;
|
|
|
|
#if defined(RGX_NUM_OS_SUPPORTED) && (RGX_NUM_OS_SUPPORTED > 1)
|
|
PVR_LOG_RETURN_VOID_IF_FALSE(PVRSRV_VZ_MODE_IS(NATIVE) ||
|
|
(KM_FW_CONNECTION_IS(ACTIVE, psDevInfo) &&
|
|
KM_OS_CONNECTION_IS(ACTIVE, psDevInfo)),
|
|
"FW-KM connection is down");
|
|
#endif
|
|
|
|
while (psFWCCBCtl->ui32ReadOffset != psFWCCBCtl->ui32WriteOffset)
|
|
{
|
|
/* Point to the next command */
|
|
const RGXFWIF_FWCCB_CMD *psFwCCBCmd = ((RGXFWIF_FWCCB_CMD *)psFWCCB) + psFWCCBCtl->ui32ReadOffset;
|
|
|
|
HTBLOGK(HTB_SF_MAIN_FWCCB_CMD, psFwCCBCmd->eCmdType);
|
|
switch (psFwCCBCmd->eCmdType)
|
|
{
|
|
case RGXFWIF_FWCCB_CMD_ZSBUFFER_BACKING:
|
|
{
|
|
if (psDevInfo->bPDPEnabled)
|
|
{
|
|
PDUMP_PANIC(psDevInfo->psDeviceNode, ZSBUFFER_BACKING,
|
|
"Request to add backing to ZSBuffer");
|
|
}
|
|
RGXProcessRequestZSBufferBacking(psDevInfo,
|
|
psFwCCBCmd->uCmdData.sCmdZSBufferBacking.ui32ZSBufferID);
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_ZSBUFFER_UNBACKING:
|
|
{
|
|
if (psDevInfo->bPDPEnabled)
|
|
{
|
|
PDUMP_PANIC(psDevInfo->psDeviceNode, ZSBUFFER_UNBACKING,
|
|
"Request to remove backing from ZSBuffer");
|
|
}
|
|
RGXProcessRequestZSBufferUnbacking(psDevInfo,
|
|
psFwCCBCmd->uCmdData.sCmdZSBufferBacking.ui32ZSBufferID);
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_FREELIST_GROW:
|
|
{
|
|
if (psDevInfo->bPDPEnabled)
|
|
{
|
|
PDUMP_PANIC(psDevInfo->psDeviceNode, FREELIST_GROW,
|
|
"Request to grow the free list");
|
|
}
|
|
RGXProcessRequestGrow(psDevInfo,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListGS.ui32FreelistID);
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION:
|
|
{
|
|
if (psDevInfo->bPDPEnabled)
|
|
{
|
|
PDUMP_PANIC(psDevInfo->psDeviceNode, FREELISTS_RECONSTRUCTION,
|
|
"Request to reconstruct free lists");
|
|
}
|
|
|
|
if (PVRSRV_VZ_MODE_IS(GUEST))
|
|
{
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: Freelist reconstruction request (%d) for %d freelists",
|
|
__func__,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32HwrCounter+1,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount));
|
|
}
|
|
else
|
|
{
|
|
PVR_ASSERT(psDevInfo->psRGXFWIfHWRInfoBufCtl);
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: Freelist reconstruction request (%d/%d) for %d freelists",
|
|
__func__,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32HwrCounter+1,
|
|
psDevInfo->psRGXFWIfHWRInfoBufCtl->ui32HwrCounter+1,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount));
|
|
}
|
|
|
|
RGXProcessRequestFreelistsReconstruction(psDevInfo,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount,
|
|
psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.aui32FreelistIDs);
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_CONTEXT_FW_PF_NOTIFICATION:
|
|
{
|
|
/* Notify client drivers */
|
|
/* Client notification of device error will be achieved by
|
|
* clients calling UM function RGXGetLastDeviceError() */
|
|
psDevInfo->eLastDeviceError = RGX_CONTEXT_RESET_REASON_FW_PAGEFAULT;
|
|
|
|
/* Notify system layer */
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDevNode = psDevInfo->psDeviceNode;
|
|
PVRSRV_DEVICE_CONFIG *psDevConfig = psDevNode->psDevConfig;
|
|
const RGXFWIF_FWCCB_CMD_FW_PAGEFAULT_DATA *psCmdFwPagefault =
|
|
&psFwCCBCmd->uCmdData.sCmdFWPagefault;
|
|
|
|
if (psDevConfig->pfnSysDevErrorNotify)
|
|
{
|
|
PVRSRV_ROBUSTNESS_NOTIFY_DATA sErrorData = {0};
|
|
|
|
sErrorData.eResetReason = RGX_CONTEXT_RESET_REASON_FW_PAGEFAULT;
|
|
sErrorData.uErrData.sFwPFErrData.sFWFaultAddr.uiAddr = psCmdFwPagefault->sFWFaultAddr.uiAddr;
|
|
|
|
psDevConfig->pfnSysDevErrorNotify(psDevConfig,
|
|
&sErrorData);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_CONTEXT_RESET_NOTIFICATION:
|
|
{
|
|
DLLIST_NODE *psNode, *psNext;
|
|
const RGXFWIF_FWCCB_CMD_CONTEXT_RESET_DATA *psCmdContextResetNotification =
|
|
&psFwCCBCmd->uCmdData.sCmdContextResetNotification;
|
|
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext = NULL;
|
|
IMG_UINT32 ui32ErrorPid = 0;
|
|
|
|
OSWRLockAcquireRead(psDevInfo->hCommonCtxtListLock);
|
|
|
|
dllist_foreach_node(&psDevInfo->sCommonCtxtListHead, psNode, psNext)
|
|
{
|
|
RGX_SERVER_COMMON_CONTEXT *psThisContext =
|
|
IMG_CONTAINER_OF(psNode, RGX_SERVER_COMMON_CONTEXT, sListNode);
|
|
|
|
/* If the notification applies to all contexts update reset info
|
|
* for all contexts, otherwise only do so for the appropriate ID.
|
|
*/
|
|
if (psCmdContextResetNotification->ui32Flags & RGXFWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_ALL_CTXS)
|
|
{
|
|
/* Notification applies to all contexts */
|
|
psThisContext->eLastResetReason = psCmdContextResetNotification->eResetReason;
|
|
psThisContext->ui32LastResetJobRef = psCmdContextResetNotification->ui32ResetJobRef;
|
|
}
|
|
else
|
|
{
|
|
/* Notification applies to one context only */
|
|
if (psThisContext->ui32ContextID == psCmdContextResetNotification->ui32ServerCommonContextID)
|
|
{
|
|
psServerCommonContext = psThisContext;
|
|
psServerCommonContext->eLastResetReason = psCmdContextResetNotification->eResetReason;
|
|
psServerCommonContext->ui32LastResetJobRef = psCmdContextResetNotification->ui32ResetJobRef;
|
|
ui32ErrorPid = RGXGetPIDFromServerMMUContext(psServerCommonContext->psServerMMUContext);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psCmdContextResetNotification->ui32Flags & RGXFWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_ALL_CTXS)
|
|
{
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: All contexts reset (Reason=%d, JobRef=0x%08x)",
|
|
__func__,
|
|
(IMG_UINT32)(psCmdContextResetNotification->eResetReason),
|
|
psCmdContextResetNotification->ui32ResetJobRef));
|
|
}
|
|
else
|
|
{
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: Context 0x%p reset (ID=0x%08x, Reason=%d, JobRef=0x%08x)",
|
|
__func__,
|
|
psServerCommonContext,
|
|
psCmdContextResetNotification->ui32ServerCommonContextID,
|
|
(IMG_UINT32)(psCmdContextResetNotification->eResetReason),
|
|
psCmdContextResetNotification->ui32ResetJobRef));
|
|
}
|
|
|
|
/* Increment error counter (if appropriate) */
|
|
if (psCmdContextResetNotification->eResetReason == RGX_CONTEXT_RESET_REASON_WGP_CHECKSUM)
|
|
{
|
|
/* Avoid wrapping the error count (which would then
|
|
* make it appear we had far fewer errors), by limiting
|
|
* it to IMG_UINT32_MAX.
|
|
*/
|
|
if (psDevInfo->sErrorCounts.ui32WGPErrorCount < IMG_UINT32_MAX)
|
|
{
|
|
psDevInfo->sErrorCounts.ui32WGPErrorCount++;
|
|
}
|
|
}
|
|
else if (psCmdContextResetNotification->eResetReason == RGX_CONTEXT_RESET_REASON_TRP_CHECKSUM)
|
|
{
|
|
/* Avoid wrapping the error count (which would then
|
|
* make it appear we had far fewer errors), by limiting
|
|
* it to IMG_UINT32_MAX.
|
|
*/
|
|
if (psDevInfo->sErrorCounts.ui32TRPErrorCount < IMG_UINT32_MAX)
|
|
{
|
|
psDevInfo->sErrorCounts.ui32TRPErrorCount++;
|
|
}
|
|
}
|
|
OSWRLockReleaseRead(psDevInfo->hCommonCtxtListLock);
|
|
|
|
/* Notify system layer */
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDevNode = psDevInfo->psDeviceNode;
|
|
PVRSRV_DEVICE_CONFIG *psDevConfig = psDevNode->psDevConfig;
|
|
|
|
if (psDevConfig->pfnSysDevErrorNotify)
|
|
{
|
|
PVRSRV_ROBUSTNESS_NOTIFY_DATA sErrorData = {0};
|
|
|
|
sErrorData.eResetReason = psCmdContextResetNotification->eResetReason;
|
|
sErrorData.pid = ui32ErrorPid;
|
|
|
|
/* Populate error data according to reset reason */
|
|
switch (psCmdContextResetNotification->eResetReason)
|
|
{
|
|
case RGX_CONTEXT_RESET_REASON_WGP_CHECKSUM:
|
|
case RGX_CONTEXT_RESET_REASON_TRP_CHECKSUM:
|
|
{
|
|
sErrorData.uErrData.sChecksumErrData.ui32ExtJobRef = psCmdContextResetNotification->ui32ResetJobRef;
|
|
sErrorData.uErrData.sChecksumErrData.eDM = psCmdContextResetNotification->eDM;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
psDevConfig->pfnSysDevErrorNotify(psDevConfig,
|
|
&sErrorData);
|
|
}
|
|
}
|
|
|
|
/* Notify if a page fault */
|
|
if (psCmdContextResetNotification->ui32Flags & RGXFWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_PF)
|
|
{
|
|
DevmemIntPFNotify(psDevInfo->psDeviceNode,
|
|
psCmdContextResetNotification->ui64PCAddress,
|
|
psCmdContextResetNotification->sFaultAddress);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_DEBUG_DUMP:
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
|
OSAtomicWrite(&psDevInfo->psDeviceNode->eDebugDumpRequested, PVRSRV_DEVICE_DEBUG_DUMP_CAPTURE);
|
|
eError = OSEventObjectSignal(psPVRSRVData->hDevicesWatchdogEvObj);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to signal FW Cmd debug dump event, dumping now instead", __func__));
|
|
PVRSRVDebugRequest(psDevInfo->psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_STATS:
|
|
{
|
|
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
|
|
IMG_PID pidTmp = psFwCCBCmd->uCmdData.sCmdUpdateStatsData.pidOwner;
|
|
IMG_INT32 i32AdjustmentValue = psFwCCBCmd->uCmdData.sCmdUpdateStatsData.i32AdjustmentValue;
|
|
|
|
switch (psFwCCBCmd->uCmdData.sCmdUpdateStatsData.eElementToUpdate)
|
|
{
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_PARTIAL_RENDERS:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(i32AdjustmentValue,0,0,0,0,0,pidTmp);
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_OUT_OF_MEMORY:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(0,i32AdjustmentValue,0,0,0,0,pidTmp);
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_TA_STORES:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(0,0,i32AdjustmentValue,0,0,0,pidTmp);
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_3D_STORES:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(0,0,0,i32AdjustmentValue,0,0,pidTmp);
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_CDM_STORES:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(0,0,0,0,i32AdjustmentValue,0,pidTmp);
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_UPDATE_NUM_TDM_STORES:
|
|
{
|
|
PVRSRVStatsUpdateRenderContextStats(0,0,0,0,0,i32AdjustmentValue,pidTmp);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
case RGXFWIF_FWCCB_CMD_CORE_CLK_RATE_CHANGE:
|
|
{
|
|
#if defined(SUPPORT_PDVFS)
|
|
PDVFS_PROCESS_CORE_CLK_RATE_CHANGE(psDevInfo,
|
|
psFwCCBCmd->uCmdData.sCmdCoreClkRateChange.ui32CoreClkRate);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case RGXFWIF_FWCCB_CMD_REQUEST_GPU_RESTART:
|
|
{
|
|
if (psDevInfo->psRGXFWIfFwSysData != NULL &&
|
|
psDevInfo->psRGXFWIfFwSysData->ePowState != RGXFWIF_POW_OFF)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
/* Power down... */
|
|
eError = PVRSRVSetDeviceSystemPowerState(psDevInfo->psDeviceNode,
|
|
PVRSRV_SYS_POWER_STATE_OFF, PVRSRV_POWER_FLAGS_NONE);
|
|
if (eError == PVRSRV_OK)
|
|
{
|
|
/* Clear the FW faulted flags... */
|
|
psDevInfo->psRGXFWIfFwSysData->ui32HWRStateFlags &= ~(RGXFWIF_HWR_FW_FAULT|RGXFWIF_HWR_RESTART_REQUESTED);
|
|
|
|
/* Power back up again... */
|
|
eError = PVRSRVSetDeviceSystemPowerState(psDevInfo->psDeviceNode,
|
|
PVRSRV_SYS_POWER_STATE_ON, PVRSRV_POWER_FLAGS_NONE);
|
|
|
|
/* Send a dummy KCCB command to ensure the FW wakes up and checks the queues... */
|
|
if (eError == PVRSRV_OK)
|
|
{
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXFWHealthCheckCmd(psDevInfo);
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
}
|
|
}
|
|
|
|
/* Notify client drivers and system layer of FW fault */
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDevNode = psDevInfo->psDeviceNode;
|
|
PVRSRV_DEVICE_CONFIG *psDevConfig = psDevNode->psDevConfig;
|
|
|
|
/* Client notification of device error will be achieved by
|
|
* clients calling UM function RGXGetLastDeviceError() */
|
|
psDevInfo->eLastDeviceError = RGX_CONTEXT_RESET_REASON_FW_EXEC_ERR;
|
|
|
|
/* Notify system layer */
|
|
if (psDevConfig->pfnSysDevErrorNotify)
|
|
{
|
|
PVRSRV_ROBUSTNESS_NOTIFY_DATA sErrorData = {0};
|
|
|
|
sErrorData.eResetReason = RGX_CONTEXT_RESET_REASON_FW_EXEC_ERR;
|
|
psDevConfig->pfnSysDevErrorNotify(psDevConfig,
|
|
&sErrorData);
|
|
}
|
|
}
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed firmware restart (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#if defined(SUPPORT_VALIDATION)
|
|
case RGXFWIF_FWCCB_CMD_REG_READ:
|
|
{
|
|
psDevInfo->sFwRegs.ui64RegVal = psFwCCBCmd->uCmdData.sCmdRgxRegReadData.ui64RegValue;
|
|
complete(&psDevInfo->sFwRegs.sRegComp);
|
|
break;
|
|
}
|
|
#if defined(SUPPORT_SOC_TIMER)
|
|
case RGXFWIF_FWCCB_CMD_SAMPLE_TIMERS:
|
|
{
|
|
if (psDevInfo->psRGXFWIfFwSysData->ui32ConfigFlags & RGXFWIF_INICFG_VALIDATE_SOCUSC_TIMER)
|
|
{
|
|
PVRSRV_ERROR eSOCtimerErr = RGXValidateSOCUSCTimer(psDevInfo,
|
|
PDUMP_NONE,
|
|
psFwCCBCmd->uCmdData.sCmdTimers.ui64timerGray,
|
|
psFwCCBCmd->uCmdData.sCmdTimers.ui64timerBinary,
|
|
psFwCCBCmd->uCmdData.sCmdTimers.aui64uscTimers);
|
|
if (PVRSRV_OK == eSOCtimerErr)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "SoC or USC Timers have increased over time"));
|
|
}
|
|
else
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "SoC or USC Timers have NOT increased over time"));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
#endif
|
|
default:
|
|
{
|
|
/* unknown command */
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Unknown Command (eCmdType=0x%08x)",
|
|
__func__, psFwCCBCmd->eCmdType));
|
|
/* Assert on magic value corruption */
|
|
PVR_ASSERT((((IMG_UINT32)psFwCCBCmd->eCmdType & RGX_CMD_MAGIC_DWORD_MASK) >> RGX_CMD_MAGIC_DWORD_SHIFT) == RGX_CMD_MAGIC_DWORD);
|
|
}
|
|
}
|
|
|
|
/* Update read offset */
|
|
psFWCCBCtl->ui32ReadOffset = (psFWCCBCtl->ui32ReadOffset + 1) & psFWCCBCtl->ui32WrapMask;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PVRSRVRGXFrameworkCopyCommand
|
|
*/
|
|
PVRSRV_ERROR PVRSRVRGXFrameworkCopyCommand(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
DEVMEM_MEMDESC *psFWFrameworkMemDesc,
|
|
IMG_PBYTE pbyGPUFRegisterList,
|
|
IMG_UINT32 ui32FrameworkRegisterSize)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_RF_REGISTERS *psRFReg;
|
|
|
|
eError = DevmemAcquireCpuVirtAddr(psFWFrameworkMemDesc,
|
|
(void **)&psRFReg);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to map firmware render context state (%u)",
|
|
__func__, eError));
|
|
return eError;
|
|
}
|
|
|
|
OSDeviceMemCopy(psRFReg, pbyGPUFRegisterList, ui32FrameworkRegisterSize);
|
|
|
|
/* Release the CPU mapping */
|
|
DevmemReleaseCpuVirtAddr(psFWFrameworkMemDesc);
|
|
|
|
/*
|
|
* Dump the FW framework buffer
|
|
*/
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDeviceNode, "Dump FWFramework buffer");
|
|
DevmemPDumpLoadMem(psFWFrameworkMemDesc, 0, ui32FrameworkRegisterSize, PDUMP_FLAGS_CONTINUOUS);
|
|
#else
|
|
PVR_UNREFERENCED_PARAMETER(psDeviceNode);
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*
|
|
* PVRSRVRGXFrameworkCreateKM
|
|
*/
|
|
PVRSRV_ERROR PVRSRVRGXFrameworkCreateKM(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
DEVMEM_MEMDESC **ppsFWFrameworkMemDesc,
|
|
IMG_UINT32 ui32FrameworkCommandSize)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
|
|
/*
|
|
Allocate device memory for the firmware GPU framework state.
|
|
Sufficient info to kick one or more DMs should be contained in this buffer
|
|
*/
|
|
PDUMPCOMMENT(psDeviceNode, "Allocate Rogue firmware framework state");
|
|
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
ui32FrameworkCommandSize,
|
|
RGX_FWCOMCTX_ALLOCFLAGS,
|
|
"FwGPUFrameworkState",
|
|
ppsFWFrameworkMemDesc);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to allocate firmware framework state (%u)",
|
|
__func__, eError));
|
|
return eError;
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXPollForGPCommandCompletion(PVRSRV_DEVICE_NODE *psDevNode,
|
|
volatile IMG_UINT32 __iomem *pui32LinMemAddr,
|
|
IMG_UINT32 ui32Value,
|
|
IMG_UINT32 ui32Mask)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
IMG_UINT32 ui32CurrentQueueLength, ui32MaxRetries;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDevNode->pvDevice;
|
|
const RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl;
|
|
|
|
ui32CurrentQueueLength = (psKCCBCtl->ui32WrapMask+1 +
|
|
psKCCBCtl->ui32WriteOffset -
|
|
psKCCBCtl->ui32ReadOffset) & psKCCBCtl->ui32WrapMask;
|
|
ui32CurrentQueueLength += psDevInfo->ui32KCCBDeferredCommandsCount;
|
|
|
|
for (ui32MaxRetries = ui32CurrentQueueLength + 1;
|
|
ui32MaxRetries > 0;
|
|
ui32MaxRetries--)
|
|
{
|
|
|
|
/*
|
|
* PVRSRVPollForValueKM flags are set to POLL_FLAG_NONE in this case so that the function
|
|
* does not generate an error message. In this case, the PollForValueKM is expected to
|
|
* timeout as there is work ongoing on the GPU which may take longer than the timeout period.
|
|
*/
|
|
eError = PVRSRVPollForValueKM(psDevNode, pui32LinMemAddr, ui32Value, ui32Mask, POLL_FLAG_NONE);
|
|
if (eError != PVRSRV_ERROR_TIMEOUT)
|
|
{
|
|
break;
|
|
}
|
|
|
|
RGXSendCommandsFromDeferredList(psDevInfo, IMG_FALSE);
|
|
}
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Failed! Error(%s) CPU linear address(%p) Expected value(%u)",
|
|
__func__, PVRSRVGetErrorString(eError),
|
|
pui32LinMemAddr, ui32Value));
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXStateFlagCtrl(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32Config,
|
|
IMG_UINT32 *pui32ConfigState,
|
|
IMG_BOOL bSetNotClear)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PVRSRV_DEV_POWER_STATE ePowerState;
|
|
RGXFWIF_KCCB_CMD sStateFlagCmd = { 0 };
|
|
PVRSRV_DEVICE_NODE *psDeviceNode;
|
|
RGXFWIF_SYSDATA *psSysData;
|
|
IMG_UINT32 ui32kCCBCommandSlot;
|
|
IMG_BOOL bWaitForFwUpdate = IMG_FALSE;
|
|
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_ERROR_NOT_SUPPORTED);
|
|
|
|
if (!psDevInfo)
|
|
{
|
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
|
}
|
|
psDeviceNode = psDevInfo->psDeviceNode;
|
|
psSysData = psDevInfo->psRGXFWIfFwSysData;
|
|
|
|
if (NULL == psSysData)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Fw Sys Config is not mapped into CPU space", __func__));
|
|
return PVRSRV_ERROR_INVALID_CPU_ADDR;
|
|
}
|
|
|
|
/* apply change and ensure the new data is written to memory
|
|
* before requesting the FW to read it
|
|
*/
|
|
ui32Config = ui32Config & RGXFWIF_INICFG_ALL;
|
|
if (bSetNotClear)
|
|
{
|
|
psSysData->ui32ConfigFlags |= ui32Config;
|
|
}
|
|
else
|
|
{
|
|
psSysData->ui32ConfigFlags &= ~ui32Config;
|
|
}
|
|
|
|
/* return current/new value to caller */
|
|
if (pui32ConfigState)
|
|
{
|
|
*pui32ConfigState = psSysData->ui32ConfigFlags;
|
|
}
|
|
|
|
OSMemoryBarrier(&psSysData->ui32ConfigFlags);
|
|
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "PVRSRVPowerLock");
|
|
|
|
/* notify FW to update setting */
|
|
eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
|
|
|
|
if ((eError == PVRSRV_OK) && (ePowerState != PVRSRV_DEV_POWER_STATE_OFF))
|
|
{
|
|
/* Ask the FW to update its cached version of the value */
|
|
sStateFlagCmd.eCmdType = RGXFWIF_KCCB_CMD_STATEFLAGS_CTRL;
|
|
|
|
eError = RGXSendCommandAndGetKCCBSlot(psDevInfo,
|
|
&sStateFlagCmd,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
&ui32kCCBCommandSlot);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXSendCommandAndGetKCCBSlot", unlock);
|
|
bWaitForFwUpdate = IMG_TRUE;
|
|
}
|
|
|
|
unlock:
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
if (bWaitForFwUpdate)
|
|
{
|
|
/* Wait for the value to be updated as the FW validates
|
|
* the parameters and modifies the ui32ConfigFlags
|
|
* accordingly
|
|
* (for completeness as registered callbacks should also
|
|
* not permit invalid transitions)
|
|
*/
|
|
eError = RGXWaitForKCCBSlotUpdate(psDevInfo, ui32kCCBCommandSlot, PDUMP_FLAGS_CONTINUOUS);
|
|
PVR_LOG_IF_ERROR(eError, "RGXWaitForKCCBSlotUpdate");
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
static
|
|
PVRSRV_ERROR RGXScheduleCleanupCommand(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
RGXFWIF_DM eDM,
|
|
RGXFWIF_KCCB_CMD *psKCCBCmd,
|
|
RGXFWIF_CLEANUP_TYPE eCleanupType,
|
|
IMG_UINT32 ui32PDumpFlags)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
IMG_UINT32 ui32kCCBCommandSlot;
|
|
|
|
/* Clean-up commands sent during frame capture intervals must be dumped even when not in capture range... */
|
|
ui32PDumpFlags |= PDUMP_FLAGS_INTERVAL;
|
|
|
|
psKCCBCmd->eCmdType = RGXFWIF_KCCB_CMD_CLEANUP;
|
|
psKCCBCmd->uCmdData.sCleanupData.eCleanupType = eCleanupType;
|
|
|
|
/*
|
|
Send the cleanup request to the firmware. If the resource is still busy
|
|
the firmware will tell us and we'll drop out with a retry.
|
|
*/
|
|
eError = RGXScheduleCommandAndGetKCCBSlot(psDevInfo,
|
|
eDM,
|
|
psKCCBCmd,
|
|
ui32PDumpFlags,
|
|
&ui32kCCBCommandSlot);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
/* If caller may retry, fail with no error message */
|
|
if ((eError != PVRSRV_ERROR_RETRY) &&
|
|
(eError != PVRSRV_ERROR_KERNEL_CCB_FULL))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR ,"RGXScheduleCommandAndGetKCCBSlot() failed (%s) in %s()",
|
|
PVRSRVGETERRORSTRING(eError), __func__));
|
|
}
|
|
goto fail_command;
|
|
}
|
|
|
|
/* Wait for command kCCB slot to be updated by FW */
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, ui32PDumpFlags,
|
|
"Wait for the firmware to reply to the cleanup command");
|
|
eError = RGXWaitForKCCBSlotUpdate(psDevInfo, ui32kCCBCommandSlot,
|
|
ui32PDumpFlags);
|
|
/*
|
|
If the firmware hasn't got back to us in a timely manner
|
|
then bail and let the caller retry the command.
|
|
*/
|
|
if (eError == PVRSRV_ERROR_TIMEOUT)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: RGXWaitForKCCBSlotUpdate timed out. Dump debug information.",
|
|
__func__));
|
|
|
|
eError = PVRSRV_ERROR_RETRY;
|
|
#if defined(DEBUG)
|
|
PVRSRVDebugRequest(psDevInfo->psDeviceNode,
|
|
DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL);
|
|
#endif
|
|
goto fail_poll;
|
|
}
|
|
else if (eError != PVRSRV_OK)
|
|
{
|
|
goto fail_poll;
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
/*
|
|
* The cleanup request to the firmware will tell us if a given resource is busy or not.
|
|
* If the RGXFWIF_KCCB_RTN_SLOT_CLEANUP_BUSY flag is set, this means that the resource is
|
|
* still in use. In this case we return a PVRSRV_ERROR_RETRY error to the client drivers
|
|
* and they will re-issue the cleanup request until it succeed.
|
|
*
|
|
* Since this retry mechanism doesn't work for pdumps, client drivers should ensure
|
|
* that cleanup requests are only submitted if the resource is unused.
|
|
* If this is not the case, the following poll will block infinitely, making sure
|
|
* the issue doesn't go unnoticed.
|
|
*/
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, ui32PDumpFlags,
|
|
"Cleanup: If this poll fails, the following resource is still in use (DM=%u, type=%u, address=0x%08x), which is incorrect in pdumps",
|
|
eDM,
|
|
psKCCBCmd->uCmdData.sCleanupData.eCleanupType,
|
|
psKCCBCmd->uCmdData.sCleanupData.uCleanupData.psContext.ui32Addr);
|
|
eError = DevmemPDumpDevmemPol32(psDevInfo->psKernelCCBRtnSlotsMemDesc,
|
|
ui32kCCBCommandSlot * sizeof(IMG_UINT32),
|
|
0,
|
|
RGXFWIF_KCCB_RTN_SLOT_CLEANUP_BUSY,
|
|
PDUMP_POLL_OPERATOR_EQUAL,
|
|
ui32PDumpFlags);
|
|
PVR_LOG_IF_ERROR(eError, "DevmemPDumpDevmemPol32");
|
|
#endif
|
|
|
|
/*
|
|
If the command has was run but a resource was busy, then the request
|
|
will need to be retried.
|
|
*/
|
|
if (unlikely(psDevInfo->pui32KernelCCBRtnSlots[ui32kCCBCommandSlot] & RGXFWIF_KCCB_RTN_SLOT_CLEANUP_BUSY))
|
|
{
|
|
if (psDevInfo->pui32KernelCCBRtnSlots[ui32kCCBCommandSlot] & RGXFWIF_KCCB_RTN_SLOT_POLL_FAILURE)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: FW poll on a HW operation failed", __func__));
|
|
}
|
|
eError = PVRSRV_ERROR_RETRY;
|
|
goto fail_requestbusy;
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail_requestbusy:
|
|
fail_poll:
|
|
fail_command:
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*
|
|
RGXRequestCommonContextCleanUp
|
|
*/
|
|
PVRSRV_ERROR RGXFWRequestCommonContextCleanUp(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext,
|
|
RGXFWIF_DM eDM,
|
|
IMG_UINT32 ui32PDumpFlags)
|
|
{
|
|
RGXFWIF_KCCB_CMD sRCCleanUpCmd = {0};
|
|
PVRSRV_ERROR eError;
|
|
PRGXFWIF_FWCOMMONCONTEXT psFWCommonContextFWAddr;
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = (PVRSRV_RGXDEV_INFO*)psDeviceNode->pvDevice;
|
|
|
|
/* Force retry if this context's CCB is currently being dumped
|
|
* as part of the stalled CCB debug */
|
|
if (psDevInfo->pvEarliestStalledClientCCB == (void*)psServerCommonContext->psClientCCB)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: Forcing retry as psDevInfo->pvEarliestStalledClientCCB = psServerCommonContext->psClientCCB <%p>",
|
|
__func__,
|
|
(void*)psServerCommonContext->psClientCCB));
|
|
return PVRSRV_ERROR_RETRY;
|
|
}
|
|
|
|
psFWCommonContextFWAddr = FWCommonContextGetFWAddress(psServerCommonContext);
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDeviceNode, "Common ctx cleanup Request DM%d [context = 0x%08x]",
|
|
eDM, psFWCommonContextFWAddr.ui32Addr);
|
|
PDUMPCOMMENT(psDeviceNode, "Wait for CCB to be empty before common ctx cleanup");
|
|
|
|
RGXCCBPDumpDrainCCB(FWCommonContextGetClientCCB(psServerCommonContext), ui32PDumpFlags);
|
|
#endif
|
|
|
|
/* Setup our command data, the cleanup call will fill in the rest */
|
|
sRCCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psContext = psFWCommonContextFWAddr;
|
|
|
|
/* Request cleanup of the firmware resource */
|
|
eError = RGXScheduleCleanupCommand(psDeviceNode->pvDevice,
|
|
eDM,
|
|
&sRCCleanUpCmd,
|
|
RGXFWIF_CLEANUP_FWCOMMONCONTEXT,
|
|
ui32PDumpFlags);
|
|
|
|
if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to schedule a memory context cleanup with error (%u)",
|
|
__func__, eError));
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*
|
|
* RGXFWRequestHWRTDataCleanUp
|
|
*/
|
|
|
|
PVRSRV_ERROR RGXFWRequestHWRTDataCleanUp(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
PRGXFWIF_HWRTDATA psHWRTData)
|
|
{
|
|
RGXFWIF_KCCB_CMD sHWRTDataCleanUpCmd = {0};
|
|
PVRSRV_ERROR eError;
|
|
|
|
PDUMPCOMMENT(psDeviceNode, "HW RTData cleanup Request [HWRTData = 0x%08x]", psHWRTData.ui32Addr);
|
|
|
|
sHWRTDataCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psHWRTData = psHWRTData;
|
|
|
|
eError = RGXScheduleCleanupCommand(psDeviceNode->pvDevice,
|
|
RGXFWIF_DM_GP,
|
|
&sHWRTDataCleanUpCmd,
|
|
RGXFWIF_CLEANUP_HWRTDATA,
|
|
PDUMP_FLAGS_NONE);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
/* If caller may retry, fail with no error message */
|
|
if ((eError != PVRSRV_ERROR_RETRY) &&
|
|
(eError != PVRSRV_ERROR_KERNEL_CCB_FULL))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to schedule a HWRTData cleanup with error (%u)",
|
|
__func__, eError));
|
|
}
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*
|
|
RGXFWRequestFreeListCleanUp
|
|
*/
|
|
PVRSRV_ERROR RGXFWRequestFreeListCleanUp(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
PRGXFWIF_FREELIST psFWFreeList)
|
|
{
|
|
RGXFWIF_KCCB_CMD sFLCleanUpCmd = {0};
|
|
PVRSRV_ERROR eError;
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "Free list cleanup Request [FreeList = 0x%08x]", psFWFreeList.ui32Addr);
|
|
|
|
/* Setup our command data, the cleanup call will fill in the rest */
|
|
sFLCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psFreelist = psFWFreeList;
|
|
|
|
/* Request cleanup of the firmware resource */
|
|
eError = RGXScheduleCleanupCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sFLCleanUpCmd,
|
|
RGXFWIF_CLEANUP_FREELIST,
|
|
PDUMP_FLAGS_NONE);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
/* If caller may retry, fail with no error message */
|
|
if ((eError != PVRSRV_ERROR_RETRY) &&
|
|
(eError != PVRSRV_ERROR_KERNEL_CCB_FULL))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to schedule a memory context cleanup with error (%u)",
|
|
__func__, eError));
|
|
}
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*
|
|
RGXFWRequestZSBufferCleanUp
|
|
*/
|
|
PVRSRV_ERROR RGXFWRequestZSBufferCleanUp(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
PRGXFWIF_ZSBUFFER psFWZSBuffer)
|
|
{
|
|
RGXFWIF_KCCB_CMD sZSBufferCleanUpCmd = {0};
|
|
PVRSRV_ERROR eError;
|
|
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode, "ZS Buffer cleanup Request [ZS Buffer = 0x%08x]", psFWZSBuffer.ui32Addr);
|
|
|
|
/* Setup our command data, the cleanup call will fill in the rest */
|
|
sZSBufferCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psZSBuffer = psFWZSBuffer;
|
|
|
|
/* Request cleanup of the firmware resource */
|
|
eError = RGXScheduleCleanupCommand(psDevInfo,
|
|
RGXFWIF_DM_3D,
|
|
&sZSBufferCleanUpCmd,
|
|
RGXFWIF_CLEANUP_ZSBUFFER,
|
|
PDUMP_FLAGS_NONE);
|
|
|
|
if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY))
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to schedule a memory context cleanup with error (%u)",
|
|
__func__, eError));
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWSetHCSDeadline(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32HCSDeadlineMs)
|
|
{
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_ERROR_NOT_SUPPORTED);
|
|
|
|
psDevInfo->psRGXFWIfRuntimeCfg->ui32HCSDeadlineMS = ui32HCSDeadlineMs;
|
|
OSWriteMemoryBarrier(&psDevInfo->psRGXFWIfRuntimeCfg->ui32HCSDeadlineMS);
|
|
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Updating the Hard Context Switching deadline inside RGXFWIfRuntimeCfg");
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
offsetof(RGXFWIF_RUNTIME_CFG, ui32HCSDeadlineMS),
|
|
ui32HCSDeadlineMs,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWHealthCheckCmd(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXFWIF_KCCB_CMD sCmpKCCBCmd = { 0 };
|
|
|
|
sCmpKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_HEALTH_CHECK;
|
|
|
|
return RGXScheduleCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sCmpKCCBCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWSetFwOsState(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32OSid,
|
|
RGXFWIF_OS_STATE_CHANGE eOSOnlineState)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
RGXFWIF_KCCB_CMD sOSOnlineStateCmd = { 0 };
|
|
RGXFWIF_SYSDATA *psFwSysData = psDevInfo->psRGXFWIfFwSysData;
|
|
|
|
sOSOnlineStateCmd.eCmdType = RGXFWIF_KCCB_CMD_OS_ONLINE_STATE_CONFIGURE;
|
|
sOSOnlineStateCmd.uCmdData.sCmdOSOnlineStateData.ui32OSid = ui32OSid;
|
|
sOSOnlineStateCmd.uCmdData.sCmdOSOnlineStateData.eNewOSState = eOSOnlineState;
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
{
|
|
IMG_BOOL bConnectionDown = IMG_FALSE;
|
|
|
|
PVR_UNREFERENCED_PARAMETER(psFwSysData);
|
|
sOSOnlineStateCmd.uCmdData.sCmdOSOnlineStateData.eNewOSState = RGXFWIF_OS_OFFLINE;
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
/* Send the offline command regardless if power lock is held or not.
|
|
* Under AutoVz this is done during regular driver deinit, store-to-ram suspend
|
|
* or (optionally) from a kernel panic callback. Deinit and suspend operations
|
|
* take the lock in the rgx pre/post power functions as expected.
|
|
* The kernel panic callback is a last resort way of letting the firmware know that
|
|
* the VM is unrecoverable and the vz connection must be disabled. It cannot wait
|
|
* on other kernel threads to finish and release the lock. */
|
|
eError = RGXSendCommand(psDevInfo,
|
|
&sOSOnlineStateCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
/* Guests and Host going offline should wait for confirmation
|
|
* from the Firmware of the state change. If this fails, break
|
|
* the connection on the OS Driver's end as backup. */
|
|
if (PVRSRV_VZ_MODE_IS(GUEST) || (ui32OSid == RGXFW_HOST_OS))
|
|
{
|
|
LOOP_UNTIL_TIMEOUT(SECONDS_TO_MICROSECONDS/2)
|
|
{
|
|
if (KM_FW_CONNECTION_IS(READY, psDevInfo))
|
|
{
|
|
bConnectionDown = IMG_TRUE;
|
|
break;
|
|
}
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
if (!bConnectionDown)
|
|
{
|
|
KM_SET_OS_CONNECTION(OFFLINE, psDevInfo);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if (PVRSRV_VZ_MODE_IS(GUEST))
|
|
{
|
|
/* no reason for Guests to update their state or any other VM's.
|
|
* This is the Hypervisor and Host driver's responsibility. */
|
|
return PVRSRV_OK;
|
|
}
|
|
else if (eOSOnlineState == RGXFWIF_OS_ONLINE)
|
|
{
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXScheduleCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sOSOnlineStateCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_ERROR_RETRY) break;
|
|
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
}
|
|
else if (psFwSysData)
|
|
{
|
|
const volatile RGXFWIF_OS_RUNTIME_FLAGS *psFwRunFlags =
|
|
(const volatile RGXFWIF_OS_RUNTIME_FLAGS*) &psFwSysData->asOsRuntimeFlagsMirror[ui32OSid];
|
|
|
|
/* Attempt several times until the FW manages to offload the OS */
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
IMG_UINT32 ui32kCCBCommandSlot;
|
|
|
|
/* Send request */
|
|
eError = RGXScheduleCommandAndGetKCCBSlot(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sOSOnlineStateCmd,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
&ui32kCCBCommandSlot);
|
|
if (unlikely(eError == PVRSRV_ERROR_RETRY)) continue;
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXScheduleCommand", return_);
|
|
|
|
/* Wait for FW to process the cmd */
|
|
eError = RGXWaitForKCCBSlotUpdate(psDevInfo, ui32kCCBCommandSlot, PDUMP_FLAGS_CONTINUOUS);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "RGXWaitForKCCBSlotUpdate", return_);
|
|
|
|
/* read the OS state */
|
|
OSMemoryBarrier(NULL);
|
|
/* check if FW finished offloading the OSID and is stopped */
|
|
if (psFwRunFlags->bfOsState == RGXFW_CONNECTION_FW_OFFLINE)
|
|
{
|
|
eError = PVRSRV_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
eError = PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
}
|
|
else
|
|
{
|
|
eError = PVRSRV_ERROR_NOT_INITIALISED;
|
|
}
|
|
|
|
return_ :
|
|
#endif
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWChangeOSidPriority(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32OSid,
|
|
IMG_UINT32 ui32Priority)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_KCCB_CMD sOSidPriorityCmd = { 0 };
|
|
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_ERROR_NOT_SUPPORTED);
|
|
|
|
sOSidPriorityCmd.eCmdType = RGXFWIF_KCCB_CMD_OSID_PRIORITY_CHANGE;
|
|
psDevInfo->psRGXFWIfRuntimeCfg->aui32OSidPriority[ui32OSid] = ui32Priority;
|
|
OSWriteMemoryBarrier(&psDevInfo->psRGXFWIfRuntimeCfg->aui32OSidPriority[ui32OSid]);
|
|
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Updating the priority of OSID%u inside RGXFWIfRuntimeCfg", ui32OSid);
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
offsetof(RGXFWIF_RUNTIME_CFG, aui32OSidPriority) + (ui32OSid * sizeof(ui32Priority)),
|
|
ui32Priority ,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXScheduleCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sOSidPriorityCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR ContextSetPriority(RGX_SERVER_COMMON_CONTEXT *psContext,
|
|
CONNECTION_DATA *psConnection,
|
|
PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32Priority,
|
|
RGXFWIF_DM eDM)
|
|
{
|
|
IMG_UINT32 ui32CmdSize;
|
|
IMG_UINT8 *pui8CmdPtr;
|
|
RGXFWIF_KCCB_CMD sPriorityCmd = { 0 };
|
|
RGXFWIF_CCB_CMD_HEADER *psCmdHeader;
|
|
RGXFWIF_CMD_PRIORITY *psCmd;
|
|
PVRSRV_ERROR eError;
|
|
IMG_INT32 i32Priority = (IMG_INT32)ui32Priority;
|
|
RGX_CLIENT_CCB *psClientCCB = FWCommonContextGetClientCCB(psContext);
|
|
|
|
eError = _CheckPriority(psDevInfo, i32Priority, psContext->eRequestor);
|
|
PVR_LOG_GOTO_IF_ERROR(eError, "_CheckPriority", fail_checkpriority);
|
|
|
|
/*
|
|
Get space for command
|
|
*/
|
|
ui32CmdSize = RGX_CCB_FWALLOC_ALIGN(sizeof(RGXFWIF_CCB_CMD_HEADER) + sizeof(RGXFWIF_CMD_PRIORITY));
|
|
|
|
eError = RGXAcquireCCB(psClientCCB,
|
|
ui32CmdSize,
|
|
(void **) &pui8CmdPtr,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to acquire space for client CCB", __func__));
|
|
}
|
|
goto fail_ccbacquire;
|
|
}
|
|
|
|
/*
|
|
Write the command header and command
|
|
*/
|
|
psCmdHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
|
|
psCmdHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_PRIORITY;
|
|
psCmdHeader->ui32CmdSize = RGX_CCB_FWALLOC_ALIGN(sizeof(RGXFWIF_CMD_PRIORITY));
|
|
pui8CmdPtr += sizeof(*psCmdHeader);
|
|
|
|
psCmd = (RGXFWIF_CMD_PRIORITY *) pui8CmdPtr;
|
|
psCmd->i32Priority = i32Priority;
|
|
pui8CmdPtr += sizeof(*psCmd);
|
|
|
|
/*
|
|
We should reserve space in the kernel CCB here and fill in the command
|
|
directly.
|
|
This is so if there isn't space in the kernel CCB we can return with
|
|
retry back to services client before we take any operations
|
|
*/
|
|
|
|
/*
|
|
Submit the command
|
|
*/
|
|
RGXReleaseCCB(psClientCCB,
|
|
ui32CmdSize,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to release space in client CCB", __func__));
|
|
return eError;
|
|
}
|
|
|
|
/* Construct the priority command. */
|
|
sPriorityCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
|
|
sPriorityCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psContext);
|
|
sPriorityCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(psClientCCB);
|
|
sPriorityCmd.uCmdData.sCmdKickData.ui32CWrapMaskUpdate = RGXGetWrapMaskCCB(psClientCCB);
|
|
sPriorityCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;
|
|
sPriorityCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset = 0;
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXScheduleCommand(psDevInfo,
|
|
eDM,
|
|
&sPriorityCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Failed to submit set priority command with error (%u)",
|
|
__func__,
|
|
eError));
|
|
goto fail_cmdacquire;
|
|
}
|
|
|
|
psContext->i32Priority = i32Priority;
|
|
|
|
return PVRSRV_OK;
|
|
|
|
fail_ccbacquire:
|
|
fail_checkpriority:
|
|
fail_cmdacquire:
|
|
PVR_ASSERT(eError != PVRSRV_OK);
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWConfigPHR(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32PHRMode)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_KCCB_CMD sCfgPHRCmd = { 0 };
|
|
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_ERROR_NOT_SUPPORTED);
|
|
|
|
sCfgPHRCmd.eCmdType = RGXFWIF_KCCB_CMD_PHR_CFG;
|
|
psDevInfo->psRGXFWIfRuntimeCfg->ui32PHRMode = ui32PHRMode;
|
|
OSWriteMemoryBarrier(&psDevInfo->psRGXFWIfRuntimeCfg->ui32PHRMode);
|
|
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Updating the Periodic Hardware Reset Mode inside RGXFWIfRuntimeCfg");
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
offsetof(RGXFWIF_RUNTIME_CFG, ui32PHRMode),
|
|
ui32PHRMode,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXScheduleCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sCfgPHRCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
return eError;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXFWConfigWdg(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32WdgPeriodUs)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
RGXFWIF_KCCB_CMD sCfgWdgCmd = { 0 };
|
|
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_ERROR_NOT_SUPPORTED);
|
|
|
|
sCfgWdgCmd.eCmdType = RGXFWIF_KCCB_CMD_WDG_CFG;
|
|
psDevInfo->psRGXFWIfRuntimeCfg->ui32WdgPeriodUs = ui32WdgPeriodUs;
|
|
OSWriteMemoryBarrier(&psDevInfo->psRGXFWIfRuntimeCfg->ui32WdgPeriodUs);
|
|
|
|
#if defined(PDUMP)
|
|
PDUMPCOMMENT(psDevInfo->psDeviceNode,
|
|
"Updating the firmware watchdog period inside RGXFWIfRuntimeCfg");
|
|
DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRuntimeCfgMemDesc,
|
|
offsetof(RGXFWIF_RUNTIME_CFG, ui32WdgPeriodUs),
|
|
ui32WdgPeriodUs,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#endif
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
eError = RGXScheduleCommand(psDevInfo,
|
|
RGXFWIF_DM_GP,
|
|
&sCfgWdgCmd,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_ERROR_RETRY)
|
|
{
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
|
|
return eError;
|
|
}
|
|
|
|
|
|
|
|
void RGXCheckForStalledClientContexts(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_BOOL bIgnorePrevious)
|
|
{
|
|
/* Attempt to detect and deal with any stalled client contexts.
|
|
* bIgnorePrevious may be set by the caller if they know a context to be
|
|
* stalled, as otherwise this function will only identify stalled
|
|
* contexts which have not been previously reported.
|
|
*/
|
|
|
|
IMG_UINT32 ui32StalledClientMask = 0;
|
|
|
|
if (!(OSTryLockAcquire(psDevInfo->hCCBStallCheckLock)))
|
|
{
|
|
PVR_LOG(("RGXCheckForStalledClientContexts: Failed to acquire hCCBStallCheckLock, returning..."));
|
|
return;
|
|
}
|
|
|
|
ui32StalledClientMask |= CheckForStalledClientTransferCtxt(psDevInfo);
|
|
|
|
ui32StalledClientMask |= CheckForStalledClientRenderCtxt(psDevInfo);
|
|
|
|
ui32StalledClientMask |= CheckForStalledClientKickSyncCtxt(psDevInfo);
|
|
|
|
if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_COMPUTE_BIT_MASK)
|
|
{
|
|
ui32StalledClientMask |= CheckForStalledClientComputeCtxt(psDevInfo);
|
|
}
|
|
|
|
/* If at least one DM stalled bit is different than before */
|
|
if (bIgnorePrevious || (psDevInfo->ui32StalledClientMask != ui32StalledClientMask))//(psDevInfo->ui32StalledClientMask ^ ui32StalledClientMask))
|
|
{
|
|
if (ui32StalledClientMask > 0)
|
|
{
|
|
static __maybe_unused const char *pszStalledAction =
|
|
#if defined(PVRSRV_STALLED_CCB_ACTION)
|
|
"force";
|
|
#else
|
|
"warn";
|
|
#endif
|
|
/* Print all the stalled DMs */
|
|
PVR_LOG(("Possible stalled client RGX contexts detected: %s%s%s%s%s%s%s%s%s",
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_GP),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TDM_2D),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TA),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_3D),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_CDM),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_RTU),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_SHG),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TQ2D),
|
|
RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TQ3D)));
|
|
|
|
PVR_LOG(("Trying to identify stalled context...(%s) [%d]",
|
|
pszStalledAction, bIgnorePrevious));
|
|
|
|
DumpStalledContextInfo(psDevInfo);
|
|
}
|
|
else
|
|
{
|
|
if (psDevInfo->ui32StalledClientMask> 0)
|
|
{
|
|
/* Indicate there are no stalled DMs */
|
|
PVR_LOG(("No further stalled client contexts exist"));
|
|
}
|
|
}
|
|
psDevInfo->ui32StalledClientMask = ui32StalledClientMask;
|
|
psDevInfo->pvEarliestStalledClientCCB = NULL;
|
|
}
|
|
OSLockRelease(psDevInfo->hCCBStallCheckLock);
|
|
}
|
|
|
|
/*
|
|
RGXUpdateHealthStatus
|
|
*/
|
|
PVRSRV_ERROR RGXUpdateHealthStatus(PVRSRV_DEVICE_NODE* psDevNode,
|
|
IMG_BOOL bCheckAfterTimePassed)
|
|
{
|
|
const PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData();
|
|
PVRSRV_DEVICE_HEALTH_STATUS eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_OK;
|
|
PVRSRV_DEVICE_HEALTH_REASON eNewReason = PVRSRV_DEVICE_HEALTH_REASON_NONE;
|
|
PVRSRV_RGXDEV_INFO* psDevInfo;
|
|
const RGXFWIF_TRACEBUF* psRGXFWIfTraceBufCtl;
|
|
const RGXFWIF_SYSDATA* psFwSysData;
|
|
const RGXFWIF_OSDATA* psFwOsData;
|
|
const RGXFWIF_CCB_CTL* psKCCBCtl;
|
|
IMG_UINT32 ui32ThreadCount;
|
|
IMG_BOOL bKCCBCmdsWaiting;
|
|
|
|
PVR_ASSERT(psDevNode != NULL);
|
|
psDevInfo = psDevNode->pvDevice;
|
|
|
|
/* If the firmware is not yet initialised or has already deinitialised, stop here */
|
|
if (psDevInfo == NULL || !psDevInfo->bFirmwareInitialised || psDevInfo->pvRegsBaseKM == NULL ||
|
|
psDevInfo->psDeviceNode == NULL || psDevInfo->psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_DEINIT)
|
|
{
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBufCtl;
|
|
psFwSysData = psDevInfo->psRGXFWIfFwSysData;
|
|
psFwOsData = psDevInfo->psRGXFWIfFwOsData;
|
|
|
|
/* If this is a quick update, then include the last current value... */
|
|
if (!bCheckAfterTimePassed)
|
|
{
|
|
eNewStatus = OSAtomicRead(&psDevNode->eHealthStatus);
|
|
eNewReason = OSAtomicRead(&psDevNode->eHealthReason);
|
|
}
|
|
|
|
/* Decrement the SLR holdoff counter (if non-zero) */
|
|
if (psDevInfo->ui32SLRHoldoffCounter > 0)
|
|
{
|
|
psDevInfo->ui32SLRHoldoffCounter--;
|
|
}
|
|
|
|
/* If Rogue is not powered on, just skip ahead and check for stalled client CCBs */
|
|
if (PVRSRVIsDevicePowered(psDevNode))
|
|
{
|
|
if (psRGXFWIfTraceBufCtl != NULL)
|
|
{
|
|
/*
|
|
Firmware thread checks...
|
|
*/
|
|
for (ui32ThreadCount = 0; ui32ThreadCount < RGXFW_THREAD_NUM; ui32ThreadCount++)
|
|
{
|
|
const IMG_CHAR* pszTraceAssertInfo = psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.szInfo;
|
|
|
|
/*
|
|
Check if the FW has hit an assert...
|
|
*/
|
|
if (*pszTraceAssertInfo != '\0')
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Firmware thread %d has asserted: %s (%s:%d)",
|
|
__func__, ui32ThreadCount, pszTraceAssertInfo,
|
|
psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.szPath,
|
|
psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.ui32LineNum));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_DEAD;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_ASSERTED;
|
|
goto _RGXUpdateHealthStatus_Exit;
|
|
}
|
|
|
|
/*
|
|
Check the threads to see if they are in the same poll locations as last time...
|
|
*/
|
|
if (bCheckAfterTimePassed)
|
|
{
|
|
if (psFwSysData->aui32CrPollAddr[ui32ThreadCount] != 0 &&
|
|
psFwSysData->aui32CrPollCount[ui32ThreadCount] == psDevInfo->aui32CrLastPollCount[ui32ThreadCount])
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Firmware stuck on CR poll: T%u polling %s (reg:0x%08X mask:0x%08X)",
|
|
__func__, ui32ThreadCount,
|
|
((psFwSysData->aui32CrPollAddr[ui32ThreadCount] & RGXFW_POLL_TYPE_SET)?("set"):("unset")),
|
|
psFwSysData->aui32CrPollAddr[ui32ThreadCount] & ~RGXFW_POLL_TYPE_SET,
|
|
psFwSysData->aui32CrPollMask[ui32ThreadCount]));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_POLL_FAILING;
|
|
goto _RGXUpdateHealthStatus_Exit;
|
|
}
|
|
psDevInfo->aui32CrLastPollCount[ui32ThreadCount] = psFwSysData->aui32CrPollCount[ui32ThreadCount];
|
|
}
|
|
}
|
|
|
|
/*
|
|
Check if the FW has faulted...
|
|
*/
|
|
if (psFwSysData->ui32HWRStateFlags & RGXFWIF_HWR_FW_FAULT)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING,
|
|
"%s: Firmware has faulted and needs to restart",
|
|
__func__));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_FAULT;
|
|
if (psFwSysData->ui32HWRStateFlags & RGXFWIF_HWR_RESTART_REQUESTED)
|
|
{
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_RESTARTING;
|
|
}
|
|
else
|
|
{
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_IDLING;
|
|
}
|
|
goto _RGXUpdateHealthStatus_Exit;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Event Object Timeouts check...
|
|
*/
|
|
if (!bCheckAfterTimePassed)
|
|
{
|
|
if (psDevInfo->ui32GEOTimeoutsLastTime > 1 && psPVRSRVData->ui32GEOConsecutiveTimeouts > psDevInfo->ui32GEOTimeoutsLastTime)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Global Event Object Timeouts have risen (from %d to %d)",
|
|
__func__,
|
|
psDevInfo->ui32GEOTimeoutsLastTime, psPVRSRVData->ui32GEOConsecutiveTimeouts));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_TIMEOUTS;
|
|
}
|
|
psDevInfo->ui32GEOTimeoutsLastTime = psPVRSRVData->ui32GEOConsecutiveTimeouts;
|
|
}
|
|
|
|
/*
|
|
Check the Kernel CCB pointer is valid. If any commands were waiting last time, then check
|
|
that some have executed since then.
|
|
*/
|
|
bKCCBCmdsWaiting = IMG_FALSE;
|
|
psKCCBCtl = psDevInfo->psKernelCCBCtl;
|
|
|
|
if (psKCCBCtl != NULL)
|
|
{
|
|
if (psKCCBCtl->ui32ReadOffset > psKCCBCtl->ui32WrapMask ||
|
|
psKCCBCtl->ui32WriteOffset > psKCCBCtl->ui32WrapMask)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: KCCB has invalid offset (ROFF=%d WOFF=%d)",
|
|
__func__, psKCCBCtl->ui32ReadOffset, psKCCBCtl->ui32WriteOffset));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_DEAD;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_QUEUE_CORRUPT;
|
|
}
|
|
|
|
if (psKCCBCtl->ui32ReadOffset != psKCCBCtl->ui32WriteOffset)
|
|
{
|
|
bKCCBCmdsWaiting = IMG_TRUE;
|
|
}
|
|
}
|
|
|
|
if (bCheckAfterTimePassed && psFwOsData != NULL)
|
|
{
|
|
IMG_UINT32 ui32KCCBCmdsExecuted = psFwOsData->ui32KCCBCmdsExecuted;
|
|
|
|
if (psDevInfo->ui32KCCBCmdsExecutedLastTime == ui32KCCBCmdsExecuted)
|
|
{
|
|
/*
|
|
If something was waiting last time then the Firmware has stopped processing commands.
|
|
*/
|
|
if (psDevInfo->bKCCBCmdsWaitingLastTime)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: No KCCB commands executed since check!",
|
|
__func__));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_QUEUE_STALLED;
|
|
}
|
|
|
|
/*
|
|
If no commands are currently pending and nothing happened since the last poll, then
|
|
schedule a dummy command to ping the firmware so we know it is alive and processing.
|
|
*/
|
|
if (!bKCCBCmdsWaiting)
|
|
{
|
|
/* Protect the PDumpLoadMem. RGXScheduleCommand() cannot take the
|
|
* PMR lock itself, because some bridge functions will take the PMR lock
|
|
* before calling RGXScheduleCommand
|
|
*/
|
|
PVRSRV_ERROR eError = RGXFWHealthCheckCmd(psDevNode->pvDevice);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Cannot schedule Health Check command! (0x%x)",
|
|
__func__, eError));
|
|
}
|
|
else
|
|
{
|
|
bKCCBCmdsWaiting = IMG_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
psDevInfo->bKCCBCmdsWaitingLastTime = bKCCBCmdsWaiting;
|
|
psDevInfo->ui32KCCBCmdsExecutedLastTime = ui32KCCBCmdsExecuted;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Interrupt counts check...
|
|
*/
|
|
if (bCheckAfterTimePassed && psFwOsData != NULL)
|
|
{
|
|
IMG_UINT32 ui32LISRCount = 0;
|
|
IMG_UINT32 ui32FWCount = 0;
|
|
IMG_UINT32 ui32MissingInts = 0;
|
|
|
|
/* Add up the total number of interrupts issued, sampled/received and missed... */
|
|
#if defined(RGX_FW_IRQ_OS_COUNTERS)
|
|
/* Only the Host OS has a sample count, so only one counter to check. */
|
|
ui32LISRCount += psDevInfo->aui32SampleIRQCount[RGXFW_HOST_OS];
|
|
ui32FWCount += OSReadHWReg32(psDevInfo->pvRegsBaseKM, gaui32FwOsIrqCntRegAddr[RGXFW_HOST_OS]);
|
|
#else
|
|
IMG_UINT32 ui32Index;
|
|
|
|
for (ui32Index = 0; ui32Index < RGXFW_THREAD_NUM; ui32Index++)
|
|
{
|
|
ui32LISRCount += psDevInfo->aui32SampleIRQCount[ui32Index];
|
|
ui32FWCount += psFwOsData->aui32InterruptCount[ui32Index];
|
|
}
|
|
#endif /* RGX_FW_IRQ_OS_COUNTERS */
|
|
|
|
if (ui32LISRCount < ui32FWCount)
|
|
{
|
|
ui32MissingInts = (ui32FWCount-ui32LISRCount);
|
|
}
|
|
|
|
if (ui32LISRCount == psDevInfo->ui32InterruptCountLastTime &&
|
|
ui32MissingInts >= psDevInfo->ui32MissingInterruptsLastTime &&
|
|
psDevInfo->ui32MissingInterruptsLastTime > 1)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: LISR has not received the last %d interrupts",
|
|
__func__, ui32MissingInts));
|
|
eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING;
|
|
eNewReason = PVRSRV_DEVICE_HEALTH_REASON_MISSING_INTERRUPTS;
|
|
|
|
/* Schedule the MISRs to help mitigate the problems of missing interrupts. */
|
|
OSScheduleMISR(psDevInfo->pvMISRData);
|
|
if (psDevInfo->pvAPMISRData != NULL)
|
|
{
|
|
OSScheduleMISR(psDevInfo->pvAPMISRData);
|
|
}
|
|
}
|
|
psDevInfo->ui32InterruptCountLastTime = ui32LISRCount;
|
|
psDevInfo->ui32MissingInterruptsLastTime = ui32MissingInts;
|
|
}
|
|
|
|
/*
|
|
Stalled CCB check...
|
|
*/
|
|
if (bCheckAfterTimePassed && (PVRSRV_DEVICE_HEALTH_STATUS_OK==eNewStatus))
|
|
{
|
|
RGXCheckForStalledClientContexts(psDevInfo, IMG_FALSE);
|
|
}
|
|
|
|
/* Notify client driver and system layer of any eNewStatus errors */
|
|
if (eNewStatus > PVRSRV_DEVICE_HEALTH_STATUS_OK)
|
|
{
|
|
/* Client notification of device error will be achieved by
|
|
* clients calling UM function RGXGetLastDeviceError() */
|
|
psDevInfo->eLastDeviceError = RGX_CONTEXT_RESET_REASON_HOST_WDG_FW_ERR;
|
|
|
|
/* Notify system layer */
|
|
{
|
|
PVRSRV_DEVICE_NODE *psDevNode = psDevInfo->psDeviceNode;
|
|
PVRSRV_DEVICE_CONFIG *psDevConfig = psDevNode->psDevConfig;
|
|
|
|
if (psDevConfig->pfnSysDevErrorNotify)
|
|
{
|
|
PVRSRV_ROBUSTNESS_NOTIFY_DATA sErrorData = {0};
|
|
|
|
sErrorData.eResetReason = RGX_CONTEXT_RESET_REASON_HOST_WDG_FW_ERR;
|
|
sErrorData.uErrData.sHostWdgData.ui32Status = (IMG_UINT32)eNewStatus;
|
|
sErrorData.uErrData.sHostWdgData.ui32Reason = (IMG_UINT32)eNewReason;
|
|
|
|
psDevConfig->pfnSysDevErrorNotify(psDevConfig,
|
|
&sErrorData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Finished, save the new status...
|
|
*/
|
|
_RGXUpdateHealthStatus_Exit:
|
|
OSAtomicWrite(&psDevNode->eHealthStatus, eNewStatus);
|
|
OSAtomicWrite(&psDevNode->eHealthReason, eNewReason);
|
|
RGXSRV_HWPERF_DEVICE_INFO(psDevInfo, RGX_HWPERF_DEV_INFO_EV_HEALTH, eNewStatus, eNewReason);
|
|
|
|
/*
|
|
* Attempt to service the HWPerf buffer to regularly transport idle/periodic
|
|
* packets to host buffer.
|
|
*/
|
|
if (psDevNode->pfnServiceHWPerf != NULL)
|
|
{
|
|
PVRSRV_ERROR eError = psDevNode->pfnServiceHWPerf(psDevNode);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: "
|
|
"Error occurred when servicing HWPerf buffer (%d)",
|
|
__func__, eError));
|
|
}
|
|
}
|
|
|
|
/* Attempt to refresh timer correlation data */
|
|
RGXTimeCorrRestartPeriodic(psDevNode);
|
|
|
|
return PVRSRV_OK;
|
|
} /* RGXUpdateHealthStatus */
|
|
|
|
#if defined(SUPPORT_AUTOVZ)
|
|
void RGXUpdateAutoVzWdgToken(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
if (likely(KM_FW_CONNECTION_IS(ACTIVE, psDevInfo) && KM_OS_CONNECTION_IS(ACTIVE, psDevInfo)))
|
|
{
|
|
/* read and write back the alive token value to confirm to the
|
|
* virtualisation watchdog that this connection is healthy */
|
|
KM_SET_OS_ALIVE_TOKEN(KM_GET_FW_ALIVE_TOKEN(psDevInfo), psDevInfo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
RGXUpdateAutoVzWatchdog
|
|
*/
|
|
void RGXUpdateAutoVzWatchdog(PVRSRV_DEVICE_NODE* psDevNode)
|
|
{
|
|
if (likely(psDevNode != NULL))
|
|
{
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDevNode->pvDevice;
|
|
|
|
if (unlikely((psDevInfo == NULL || !psDevInfo->bFirmwareInitialised || !psDevInfo->bRGXPowered ||
|
|
psDevInfo->pvRegsBaseKM == NULL || psDevNode->eDevState == PVRSRV_DEVICE_STATE_DEINIT)))
|
|
{
|
|
/* If the firmware is not initialised, stop here */
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRVPowerLock(psDevNode);
|
|
PVR_LOG_RETURN_VOID_IF_ERROR(eError, "PVRSRVPowerLock");
|
|
|
|
RGXUpdateAutoVzWdgToken(psDevInfo);
|
|
PVRSRVPowerUnlock(psDevNode);
|
|
}
|
|
}
|
|
}
|
|
#endif /* SUPPORT_AUTOVZ */
|
|
|
|
PVRSRV_ERROR CheckStalledClientCommonContext(RGX_SERVER_COMMON_CONTEXT *psCurrentServerCommonContext, RGX_KICK_TYPE_DM eKickTypeDM)
|
|
{
|
|
if (psCurrentServerCommonContext == NULL)
|
|
{
|
|
/* the context has already been freed so there is nothing to do here */
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
return CheckForStalledCCB(psCurrentServerCommonContext->psDevInfo->psDeviceNode,
|
|
psCurrentServerCommonContext->psClientCCB,
|
|
eKickTypeDM);
|
|
}
|
|
|
|
void DumpFWCommonContextInfo(RGX_SERVER_COMMON_CONTEXT *psCurrentServerCommonContext,
|
|
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
|
void *pvDumpDebugFile,
|
|
IMG_UINT32 ui32VerbLevel)
|
|
{
|
|
if (psCurrentServerCommonContext == NULL)
|
|
{
|
|
/* the context has already been freed so there is nothing to do here */
|
|
return;
|
|
}
|
|
|
|
if (DD_VERB_LVL_ENABLED(ui32VerbLevel, DEBUG_REQUEST_VERBOSITY_HIGH))
|
|
{
|
|
/* If high verbosity requested, dump whole CCB */
|
|
DumpCCB(psCurrentServerCommonContext->psDevInfo,
|
|
psCurrentServerCommonContext->sFWCommonContextFWAddr,
|
|
psCurrentServerCommonContext->psClientCCB,
|
|
pfnDumpDebugPrintf,
|
|
pvDumpDebugFile);
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, only dump first stalled command in the CCB */
|
|
DumpStalledCCBCommand(psCurrentServerCommonContext->sFWCommonContextFWAddr,
|
|
psCurrentServerCommonContext->psClientCCB,
|
|
pfnDumpDebugPrintf,
|
|
pvDumpDebugFile);
|
|
}
|
|
}
|
|
|
|
PVRSRV_ERROR AttachKickResourcesCleanupCtls(PRGXFWIF_CLEANUP_CTL *apsCleanupCtl,
|
|
IMG_UINT32 *pui32NumCleanupCtl,
|
|
RGXFWIF_DM eDM,
|
|
IMG_BOOL bKick,
|
|
RGX_KM_HW_RT_DATASET *psKMHWRTDataSet,
|
|
RGX_ZSBUFFER_DATA *psZSBuffer,
|
|
RGX_ZSBUFFER_DATA *psMSAAScratchBuffer)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
PRGXFWIF_CLEANUP_CTL *psCleanupCtlWrite = apsCleanupCtl;
|
|
|
|
PVR_ASSERT((eDM == RGXFWIF_DM_GEOM) || (eDM == RGXFWIF_DM_3D));
|
|
PVR_RETURN_IF_INVALID_PARAM((eDM == RGXFWIF_DM_GEOM) || (eDM == RGXFWIF_DM_3D));
|
|
|
|
if (bKick)
|
|
{
|
|
if (psKMHWRTDataSet)
|
|
{
|
|
PRGXFWIF_CLEANUP_CTL psCleanupCtl;
|
|
|
|
eError = RGXSetFirmwareAddress(&psCleanupCtl, psKMHWRTDataSet->psHWRTDataFwMemDesc,
|
|
offsetof(RGXFWIF_HWRTDATA, sCleanupState),
|
|
RFW_FWADDR_NOREF_FLAG);
|
|
PVR_RETURN_IF_ERROR(eError);
|
|
|
|
*(psCleanupCtlWrite++) = psCleanupCtl;
|
|
}
|
|
|
|
if (eDM == RGXFWIF_DM_3D)
|
|
{
|
|
RGXFWIF_PRBUFFER_TYPE eBufferType;
|
|
RGX_ZSBUFFER_DATA *psBuffer = NULL;
|
|
|
|
for (eBufferType = RGXFWIF_PRBUFFER_START; eBufferType < RGXFWIF_PRBUFFER_MAXSUPPORTED; eBufferType++)
|
|
{
|
|
switch (eBufferType)
|
|
{
|
|
case RGXFWIF_PRBUFFER_ZSBUFFER:
|
|
psBuffer = psZSBuffer;
|
|
break;
|
|
case RGXFWIF_PRBUFFER_MSAABUFFER:
|
|
psBuffer = psMSAAScratchBuffer;
|
|
break;
|
|
case RGXFWIF_PRBUFFER_MAXSUPPORTED:
|
|
psBuffer = NULL;
|
|
break;
|
|
}
|
|
if (psBuffer)
|
|
{
|
|
(psCleanupCtlWrite++)->ui32Addr = psBuffer->sZSBufferFWDevVAddr.ui32Addr +
|
|
offsetof(RGXFWIF_PRBUFFER, sCleanupState);
|
|
psBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*pui32NumCleanupCtl = psCleanupCtlWrite - apsCleanupCtl;
|
|
PVR_ASSERT(*pui32NumCleanupCtl <= RGXFWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS);
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXResetHWRLogs(PVRSRV_DEVICE_NODE *psDevNode)
|
|
{
|
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
RGXFWIF_HWRINFOBUF *psHWRInfoBuf;
|
|
IMG_UINT32 i;
|
|
|
|
if (psDevNode->pvDevice == NULL)
|
|
{
|
|
return PVRSRV_ERROR_INVALID_DEVINFO;
|
|
}
|
|
psDevInfo = psDevNode->pvDevice;
|
|
|
|
psHWRInfoBuf = psDevInfo->psRGXFWIfHWRInfoBufCtl;
|
|
|
|
for (i = 0 ; i < RGXFWIF_DM_MAX ; i++)
|
|
{
|
|
/* Reset the HWR numbers */
|
|
psHWRInfoBuf->aui32HwrDmLockedUpCount[i] = 0;
|
|
psHWRInfoBuf->aui32HwrDmFalseDetectCount[i] = 0;
|
|
psHWRInfoBuf->aui32HwrDmRecoveredCount[i] = 0;
|
|
psHWRInfoBuf->aui32HwrDmOverranCount[i] = 0;
|
|
}
|
|
|
|
for (i = 0 ; i < RGXFWIF_HWINFO_MAX ; i++)
|
|
{
|
|
psHWRInfoBuf->sHWRInfo[i].ui32HWRNumber = 0;
|
|
}
|
|
|
|
psHWRInfoBuf->ui32WriteIndex = 0;
|
|
psHWRInfoBuf->ui32DDReqCount = 0;
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXGetPhyAddr(PMR *psPMR,
|
|
IMG_DEV_PHYADDR *psPhyAddr,
|
|
IMG_UINT32 ui32LogicalOffset,
|
|
IMG_UINT32 ui32Log2PageSize,
|
|
IMG_UINT32 ui32NumOfPages,
|
|
IMG_BOOL *bValid)
|
|
{
|
|
|
|
PVRSRV_ERROR eError;
|
|
|
|
eError = PMRLockSysPhysAddresses(psPMR);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: PMRLockSysPhysAddresses failed (%u)",
|
|
__func__,
|
|
eError));
|
|
return eError;
|
|
}
|
|
|
|
eError = PMR_DevPhysAddr(psPMR,
|
|
ui32Log2PageSize,
|
|
ui32NumOfPages,
|
|
ui32LogicalOffset,
|
|
psPhyAddr,
|
|
bValid);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: PMR_DevPhysAddr failed (%u)",
|
|
__func__,
|
|
eError));
|
|
return eError;
|
|
}
|
|
|
|
|
|
eError = PMRUnlockSysPhysAddresses(psPMR);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: PMRUnLockSysPhysAddresses failed (%u)",
|
|
__func__,
|
|
eError));
|
|
return eError;
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
#if defined(PDUMP)
|
|
PVRSRV_ERROR RGXPdumpDrainKCCB(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32WriteOffset)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
|
|
if (psDevInfo->bDumpedKCCBCtlAlready)
|
|
{
|
|
/* exiting capture range or pdump block */
|
|
psDevInfo->bDumpedKCCBCtlAlready = IMG_FALSE;
|
|
|
|
/* make sure previous cmd is drained in pdump in case we will 'jump' over some future cmds */
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode,
|
|
PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_POWER,
|
|
"kCCB(%p): Draining rgxfw_roff (0x%x) == woff (0x%x)",
|
|
psDevInfo->psKernelCCBCtl,
|
|
ui32WriteOffset,
|
|
ui32WriteOffset);
|
|
eError = DevmemPDumpDevmemPol32(psDevInfo->psKernelCCBCtlMemDesc,
|
|
offsetof(RGXFWIF_CCB_CTL, ui32ReadOffset),
|
|
ui32WriteOffset,
|
|
0xffffffff,
|
|
PDUMP_POLL_OPERATOR_EQUAL,
|
|
PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_POWER);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: problem pdumping POL for kCCBCtl (%d)", __func__, eError));
|
|
}
|
|
}
|
|
|
|
return eError;
|
|
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
|
|
@Function RGXClientConnectCompatCheck_ClientAgainstFW
|
|
|
|
@Description
|
|
|
|
Check compatibility of client and firmware (build options)
|
|
at the connection time.
|
|
|
|
@Input psDeviceNode - device node
|
|
@Input ui32ClientBuildOptions - build options for the client
|
|
|
|
@Return PVRSRV_ERROR - depending on mismatch found
|
|
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXClientConnectCompatCheck_ClientAgainstFW(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32ClientBuildOptions)
|
|
{
|
|
#if !defined(NO_HARDWARE) || defined(PDUMP)
|
|
#if !defined(NO_HARDWARE)
|
|
IMG_UINT32 ui32BuildOptionsMismatch;
|
|
IMG_UINT32 ui32BuildOptionsFW;
|
|
#endif
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
#endif
|
|
PVRSRV_VZ_RET_IF_MODE(GUEST, PVRSRV_OK);
|
|
|
|
#if !defined(NO_HARDWARE)
|
|
if (psDevInfo == NULL || psDevInfo->psRGXFWIfOsInitMemDesc == NULL)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: Cannot acquire kernel fw compatibility check info, RGXFWIF_OSINIT structure not allocated.",
|
|
__func__));
|
|
return PVRSRV_ERROR_NOT_INITIALISED;
|
|
}
|
|
|
|
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
|
|
{
|
|
if (*((volatile IMG_BOOL *) &psDevInfo->psRGXFWIfOsInit->sRGXCompChecks.bUpdated))
|
|
{
|
|
/* No need to wait if the FW has already updated the values */
|
|
break;
|
|
}
|
|
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
|
|
} END_LOOP_UNTIL_TIMEOUT();
|
|
#endif
|
|
|
|
#if defined(PDUMP)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
|
|
PDUMPCOMMENT(psDeviceNode, "Compatibility check: client and FW build options");
|
|
eError = DevmemPDumpDevmemPol32(psDevInfo->psRGXFWIfOsInitMemDesc,
|
|
offsetof(RGXFWIF_OSINIT, sRGXCompChecks) +
|
|
offsetof(RGXFWIF_COMPCHECKS, ui32BuildOptions),
|
|
ui32ClientBuildOptions,
|
|
0xffffffff,
|
|
PDUMP_POLL_OPERATOR_EQUAL,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR,
|
|
"%s: problem pdumping POL for psRGXFWIfOsInitMemDesc (%d)",
|
|
__func__,
|
|
eError));
|
|
return eError;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(NO_HARDWARE)
|
|
ui32BuildOptionsFW = psDevInfo->psRGXFWIfOsInit->sRGXCompChecks.ui32BuildOptions;
|
|
ui32BuildOptionsMismatch = ui32ClientBuildOptions ^ ui32BuildOptionsFW;
|
|
|
|
if (ui32BuildOptionsMismatch != 0)
|
|
{
|
|
if ((ui32ClientBuildOptions & ui32BuildOptionsMismatch) != 0)
|
|
{
|
|
PVR_LOG(("(FAIL) RGXDevInitCompatCheck: Mismatch in Firmware and client build options; "
|
|
"extra options present in client: (0x%x). Please check rgx_options.h",
|
|
ui32ClientBuildOptions & ui32BuildOptionsMismatch ));
|
|
}
|
|
|
|
if ((ui32BuildOptionsFW & ui32BuildOptionsMismatch) != 0)
|
|
{
|
|
PVR_LOG(("(FAIL) RGXDevInitCompatCheck: Mismatch in Firmware and client build options; "
|
|
"extra options present in Firmware: (0x%x). Please check rgx_options.h",
|
|
ui32BuildOptionsFW & ui32BuildOptionsMismatch ));
|
|
}
|
|
|
|
return PVRSRV_ERROR_BUILD_OPTIONS_MISMATCH;
|
|
}
|
|
else
|
|
{
|
|
PVR_DPF((PVR_DBG_MESSAGE, "%s: Firmware and client build options match. [ OK ]", __func__));
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
|
|
@Function RGXFwRawHeapAllocMap
|
|
|
|
@Description Register firmware heap for the specified guest OSID
|
|
|
|
@Input psDeviceNode - device node
|
|
@Input ui32OSID - Guest OSID
|
|
@Input sDevPAddr - Heap address
|
|
@Input ui64DevPSize - Heap size
|
|
|
|
@Return PVRSRV_ERROR - PVRSRV_OK if heap setup was successful.
|
|
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXFwRawHeapAllocMap(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
IMG_UINT32 ui32OSID,
|
|
IMG_DEV_PHYADDR sDevPAddr,
|
|
IMG_UINT64 ui64DevPSize)
|
|
{
|
|
PVRSRV_ERROR eError;
|
|
IMG_CHAR szRegionRAName[RA_MAX_NAME_LENGTH];
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
PVRSRV_MEMALLOCFLAGS_T uiRawFwHeapAllocFlags = (RGX_FWSHAREDMEM_GPU_ONLY_ALLOCFLAGS |
|
|
PVRSRV_MEMALLOCFLAG_PHYS_HEAP_HINT(FW_PREMAP0 + ui32OSID));
|
|
PHYS_HEAP_CONFIG *psFwMainConfig = FindPhysHeapConfig(psDeviceNode->psDevConfig,
|
|
PHYS_HEAP_USAGE_FW_MAIN);
|
|
PHYS_HEAP_CONFIG sFwHeapConfig;
|
|
|
|
PVRSRV_VZ_RET_IF_NOT_MODE(HOST, PVRSRV_OK);
|
|
|
|
if (psFwMainConfig == NULL)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "FW_MAIN heap config not found."));
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
OSSNPrintf(szRegionRAName, sizeof(szRegionRAName), RGX_FIRMWARE_GUEST_RAW_HEAP_IDENT, ui32OSID);
|
|
|
|
if (!ui64DevPSize ||
|
|
!sDevPAddr.uiAddr ||
|
|
ui32OSID >= RGX_NUM_OS_SUPPORTED ||
|
|
ui64DevPSize != RGX_FIRMWARE_RAW_HEAP_SIZE)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "Invalid parameters for %s", szRegionRAName));
|
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
|
}
|
|
|
|
sFwHeapConfig = *psFwMainConfig;
|
|
sFwHeapConfig.sStartAddr.uiAddr = 0;
|
|
sFwHeapConfig.sCardBase.uiAddr = sDevPAddr.uiAddr;
|
|
sFwHeapConfig.uiSize = RGX_FIRMWARE_RAW_HEAP_SIZE;
|
|
sFwHeapConfig.eType = PHYS_HEAP_TYPE_LMA;
|
|
|
|
eError = PhysmemCreateHeapLMA(psDeviceNode, &sFwHeapConfig, szRegionRAName, &psDeviceNode->apsFWPremapPhysHeap[ui32OSID]);
|
|
PVR_LOG_RETURN_IF_ERROR_VA(eError, "PhysmemCreateHeapLMA:PREMAP [%d]", ui32OSID);
|
|
|
|
eError = PhysHeapAcquire(psDeviceNode->apsFWPremapPhysHeap[ui32OSID]);
|
|
PVR_LOG_RETURN_IF_ERROR_VA(eError, "PhysHeapAcquire:PREMAP [%d]", ui32OSID);
|
|
|
|
psDeviceNode->apsPhysHeap[PVRSRV_PHYS_HEAP_FW_PREMAP0 + ui32OSID] = psDeviceNode->apsFWPremapPhysHeap[ui32OSID];
|
|
|
|
PDUMPCOMMENT(psDeviceNode, "Allocate and map raw firmware heap for OSID: [%d]", ui32OSID);
|
|
|
|
#if (RGX_NUM_OS_SUPPORTED > 1)
|
|
/* don't clear the heap of other guests on allocation */
|
|
uiRawFwHeapAllocFlags &= (ui32OSID > RGXFW_HOST_OS) ? (~PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC) : (~0ULL);
|
|
#endif
|
|
|
|
/* if the firmware is already powered up, consider the firmware heaps are pre-mapped. */
|
|
if (psDeviceNode->bAutoVzFwIsUp)
|
|
{
|
|
uiRawFwHeapAllocFlags &= RGX_AUTOVZ_KEEP_FW_DATA_MASK(psDeviceNode->bAutoVzFwIsUp);
|
|
DevmemHeapSetPremapStatus(psDevInfo->psGuestFirmwareRawHeap[ui32OSID], IMG_TRUE);
|
|
}
|
|
|
|
eError = DevmemFwAllocate(psDevInfo,
|
|
RGX_FIRMWARE_RAW_HEAP_SIZE,
|
|
uiRawFwHeapAllocFlags,
|
|
psDevInfo->psGuestFirmwareRawHeap[ui32OSID]->pszName,
|
|
&psDevInfo->psGuestFirmwareRawMemDesc[ui32OSID]);
|
|
PVR_LOG_RETURN_IF_ERROR(eError, "DevmemFwAllocate");
|
|
|
|
/* Mark this devmem heap as premapped so allocations will not require device mapping. */
|
|
DevmemHeapSetPremapStatus(psDevInfo->psGuestFirmwareRawHeap[ui32OSID], IMG_TRUE);
|
|
|
|
if (ui32OSID == RGXFW_HOST_OS)
|
|
{
|
|
/* if the Host's raw fw heap is premapped, mark its main & config sub-heaps accordingly
|
|
* No memory allocated from these sub-heaps will be individually mapped into the device's
|
|
* address space so they can remain marked permanently as premapped. */
|
|
DevmemHeapSetPremapStatus(psDevInfo->psFirmwareMainHeap, IMG_TRUE);
|
|
DevmemHeapSetPremapStatus(psDevInfo->psFirmwareConfigHeap, IMG_TRUE);
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
|
|
@Function RGXFwRawHeapUnmapFree
|
|
|
|
@Description Unregister firmware heap for the specified guest OSID
|
|
|
|
@Input psDeviceNode - device node
|
|
@Input ui32OSID - Guest OSID
|
|
|
|
******************************************************************************/
|
|
void RGXFwRawHeapUnmapFree(PVRSRV_DEVICE_NODE *psDeviceNode,
|
|
IMG_UINT32 ui32OSID)
|
|
{
|
|
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
|
|
|
|
/* remove the premap status, so the heap can be unmapped and freed */
|
|
if (psDevInfo->psGuestFirmwareRawHeap[ui32OSID])
|
|
{
|
|
DevmemHeapSetPremapStatus(psDevInfo->psGuestFirmwareRawHeap[ui32OSID], IMG_FALSE);
|
|
}
|
|
|
|
if (psDevInfo->psGuestFirmwareRawMemDesc[ui32OSID])
|
|
{
|
|
DevmemFwUnmapAndFree(psDevInfo, psDevInfo->psGuestFirmwareRawMemDesc[ui32OSID]);
|
|
psDevInfo->psGuestFirmwareRawMemDesc[ui32OSID] = NULL;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvHalt
|
|
|
|
@Description Halt the RISC-V FW core (required for certain operations
|
|
done through Debug Module)
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvHalt(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode,
|
|
PDUMP_FLAGS_CONTINUOUS, "Halt RISC-V FW");
|
|
|
|
/* Send halt request (no need to select one or more harts on this RISC-V core) */
|
|
PDUMPREG32(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_HALTREQ_EN |
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until hart is halted */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLHALTED_EN,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLHALTED_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
/* Clear halt request */
|
|
PDUMPREG32(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Send halt request (no need to select one or more harts on this RISC-V core) */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_HALTREQ_EN |
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN);
|
|
|
|
/* Wait until hart is halted */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_DMSTATUS/sizeof(IMG_UINT32),
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLHALTED_EN,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLHALTED_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Hart not halted (0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMSTATUS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
/* Clear halt request */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN);
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvIsHalted
|
|
|
|
@Description Check if the RISC-V FW is halted
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
|
|
@Return IMG_BOOL
|
|
******************************************************************************/
|
|
IMG_BOOL RGXRiscvIsHalted(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
#if defined(NO_HARDWARE)
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
/* Assume the core is always halted in nohw */
|
|
return IMG_TRUE;
|
|
#else
|
|
|
|
return (OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMSTATUS) &
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLHALTED_EN) != 0U;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvResume
|
|
|
|
@Description Resume the RISC-V FW core
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvResume(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode,
|
|
PDUMP_FLAGS_CONTINUOUS, "Resume RISC-V FW");
|
|
|
|
/* Send resume request (no need to select one or more harts on this RISC-V core) */
|
|
PDUMPREG32(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_RESUMEREQ_EN |
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until hart is resumed */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLRESUMEACK_EN,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLRESUMEACK_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
/* Clear resume request */
|
|
PDUMPREG32(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Send resume request (no need to select one or more harts on this RISC-V core) */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_RESUMEREQ_EN |
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN);
|
|
|
|
/* Wait until hart is resumed */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_DMSTATUS/sizeof(IMG_UINT32),
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLRESUMEACK_EN,
|
|
RGX_CR_FWCORE_DMI_DMSTATUS_ALLRESUMEACK_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Hart not resumed (0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMSTATUS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
/* Clear resume request */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DMCONTROL,
|
|
RGX_CR_FWCORE_DMI_DMCONTROL_DMACTIVE_EN);
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvCheckAbstractCmdError
|
|
|
|
@Description Check for RISC-V abstract command errors and clear them
|
|
|
|
@Input psDevInfo Pointer to GPU device info
|
|
|
|
@Return RGXRISCVFW_ABSTRACT_CMD_ERR
|
|
******************************************************************************/
|
|
static RGXRISCVFW_ABSTRACT_CMD_ERR RGXRiscvCheckAbstractCmdError(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXRISCVFW_ABSTRACT_CMD_ERR eCmdErr;
|
|
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
eCmdErr = RISCV_ABSTRACT_CMD_NO_ERROR;
|
|
|
|
/* Check error status */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
RISCV_ABSTRACT_CMD_NO_ERROR << RGX_CR_FWCORE_DMI_ABSTRACTCS_CMDERR_SHIFT,
|
|
~RGX_CR_FWCORE_DMI_ABSTRACTCS_CMDERR_CLRMSK,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
#else
|
|
void __iomem *pvRegsBaseKM = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Check error status */
|
|
eCmdErr = (OSReadHWReg32(pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS)
|
|
& ~RGX_CR_FWCORE_DMI_ABSTRACTCS_CMDERR_CLRMSK)
|
|
>> RGX_CR_FWCORE_DMI_ABSTRACTCS_CMDERR_SHIFT;
|
|
|
|
if (eCmdErr != RISCV_ABSTRACT_CMD_NO_ERROR)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "RISC-V FW abstract command error %u", eCmdErr));
|
|
|
|
/* Clear the error (note CMDERR field is write-1-to-clear) */
|
|
OSWriteHWReg32(pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
~RGX_CR_FWCORE_DMI_ABSTRACTCS_CMDERR_CLRMSK);
|
|
}
|
|
#endif
|
|
|
|
return eCmdErr;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvReadReg
|
|
|
|
@Description Read a value from the given RISC-V register (GPR or CSR)
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32RegAddr RISC-V register address
|
|
|
|
@Output pui32Value Read value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvReadReg(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32RegAddr,
|
|
IMG_UINT32 *pui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32RegAddr);
|
|
PVR_UNREFERENCED_PARAMETER(pui32Value);
|
|
|
|
/* Reading HW registers is not supported in nohw/pdump */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Send abstract register read command */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_REGISTER << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_READ |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT |
|
|
ui32RegAddr);
|
|
|
|
/* Wait until abstract command is completed */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_ABSTRACTCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Abstract command did not complete in time (abstractcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
if (RGXRiscvCheckAbstractCmdError(psDevInfo) == RISCV_ABSTRACT_CMD_NO_ERROR)
|
|
{
|
|
/* Read register value */
|
|
*pui32Value = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA0);
|
|
}
|
|
else
|
|
{
|
|
*pui32Value = 0U;
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvPollReg
|
|
|
|
@Description Poll for a value from the given RISC-V register (GPR or CSR)
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32RegAddr RISC-V register address
|
|
@Input ui32Value Expected value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvPollReg(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32RegAddr,
|
|
IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Poll RISC-V register 0x%x (expected 0x%08x)",
|
|
ui32RegAddr, ui32Value);
|
|
|
|
/* Send abstract register read command */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_REGISTER << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_READ |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT |
|
|
ui32RegAddr,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until abstract command is completed */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
RGXRiscvCheckAbstractCmdError(psDevInfo);
|
|
|
|
/* Check read value */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_DATA0,
|
|
ui32Value,
|
|
0xFFFFFFFF,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
return PVRSRV_OK;
|
|
#else
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32RegAddr);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Value);
|
|
|
|
/* Polling HW registers is currently not required driverlive */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvWriteReg
|
|
|
|
@Description Write a value to the given RISC-V register (GPR or CSR)
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32RegAddr RISC-V register address
|
|
@Input ui32Value Write value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvWriteReg(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32RegAddr,
|
|
IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Write RISC-V register 0x%x (value 0x%08x)",
|
|
ui32RegAddr, ui32Value);
|
|
|
|
/* Prepare data to be written to register */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DATA0,
|
|
ui32Value, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Send abstract register write command */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_REGISTER << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_WRITE |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT |
|
|
ui32RegAddr,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until abstract command is completed */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Prepare data to be written to register */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA0, ui32Value);
|
|
|
|
/* Send abstract register write command */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_REGISTER << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_WRITE |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT |
|
|
ui32RegAddr);
|
|
|
|
/* Wait until abstract command is completed */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_ABSTRACTCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Abstract command did not complete in time (abstractcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvCheckSysBusError
|
|
|
|
@Description Check for RISC-V system bus errors and clear them
|
|
|
|
@Input psDevInfo Pointer to GPU device info
|
|
|
|
@Return RGXRISCVFW_SYSBUS_ERR
|
|
******************************************************************************/
|
|
static __maybe_unused RGXRISCVFW_SYSBUS_ERR RGXRiscvCheckSysBusError(PVRSRV_RGXDEV_INFO *psDevInfo)
|
|
{
|
|
RGXRISCVFW_SYSBUS_ERR eSBError;
|
|
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
eSBError = RISCV_SYSBUS_NO_ERROR;
|
|
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_SBCS,
|
|
RISCV_SYSBUS_NO_ERROR << RGX_CR_FWCORE_DMI_SBCS_SBERROR_SHIFT,
|
|
~RGX_CR_FWCORE_DMI_SBCS_SBERROR_CLRMSK,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
#else
|
|
void __iomem *pvRegsBaseKM = psDevInfo->pvRegsBaseKM;
|
|
|
|
eSBError = (OSReadHWReg32(pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBCS)
|
|
& ~RGX_CR_FWCORE_DMI_SBCS_SBERROR_CLRMSK)
|
|
>> RGX_CR_FWCORE_DMI_SBCS_SBERROR_SHIFT;
|
|
|
|
if (eSBError != RISCV_SYSBUS_NO_ERROR)
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "RISC-V FW system bus error %u", eSBError));
|
|
|
|
/* Clear the error (note SBERROR field is write-1-to-clear) */
|
|
OSWriteHWReg32(pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBCS,
|
|
~RGX_CR_FWCORE_DMI_SBCS_SBERROR_CLRMSK);
|
|
}
|
|
#endif
|
|
|
|
return eSBError;
|
|
}
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvReadAbstractMem
|
|
|
|
@Description Read a value at the given address in RISC-V memory space
|
|
using RISC-V abstract memory commands
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
|
|
@Output pui32Value Read value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvReadAbstractMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 *pui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Addr);
|
|
PVR_UNREFERENCED_PARAMETER(pui32Value);
|
|
|
|
/* Reading memory is not supported in nohw/pdump */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Prepare read address */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA1, ui32Addr);
|
|
|
|
/* Send abstract memory read command */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_MEMORY << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_READ |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT);
|
|
|
|
/* Wait until abstract command is completed */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_ABSTRACTCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Abstract command did not complete in time (abstractcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
if (RGXRiscvCheckAbstractCmdError(psDevInfo) == RISCV_ABSTRACT_CMD_NO_ERROR)
|
|
{
|
|
/* Read memory value */
|
|
*pui32Value = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA0);
|
|
}
|
|
else
|
|
{
|
|
*pui32Value = 0U;
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
#endif
|
|
}
|
|
#endif /* !defined(EMULATOR) */
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvPollAbstractMem
|
|
|
|
@Description Poll for a value at the given address in RISC-V memory space
|
|
using RISC-V abstract memory commands
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Expected value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvPollAbstractMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Poll RISC-V address 0x%x (expected 0x%08x)",
|
|
ui32Addr, ui32Value);
|
|
|
|
/* Prepare read address */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DATA1,
|
|
ui32Addr, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Send abstract memory read command */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_MEMORY << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_READ |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until abstract command is completed */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
RGXRiscvCheckAbstractCmdError(psDevInfo);
|
|
|
|
/* Check read value */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_DATA0,
|
|
ui32Value,
|
|
0xFFFFFFFF,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
return PVRSRV_OK;
|
|
#else
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Addr);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Value);
|
|
|
|
/* Polling memory is currently not required driverlive */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#endif
|
|
}
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvReadSysBusMem
|
|
|
|
@Description Read a value at the given address in RISC-V memory space
|
|
using the RISC-V system bus
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
|
|
@Output pui32Value Read value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvReadSysBusMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 *pui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Addr);
|
|
PVR_UNREFERENCED_PARAMETER(pui32Value);
|
|
|
|
/* Reading memory is not supported in nohw/pdump */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Configure system bus to read 32 bit every time a new address is provided */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_SBCS,
|
|
(RGXRISCVFW_DMI_SBCS_SBACCESS_32BIT << RGX_CR_FWCORE_DMI_SBCS_SBACCESS_SHIFT) |
|
|
RGX_CR_FWCORE_DMI_SBCS_SBREADONADDR_EN);
|
|
|
|
/* Perform read */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBADDRESS0, ui32Addr);
|
|
|
|
/* Wait until system bus is idle */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_SBCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_SBCS_SBBUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: System Bus did not go idle in time (sbcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
if (RGXRiscvCheckSysBusError(psDevInfo) == RISCV_SYSBUS_NO_ERROR)
|
|
{
|
|
/* Read value from debug system bus */
|
|
*pui32Value = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBDATA0);
|
|
}
|
|
else
|
|
{
|
|
*pui32Value = 0U;
|
|
}
|
|
|
|
return PVRSRV_OK;
|
|
#endif
|
|
}
|
|
#endif /* !defined(EMULATOR) */
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvPollSysBusMem
|
|
|
|
@Description Poll for a value at the given address in RISC-V memory space
|
|
using the RISC-V system bus
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Expected value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvPollSysBusMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Poll RISC-V address 0x%x (expected 0x%08x)",
|
|
ui32Addr, ui32Value);
|
|
|
|
/* Configure system bus to read 32 bit every time a new address is provided */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_SBCS,
|
|
(RGXRISCVFW_DMI_SBCS_SBACCESS_32BIT << RGX_CR_FWCORE_DMI_SBCS_SBACCESS_SHIFT) |
|
|
RGX_CR_FWCORE_DMI_SBCS_SBREADONADDR_EN,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Perform read */
|
|
PDUMPREG32(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_SBADDRESS0,
|
|
ui32Addr,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until system bus is idle */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_SBCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_SBCS_SBBUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
RGXRiscvCheckSysBusError(psDevInfo);
|
|
|
|
/* Check read value */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_SBDATA0,
|
|
ui32Value,
|
|
0xFFFFFFFF,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
|
return PVRSRV_OK;
|
|
#else
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Addr);
|
|
PVR_UNREFERENCED_PARAMETER(ui32Value);
|
|
|
|
/* Polling memory is currently not required driverlive */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#endif
|
|
}
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvReadMem
|
|
|
|
@Description Read a value at the given address in RISC-V memory space
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
|
|
@Output pui32Value Read value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXRiscvReadMem(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32Addr,
|
|
IMG_UINT32 *pui32Value)
|
|
{
|
|
if (ui32Addr >= RGXRISCVFW_COREMEM_BASE && ui32Addr <= RGXRISCVFW_COREMEM_END)
|
|
{
|
|
return RGXRiscvReadAbstractMem(psDevInfo, ui32Addr, pui32Value);
|
|
}
|
|
|
|
return RGXRiscvReadSysBusMem(psDevInfo, ui32Addr, pui32Value);
|
|
}
|
|
#endif /* !defined(EMULATOR) */
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvPollMem
|
|
|
|
@Description Poll a value at the given address in RISC-V memory space
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Expected value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvPollMem(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32Addr,
|
|
IMG_UINT32 ui32Value)
|
|
{
|
|
if (ui32Addr >= RGXRISCVFW_COREMEM_BASE && ui32Addr <= RGXRISCVFW_COREMEM_END)
|
|
{
|
|
return RGXRiscvPollAbstractMem(psDevInfo, ui32Addr, ui32Value);
|
|
}
|
|
|
|
return RGXRiscvPollSysBusMem(psDevInfo, ui32Addr, ui32Value);
|
|
}
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvWriteAbstractMem
|
|
|
|
@Description Write a value at the given address in RISC-V memory space
|
|
using RISC-V abstract memory commands
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Write value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvWriteAbstractMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Write RISC-V address 0x%x (value 0x%08x)",
|
|
ui32Addr, ui32Value);
|
|
|
|
/* Prepare write address */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DATA1,
|
|
ui32Addr, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Prepare write data */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_DATA0,
|
|
ui32Value, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Send abstract register write command */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_MEMORY << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_WRITE |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until abstract command is completed */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Prepare write address */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA1, ui32Addr);
|
|
|
|
/* Prepare write data */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_DATA0, ui32Value);
|
|
|
|
/* Send abstract memory write command */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_COMMAND,
|
|
(RGXRISCVFW_DMI_COMMAND_ACCESS_MEMORY << RGX_CR_FWCORE_DMI_COMMAND_CMDTYPE_SHIFT) |
|
|
RGXRISCVFW_DMI_COMMAND_WRITE |
|
|
RGXRISCVFW_DMI_COMMAND_AAxSIZE_32BIT);
|
|
|
|
/* Wait until abstract command is completed */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_ABSTRACTCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_ABSTRACTCS_BUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: Abstract command did not complete in time (abstractcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_ABSTRACTCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvWriteSysBusMem
|
|
|
|
@Description Write a value at the given address in RISC-V memory space
|
|
using the RISC-V system bus
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Write value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR
|
|
RGXRiscvWriteSysBusMem(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Addr, IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PDUMPCOMMENTWITHFLAGS(psDevInfo->psDeviceNode, PDUMP_FLAGS_CONTINUOUS,
|
|
"Write RISC-V address 0x%x (value 0x%08x)",
|
|
ui32Addr, ui32Value);
|
|
|
|
/* Configure system bus to read 32 bit every time a new address is provided */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_SBCS,
|
|
RGXRISCVFW_DMI_SBCS_SBACCESS_32BIT << RGX_CR_FWCORE_DMI_SBCS_SBACCESS_SHIFT,
|
|
PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Prepare write address */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_SBADDRESS0,
|
|
ui32Addr, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Prepare write data and initiate write */
|
|
PDUMPREG32(psDevInfo->psDeviceNode, RGX_PDUMPREG_NAME, RGX_CR_FWCORE_DMI_SBDATA0,
|
|
ui32Value, PDUMP_FLAGS_CONTINUOUS);
|
|
|
|
/* Wait until system bus is idle */
|
|
PDUMPREGPOL(psDevInfo->psDeviceNode,
|
|
RGX_PDUMPREG_NAME,
|
|
RGX_CR_FWCORE_DMI_SBCS,
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_SBCS_SBBUSY_EN,
|
|
PDUMP_FLAGS_CONTINUOUS,
|
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
#else
|
|
IMG_UINT32 __iomem *pui32RegsBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Configure system bus for 32 bit accesses */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_FWCORE_DMI_SBCS,
|
|
RGXRISCVFW_DMI_SBCS_SBACCESS_32BIT << RGX_CR_FWCORE_DMI_SBCS_SBACCESS_SHIFT);
|
|
|
|
/* Prepare write address */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBADDRESS0, ui32Addr);
|
|
|
|
/* Prepare write data and initiate write */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBDATA0, ui32Value);
|
|
|
|
/* Wait until system bus is idle */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
pui32RegsBase + RGX_CR_FWCORE_DMI_SBCS/sizeof(IMG_UINT32),
|
|
0U,
|
|
RGX_CR_FWCORE_DMI_SBCS_SBBUSY_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: System Bus did not go idle in time (sbcs = 0x%x)",
|
|
__func__, OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_FWCORE_DMI_SBCS)));
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvWriteMem
|
|
|
|
@Description Write a value to the given address in RISC-V memory space
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@Input ui32Addr Address in RISC-V memory space
|
|
@Input ui32Value Write value
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
static PVRSRV_ERROR RGXRiscvWriteMem(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32Addr,
|
|
IMG_UINT32 ui32Value)
|
|
{
|
|
if (ui32Addr >= RGXRISCVFW_COREMEM_BASE && ui32Addr <= RGXRISCVFW_COREMEM_END)
|
|
{
|
|
return RGXRiscvWriteAbstractMem(psDevInfo, ui32Addr, ui32Value);
|
|
}
|
|
|
|
return RGXRiscvWriteSysBusMem(psDevInfo, ui32Addr, ui32Value);
|
|
}
|
|
#endif /* !defined(EMULATOR) */
|
|
|
|
/*!
|
|
*******************************************************************************
|
|
@Function RGXRiscvDmiOp
|
|
|
|
@Description Acquire the powerlock and perform an operation on the RISC-V
|
|
Debug Module Interface, but only if the GPU is powered on.
|
|
|
|
@Input psDevInfo Pointer to device info
|
|
@InOut pui64DMI Encoding of a request for the RISC-V Debug
|
|
Module with same format as the 'dmi' register
|
|
from the RISC-V debug specification (v0.13+).
|
|
On return, this is updated with the result of
|
|
the request, encoded the same way.
|
|
|
|
@Return PVRSRV_ERROR
|
|
******************************************************************************/
|
|
PVRSRV_ERROR RGXRiscvDmiOp(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT64 *pui64DMI)
|
|
{
|
|
#if defined(NO_HARDWARE) && defined(PDUMP)
|
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
|
PVR_UNREFERENCED_PARAMETER(pui64DMI);
|
|
|
|
/* Accessing DM registers is not supported in nohw/pdump */
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
#else
|
|
#define DMI_BASE RGX_CR_FWCORE_DMI_RESERVED00
|
|
#define DMI_STRIDE (RGX_CR_FWCORE_DMI_RESERVED01 - RGX_CR_FWCORE_DMI_RESERVED00)
|
|
#define DMI_REG(r) ((DMI_BASE) + (DMI_STRIDE) * (r))
|
|
|
|
#define DMI_OP_SHIFT 0U
|
|
#define DMI_OP_MASK 0x3ULL
|
|
#define DMI_DATA_SHIFT 2U
|
|
#define DMI_DATA_MASK 0x3FFFFFFFCULL
|
|
#define DMI_ADDRESS_SHIFT 34U
|
|
#define DMI_ADDRESS_MASK 0xFC00000000ULL
|
|
|
|
#define DMI_OP_NOP 0U
|
|
#define DMI_OP_READ 1U
|
|
#define DMI_OP_WRITE 2U
|
|
#define DMI_OP_RESERVED 3U
|
|
|
|
#define DMI_OP_STATUS_SUCCESS 0U
|
|
#define DMI_OP_STATUS_RESERVED 1U
|
|
#define DMI_OP_STATUS_FAILED 2U
|
|
#define DMI_OP_STATUS_BUSY 3U
|
|
|
|
PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode;
|
|
PVRSRV_DEV_POWER_STATE ePowerState;
|
|
PVRSRV_ERROR eError;
|
|
IMG_UINT64 ui64Op, ui64Address, ui64Data;
|
|
|
|
ui64Op = (*pui64DMI & DMI_OP_MASK) >> DMI_OP_SHIFT;
|
|
ui64Address = (*pui64DMI & DMI_ADDRESS_MASK) >> DMI_ADDRESS_SHIFT;
|
|
ui64Data = (*pui64DMI & DMI_DATA_MASK) >> DMI_DATA_SHIFT;
|
|
|
|
eError = PVRSRVPowerLock(psDeviceNode);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: failed to acquire powerlock (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
ui64Op = DMI_OP_STATUS_FAILED;
|
|
goto dmiop_update;
|
|
}
|
|
|
|
eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
|
|
|
|
if (eError != PVRSRV_OK)
|
|
{
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: failed to retrieve RGX power state (%s)",
|
|
__func__, PVRSRVGetErrorString(eError)));
|
|
ui64Op = DMI_OP_STATUS_FAILED;
|
|
goto dmiop_release_lock;
|
|
}
|
|
|
|
if (ePowerState == PVRSRV_DEV_POWER_STATE_ON)
|
|
{
|
|
switch (ui64Op)
|
|
{
|
|
case DMI_OP_NOP:
|
|
ui64Op = DMI_OP_STATUS_SUCCESS;
|
|
break;
|
|
case DMI_OP_WRITE:
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM,
|
|
DMI_REG(ui64Address),
|
|
(IMG_UINT32)ui64Data);
|
|
ui64Op = DMI_OP_STATUS_SUCCESS;
|
|
break;
|
|
case DMI_OP_READ:
|
|
ui64Data = (IMG_UINT64)OSReadHWReg32(psDevInfo->pvRegsBaseKM,
|
|
DMI_REG(ui64Address));
|
|
ui64Op = DMI_OP_STATUS_SUCCESS;
|
|
break;
|
|
default:
|
|
PVR_DPF((PVR_DBG_ERROR, "%s: unknown op %u", __func__, (IMG_UINT32)ui64Op));
|
|
ui64Op = DMI_OP_STATUS_FAILED;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PVR_DPF((PVR_DBG_WARNING, "%s: Accessing RISC-V Debug Module is not "
|
|
"possible while the GPU is powered off", __func__));
|
|
|
|
ui64Op = DMI_OP_STATUS_FAILED;
|
|
}
|
|
|
|
dmiop_release_lock:
|
|
PVRSRVPowerUnlock(psDeviceNode);
|
|
|
|
dmiop_update:
|
|
*pui64DMI = (ui64Op << DMI_OP_SHIFT) |
|
|
(ui64Address << DMI_ADDRESS_SHIFT) |
|
|
(ui64Data << DMI_DATA_SHIFT);
|
|
|
|
return eError;
|
|
#endif
|
|
}
|
|
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
/*
|
|
RGXReadMETAAddr
|
|
*/
|
|
static PVRSRV_ERROR RGXReadMETAAddr(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32METAAddr, IMG_UINT32 *pui32Value)
|
|
{
|
|
IMG_UINT8 __iomem *pui8RegBase = psDevInfo->pvRegsBaseKM;
|
|
IMG_UINT32 ui32Value;
|
|
|
|
/* Wait for Slave Port to be Ready */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
(IMG_UINT32 __iomem *) (pui8RegBase + RGX_CR_META_SP_MSLVCTRL1),
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
/* Issue the Read */
|
|
OSWriteHWReg32(
|
|
psDevInfo->pvRegsBaseKM,
|
|
RGX_CR_META_SP_MSLVCTRL0,
|
|
ui32METAAddr | RGX_CR_META_SP_MSLVCTRL0_RD_EN);
|
|
(void) OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVCTRL0);
|
|
|
|
/* Wait for Slave Port to be Ready: read complete */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
(IMG_UINT32 __iomem *) (pui8RegBase + RGX_CR_META_SP_MSLVCTRL1),
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
/* Read the value */
|
|
ui32Value = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVDATAX);
|
|
|
|
*pui32Value = ui32Value;
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
|
|
/*
|
|
RGXWriteMETAAddr
|
|
*/
|
|
static PVRSRV_ERROR RGXWriteMETAAddr(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32METAAddr, IMG_UINT32 ui32Value)
|
|
{
|
|
IMG_UINT8 __iomem *pui8RegBase = psDevInfo->pvRegsBaseKM;
|
|
|
|
/* Wait for Slave Port to be Ready */
|
|
if (PVRSRVPollForValueKM(psDevInfo->psDeviceNode,
|
|
(IMG_UINT32 __iomem *)(pui8RegBase + RGX_CR_META_SP_MSLVCTRL1),
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN,
|
|
POLL_FLAG_LOG_ERROR) != PVRSRV_OK)
|
|
{
|
|
return PVRSRV_ERROR_TIMEOUT;
|
|
}
|
|
|
|
/* Issue the Write */
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVCTRL0, ui32METAAddr);
|
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVDATAT, ui32Value);
|
|
|
|
return PVRSRV_OK;
|
|
}
|
|
#endif
|
|
|
|
PVRSRV_ERROR RGXReadFWModuleAddr(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32FWAddr, IMG_UINT32 *pui32Value)
|
|
{
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META))
|
|
{
|
|
return RGXReadMETAAddr(psDevInfo, ui32FWAddr, pui32Value);
|
|
}
|
|
#endif
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, RISCV_FW_PROCESSOR))
|
|
{
|
|
return RGXRiscvReadMem(psDevInfo, ui32FWAddr, pui32Value);
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXWriteFWModuleAddr(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32FWAddr, IMG_UINT32 ui32Value)
|
|
{
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META))
|
|
{
|
|
return RGXWriteMETAAddr(psDevInfo, ui32FWAddr, ui32Value);
|
|
}
|
|
#endif
|
|
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, RISCV_FW_PROCESSOR))
|
|
{
|
|
return RGXRiscvWriteMem(psDevInfo, ui32FWAddr, ui32Value);
|
|
}
|
|
#endif
|
|
|
|
return PVRSRV_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
PVRSRV_ERROR RGXGetFwMapping(PVRSRV_RGXDEV_INFO *psDevInfo,
|
|
IMG_UINT32 ui32FwVA,
|
|
IMG_CPU_PHYADDR *psCpuPA,
|
|
IMG_DEV_PHYADDR *psDevPA,
|
|
IMG_UINT64 *pui64RawPTE)
|
|
{
|
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
IMG_CPU_PHYADDR sCpuPA = {0U};
|
|
IMG_DEV_PHYADDR sDevPA = {0U};
|
|
IMG_UINT64 ui64RawPTE = 0U;
|
|
MMU_FAULT_DATA sFaultData = {0U};
|
|
MMU_CONTEXT *psFwMMUCtx = psDevInfo->psKernelMMUCtx;
|
|
IMG_UINT32 ui32FwHeapBase = (IMG_UINT32) (RGX_FIRMWARE_RAW_HEAP_BASE & UINT_MAX);
|
|
IMG_UINT32 ui32FwHeapEnd = ui32FwHeapBase + (RGX_NUM_OS_SUPPORTED * RGX_FIRMWARE_RAW_HEAP_SIZE);
|
|
IMG_UINT32 ui32OSID = (ui32FwVA - ui32FwHeapBase) / RGX_FIRMWARE_RAW_HEAP_SIZE;
|
|
IMG_UINT32 ui32HeapId;
|
|
PHYS_HEAP *psPhysHeap;
|
|
|
|
/* MIPS uses the same page size as the OS, while others default to 4K pages */
|
|
IMG_UINT32 ui32FwPageSize = RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS) ?
|
|
OSGetPageSize() : BIT(RGX_MMUCTRL_PAGE_4KB_RANGE_SHIFT);
|
|
IMG_UINT32 ui32PageOffset = (ui32FwVA & (ui32FwPageSize - 1));
|
|
|
|
PVR_LOG_GOTO_IF_INVALID_PARAM((ui32OSID < RGX_NUM_OS_SUPPORTED),
|
|
eError, ErrorExit);
|
|
|
|
PVR_LOG_GOTO_IF_INVALID_PARAM(((psCpuPA != NULL) ||
|
|
(psDevPA != NULL) ||
|
|
(pui64RawPTE != NULL)),
|
|
eError, ErrorExit);
|
|
|
|
PVR_LOG_GOTO_IF_INVALID_PARAM(((ui32FwVA >= ui32FwHeapBase) &&
|
|
(ui32FwVA < ui32FwHeapEnd)),
|
|
eError, ErrorExit);
|
|
|
|
ui32HeapId = (ui32OSID == RGXFW_HOST_OS) ?
|
|
PVRSRV_PHYS_HEAP_FW_MAIN : (PVRSRV_PHYS_HEAP_FW_PREMAP0 + ui32OSID);
|
|
psPhysHeap = psDevInfo->psDeviceNode->apsPhysHeap[ui32HeapId];
|
|
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS))
|
|
{
|
|
/* MIPS is equipped with a dedicated MMU */
|
|
RGXMipsCheckFaultAddress(psFwMMUCtx, ui32FwVA, &sFaultData);
|
|
}
|
|
else
|
|
{
|
|
IMG_UINT64 ui64FwDataBaseMask;
|
|
IMG_DEV_VIRTADDR sDevVAddr;
|
|
|
|
#if defined(RGX_FEATURE_META_MAX_VALUE_IDX)
|
|
if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META))
|
|
{
|
|
ui64FwDataBaseMask = ~(RGXFW_SEGMMU_DATA_META_CACHE_MASK |
|
|
RGXFW_SEGMMU_DATA_VIVT_SLC_CACHE_MASK |
|
|
RGXFW_SEGMMU_DATA_BASE_ADDRESS);
|
|
}
|
|
else
|
|
#endif
|
|
#if defined(RGX_FEATURE_RISCV_FW_PROCESSOR_BIT_MASK) && !defined(EMULATOR)
|
|
if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, RISCV_FW_PROCESSOR))
|
|
{
|
|
ui64FwDataBaseMask = ~(RGXRISCVFW_GET_REGION_BASE(0xF));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
PVR_LOG_GOTO_WITH_ERROR("RGXGetFwMapping", eError, PVRSRV_ERROR_NOT_IMPLEMENTED, ErrorExit);
|
|
}
|
|
|
|
sDevVAddr.uiAddr = (ui32FwVA & ui64FwDataBaseMask) | RGX_FIRMWARE_RAW_HEAP_BASE;
|
|
|
|
/* Fw CPU shares a subset of the GPU's VA space */
|
|
MMU_CheckFaultAddress(psFwMMUCtx, &sDevVAddr, &sFaultData);
|
|
}
|
|
|
|
ui64RawPTE = sFaultData.sLevelData[MMU_LEVEL_1].ui64Address;
|
|
|
|
if (eError == PVRSRV_OK)
|
|
{
|
|
IMG_BOOL bValidPage = (RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS)) ?
|
|
BITMASK_HAS(ui64RawPTE, RGXMIPSFW_TLB_VALID) :
|
|
BITMASK_HAS(ui64RawPTE, RGX_MMUCTRL_PT_DATA_VALID_EN);
|
|
if (!bValidPage)
|
|
{
|
|
/* don't report invalid pages */
|
|
eError = PVRSRV_ERROR_DEVICEMEM_NO_MAPPING;
|
|
}
|
|
else
|
|
{
|
|
sDevPA.uiAddr = ui32PageOffset + ((RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS)) ?
|
|
RGXMIPSFW_TLB_GET_PA(ui64RawPTE) :
|
|
(ui64RawPTE & ~RGX_MMUCTRL_PT_DATA_PAGE_CLRMSK));
|
|
|
|
/* Only the Host's Firmware heap is present in the Host's CPU IPA space */
|
|
if (ui32OSID == RGXFW_HOST_OS)
|
|
{
|
|
PhysHeapDevPAddrToCpuPAddr(psPhysHeap, 1, &sCpuPA, &sDevPA);
|
|
}
|
|
else
|
|
{
|
|
sCpuPA.uiAddr = 0U;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psCpuPA != NULL)
|
|
{
|
|
*psCpuPA = sCpuPA;
|
|
}
|
|
|
|
if (psDevPA != NULL)
|
|
{
|
|
*psDevPA = sDevPA;
|
|
}
|
|
|
|
if (pui64RawPTE != NULL)
|
|
{
|
|
*pui64RawPTE = ui64RawPTE;
|
|
}
|
|
|
|
ErrorExit:
|
|
return eError;
|
|
}
|
|
|
|
/******************************************************************************
|
|
End of file (rgxfwutils.c)
|
|
******************************************************************************/
|