| /*************************************************************************/ /*! |
| @File |
| @Title Rgx debug information |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description RGX debugging functions |
| @License Dual MIT/GPLv2 |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| Alternatively, the contents of this file may be used under the terms of |
| the GNU General Public License Version 2 ("GPL") in which case the provisions |
| of GPL are applicable instead of those above. |
| |
| If you wish to allow use of your version of this file only under the terms of |
| GPL, and not to allow others to use your version of this file under the terms |
| of the MIT license, indicate your decision by deleting the provisions above |
| and replace them with the notice and other provisions required by GPL as set |
| out in the file called "GPL-COPYING" included in this distribution. If you do |
| not delete the provisions above, a recipient may use your version of this file |
| under the terms of either the MIT license or GPL. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS |
| PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
| BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ /**************************************************************************/ |
| //#define PVR_DPF_FUNCTION_TRACE_ON 1 |
| #undef PVR_DPF_FUNCTION_TRACE_ON |
| |
| #include "img_defs.h" |
| #include "rgxdefs_km.h" |
| #include "rgxdevice.h" |
| #include "rgxmem.h" |
| #include "allocmem.h" |
| #include "cache_km.h" |
| #include "osfunc.h" |
| |
| #include "rgxdebug.h" |
| #include "pvrversion.h" |
| #include "pvr_debug.h" |
| #include "srvkm.h" |
| #include "rgxutils.h" |
| #include "tlstream.h" |
| #include "rgxfwutils.h" |
| #include "pvrsrv.h" |
| #include "services_km.h" |
| |
| #include "rgxfwimageutils.h" |
| #include "devicemem.h" |
| #include "devicemem_pdump.h" |
| #include "devicemem_utils.h" |
| #include "rgx_fwif_km.h" |
| #include "rgx_fwif_sf.h" |
| #include "rgxfw_log_helper.h" |
| #include "fwtrace_string.h" |
| #include "rgxfwimageutils.h" |
| #include "rgxfwload.h" |
| |
| #include "rgxta3d.h" |
| #include "rgxkicksync.h" |
| #include "rgxcompute.h" |
| #include "rgxtransfer.h" |
| #include "rgxtdmtransfer.h" |
| #include "rgxtimecorr.h" |
| #include "rgx_options.h" |
| #include "rgxinit.h" |
| #include "devicemem_history_server.h" |
| #include "info_page.h" |
| #include "rgx_bvnc_defs_km.h" |
| #define PVR_DUMP_DRIVER_INFO(x, y) \ |
| PVR_DUMPDEBUG_LOG("%s info: %d.%d @ %8d (%s) build options: 0x%08x", \ |
| (x), \ |
| PVRVERSION_UNPACK_MAJ((y).ui32BuildVersion), \ |
| PVRVERSION_UNPACK_MIN((y).ui32BuildVersion), \ |
| (y).ui32BuildRevision, \ |
| (BUILD_TYPE_DEBUG == (y).ui32BuildType) ? "debug":"release", \ |
| (y).ui32BuildOptions); |
| |
| #define PVR_DUMP_FIRMWARE_INFO(x) \ |
| PVR_DUMPDEBUG_LOG("FW info: %d.%d @ %8d (%s) build options: 0x%08x", \ |
| PVRVERSION_UNPACK_MAJ((x).ui32DDKVersion), \ |
| PVRVERSION_UNPACK_MIN((x).ui32DDKVersion), \ |
| (x).ui32DDKBuild, \ |
| ((x).ui32BuildOptions & OPTIONS_DEBUG_MASK) ? "debug":"release",\ |
| (x).ui32BuildOptions); |
| |
| |
| #define RGX_DEBUG_STR_SIZE (150) |
| #define MAX_FW_DESCRIPTION_LENGTH (500u) |
| |
| #define RGX_CR_BIF_CAT_BASE0 (0x1200U) |
| #define RGX_CR_BIF_CAT_BASE1 (0x1208U) |
| |
| #define RGX_CR_BIF_CAT_BASEN(n) \ |
| RGX_CR_BIF_CAT_BASE0 + \ |
| ((RGX_CR_BIF_CAT_BASE1 - RGX_CR_BIF_CAT_BASE0) * n) |
| |
| |
| #define RGXDBG_BIF_IDS \ |
| X(BIF0)\ |
| X(BIF1)\ |
| X(TEXAS_BIF)\ |
| X(DPX_BIF) |
| |
| #define RGXDBG_SIDEBAND_TYPES \ |
| X(META)\ |
| X(TLA)\ |
| X(DMA)\ |
| X(VDMM)\ |
| X(CDM)\ |
| X(IPP)\ |
| X(PM)\ |
| X(TILING)\ |
| X(MCU)\ |
| X(PDS)\ |
| X(PBE)\ |
| X(VDMS)\ |
| X(IPF)\ |
| X(ISP)\ |
| X(TPF)\ |
| X(USCS)\ |
| X(PPP)\ |
| X(VCE)\ |
| X(TPF_CPF)\ |
| X(IPF_CPF)\ |
| X(FBCDC) |
| |
| typedef enum |
| { |
| #define X(NAME) RGXDBG_##NAME, |
| RGXDBG_BIF_IDS |
| #undef X |
| } RGXDBG_BIF_ID; |
| |
| typedef enum |
| { |
| #define X(NAME) RGXDBG_##NAME, |
| RGXDBG_SIDEBAND_TYPES |
| #undef X |
| } RGXDBG_SIDEBAND_TYPE; |
| |
| static const IMG_CHAR *const pszPowStateName[] = |
| { |
| #define X(NAME) #NAME, |
| RGXFWIF_POW_STATES |
| #undef X |
| }; |
| |
| static const IMG_CHAR *const pszBIFNames[] = |
| { |
| #define X(NAME) #NAME, |
| RGXDBG_BIF_IDS |
| #undef X |
| }; |
| |
| static IMG_UINT32 gui32FaultIndex = 0; |
| static MMU_FAULT_DATA gsMMUFaultData[RGXFWIF_HWINFO_MAX]; |
| |
| typedef struct _IMG_FLAGS2DESC_ |
| { |
| IMG_UINT32 uiFlag; |
| const IMG_CHAR *pszLabel; |
| } IMG_FLAGS2DESC; |
| |
| static const IMG_FLAGS2DESC asCSW2Description[] = |
| { |
| {RGXFWIF_INICFG_CTXSWITCH_TA_EN, " TA;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_3D_EN, " 3D;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_CDM_EN, " CDM;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_MODE_RAND, " Random;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_SRESET_EN, " SoftReset;"}, |
| {RGXFWIF_INICFG_VDM_CTX_STORE_MODE_INDEX, " VDM CS INDEX mode;"}, |
| {RGXFWIF_INICFG_VDM_CTX_STORE_MODE_INSTANCE, " VDM CS INSTANCE mode;"}, |
| {RGXFWIF_INICFG_VDM_CTX_STORE_MODE_LIST, " VDM CS LIST mode;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_PROFILE_FAST, " Fast CSW profile;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_PROFILE_MEDIUM, " Medium CSW profile;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_PROFILE_SLOW, " Slow CSW profile;"}, |
| {RGXFWIF_INICFG_CTXSWITCH_PROFILE_NODELAY, " No Delay CSW profile;"} |
| }; |
| |
| static const IMG_FLAGS2DESC asMisc2Description[] = |
| { |
| {RGXFWIF_INICFG_POW_RASCALDUST, " Power Rascal/Dust;"}, |
| {RGXFWIF_INICFG_HWPERF_EN, " HwPerf EN;"}, |
| {RGXFWIF_INICFG_HWR_EN, " HWR EN;"}, |
| {RGXFWIF_INICFG_CHECK_MLIST_EN, " Check MList;"}, |
| {RGXFWIF_INICFG_DISABLE_CLKGATING_EN, " ClockGating Off;"}, |
| {RGXFWIF_INICFG_POLL_COUNTERS_EN, " Poll Counters;"}, |
| {RGXFWIF_INICFG_REGCONFIG_EN, " Register Config;"}, |
| {RGXFWIF_INICFG_ASSERT_ON_OUTOFMEMORY, " Assert on OOM;"}, |
| {RGXFWIF_INICFG_HWP_DISABLE_FILTER, " HWP Filter Off;"}, |
| {RGXFWIF_INICFG_CUSTOM_PERF_TIMER_EN, " Custom PerfTimer;"}, |
| {RGXFWIF_INICFG_CDM_KILL_MODE_RAND_EN, " CDM Random kill;"}, |
| {RGXFWIF_INICFG_DISABLE_DM_OVERLAP, " DM Overlap Off;"}, |
| {RGXFWIF_INICFG_METAT1_MAIN, " Main;"}, |
| {RGXFWIF_INICFG_METAT1_DUMMY, " Dummy;"}, |
| {RGXFWIF_INICFG_ASSERT_ON_HWR_TRIGGER, " Assert on HWR;"}, |
| {RGXFWIF_INICFG_WORKEST_V1, " Workload Estim v1;"}, |
| {RGXFWIF_INICFG_WORKEST_V2, " Workload Estim v2;"}, |
| {RGXFWIF_INICFG_PDVFS_V1, " PDVFS v1;"}, |
| {RGXFWIF_INICFG_PDVFS_V2, " PDVFS v2;"} |
| }; |
| |
| static const IMG_FLAGS2DESC asHwrState2Description[] = |
| { |
| {RGXFWIF_HWR_HARDWARE_OK, " HWR OK;"}, |
| {RGXFWIF_HWR_ANALYSIS_DONE, " Analysis done;"}, |
| {RGXFWIF_HWR_GENERAL_LOCKUP, " General lockup;"}, |
| {RGXFWIF_HWR_DM_RUNNING_OK, " DM running ok;"}, |
| {RGXFWIF_HWR_DM_STALLING, " DM stalling;"}, |
| {RGXFWIF_HWR_FW_FAULT, " FW fault;"}, |
| {RGXFWIF_HWR_RESTART_REQUESTED, " Restarting;"}, |
| }; |
| |
| static const IMG_FLAGS2DESC asDmState2Description[] = |
| { |
| {RGXFWIF_DM_STATE_WORKING, " working;"}, |
| {RGXFWIF_DM_STATE_READY_FOR_HWR, " ready for hwr;"}, |
| {RGXFWIF_DM_STATE_NEEDS_SKIP, " needs skip;"}, |
| {RGXFWIF_DM_STATE_NEEDS_PR_CLEANUP, " needs PR cleanup;"}, |
| {RGXFWIF_DM_STATE_NEEDS_TRACE_CLEAR, " needs trace clear;"}, |
| {RGXFWIF_DM_STATE_GUILTY_LOCKUP, " guilty lockup;"}, |
| {RGXFWIF_DM_STATE_INNOCENT_LOCKUP, " innocent lockup;"}, |
| {RGXFWIF_DM_STATE_GUILTY_OVERRUNING, " guilty overrunning;"}, |
| {RGXFWIF_DM_STATE_INNOCENT_OVERRUNING, " innocent overrunning;"}, |
| {RGXFWIF_DM_STATE_HARD_CONTEXT_SWITCH, " hard context switching;"}, |
| }; |
| |
| #if !defined(NO_HARDWARE) |
| /* Translation of MIPS exception encoding */ |
| typedef struct _MIPS_EXCEPTION_ENCODING_ |
| { |
| const IMG_CHAR *const pszStr; /* Error type */ |
| const IMG_BOOL bIsFatal; /* Error is fatal or non-fatal */ |
| } MIPS_EXCEPTION_ENCODING; |
| |
| static const MIPS_EXCEPTION_ENCODING apsMIPSExcCodes[] = |
| { |
| {"Interrupt", IMG_FALSE}, |
| {"TLB modified exception", IMG_FALSE}, |
| {"TLB exception (load/instruction fetch)", IMG_FALSE}, |
| {"TLB exception (store)", IMG_FALSE}, |
| {"Address error exception (load/instruction fetch)", IMG_TRUE}, |
| {"Address error exception (store)", IMG_TRUE}, |
| {"Bus error exception (instruction fetch)", IMG_TRUE}, |
| {"Bus error exception (load/store)", IMG_TRUE}, |
| {"Syscall exception", IMG_FALSE}, |
| {"Breakpoint exception (FW assert)", IMG_FALSE}, |
| {"Reserved instruction exception", IMG_TRUE}, |
| {"Coprocessor Unusable exception", IMG_FALSE}, |
| {"Arithmetic Overflow exception", IMG_FALSE}, |
| {"Trap exception", IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {"Implementation-Specific Exception 1 (COP2)", IMG_FALSE}, |
| {"CorExtend Unusable", IMG_FALSE}, |
| {"Coprocessor 2 exceptions", IMG_FALSE}, |
| {"TLB Read-Inhibit", IMG_TRUE}, |
| {"TLB Execute-Inhibit", IMG_TRUE}, |
| {NULL, IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {"Reference to WatchHi/WatchLo address", IMG_FALSE}, |
| {"Machine check", IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {"DSP Module State Disabled exception", IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| {NULL, IMG_FALSE}, |
| /* Can only happen in MIPS debug mode */ |
| {"Parity error", IMG_FALSE}, |
| {NULL, IMG_FALSE} |
| }; |
| |
| static IMG_CHAR const *_GetMIPSExcString(IMG_UINT32 ui32ExcCode) |
| { |
| if (ui32ExcCode >= sizeof(apsMIPSExcCodes)/sizeof(MIPS_EXCEPTION_ENCODING)) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "Only %lu exceptions available in MIPS, %u is not a valid exception code", |
| (unsigned long)sizeof(apsMIPSExcCodes)/sizeof(MIPS_EXCEPTION_ENCODING), ui32ExcCode)); |
| return NULL; |
| } |
| |
| return apsMIPSExcCodes[ui32ExcCode].pszStr; |
| } |
| #endif |
| |
| typedef struct _RGXMIPSFW_C0_DEBUG_TBL_ENTRY_ |
| { |
| IMG_UINT32 ui32Mask; |
| const IMG_CHAR * pszExplanation; |
| } RGXMIPSFW_C0_DEBUG_TBL_ENTRY; |
| |
| #if !defined(NO_HARDWARE) |
| static const RGXMIPSFW_C0_DEBUG_TBL_ENTRY sMIPS_C0_DebugTable[] = |
| { |
| { RGXMIPSFW_C0_DEBUG_DSS, "Debug single-step exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DBP, "Debug software breakpoint exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DDBL, "Debug data break exception occurred on a load" }, |
| { RGXMIPSFW_C0_DEBUG_DDBS, "Debug data break exception occurred on a store" }, |
| { RGXMIPSFW_C0_DEBUG_DIB, "Debug instruction break exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DINT, "Debug interrupt exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DIBIMPR, "Imprecise debug instruction break exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DDBLIMPR, "Imprecise debug data break load exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DDBSIMPR, "Imprecise debug data break store exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_IEXI, "Imprecise error exception inhibit controls exception occurred" }, |
| { RGXMIPSFW_C0_DEBUG_DBUSEP, "Data access Bus Error exception pending" }, |
| { RGXMIPSFW_C0_DEBUG_CACHEEP, "Imprecise Cache Error pending" }, |
| { RGXMIPSFW_C0_DEBUG_MCHECKP, "Imprecise Machine Check exception pending" }, |
| { RGXMIPSFW_C0_DEBUG_IBUSEP, "Instruction fetch Bus Error exception pending" }, |
| { RGXMIPSFW_C0_DEBUG_DBD, "Debug exception occurred in branch delay slot" } |
| }; |
| #endif |
| |
| static PVRSRV_ERROR |
| RGXPollMetaRegThroughSP(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32RegOffset, |
| IMG_UINT32 ui32PollValue, IMG_UINT32 ui32Mask) |
| { |
| IMG_UINT32 ui32RegValue, ui32NumPolls = 0; |
| PVRSRV_ERROR eError; |
| |
| do |
| { |
| eError = RGXReadWithSP(psDevInfo, ui32RegOffset, &ui32RegValue); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| } while (((ui32RegValue & ui32Mask) != ui32PollValue) && (ui32NumPolls++ < 1000)); |
| |
| return ((ui32RegValue & ui32Mask) == ui32PollValue) ? PVRSRV_OK : PVRSRV_ERROR_RETRY; |
| } |
| |
| static PVRSRV_ERROR |
| RGXReadMetaCoreReg(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32RegAddr, IMG_UINT32 *pui32RegVal) |
| { |
| PVRSRV_ERROR eError; |
| |
| /* Core Read Ready? */ |
| eError = RGXPollMetaRegThroughSP(psDevInfo, |
| META_CR_TXUXXRXRQ_OFFSET, |
| META_CR_TXUXXRXRQ_DREADY_BIT, |
| META_CR_TXUXXRXRQ_DREADY_BIT); |
| PVR_LOGR_IF_ERROR(eError, "RGXPollMetaRegThroughSP"); |
| |
| /* Set the reg we are interested in reading */ |
| eError = RGXWriteWithSP(psDevInfo, META_CR_TXUXXRXRQ_OFFSET, |
| ui32RegAddr | META_CR_TXUXXRXRQ_RDnWR_BIT); |
| PVR_LOGR_IF_ERROR(eError, "RGXWriteWithSP"); |
| |
| /* Core Read Done? */ |
| eError = RGXPollMetaRegThroughSP(psDevInfo, |
| META_CR_TXUXXRXRQ_OFFSET, |
| META_CR_TXUXXRXRQ_DREADY_BIT, |
| META_CR_TXUXXRXRQ_DREADY_BIT); |
| PVR_LOGR_IF_ERROR(eError, "RGXPollMetaRegThroughSP"); |
| |
| /* Read the value */ |
| return RGXReadWithSP(psDevInfo, META_CR_TXUXXRXDT_OFFSET, pui32RegVal); |
| } |
| |
| PVRSRV_ERROR |
| RGXReadWithSP(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32FWAddr, IMG_UINT32 *pui32Value) |
| { |
| PVRSRV_ERROR eError = RGXReadMETAAddr(psDevInfo, ui32FWAddr, pui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXReadWithSP error: %s", PVRSRVGetErrorString(eError))); |
| } |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR |
| RGXWriteWithSP(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32FWAddr, IMG_UINT32 ui32Value) |
| { |
| PVRSRV_ERROR eError = RGXWriteMETAAddr(psDevInfo, ui32FWAddr, ui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXWriteMETAAddr error: %s", PVRSRVGetErrorString(eError))); |
| } |
| return eError; |
| } |
| |
| #if !defined(NO_HARDWARE) && !defined(SUPPORT_TRUSTED_DEVICE) |
| static PVRSRV_ERROR _ValidateWithSP(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DEV_VIRTADDR *psFWAddr, |
| void *pvHostCodeAddr, |
| IMG_UINT32 ui32MaxLen, |
| const IMG_CHAR *pszDesc, |
| IMG_UINT32 ui32StartOffset) |
| { |
| PVRSRV_ERROR eError; |
| IMG_UINT32 ui32Value, i; |
| IMG_UINT32 ui32FWCodeDevVAAddr = psFWAddr->ui32Addr + ui32StartOffset; |
| IMG_UINT32 *pui32FWCode = (IMG_PUINT32) ((IMG_PBYTE)pvHostCodeAddr + ui32StartOffset); |
| |
| ui32MaxLen -= ui32StartOffset; |
| ui32MaxLen /= sizeof(IMG_UINT32); /* Byte -> 32 bit words */ |
| |
| for (i = 0; i < ui32MaxLen; i++) |
| { |
| eError = RGXReadMETAAddr(psDevInfo, ui32FWCodeDevVAAddr, &ui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "_ValidateWithSP error: %s", PVRSRVGetErrorString(eError))); |
| return eError; |
| } |
| |
| PVR_DPF((PVR_DBG_VERBOSE, "0x%x: CPU 0x%08x, FW 0x%08x", i * 4, pui32FWCode[i], ui32Value)); |
| |
| if (pui32FWCode[i] != ui32Value) |
| { |
| PVR_DUMPDEBUG_LOG("_ValidateWithSP: Mismatch while validating %s at offset 0x%x: CPU 0x%08x (%p), FW 0x%08x (%x)", |
| pszDesc, |
| (i * 4) + ui32StartOffset, pui32FWCode[i], pui32FWCode, ui32Value, ui32FWCodeDevVAAddr); |
| return PVRSRV_ERROR_FW_IMAGE_MISMATCH; |
| } |
| |
| ui32FWCodeDevVAAddr += 4; |
| } |
| |
| PVR_DUMPDEBUG_LOG("Match between Host and Meta view of the %s", pszDesc); |
| return PVRSRV_OK; |
| } |
| #endif |
| |
| #if !defined(NO_HARDWARE) |
| static PVRSRV_ERROR _ValidateFWImageForMIPS(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| char *pszFormat) |
| { |
| #if !defined(SUPPORT_TRUSTED_DEVICE) |
| PVRSRV_ERROR eError; |
| IMG_PUINT32 *pui32HostFWCode = NULL; |
| struct RGXFW *psRGXFW = NULL; |
| const IMG_BYTE *pbRGXFirmware = NULL; |
| IMG_UINT32 *pui32CodeMemoryPointer; |
| IMG_UINT32 ui32MaxLenInBytes = psDevInfo->ui32FWCodeSizeInBytes; |
| RGX_LAYER_PARAMS sLayerParams; |
| sLayerParams.psDevInfo = psDevInfo; |
| |
| /* Load FW from system for code verification */ |
| pui32HostFWCode = OSAllocZMem(psDevInfo->ui32FWCodeSizeInBytes); |
| if (pui32HostFWCode == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Failed in allocating memory for FW code. " |
| "So skipping FW code verification", |
| __func__)); |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| |
| /* Load FW image */ |
| pbRGXFirmware = RGXLoadAndGetFWData(psDevInfo->psDeviceNode, &psRGXFW); |
| if (!pbRGXFirmware) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed to load FW image file.",__func__)); |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| goto cleanup_initfw; |
| } |
| |
| eError = ProcessELFCommandStream(&sLayerParams, pbRGXFirmware, (IMG_PBYTE) pui32HostFWCode, NULL); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed in parsing FW image file.", __func__)); |
| goto cleanup_initfw; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWCodeMemDesc, (void **)&pui32CodeMemoryPointer); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Error in acquiring MIPS FW code memory area (%s)", |
| __func__, |
| PVRSRVGetErrorString(eError))); |
| goto cleanup_initfw; |
| } |
| |
| ui32MaxLenInBytes /= sizeof(IMG_UINT32); /* Byte -> 32 bit words */ |
| |
| if (OSMemCmp(pui32HostFWCode, pui32CodeMemoryPointer, ui32MaxLenInBytes) == 0) |
| { |
| PVR_DUMPDEBUG_LOG("%s Match between Host and MIPS views of the FW code", pszFormat); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%s Mismatch between Host and MIPS views of the FW code", pszFormat); |
| } |
| |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWCodeMemDesc); |
| |
| cleanup_initfw: |
| if (psRGXFW) |
| { |
| RGXUnloadFirmware(psRGXFW); |
| } |
| |
| if (pui32HostFWCode) |
| { |
| OSFreeMem(pui32HostFWCode); |
| } |
| return eError; |
| #else |
| PVR_UNREFERENCED_PARAMETER(pfnDumpDebugPrintf); |
| PVR_UNREFERENCED_PARAMETER(pvDumpDebugFile); |
| PVR_UNREFERENCED_PARAMETER(psDevInfo); |
| PVR_UNREFERENCED_PARAMETER(pszFormat); |
| return PVRSRV_OK; |
| #endif |
| } |
| #endif |
| |
| static PVRSRV_ERROR _ValidateFWImageForMETA(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| #if !defined(NO_HARDWARE) && !defined(SUPPORT_TRUSTED_DEVICE) |
| IMG_UINT32 *pui32HostFWCode = NULL, *pui32HostFWCoremem = NULL; |
| struct RGXFW *psRGXFW = NULL; |
| const IMG_BYTE *pbRGXFirmware = NULL; |
| RGXFWIF_DEV_VIRTADDR sFWAddr; |
| PVRSRV_ERROR eError; |
| RGX_LAYER_PARAMS sLayerParams; |
| sLayerParams.psDevInfo = psDevInfo; |
| |
| if (psDevInfo->pvRegsBaseKM == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: RGX registers not mapped yet!", __func__)); |
| return PVRSRV_ERROR_BAD_MAPPING; |
| } |
| |
| /* Load FW from system for code verification */ |
| pui32HostFWCode = OSAllocZMem(psDevInfo->ui32FWCodeSizeInBytes); |
| if (pui32HostFWCode == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Failed in allocating memory for FW code. " |
| "So skipping FW code verification", |
| __func__)); |
| return PVRSRV_ERROR_OUT_OF_MEMORY; |
| } |
| |
| if (psDevInfo->ui32FWCorememCodeSizeInBytes) |
| { |
| pui32HostFWCoremem = OSAllocZMem(psDevInfo->ui32FWCorememCodeSizeInBytes); |
| if (pui32HostFWCoremem == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Failed in allocating memory for FW core code. " |
| "So skipping FW code verification", |
| __func__)); |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto freeHostFWCode; |
| } |
| } |
| |
| /* Load FW image */ |
| pbRGXFirmware = RGXLoadAndGetFWData(psDevInfo->psDeviceNode, &psRGXFW); |
| if (!pbRGXFirmware) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed in loading FW image file.", __func__)); |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| goto cleanup_initfw; |
| } |
| |
| eError = ProcessLDRCommandStream(&sLayerParams, pbRGXFirmware, |
| (IMG_PBYTE) pui32HostFWCode, NULL, |
| (IMG_PBYTE) pui32HostFWCoremem, NULL, NULL); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed in parsing FW image file.", __func__)); |
| goto cleanup_initfw; |
| } |
| |
| /* starting checking after BOOT LOADER config */ |
| sFWAddr.ui32Addr = RGXFW_BOOTLDR_META_ADDR; |
| eError = _ValidateWithSP(pfnDumpDebugPrintf, pvDumpDebugFile, |
| psDevInfo, &sFWAddr, |
| pui32HostFWCode, psDevInfo->ui32FWCodeSizeInBytes, |
| "FW code", RGXFW_MAX_BOOTLDR_OFFSET); |
| if (eError != PVRSRV_OK) |
| { |
| goto cleanup_initfw; |
| } |
| |
| if (psDevInfo->ui32FWCorememCodeSizeInBytes) |
| { |
| sFWAddr.ui32Addr = RGXGetFWImageSectionAddress(NULL, META_COREMEM_CODE); |
| |
| eError = _ValidateWithSP(pfnDumpDebugPrintf, pvDumpDebugFile, |
| psDevInfo, &sFWAddr, |
| pui32HostFWCoremem, psDevInfo->ui32FWCorememCodeSizeInBytes, |
| "FW coremem code", 0); |
| } |
| |
| cleanup_initfw: |
| if (psRGXFW) |
| { |
| RGXUnloadFirmware(psRGXFW); |
| } |
| |
| if (pui32HostFWCoremem) |
| { |
| OSFreeMem(pui32HostFWCoremem); |
| } |
| freeHostFWCode: |
| if (pui32HostFWCode) |
| { |
| OSFreeMem(pui32HostFWCode); |
| } |
| return eError; |
| #else |
| PVR_UNREFERENCED_PARAMETER(pfnDumpDebugPrintf); |
| PVR_UNREFERENCED_PARAMETER(pvDumpDebugFile); |
| PVR_UNREFERENCED_PARAMETER(psDevInfo); |
| return PVRSRV_OK; |
| #endif |
| } |
| |
| #if defined(SUPPORT_EXTRA_METASP_DEBUG) |
| PVRSRV_ERROR ValidateFWOnLoad(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| #if !defined(NO_HARDWARE) && !defined(SUPPORT_TRUSTED_DEVICE) |
| IMG_PBYTE pbCodeMemoryPointer; |
| PVRSRV_ERROR eError; |
| RGXFWIF_DEV_VIRTADDR sFWAddr; |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWCodeMemDesc, (void **)&pbCodeMemoryPointer); |
| if (eError != PVRSRV_OK) |
| { |
| return eError; |
| } |
| |
| sFWAddr.ui32Addr = RGXFW_BOOTLDR_META_ADDR; |
| eError = _ValidateWithSP(NULL, NULL, psDevInfo, &sFWAddr, pbCodeMemoryPointer, psDevInfo->ui32FWCodeSizeInBytes, "FW code", 0); |
| if (eError != PVRSRV_OK) |
| { |
| goto releaseFWCodeMapping; |
| } |
| |
| if (psDevInfo->ui32FWCorememCodeSizeInBytes) |
| { |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWCorememMemDesc, (void **)&pbCodeMemoryPointer); |
| if (eError != PVRSRV_OK) |
| { |
| goto releaseFWCoreCodeMapping; |
| } |
| |
| sFWAddr.ui32Addr = RGXGetFWImageSectionAddress(NULL, META_COREMEM_CODE); |
| |
| eError = _ValidateWithSP(NULL, NULL, psDevInfo, &sFWAddr, pbCodeMemoryPointer, |
| psDevInfo->ui32FWCorememCodeSizeInBytes, "FW coremem code", 0); |
| } |
| |
| releaseFWCoreCodeMapping: |
| if (psDevInfo->ui32FWCorememCodeSizeInBytes) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWCorememMemDesc); |
| } |
| releaseFWCodeMapping: |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWCodeMemDesc); |
| |
| return eError; |
| #else |
| PVR_UNREFERENCED_PARAMETER(psDevInfo); |
| return PVRSRV_OK; |
| #endif |
| } |
| #endif |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDecodePMPC |
| |
| @Description |
| |
| Return the name for the PM managed Page Catalogues |
| |
| @Input ui32PC - Page Catalogue number |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static const IMG_CHAR* _RGXDecodePMPC(IMG_UINT32 ui32PC) |
| { |
| const IMG_CHAR* pszPMPC = " (-)"; |
| |
| switch (ui32PC) |
| { |
| case 0x8: pszPMPC = " (PM-VCE0)"; break; |
| case 0x9: pszPMPC = " (PM-TE0)"; break; |
| case 0xA: pszPMPC = " (PM-ZLS0)"; break; |
| case 0xB: pszPMPC = " (PM-ALIST0)"; break; |
| case 0xC: pszPMPC = " (PM-VCE1)"; break; |
| case 0xD: pszPMPC = " (PM-TE1)"; break; |
| case 0xE: pszPMPC = " (PM-ZLS1)"; break; |
| case 0xF: pszPMPC = " (PM-ALIST1)"; break; |
| } |
| |
| return pszPMPC; |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDecodeBIFReqTags |
| |
| @Description |
| |
| Decode the BIF Tag ID and sideband data fields from BIF_FAULT_BANK_REQ_STATUS regs |
| |
| @Input eBankID - BIF identifier |
| @Input ui32TagID - Tag ID value |
| @Input ui32TagSB - Tag Sideband data |
| @Output ppszTagID - Decoded string from the Tag ID |
| @Output ppszTagSB - Decoded string from the Tag SB |
| @Output pszScratchBuf - Buffer provided to the function to generate the debug strings |
| @Input ui32ScratchBufSize - Size of the provided buffer |
| |
| @Return void |
| |
| ******************************************************************************/ |
| #include "rgxmhdefs_km.h" |
| |
| static void _RGXDecodeBIFReqTagsXE(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32TagID, |
| IMG_UINT32 ui32TagSB, |
| IMG_CHAR **ppszTagID, |
| IMG_CHAR **ppszTagSB, |
| IMG_CHAR *pszScratchBuf, |
| IMG_UINT32 ui32ScratchBufSize) |
| { |
| /* default to unknown */ |
| IMG_CHAR *pszTagID = "-"; |
| IMG_CHAR *pszTagSB = "-"; |
| |
| PVR_ASSERT(ppszTagID != NULL); |
| PVR_ASSERT(ppszTagSB != NULL); |
| |
| switch (ui32TagID) |
| { |
| /* MMU tags */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PT: |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PD: |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PC: |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PM: |
| { |
| switch (ui32TagID) |
| { |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PT: pszTagID = "MMU PT"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PD: pszTagID = "MMU PD"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PC: pszTagID = "MMU PC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MMU_PM: pszTagID = "MMU PM"; break; |
| } |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PT_REQUEST: pszTagSB = "PT"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PD_REQUEST: pszTagSB = "PD"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PC_REQUEST: pszTagSB = "PC"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PM_PT_REQUEST: pszTagSB = "PM PT"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PM_PD_REQUEST: pszTagSB = "PM PD"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PM_PC_REQUEST: pszTagSB = "PM PC"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PM_PD_WREQUEST: pszTagSB = "PM PD W"; break; |
| case RGX_MH_TAG_SB_MMU_ENCODING_MMU_TAG_PM_PC_WREQUEST: pszTagSB = "PM PC W"; break; |
| } |
| break; |
| } |
| |
| /* MIPS */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_MIPS: |
| { |
| pszTagID = "MIPS"; |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_MIPS_ENCODING_MIPS_TAG_OPCODE_FETCH: pszTagSB = "Opcode"; break; |
| case RGX_MH_TAG_SB_MIPS_ENCODING_MIPS_TAG_DATA_ACCESS: pszTagSB = "Data"; break; |
| } |
| break; |
| } |
| |
| /* CDM tags */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG0: |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG1: |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG2: |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG3: |
| { |
| switch (ui32TagID) |
| { |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG0: pszTagID = "CDM Stage 0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG1: pszTagID = "CDM Stage 1"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG2: pszTagID = "CDM Stage 2"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_CDM_STG3: pszTagID = "CDM Stage 3"; break; |
| } |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_CDM_ENCODING_CDM_TAG_CONTROL_STREAM: pszTagSB = "Control"; break; |
| case RGX_MH_TAG_SB_CDM_ENCODING_CDM_TAG_INDIRECT_DATA: pszTagSB = "Indirect"; break; |
| case RGX_MH_TAG_SB_CDM_ENCODING_CDM_TAG_EVENT_DATA: pszTagSB = "Event"; break; |
| case RGX_MH_TAG_SB_CDM_ENCODING_CDM_TAG_CONTEXT_STATE: pszTagSB = "Context"; break; |
| } |
| break; |
| } |
| |
| /* VDM tags */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG0: |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG1: |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG2: |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG3: |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG4: |
| { |
| switch (ui32TagID) |
| { |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG0: pszTagID = "VDM Stage 0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG1: pszTagID = "VDM Stage 1"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG2: pszTagID = "VDM Stage 2"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG3: pszTagID = "VDM Stage 3"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG4: pszTagID = "VDM Stage 4"; break; |
| } |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_VDM_ENCODING_VDM_TAG_CONTROL: pszTagSB = "Control"; break; |
| case RGX_MH_TAG_SB_VDM_ENCODING_VDM_TAG_STATE: pszTagSB = "State"; break; |
| case RGX_MH_TAG_SB_VDM_ENCODING_VDM_TAG_INDEX: pszTagSB = "Index"; break; |
| case RGX_MH_TAG_SB_VDM_ENCODING_VDM_TAG_STACK: pszTagSB = "Stack"; break; |
| case RGX_MH_TAG_SB_VDM_ENCODING_VDM_TAG_CONTEXT: pszTagSB = "Context"; break; |
| } |
| break; |
| } |
| |
| /* PDS */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_PDS_0: |
| pszTagID = "PDS req 0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_PDS_1: |
| pszTagID = "PDS req 1"; break; |
| |
| /* MCU */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_USCA: |
| pszTagID = "MCU USCA"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_USCB: |
| pszTagID = "MCU USCB"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_USCC: |
| pszTagID = "MCU USCC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_USCD: |
| pszTagID = "MCU USCD"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_PDS_USCA: |
| pszTagID = "MCU PDS USCA"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_PDS_USCB: |
| pszTagID = "MCU PDS USCB"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_PDS_USCC: |
| pszTagID = "MCU PDS USCC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_PDS_USCD: |
| pszTagID = "MCU PDSUSCD"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_MCU_PDSRW: |
| pszTagID = "PDS PDSRW"; break; |
| |
| /* TCU */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_TCU_0: |
| pszTagID = "TCU req 0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TCU_1: |
| pszTagID = "TCU req 1"; break; |
| |
| /* FBCDC */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_FBCDC_0: |
| pszTagID = "FBCDC0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_FBCDC_1: |
| pszTagID = "FBCDC1"; break; |
| |
| /* USC Shared */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_USC: |
| pszTagID = "USCS"; break; |
| |
| /* ISP */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_ISP_ZLS: |
| pszTagID = "ISP0 ZLS"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_ISP_DS: |
| pszTagID = "ISP0 DS"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_ISP1_ZLS: |
| pszTagID = "ISP1 ZLS"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_ISP1_DS: |
| pszTagID = "ISP1 DS"; break; |
| |
| /* TPF */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF: |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF_PBCDBIAS: |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF_SPF: |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1: |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1_PBCDBIAS: |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1_SPF: |
| { |
| switch (ui32TagID) |
| { |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF: pszTagID = "TPF0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF_PBCDBIAS: pszTagID = "TPF0 DBIAS"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF_SPF: pszTagID = "TPF0 SPF"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1: pszTagID = "TPF1"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1_PBCDBIAS: pszTagID = "TPF1 DBIAS"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TPF1_SPF: pszTagID = "TPF1 SPF"; break; |
| } |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_TPF_ENCODING_TPF_TAG_PDS_STATE: pszTagSB = "PDS state"; break; |
| case RGX_MH_TAG_SB_TPF_ENCODING_TPF_TAG_DEPTH_BIAS: pszTagSB = "Depth bias"; break; |
| case RGX_MH_TAG_SB_TPF_ENCODING_TPF_TAG_FLOOR_OFFSET_DATA: pszTagSB = "Floor offset"; break; |
| case RGX_MH_TAG_SB_TPF_ENCODING_TPF_TAG_DELTA_DATA: pszTagSB = "Delta"; break; |
| } |
| break; |
| } |
| |
| /* IPF */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF_CREQ: |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF_OTHERS: |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF1_CREQ: |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF1_OTHERS: |
| { |
| switch (ui32TagID) |
| { |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF_CREQ: pszTagID = "IPF0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF_OTHERS: pszTagID = "IPF0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF1_CREQ: pszTagID = "IPF1"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPF1_OTHERS: pszTagID = "IPF1"; break; |
| } |
| |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_ISP_IPP_PIPES)) |
| { |
| if (ui32TagID < RGX_GET_FEATURE_VALUE(psDevInfo, NUM_ISP_IPP_PIPES)) |
| { |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, "CReq%d", ui32TagID); |
| pszTagSB = pszScratchBuf; |
| } |
| else if (ui32TagID < 2 * RGX_GET_FEATURE_VALUE(psDevInfo, NUM_ISP_IPP_PIPES)) |
| { |
| ui32TagID -= RGX_GET_FEATURE_VALUE(psDevInfo, NUM_ISP_IPP_PIPES); |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, "PReq%d", ui32TagID); |
| pszTagSB = pszScratchBuf; |
| } |
| else |
| { |
| switch (ui32TagSB - 2 * RGX_GET_FEATURE_VALUE(psDevInfo, NUM_ISP_IPP_PIPES)) |
| { |
| case 0: pszTagSB = "RReq"; break; |
| case 1: pszTagSB = "DBSC"; break; |
| case 2: pszTagSB = "CPF"; break; |
| case 3: pszTagSB = "Delta"; break; |
| } |
| } |
| } |
| break; |
| } |
| |
| /* VDM Stage 5 (temporary) */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_VDM_STG5: |
| pszTagID = "VDM Stage 5"; break; |
| |
| /* TA */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_PPP: |
| pszTagID = "PPP"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_TPWRTC: |
| pszTagID = "TPW RTC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_TEACRTC: |
| pszTagID = "TEAC RTC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_PSGRTC: |
| pszTagID = "PSG RTC"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_PSGREGION: |
| pszTagID = "PSG Region"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_PSGSTREAM: |
| pszTagID = "PSG Stream"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_TPW: |
| pszTagID = "TPW"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_TA_TPC: |
| pszTagID = "TPC"; break; |
| |
| /* PM */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_PM_ALLOC: |
| { |
| pszTagID = "PMA"; |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_TAFSTACK: pszTagSB = "TA Fstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_TAMLIST: pszTagSB = "TA MList"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_3DFSTACK: pszTagSB = "3D Fstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_3DMLIST: pszTagSB = "3D MList"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_PMCTX0: pszTagSB = "Context0"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_PMCTX1: pszTagSB = "Context1"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_MAVP: pszTagSB = "MAVP"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_UFSTACK: pszTagSB = "UFstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_TAMMUSTACK: pszTagSB = "TA MMUstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_3DMMUSTACK: pszTagSB = "3D MMUstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_TAUFSTACK: pszTagSB = "TA UFstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_3DUFSTACK: pszTagSB = "3D UFstack"; break; |
| case RGX_MH_TAG_SB_PMA_ENCODING_PM_TAG_PMA_TAVFP: pszTagSB = "TA VFP"; break; |
| } |
| break; |
| } |
| case RGX_MH_TAG_ENCODING_MH_TAG_PM_DEALLOC: |
| { |
| pszTagID = "PMD"; |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_TAFSTACK: pszTagSB = "TA Fstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_TAMLIST: pszTagSB = "TA MList"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_3DFSTACK: pszTagSB = "3D Fstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_3DMLIST: pszTagSB = "3D MList"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_PMCTX0: pszTagSB = "Context0"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_PMCTX1: pszTagSB = "Context1"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_UFSTACK: pszTagSB = "UFstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_TAMMUSTACK: pszTagSB = "TA MMUstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_3DMMUSTACK: pszTagSB = "3D MMUstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_TAUFSTACK: pszTagSB = "TA UFstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_3DUFSTACK: pszTagSB = "3D UFstack"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_TAVFP: pszTagSB = "TA VFP"; break; |
| case RGX_MH_TAG_SB_PMD_ENCODING_PM_TAG_PMD_3DVFP: pszTagSB = "3D VFP"; break; |
| } |
| break; |
| } |
| |
| /* TDM */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_TDM_DMA: |
| { |
| pszTagID = "TDM DMA"; |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_TDM_DMA_ENCODING_TDM_DMA_TAG_CTL_STREAM: pszTagSB = "Ctl stream"; break; |
| case RGX_MH_TAG_SB_TDM_DMA_ENCODING_TDM_DMA_TAG_CTX_BUFFER: pszTagSB = "Ctx buffer"; break; |
| case RGX_MH_TAG_SB_TDM_DMA_ENCODING_TDM_DMA_TAG_QUEUE_CTL: pszTagSB = "Queue ctl"; break; |
| } |
| break; |
| } |
| case RGX_MH_TAG_ENCODING_MH_TAG_TDM_CTL: |
| { |
| pszTagID = "TDM CTL"; |
| switch (ui32TagSB) |
| { |
| case RGX_MH_TAG_SB_TDM_CTL_ENCODING_TDM_CTL_TAG_FENCE: pszTagSB = "Fence"; break; |
| case RGX_MH_TAG_SB_TDM_CTL_ENCODING_TDM_CTL_TAG_CONTEXT: pszTagSB = "Context"; break; |
| case RGX_MH_TAG_SB_TDM_CTL_ENCODING_TDM_CTL_TAG_QUEUE: pszTagSB = "Queue"; break; |
| } |
| break; |
| } |
| |
| /* PBE */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_PBE0: |
| pszTagID = "PBE0"; break; |
| case RGX_MH_TAG_ENCODING_MH_TAG_PBE1: |
| pszTagID = "PBE1"; break; |
| |
| /* IPP */ |
| case RGX_MH_TAG_ENCODING_MH_TAG_IPP: |
| pszTagID = "IPP"; break; |
| } |
| |
| *ppszTagID = pszTagID; |
| *ppszTagSB = pszTagSB; |
| } |
| |
| |
| static void _RGXDecodeBIFReqTags(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXDBG_BIF_ID eBankID, |
| IMG_UINT32 ui32TagID, |
| IMG_UINT32 ui32TagSB, |
| IMG_CHAR **ppszTagID, |
| IMG_CHAR **ppszTagSB, |
| IMG_CHAR *pszScratchBuf, |
| IMG_UINT32 ui32ScratchBufSize) |
| { |
| /* default to unknown */ |
| IMG_CHAR *pszTagID = "-"; |
| IMG_CHAR *pszTagSB = "-"; |
| |
| PVR_ASSERT(ppszTagID != NULL); |
| PVR_ASSERT(ppszTagSB != NULL); |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, XE_MEMORY_HIERARCHY)) |
| { |
| _RGXDecodeBIFReqTagsXE(psDevInfo, ui32TagID, ui32TagSB, ppszTagID, ppszTagSB, pszScratchBuf, ui32ScratchBufSize); |
| return; |
| } |
| |
| switch (ui32TagID) |
| { |
| case 0x0: |
| { |
| pszTagID = "MMU"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Table"; break; |
| case 0x1: pszTagSB = "Directory"; break; |
| case 0x2: pszTagSB = "Catalogue"; break; |
| } |
| break; |
| } |
| case 0x1: |
| { |
| pszTagID = "TLA"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Pixel data"; break; |
| case 0x1: pszTagSB = "Command stream data"; break; |
| case 0x2: pszTagSB = "Fence or flush"; break; |
| } |
| break; |
| } |
| case 0x2: |
| { |
| pszTagID = "HOST"; |
| break; |
| } |
| case 0x3: |
| { |
| if (!RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS)) |
| { |
| pszTagID = "META"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "DCache - Thread 0"; break; |
| case 0x1: pszTagSB = "ICache - Thread 0"; break; |
| case 0x2: pszTagSB = "JTag - Thread 0"; break; |
| case 0x3: pszTagSB = "Slave bus - Thread 0"; break; |
| case 0x4: pszTagSB = "DCache - Thread "; break; |
| case 0x5: pszTagSB = "ICache - Thread 1"; break; |
| case 0x6: pszTagSB = "JTag - Thread 1"; break; |
| case 0x7: pszTagSB = "Slave bus - Thread 1"; break; |
| } |
| } |
| else if (RGX_IS_ERN_SUPPORTED(psDevInfo, 57596)) |
| { |
| pszTagID="TCU"; |
| } |
| else |
| { |
| /* Unreachable code */ |
| PVR_ASSERT(IMG_FALSE); |
| } |
| break; |
| } |
| case 0x4: |
| { |
| pszTagID = "USC"; |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, |
| "Cache line %d", (ui32TagSB & 0x3f)); |
| pszTagSB = pszScratchBuf; |
| break; |
| } |
| case 0x5: |
| { |
| pszTagID = "PBE"; |
| break; |
| } |
| case 0x6: |
| { |
| pszTagID = "ISP"; |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "ZLS"; break; |
| case 0x20: pszTagSB = "Occlusion Query"; break; |
| } |
| break; |
| } |
| case 0x7: |
| { |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, CLUSTER_GROUPING)) |
| { |
| if (eBankID == RGXDBG_TEXAS_BIF) |
| { |
| pszTagID = "IPF"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "CPF"; break; |
| case 0x1: pszTagSB = "DBSC"; break; |
| case 0x2: |
| case 0x4: |
| case 0x6: |
| case 0x8: pszTagSB = "Control Stream"; break; |
| case 0x3: |
| case 0x5: |
| case 0x7: |
| case 0x9: pszTagSB = "Primitive Block"; break; |
| } |
| } |
| else |
| { |
| pszTagID = "IPP"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Macrotile Header"; break; |
| case 0x1: pszTagSB = "Region Header"; break; |
| } |
| } |
| } |
| else if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, SIMPLE_INTERNAL_PARAMETER_FORMAT)) |
| { |
| pszTagID = "IPF"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Region Header"; break; |
| case 0x1: pszTagSB = "DBSC"; break; |
| case 0x2: pszTagSB = "CPF"; break; |
| case 0x3: pszTagSB = "Control Stream"; break; |
| case 0x4: pszTagSB = "Primitive Block"; break; |
| } |
| } |
| else |
| { |
| pszTagID = "IPF"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Macrotile Header"; break; |
| case 0x1: pszTagSB = "Region Header"; break; |
| case 0x2: pszTagSB = "DBSC"; break; |
| case 0x3: pszTagSB = "CPF"; break; |
| case 0x4: |
| case 0x6: |
| case 0x8: pszTagSB = "Control Stream"; break; |
| case 0x5: |
| case 0x7: |
| case 0x9: pszTagSB = "Primitive Block"; break; |
| } |
| } |
| break; |
| } |
| case 0x8: |
| { |
| pszTagID = "CDM"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Control Stream"; break; |
| case 0x1: pszTagSB = "Indirect Data"; break; |
| case 0x2: pszTagSB = "Event Write"; break; |
| case 0x3: pszTagSB = "Context State"; break; |
| } |
| break; |
| } |
| case 0x9: |
| { |
| pszTagID = "VDM"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Control Stream"; break; |
| case 0x1: pszTagSB = "PPP State"; break; |
| case 0x2: pszTagSB = "Index Data"; break; |
| case 0x4: pszTagSB = "Call Stack"; break; |
| case 0x8: pszTagSB = "Context State"; break; |
| } |
| break; |
| } |
| case 0xA: |
| { |
| pszTagID = "PM"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "PMA_TAFSTACK"; break; |
| case 0x1: pszTagSB = "PMA_TAMLIST"; break; |
| case 0x2: pszTagSB = "PMA_3DFSTACK"; break; |
| case 0x3: pszTagSB = "PMA_3DMLIST"; break; |
| case 0x4: pszTagSB = "PMA_PMCTX0"; break; |
| case 0x5: pszTagSB = "PMA_PMCTX1"; break; |
| case 0x6: pszTagSB = "PMA_MAVP"; break; |
| case 0x7: pszTagSB = "PMA_UFSTACK"; break; |
| case 0x8: pszTagSB = "PMD_TAFSTACK"; break; |
| case 0x9: pszTagSB = "PMD_TAMLIST"; break; |
| case 0xA: pszTagSB = "PMD_3DFSTACK"; break; |
| case 0xB: pszTagSB = "PMD_3DMLIST"; break; |
| case 0xC: pszTagSB = "PMD_PMCTX0"; break; |
| case 0xD: pszTagSB = "PMD_PMCTX1"; break; |
| case 0xF: pszTagSB = "PMD_UFSTACK"; break; |
| case 0x10: pszTagSB = "PMA_TAMMUSTACK"; break; |
| case 0x11: pszTagSB = "PMA_3DMMUSTACK"; break; |
| case 0x12: pszTagSB = "PMD_TAMMUSTACK"; break; |
| case 0x13: pszTagSB = "PMD_3DMMUSTACK"; break; |
| case 0x14: pszTagSB = "PMA_TAUFSTACK"; break; |
| case 0x15: pszTagSB = "PMA_3DUFSTACK"; break; |
| case 0x16: pszTagSB = "PMD_TAUFSTACK"; break; |
| case 0x17: pszTagSB = "PMD_3DUFSTACK"; break; |
| case 0x18: pszTagSB = "PMA_TAVFP"; break; |
| case 0x19: pszTagSB = "PMD_3DVFP"; break; |
| case 0x1A: pszTagSB = "PMD_TAVFP"; break; |
| } |
| break; |
| } |
| case 0xB: |
| { |
| pszTagID = "TA"; |
| switch (ui32TagSB) |
| { |
| case 0x1: pszTagSB = "VCE"; break; |
| case 0x2: pszTagSB = "TPC"; break; |
| case 0x3: pszTagSB = "TE Control Stream"; break; |
| case 0x4: pszTagSB = "TE Region Header"; break; |
| case 0x5: pszTagSB = "TE Render Target Cache"; break; |
| case 0x6: pszTagSB = "TEAC Render Target Cache"; break; |
| case 0x7: pszTagSB = "VCE Render Target Cache"; break; |
| case 0x8: pszTagSB = "PPP Context State"; break; |
| } |
| break; |
| } |
| case 0xC: |
| { |
| pszTagID = "TPF"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "TPF0: Primitive Block"; break; |
| case 0x1: pszTagSB = "TPF0: Depth Bias"; break; |
| case 0x2: pszTagSB = "TPF0: Per Primitive IDs"; break; |
| case 0x3: pszTagSB = "CPF - Tables"; break; |
| case 0x4: pszTagSB = "TPF1: Primitive Block"; break; |
| case 0x5: pszTagSB = "TPF1: Depth Bias"; break; |
| case 0x6: pszTagSB = "TPF1: Per Primitive IDs"; break; |
| case 0x7: pszTagSB = "CPF - Data: Pipe 0"; break; |
| case 0x8: pszTagSB = "TPF2: Primitive Block"; break; |
| case 0x9: pszTagSB = "TPF2: Depth Bias"; break; |
| case 0xA: pszTagSB = "TPF2: Per Primitive IDs"; break; |
| case 0xB: pszTagSB = "CPF - Data: Pipe 1"; break; |
| case 0xC: pszTagSB = "TPF3: Primitive Block"; break; |
| case 0xD: pszTagSB = "TPF3: Depth Bias"; break; |
| case 0xE: pszTagSB = "TPF3: Per Primitive IDs"; break; |
| case 0xF: pszTagSB = "CPF - Data: Pipe 2"; break; |
| } |
| break; |
| } |
| case 0xD: |
| { |
| pszTagID = "PDS"; |
| break; |
| } |
| case 0xE: |
| { |
| pszTagID = "MCU"; |
| { |
| IMG_UINT32 ui32Burst = (ui32TagSB >> 5) & 0x7; |
| IMG_UINT32 ui32GroupEnc = (ui32TagSB >> 2) & 0x7; |
| IMG_UINT32 ui32Group = ui32TagSB & 0x3; |
| |
| IMG_CHAR* pszBurst = ""; |
| IMG_CHAR* pszGroupEnc = ""; |
| IMG_CHAR* pszGroup = ""; |
| |
| switch (ui32Burst) |
| { |
| case 0x0: |
| case 0x1: pszBurst = "128bit word within the Lower 256bits"; break; |
| case 0x2: |
| case 0x3: pszBurst = "128bit word within the Upper 256bits"; break; |
| case 0x4: pszBurst = "Lower 256bits"; break; |
| case 0x5: pszBurst = "Upper 256bits"; break; |
| case 0x6: pszBurst = "512 bits"; break; |
| } |
| switch (ui32GroupEnc) |
| { |
| case 0x0: pszGroupEnc = "TPUA_USC"; break; |
| case 0x1: pszGroupEnc = "TPUB_USC"; break; |
| case 0x2: pszGroupEnc = "USCA_USC"; break; |
| case 0x3: pszGroupEnc = "USCB_USC"; break; |
| case 0x4: pszGroupEnc = "PDS_USC"; break; |
| case 0x5: |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_CLUSTERS) && |
| 6 > RGX_GET_FEATURE_VALUE(psDevInfo, NUM_CLUSTERS)) |
| { |
| pszGroupEnc = "PDSRW"; |
| } else if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_CLUSTERS) && |
| 6 == RGX_GET_FEATURE_VALUE(psDevInfo, NUM_CLUSTERS)) |
| { |
| pszGroupEnc = "UPUC_USC"; |
| } |
| break; |
| case 0x6: |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_CLUSTERS) && |
| 6 == RGX_GET_FEATURE_VALUE(psDevInfo, NUM_CLUSTERS)) |
| { |
| pszGroupEnc = "TPUC_USC"; |
| } |
| break; |
| case 0x7: |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_CLUSTERS) && |
| 6 == RGX_GET_FEATURE_VALUE(psDevInfo, NUM_CLUSTERS)) |
| { |
| pszGroupEnc = "PDSRW"; |
| } |
| break; |
| } |
| switch (ui32Group) |
| { |
| case 0x0: pszGroup = "Banks 0-3"; break; |
| case 0x1: pszGroup = "Banks 4-7"; break; |
| case 0x2: pszGroup = "Banks 8-11"; break; |
| case 0x3: pszGroup = "Banks 12-15"; break; |
| } |
| |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, |
| "%s, %s, %s", pszBurst, pszGroupEnc, pszGroup); |
| pszTagSB = pszScratchBuf; |
| } |
| break; |
| } |
| case 0xF: |
| { |
| pszTagID = "FB_CDC"; |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, XT_TOP_INFRASTRUCTURE)) |
| { |
| IMG_UINT32 ui32Req = (ui32TagSB >> 0) & 0xf; |
| IMG_UINT32 ui32MCUSB = (ui32TagSB >> 4) & 0x3; |
| IMG_CHAR* pszReqOrig = ""; |
| |
| switch (ui32Req) |
| { |
| case 0x0: pszReqOrig = "FBC Request, originator ZLS"; break; |
| case 0x1: pszReqOrig = "FBC Request, originator PBE"; break; |
| case 0x2: pszReqOrig = "FBC Request, originator Host"; break; |
| case 0x3: pszReqOrig = "FBC Request, originator TLA"; break; |
| case 0x4: pszReqOrig = "FBDC Request, originator ZLS"; break; |
| case 0x5: pszReqOrig = "FBDC Request, originator MCU"; break; |
| case 0x6: pszReqOrig = "FBDC Request, originator Host"; break; |
| case 0x7: pszReqOrig = "FBDC Request, originator TLA"; break; |
| case 0x8: pszReqOrig = "FBC Request, originator ZLS Requester Fence"; break; |
| case 0x9: pszReqOrig = "FBC Request, originator PBE Requester Fence"; break; |
| case 0xa: pszReqOrig = "FBC Request, originator Host Requester Fence"; break; |
| case 0xb: pszReqOrig = "FBC Request, originator TLA Requester Fence"; break; |
| case 0xc: pszReqOrig = "Reserved"; break; |
| case 0xd: pszReqOrig = "Reserved"; break; |
| case 0xe: pszReqOrig = "FBDC Request, originator FBCDC(Host) Memory Fence"; break; |
| case 0xf: pszReqOrig = "FBDC Request, originator FBCDC(TLA) Memory Fence"; break; |
| } |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, |
| "%s, MCU sideband 0x%X", pszReqOrig, ui32MCUSB); |
| pszTagSB = pszScratchBuf; |
| } |
| else |
| { |
| IMG_UINT32 ui32Req = (ui32TagSB >> 2) & 0x7; |
| IMG_UINT32 ui32MCUSB = (ui32TagSB >> 0) & 0x3; |
| IMG_CHAR* pszReqOrig = ""; |
| |
| switch (ui32Req) |
| { |
| case 0x0: pszReqOrig = "FBC Request, originator ZLS"; break; |
| case 0x1: pszReqOrig = "FBC Request, originator PBE"; break; |
| case 0x2: pszReqOrig = "FBC Request, originator Host"; break; |
| case 0x3: pszReqOrig = "FBC Request, originator TLA"; break; |
| case 0x4: pszReqOrig = "FBDC Request, originator ZLS"; break; |
| case 0x5: pszReqOrig = "FBDC Request, originator MCU"; break; |
| case 0x6: pszReqOrig = "FBDC Request, originator Host"; break; |
| case 0x7: pszReqOrig = "FBDC Request, originator TLA"; break; |
| } |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, |
| "%s, MCU sideband 0x%X", pszReqOrig, ui32MCUSB); |
| pszTagSB = pszScratchBuf; |
| } |
| break; |
| } |
| } /* switch(TagID) */ |
| |
| *ppszTagID = pszTagID; |
| *ppszTagSB = pszTagSB; |
| } |
| |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDecodeMMULevel |
| |
| @Description |
| |
| Return the name for the MMU level that faulted. |
| |
| @Input ui32MMULevel - MMU level |
| |
| @Return IMG_CHAR* to the sting describing the MMU level that faulted. |
| |
| ******************************************************************************/ |
| static const IMG_CHAR* _RGXDecodeMMULevel(IMG_UINT32 ui32MMULevel) |
| { |
| const IMG_CHAR* pszMMULevel = ""; |
| |
| switch (ui32MMULevel) |
| { |
| case 0x0: pszMMULevel = " (Page Table)"; break; |
| case 0x1: pszMMULevel = " (Page Directory)"; break; |
| case 0x2: pszMMULevel = " (Page Catalog)"; break; |
| case 0x3: pszMMULevel = " (Cat Base)"; break; |
| } |
| |
| return pszMMULevel; |
| } |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDecodeMMUReqTags |
| |
| @Description |
| |
| Decodes the MMU Tag ID and Sideband data fields from RGX_CR_MMU_FAULT_META_STATUS and |
| RGX_CR_MMU_FAULT_STATUS regs. |
| |
| @Input ui32TagID - Tag ID value |
| @Input ui32TagSB - Tag Sideband data |
| @Input bRead - Read flag |
| @Output ppszTagID - Decoded string from the Tag ID |
| @Output ppszTagSB - Decoded string from the Tag SB |
| @Output pszScratchBuf - Buffer provided to the function to generate the debug strings |
| @Input ui32ScratchBufSize - Size of the provided buffer |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDecodeMMUReqTags(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32TagID, |
| IMG_UINT32 ui32TagSB, |
| IMG_BOOL bRead, |
| IMG_CHAR **ppszTagID, |
| IMG_CHAR **ppszTagSB, |
| IMG_CHAR *pszScratchBuf, |
| IMG_UINT32 ui32ScratchBufSize) |
| { |
| IMG_INT32 i32SideBandType = -1; |
| IMG_CHAR *pszTagID = "-"; |
| IMG_CHAR *pszTagSB = "-"; |
| |
| PVR_ASSERT(ppszTagID != NULL); |
| PVR_ASSERT(ppszTagSB != NULL); |
| |
| |
| switch (ui32TagID) |
| { |
| case 0: pszTagID = "META (Jones)"; i32SideBandType = RGXDBG_META; break; |
| case 1: pszTagID = "TLA (Jones)"; i32SideBandType = RGXDBG_TLA; break; |
| case 2: pszTagID = "DMA (Jones)"; i32SideBandType = RGXDBG_DMA; break; |
| case 3: pszTagID = "VDMM (Jones)"; i32SideBandType = RGXDBG_VDMM; break; |
| case 4: pszTagID = "CDM (Jones)"; i32SideBandType = RGXDBG_CDM; break; |
| case 5: pszTagID = "IPP (Jones)"; i32SideBandType = RGXDBG_IPP; break; |
| case 6: pszTagID = "PM (Jones)"; i32SideBandType = RGXDBG_PM; break; |
| case 7: pszTagID = "Tiling (Jones)"; i32SideBandType = RGXDBG_TILING; break; |
| case 8: pszTagID = "MCU (Texas 0)"; i32SideBandType = RGXDBG_MCU; break; |
| case 12: pszTagID = "VDMS (Black Pearl 0)"; i32SideBandType = RGXDBG_VDMS; break; |
| case 13: pszTagID = "IPF (Black Pearl 0)"; i32SideBandType = RGXDBG_IPF; break; |
| case 14: pszTagID = "ISP (Black Pearl 0)"; i32SideBandType = RGXDBG_ISP; break; |
| case 15: pszTagID = "TPF (Black Pearl 0)"; i32SideBandType = RGXDBG_TPF; break; |
| case 16: pszTagID = "USCS (Black Pearl 0)"; i32SideBandType = RGXDBG_USCS; break; |
| case 17: pszTagID = "PPP (Black Pearl 0)"; i32SideBandType = RGXDBG_PPP; break; |
| case 20: pszTagID = "MCU (Texas 1)"; i32SideBandType = RGXDBG_MCU; break; |
| case 24: pszTagID = "MCU (Texas 2)"; i32SideBandType = RGXDBG_MCU; break; |
| case 28: pszTagID = "VDMS (Black Pearl 1)"; i32SideBandType = RGXDBG_VDMS; break; |
| case 29: pszTagID = "IPF (Black Pearl 1)"; i32SideBandType = RGXDBG_IPF; break; |
| case 30: pszTagID = "ISP (Black Pearl 1)"; i32SideBandType = RGXDBG_ISP; break; |
| case 31: pszTagID = "TPF (Black Pearl 1)"; i32SideBandType = RGXDBG_TPF; break; |
| case 32: pszTagID = "USCS (Black Pearl 1)"; i32SideBandType = RGXDBG_USCS; break; |
| case 33: pszTagID = "PPP (Black Pearl 1)"; i32SideBandType = RGXDBG_PPP; break; |
| case 36: pszTagID = "MCU (Texas 3)"; i32SideBandType = RGXDBG_MCU; break; |
| case 40: pszTagID = "MCU (Texas 4)"; i32SideBandType = RGXDBG_MCU; break; |
| case 44: pszTagID = "VDMS (Black Pearl 2)"; i32SideBandType = RGXDBG_VDMS; break; |
| case 45: pszTagID = "IPF (Black Pearl 2)"; i32SideBandType = RGXDBG_IPF; break; |
| case 46: pszTagID = "ISP (Black Pearl 2)"; i32SideBandType = RGXDBG_ISP; break; |
| case 47: pszTagID = "TPF (Black Pearl 2)"; i32SideBandType = RGXDBG_TPF; break; |
| case 48: pszTagID = "USCS (Black Pearl 2)"; i32SideBandType = RGXDBG_USCS; break; |
| case 49: pszTagID = "PPP (Black Pearl 2)"; i32SideBandType = RGXDBG_PPP; break; |
| case 52: pszTagID = "MCU (Texas 5)"; i32SideBandType = RGXDBG_MCU; break; |
| case 56: pszTagID = "MCU (Texas 6)"; i32SideBandType = RGXDBG_MCU; break; |
| case 60: pszTagID = "VDMS (Black Pearl 3)"; i32SideBandType = RGXDBG_VDMS; break; |
| case 61: pszTagID = "IPF (Black Pearl 3)"; i32SideBandType = RGXDBG_IPF; break; |
| case 62: pszTagID = "ISP (Black Pearl 3)"; i32SideBandType = RGXDBG_ISP; break; |
| case 63: pszTagID = "TPF (Black Pearl 3)"; i32SideBandType = RGXDBG_TPF; break; |
| case 64: pszTagID = "USCS (Black Pearl 3)"; i32SideBandType = RGXDBG_USCS; break; |
| case 65: pszTagID = "PPP (Black Pearl 3)"; i32SideBandType = RGXDBG_PPP; break; |
| case 68: pszTagID = "MCU (Texas 7)"; i32SideBandType = RGXDBG_MCU; break; |
| } |
| if (('-' == pszTagID[0]) && '\n' == pszTagID[1]) |
| { |
| |
| if (RGX_IS_ERN_SUPPORTED(psDevInfo, 50539) || |
| (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, FBCDC_ARCHITECTURE) && RGX_GET_FEATURE_VALUE(psDevInfo, FBCDC_ARCHITECTURE) >= 3)) |
| { |
| switch (ui32TagID) |
| { |
| case 18: pszTagID = "TPF_CPF (Black Pearl 0)"; i32SideBandType = RGXDBG_TPF_CPF; break; |
| case 19: pszTagID = "IPF_CPF (Black Pearl 0)"; i32SideBandType = RGXDBG_IPF_CPF; break; |
| case 34: pszTagID = "TPF_CPF (Black Pearl 1)"; i32SideBandType = RGXDBG_TPF_CPF; break; |
| case 35: pszTagID = "IPF_CPF (Black Pearl 1)"; i32SideBandType = RGXDBG_IPF_CPF; break; |
| case 50: pszTagID = "TPF_CPF (Black Pearl 2)"; i32SideBandType = RGXDBG_TPF_CPF; break; |
| case 51: pszTagID = "IPF_CPF (Black Pearl 2)"; i32SideBandType = RGXDBG_IPF_CPF; break; |
| case 66: pszTagID = "TPF_CPF (Black Pearl 3)"; i32SideBandType = RGXDBG_TPF_CPF; break; |
| case 67: pszTagID = "IPF_CPF (Black Pearl 3)"; i32SideBandType = RGXDBG_IPF_CPF; break; |
| } |
| |
| if (RGX_IS_ERN_SUPPORTED(psDevInfo, 50539)) |
| { |
| switch (ui32TagID) |
| { |
| case 9: pszTagID = "PBE (Texas 0)"; i32SideBandType = RGXDBG_PBE; break; |
| case 10: pszTagID = "PDS (Texas 0)"; i32SideBandType = RGXDBG_PDS; break; |
| case 11: pszTagID = "FBCDC (Texas 0)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 21: pszTagID = "PBE (Texas 1)"; i32SideBandType = RGXDBG_PBE; break; |
| case 22: pszTagID = "PDS (Texas 1)"; i32SideBandType = RGXDBG_PDS; break; |
| case 23: pszTagID = "FBCDC (Texas 1)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 25: pszTagID = "PBE (Texas 2)"; i32SideBandType = RGXDBG_PBE; break; |
| case 26: pszTagID = "PDS (Texas 2)"; i32SideBandType = RGXDBG_PDS; break; |
| case 27: pszTagID = "FBCDC (Texas 2)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 37: pszTagID = "PBE (Texas 3)"; i32SideBandType = RGXDBG_PBE; break; |
| case 38: pszTagID = "PDS (Texas 3)"; i32SideBandType = RGXDBG_PDS; break; |
| case 39: pszTagID = "FBCDC (Texas 3)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 41: pszTagID = "PBE (Texas 4)"; i32SideBandType = RGXDBG_PBE; break; |
| case 42: pszTagID = "PDS (Texas 4)"; i32SideBandType = RGXDBG_PDS; break; |
| case 43: pszTagID = "FBCDC (Texas 4)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 53: pszTagID = "PBE (Texas 5)"; i32SideBandType = RGXDBG_PBE; break; |
| case 54: pszTagID = "PDS (Texas 5)"; i32SideBandType = RGXDBG_PDS; break; |
| case 55: pszTagID = "FBCDC (Texas 5)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 57: pszTagID = "PBE (Texas 6)"; i32SideBandType = RGXDBG_PBE; break; |
| case 58: pszTagID = "PDS (Texas 6)"; i32SideBandType = RGXDBG_PDS; break; |
| case 59: pszTagID = "FBCDC (Texas 6)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 69: pszTagID = "PBE (Texas 7)"; i32SideBandType = RGXDBG_PBE; break; |
| case 70: pszTagID = "PDS (Texas 7)"; i32SideBandType = RGXDBG_PDS; break; |
| case 71: pszTagID = "FBCDC (Texas 7)"; i32SideBandType = RGXDBG_FBCDC; break; |
| } |
| }else |
| { |
| switch (ui32TagID) |
| { |
| case 9: pszTagID = "PDS (Texas 0)"; i32SideBandType = RGXDBG_PDS; break; |
| case 10: pszTagID = "PBE (Texas 0)"; i32SideBandType = RGXDBG_PBE; break; |
| case 11: pszTagID = "FBCDC (Texas 0)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 21: pszTagID = "PDS (Texas 1)"; i32SideBandType = RGXDBG_PDS; break; |
| case 22: pszTagID = "PBE (Texas 1)"; i32SideBandType = RGXDBG_PBE; break; |
| case 23: pszTagID = "FBCDC (Texas 1)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 25: pszTagID = "PDS (Texas 2)"; i32SideBandType = RGXDBG_PDS; break; |
| case 26: pszTagID = "PBE (Texas 2)"; i32SideBandType = RGXDBG_PBE; break; |
| case 27: pszTagID = "FBCDC (Texas 2)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 37: pszTagID = "PDS (Texas 3)"; i32SideBandType = RGXDBG_PDS; break; |
| case 38: pszTagID = "PBE (Texas 3)"; i32SideBandType = RGXDBG_PBE; break; |
| case 39: pszTagID = "FBCDC (Texas 3)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 41: pszTagID = "PDS (Texas 4)"; i32SideBandType = RGXDBG_PDS; break; |
| case 42: pszTagID = "PBE (Texas 4)"; i32SideBandType = RGXDBG_PBE; break; |
| case 43: pszTagID = "FBCDC (Texas 4)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 53: pszTagID = "PDS (Texas 5)"; i32SideBandType = RGXDBG_PDS; break; |
| case 54: pszTagID = "PBE (Texas 5)"; i32SideBandType = RGXDBG_PBE; break; |
| case 55: pszTagID = "FBCDC (Texas 5)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 57: pszTagID = "PDS (Texas 6)"; i32SideBandType = RGXDBG_PDS; break; |
| case 58: pszTagID = "PBE (Texas 6)"; i32SideBandType = RGXDBG_PBE; break; |
| case 59: pszTagID = "FBCDC (Texas 6)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 69: pszTagID = "PDS (Texas 7)"; i32SideBandType = RGXDBG_PDS; break; |
| case 70: pszTagID = "PBE (Texas 7)"; i32SideBandType = RGXDBG_PBE; break; |
| case 71: pszTagID = "FBCDC (Texas 7)"; i32SideBandType = RGXDBG_FBCDC; break; |
| } |
| } |
| }else |
| { |
| switch (ui32TagID) |
| { |
| case 9: pszTagID = "PDS (Texas 0)"; i32SideBandType = RGXDBG_PDS; break; |
| case 10: pszTagID = "PBE0 (Texas 0)"; i32SideBandType = RGXDBG_PBE; break; |
| case 11: pszTagID = "PBE1 (Texas 0)"; i32SideBandType = RGXDBG_PBE; break; |
| case 18: pszTagID = "VCE (Black Pearl 0)"; i32SideBandType = RGXDBG_VCE; break; |
| case 19: pszTagID = "FBCDC (Black Pearl 0)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 21: pszTagID = "PDS (Texas 1)"; i32SideBandType = RGXDBG_PDS; break; |
| case 22: pszTagID = "PBE0 (Texas 1)"; i32SideBandType = RGXDBG_PBE; break; |
| case 23: pszTagID = "PBE1 (Texas 1)"; i32SideBandType = RGXDBG_PBE; break; |
| case 25: pszTagID = "PDS (Texas 2)"; i32SideBandType = RGXDBG_PDS; break; |
| case 26: pszTagID = "PBE0 (Texas 2)"; i32SideBandType = RGXDBG_PBE; break; |
| case 27: pszTagID = "PBE1 (Texas 2)"; i32SideBandType = RGXDBG_PBE; break; |
| case 34: pszTagID = "VCE (Black Pearl 1)"; i32SideBandType = RGXDBG_VCE; break; |
| case 35: pszTagID = "FBCDC (Black Pearl 1)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 37: pszTagID = "PDS (Texas 3)"; i32SideBandType = RGXDBG_PDS; break; |
| case 38: pszTagID = "PBE0 (Texas 3)"; i32SideBandType = RGXDBG_PBE; break; |
| case 39: pszTagID = "PBE1 (Texas 3)"; i32SideBandType = RGXDBG_PBE; break; |
| case 41: pszTagID = "PDS (Texas 4)"; i32SideBandType = RGXDBG_PDS; break; |
| case 42: pszTagID = "PBE0 (Texas 4)"; i32SideBandType = RGXDBG_PBE; break; |
| case 43: pszTagID = "PBE1 (Texas 4)"; i32SideBandType = RGXDBG_PBE; break; |
| case 50: pszTagID = "VCE (Black Pearl 2)"; i32SideBandType = RGXDBG_VCE; break; |
| case 51: pszTagID = "FBCDC (Black Pearl 2)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 53: pszTagID = "PDS (Texas 5)"; i32SideBandType = RGXDBG_PDS; break; |
| case 54: pszTagID = "PBE0 (Texas 5)"; i32SideBandType = RGXDBG_PBE; break; |
| case 55: pszTagID = "PBE1 (Texas 5)"; i32SideBandType = RGXDBG_PBE; break; |
| case 57: pszTagID = "PDS (Texas 6)"; i32SideBandType = RGXDBG_PDS; break; |
| case 58: pszTagID = "PBE0 (Texas 6)"; i32SideBandType = RGXDBG_PBE; break; |
| case 59: pszTagID = "PBE1 (Texas 6)"; i32SideBandType = RGXDBG_PBE; break; |
| case 66: pszTagID = "VCE (Black Pearl 3)"; i32SideBandType = RGXDBG_VCE; break; |
| case 67: pszTagID = "FBCDC (Black Pearl 3)"; i32SideBandType = RGXDBG_FBCDC; break; |
| case 69: pszTagID = "PDS (Texas 7)"; i32SideBandType = RGXDBG_PDS; break; |
| case 70: pszTagID = "PBE0 (Texas 7)"; i32SideBandType = RGXDBG_PBE; break; |
| case 71: pszTagID = "PBE1 (Texas 7)"; i32SideBandType = RGXDBG_PBE; break; |
| } |
| } |
| |
| } |
| |
| switch (i32SideBandType) |
| { |
| case RGXDBG_META: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "DCache - Thread 0"; break; |
| case 0x1: pszTagSB = "ICache - Thread 0"; break; |
| case 0x2: pszTagSB = "JTag - Thread 0"; break; |
| case 0x3: pszTagSB = "Slave bus - Thread 0"; break; |
| case 0x4: pszTagSB = "DCache - Thread 1"; break; |
| case 0x5: pszTagSB = "ICache - Thread 1"; break; |
| case 0x6: pszTagSB = "JTag - Thread 1"; break; |
| case 0x7: pszTagSB = "Slave bus - Thread 1"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_TLA: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Pixel data"; break; |
| case 0x1: pszTagSB = "Command stream data"; break; |
| case 0x2: pszTagSB = "Fence or flush"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_VDMM: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Control Stream - Read Only"; break; |
| case 0x1: pszTagSB = "PPP State - Read Only"; break; |
| case 0x2: pszTagSB = "Indices - Read Only"; break; |
| case 0x4: pszTagSB = "Call Stack - Read/Write"; break; |
| case 0x6: pszTagSB = "DrawIndirect - Read Only"; break; |
| case 0xA: pszTagSB = "Context State - Write Only"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_CDM: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Control Stream"; break; |
| case 0x1: pszTagSB = "Indirect Data"; break; |
| case 0x2: pszTagSB = "Event Write"; break; |
| case 0x3: pszTagSB = "Context State"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_IPP: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Macrotile Header"; break; |
| case 0x1: pszTagSB = "Region Header"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_PM: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "PMA_TAFSTACK"; break; |
| case 0x1: pszTagSB = "PMA_TAMLIST"; break; |
| case 0x2: pszTagSB = "PMA_3DFSTACK"; break; |
| case 0x3: pszTagSB = "PMA_3DMLIST"; break; |
| case 0x4: pszTagSB = "PMA_PMCTX0"; break; |
| case 0x5: pszTagSB = "PMA_PMCTX1"; break; |
| case 0x6: pszTagSB = "PMA_MAVP"; break; |
| case 0x7: pszTagSB = "PMA_UFSTACK"; break; |
| case 0x8: pszTagSB = "PMD_TAFSTACK"; break; |
| case 0x9: pszTagSB = "PMD_TAMLIST"; break; |
| case 0xA: pszTagSB = "PMD_3DFSTACK"; break; |
| case 0xB: pszTagSB = "PMD_3DMLIST"; break; |
| case 0xC: pszTagSB = "PMD_PMCTX0"; break; |
| case 0xD: pszTagSB = "PMD_PMCTX1"; break; |
| case 0xF: pszTagSB = "PMD_UFSTACK"; break; |
| case 0x10: pszTagSB = "PMA_TAMMUSTACK"; break; |
| case 0x11: pszTagSB = "PMA_3DMMUSTACK"; break; |
| case 0x12: pszTagSB = "PMD_TAMMUSTACK"; break; |
| case 0x13: pszTagSB = "PMD_3DMMUSTACK"; break; |
| case 0x14: pszTagSB = "PMA_TAUFSTACK"; break; |
| case 0x15: pszTagSB = "PMA_3DUFSTACK"; break; |
| case 0x16: pszTagSB = "PMD_TAUFSTACK"; break; |
| case 0x17: pszTagSB = "PMD_3DUFSTACK"; break; |
| case 0x18: pszTagSB = "PMA_TAVFP"; break; |
| case 0x19: pszTagSB = "PMD_3DVFP"; break; |
| case 0x1A: pszTagSB = "PMD_TAVFP"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_TILING: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "PSG Control Stream TP0"; break; |
| case 0x1: pszTagSB = "TPC TP0"; break; |
| case 0x2: pszTagSB = "VCE0"; break; |
| case 0x3: pszTagSB = "VCE1"; break; |
| case 0x4: pszTagSB = "PSG Control Stream TP1"; break; |
| case 0x5: pszTagSB = "TPC TP1"; break; |
| case 0x8: pszTagSB = "PSG Region Header TP0"; break; |
| case 0xC: pszTagSB = "PSG Region Header TP1"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_VDMS: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Context State - Write Only"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_IPF: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x00: |
| case 0x20: pszTagSB = "CPF"; break; |
| case 0x01: pszTagSB = "DBSC"; break; |
| case 0x02: |
| case 0x04: |
| case 0x06: |
| case 0x08: |
| case 0x0A: |
| case 0x0C: |
| case 0x0E: |
| case 0x10: pszTagSB = "Control Stream"; break; |
| case 0x03: |
| case 0x05: |
| case 0x07: |
| case 0x09: |
| case 0x0B: |
| case 0x0D: |
| case 0x0F: |
| case 0x11: pszTagSB = "Primitive Block"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_ISP: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "ZLS read/write"; break; |
| case 0x20: pszTagSB = "Occlusion query read/write"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_TPF: |
| { |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "TPF0: Primitive Block"; break; |
| case 0x1: pszTagSB = "TPF0: Depth Bias"; break; |
| case 0x2: pszTagSB = "TPF0: Per Primitive IDs"; break; |
| case 0x3: pszTagSB = "CPF - Tables"; break; |
| case 0x4: pszTagSB = "TPF1: Primitive Block"; break; |
| case 0x5: pszTagSB = "TPF1: Depth Bias"; break; |
| case 0x6: pszTagSB = "TPF1: Per Primitive IDs"; break; |
| case 0x7: pszTagSB = "CPF - Data: Pipe 0"; break; |
| case 0x8: pszTagSB = "TPF2: Primitive Block"; break; |
| case 0x9: pszTagSB = "TPF2: Depth Bias"; break; |
| case 0xA: pszTagSB = "TPF2: Per Primitive IDs"; break; |
| case 0xB: pszTagSB = "CPF - Data: Pipe 1"; break; |
| case 0xC: pszTagSB = "TPF3: Primitive Block"; break; |
| case 0xD: pszTagSB = "TPF3: Depth Bias"; break; |
| case 0xE: pszTagSB = "TPF3: Per Primitive IDs"; break; |
| case 0xF: pszTagSB = "CPF - Data: Pipe 2"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_FBCDC: |
| { |
| /* |
| * FBC faults on a 4-cluster phantom does not always set SB |
| * bit 5, but since FBC is write-only and FBDC is read-only, |
| * we can set bit 5 if this is a write fault, before decoding. |
| */ |
| if (bRead == IMG_FALSE) |
| { |
| ui32TagSB |= 0x20; |
| } |
| |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "FBDC Request, originator ZLS"; break; |
| case 0x02: pszTagSB = "FBDC Request, originator MCU Dust 0"; break; |
| case 0x03: pszTagSB = "FBDC Request, originator MCU Dust 1"; break; |
| case 0x20: pszTagSB = "FBC Request, originator ZLS"; break; |
| case 0x22: pszTagSB = "FBC Request, originator PBE Dust 0, Cluster 0"; break; |
| case 0x23: pszTagSB = "FBC Request, originator PBE Dust 0, Cluster 1"; break; |
| case 0x24: pszTagSB = "FBC Request, originator PBE Dust 1, Cluster 0"; break; |
| case 0x25: pszTagSB = "FBC Request, originator PBE Dust 1, Cluster 1"; break; |
| case 0x28: pszTagSB = "FBC Request, originator ZLS Fence"; break; |
| case 0x2a: pszTagSB = "FBC Request, originator PBE Dust 0, Cluster 0, Fence"; break; |
| case 0x2b: pszTagSB = "FBC Request, originator PBE Dust 0, Cluster 1, Fence"; break; |
| case 0x2c: pszTagSB = "FBC Request, originator PBE Dust 1, Cluster 0, Fence"; break; |
| case 0x2d: pszTagSB = "FBC Request, originator PBE Dust 1, Cluster 1, Fence"; break; |
| } |
| break; |
| } |
| |
| case RGXDBG_MCU: |
| { |
| IMG_UINT32 ui32SetNumber = (ui32TagSB >> 5) & 0x7; |
| IMG_UINT32 ui32WayNumber = (ui32TagSB >> 2) & 0x7; |
| IMG_UINT32 ui32Group = ui32TagSB & 0x3; |
| |
| IMG_CHAR* pszGroup = ""; |
| |
| switch (ui32Group) |
| { |
| case 0x0: pszGroup = "Banks 0-1"; break; |
| case 0x1: pszGroup = "Banks 2-3"; break; |
| case 0x2: pszGroup = "Banks 4-5"; break; |
| case 0x3: pszGroup = "Banks 6-7"; break; |
| } |
| |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, |
| "Set=%d, Way=%d, %s", ui32SetNumber, ui32WayNumber, pszGroup); |
| pszTagSB = pszScratchBuf; |
| break; |
| } |
| |
| default: |
| { |
| OSSNPrintf(pszScratchBuf, ui32ScratchBufSize, "SB=0x%02x", ui32TagSB); |
| pszTagSB = pszScratchBuf; |
| break; |
| } |
| } |
| |
| *ppszTagID = pszTagID; |
| *ppszTagSB = pszTagSB; |
| } |
| |
| static void ConvertOSTimestampToSAndNS(IMG_UINT64 ui64OSTimer, |
| IMG_UINT64 *pui64Seconds, |
| IMG_UINT64 *pui64Nanoseconds) |
| { |
| IMG_UINT32 ui32Remainder; |
| |
| *pui64Seconds = OSDivide64r64(ui64OSTimer, 1000000000, &ui32Remainder); |
| *pui64Nanoseconds = ui64OSTimer - (*pui64Seconds * 1000000000ULL); |
| } |
| |
| |
| typedef enum _DEVICEMEM_HISTORY_QUERY_INDEX_ |
| { |
| DEVICEMEM_HISTORY_QUERY_INDEX_PRECEDING, |
| DEVICEMEM_HISTORY_QUERY_INDEX_FAULTED, |
| DEVICEMEM_HISTORY_QUERY_INDEX_NEXT, |
| DEVICEMEM_HISTORY_QUERY_INDEX_COUNT, |
| } DEVICEMEM_HISTORY_QUERY_INDEX; |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _PrintDevicememHistoryQueryResult |
| |
| @Description |
| |
| Print details of a single result from a DevicememHistory query |
| |
| @Input pfnDumpDebugPrintf - Debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psFaultProcessInfo - The process info derived from the page fault |
| @Input psResult - The DevicememHistory result to be printed |
| @Input ui32Index - The index of the result |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _PrintDevicememHistoryQueryResult(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| RGXMEM_PROCESS_INFO *psFaultProcessInfo, |
| DEVICEMEM_HISTORY_QUERY_OUT_RESULT *psResult, |
| IMG_UINT32 ui32Index) |
| { |
| IMG_UINT32 ui32Remainder; |
| IMG_UINT64 ui64Seconds, ui64Nanoseconds; |
| |
| ConvertOSTimestampToSAndNS(psResult->ui64When, |
| &ui64Seconds, |
| &ui64Nanoseconds); |
| |
| if (psFaultProcessInfo->uiPID != RGXMEM_SERVER_PID_FIRMWARE) |
| { |
| PVR_DUMPDEBUG_LOG(" [%u] Name: %s Base address: " IMG_DEV_VIRTADDR_FMTSPEC |
| " Size: " IMG_DEVMEM_SIZE_FMTSPEC |
| " Operation: %s Modified: %" IMG_UINT64_FMTSPEC |
| " us ago (OS time %" IMG_UINT64_FMTSPEC |
| ".%09" IMG_UINT64_FMTSPEC " s)", |
| ui32Index, |
| psResult->szString, |
| psResult->sBaseDevVAddr.uiAddr, |
| psResult->uiSize, |
| psResult->bMap ? "Map": "Unmap", |
| OSDivide64r64(psResult->ui64Age, 1000, &ui32Remainder), |
| ui64Seconds, |
| ui64Nanoseconds); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" [%u] Name: %s Base address: " IMG_DEV_VIRTADDR_FMTSPEC |
| " Size: " IMG_DEVMEM_SIZE_FMTSPEC |
| " Operation: %s Modified: %" IMG_UINT64_FMTSPEC |
| " us ago (OS time %" IMG_UINT64_FMTSPEC |
| ".%09" IMG_UINT64_FMTSPEC |
| ") PID: %u (%s)", |
| ui32Index, |
| psResult->szString, |
| psResult->sBaseDevVAddr.uiAddr, |
| psResult->uiSize, |
| psResult->bMap ? "Map": "Unmap", |
| OSDivide64r64(psResult->ui64Age, 1000, &ui32Remainder), |
| ui64Seconds, |
| ui64Nanoseconds, |
| psResult->sProcessInfo.uiPID, |
| psResult->sProcessInfo.szProcessName); |
| } |
| |
| if (!psResult->bRange) |
| { |
| PVR_DUMPDEBUG_LOG(" Whole allocation was %s", psResult->bMap ? "mapped": "unmapped"); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" Pages %u to %u (" IMG_DEV_VIRTADDR_FMTSPEC "-" IMG_DEV_VIRTADDR_FMTSPEC ") %s%s", |
| psResult->ui32StartPage, |
| psResult->ui32StartPage + psResult->ui32PageCount - 1, |
| psResult->sMapStartAddr.uiAddr, |
| psResult->sMapEndAddr.uiAddr, |
| psResult->bAll ? "(whole allocation) " : "", |
| psResult->bMap ? "mapped": "unmapped"); |
| } |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _PrintDevicememHistoryQueryOut |
| |
| @Description |
| |
| Print details of all the results from a DevicememHistory query |
| |
| @Input pfnDumpDebugPrintf - Debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psFaultProcessInfo - The process info derived from the page fault |
| @Input psQueryOut - Storage for the query results |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _PrintDevicememHistoryQueryOut(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| RGXMEM_PROCESS_INFO *psFaultProcessInfo, |
| DEVICEMEM_HISTORY_QUERY_OUT *psQueryOut) |
| { |
| IMG_UINT32 i; |
| |
| if (psQueryOut->ui32NumResults == 0) |
| { |
| PVR_DUMPDEBUG_LOG(" No results"); |
| } |
| else |
| { |
| for (i = 0; i < psQueryOut->ui32NumResults; i++) |
| { |
| _PrintDevicememHistoryQueryResult(pfnDumpDebugPrintf, pvDumpDebugFile, |
| psFaultProcessInfo, |
| &psQueryOut->sResults[i], |
| i); |
| } |
| } |
| } |
| |
| /* table of HW page size values and the equivalent */ |
| static const unsigned int aui32HWPageSizeTable[][2] = |
| { |
| { 0, PVRSRV_4K_PAGE_SIZE }, |
| { 1, PVRSRV_16K_PAGE_SIZE }, |
| { 2, PVRSRV_64K_PAGE_SIZE }, |
| { 3, PVRSRV_256K_PAGE_SIZE }, |
| { 4, PVRSRV_1M_PAGE_SIZE }, |
| { 5, PVRSRV_2M_PAGE_SIZE } |
| }; |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _PageSizeHWToBytes |
| |
| @Description |
| |
| Convert a HW page size value to its size in bytes |
| |
| @Input ui32PageSizeHW - The HW page size value |
| |
| @Return IMG_UINT32 The page size in bytes |
| |
| ******************************************************************************/ |
| static IMG_UINT32 _PageSizeHWToBytes(IMG_UINT32 ui32PageSizeHW) |
| { |
| if (ui32PageSizeHW > 5) |
| { |
| /* This is invalid, so return a default value as we cannot ASSERT in this code! */ |
| return PVRSRV_4K_PAGE_SIZE; |
| } |
| |
| return aui32HWPageSizeTable[ui32PageSizeHW][1]; |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _GetDevicememHistoryData |
| |
| @Description |
| |
| Get the DevicememHistory results for the given PID and faulting device virtual address. |
| The function will query DevicememHistory for information about the faulting page, as well |
| as the page before and after. |
| |
| @Input uiPID - The process ID to search for allocations belonging to |
| @Input sFaultDevVAddr - The device address to search for allocations at/before/after |
| @Input asQueryOut - Storage for the query results |
| @Input ui32PageSizeBytes - Faulted page size in bytes |
| |
| @Return IMG_BOOL - IMG_TRUE if any results were found for this page fault |
| |
| ******************************************************************************/ |
| static IMG_BOOL _GetDevicememHistoryData(IMG_PID uiPID, IMG_DEV_VIRTADDR sFaultDevVAddr, |
| DEVICEMEM_HISTORY_QUERY_OUT asQueryOut[DEVICEMEM_HISTORY_QUERY_INDEX_COUNT], |
| IMG_UINT32 ui32PageSizeBytes) |
| { |
| IMG_UINT32 i; |
| DEVICEMEM_HISTORY_QUERY_IN sQueryIn; |
| IMG_BOOL bAnyHits = IMG_FALSE; |
| |
| /* if the page fault originated in the firmware then the allocation may |
| * appear to belong to any PID, because FW allocations are attributed |
| * to the client process creating the allocation, so instruct the |
| * devicemem_history query to search all available PIDs |
| */ |
| if (uiPID == RGXMEM_SERVER_PID_FIRMWARE) |
| { |
| sQueryIn.uiPID = DEVICEMEM_HISTORY_PID_ANY; |
| } |
| else |
| { |
| sQueryIn.uiPID = uiPID; |
| } |
| |
| /* query the DevicememHistory about the preceding / faulting / next page */ |
| |
| for (i = DEVICEMEM_HISTORY_QUERY_INDEX_PRECEDING; i < DEVICEMEM_HISTORY_QUERY_INDEX_COUNT; i++) |
| { |
| IMG_BOOL bHits; |
| |
| switch (i) |
| { |
| case DEVICEMEM_HISTORY_QUERY_INDEX_PRECEDING: |
| sQueryIn.sDevVAddr.uiAddr = (sFaultDevVAddr.uiAddr & ~(IMG_UINT64)(ui32PageSizeBytes - 1)) - 1; |
| break; |
| case DEVICEMEM_HISTORY_QUERY_INDEX_FAULTED: |
| sQueryIn.sDevVAddr = sFaultDevVAddr; |
| break; |
| case DEVICEMEM_HISTORY_QUERY_INDEX_NEXT: |
| sQueryIn.sDevVAddr.uiAddr = (sFaultDevVAddr.uiAddr & ~(IMG_UINT64)(ui32PageSizeBytes - 1)) + ui32PageSizeBytes; |
| break; |
| } |
| |
| /* First try matching any record at the exact address... */ |
| bHits = DevicememHistoryQuery(&sQueryIn, &asQueryOut[i], ui32PageSizeBytes, IMG_FALSE); |
| if (!bHits) |
| { |
| /* If not matched then try matching any record in the same page... */ |
| bHits = DevicememHistoryQuery(&sQueryIn, &asQueryOut[i], ui32PageSizeBytes, IMG_TRUE); |
| } |
| |
| if (bHits) |
| { |
| bAnyHits = IMG_TRUE; |
| } |
| } |
| |
| return bAnyHits; |
| } |
| |
| /* stored data about one page fault */ |
| typedef struct _FAULT_INFO_ |
| { |
| /* the process info of the memory context that page faulted */ |
| RGXMEM_PROCESS_INFO sProcessInfo; |
| IMG_DEV_VIRTADDR sFaultDevVAddr; |
| MMU_FAULT_DATA sMMUFaultData; |
| DEVICEMEM_HISTORY_QUERY_OUT asQueryOut[DEVICEMEM_HISTORY_QUERY_INDEX_COUNT]; |
| /* the CR timer value at the time of the fault, recorded by the FW. |
| * used to differentiate different page faults |
| */ |
| IMG_UINT64 ui64CRTimer; |
| /* time when this FAULT_INFO entry was added. used for timing |
| * reference against the map/unmap information |
| */ |
| IMG_UINT64 ui64When; |
| } FAULT_INFO; |
| |
| /* history list of page faults. |
| * Keeps the first `n` page faults and the last `n` page faults, like the FW |
| * HWR log |
| */ |
| typedef struct _FAULT_INFO_LOG_ |
| { |
| IMG_UINT32 ui32Head; |
| IMG_UINT32 ui32NumWrites; |
| /* the number of faults in this log need not correspond exactly to |
| * the HWINFO number of the FW, as the FW HWINFO log may contain |
| * non-page fault HWRs |
| */ |
| FAULT_INFO asFaults[RGXFWIF_HWINFO_MAX]; |
| } FAULT_INFO_LOG; |
| |
| static FAULT_INFO_LOG gsFaultInfoLog = { 0 }; |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _QueryFaultInfo |
| |
| @Description |
| |
| Searches the local list of previously analysed page faults to see if the given |
| fault has already been analysed and if so, returns a pointer to the analysis |
| object (FAULT_INFO *), otherwise returns NULL. |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input sFaultDevVAddr - The faulting device virtual address |
| @Input ui64CRTimer - The CR timer value recorded by the FW at the time of the fault |
| |
| @Return FAULT_INFO* Pointer to an existing fault analysis structure if found, otherwise NULL |
| |
| ******************************************************************************/ |
| static FAULT_INFO *_QueryFaultInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| IMG_DEV_VIRTADDR sFaultDevVAddr, |
| IMG_UINT64 ui64CRTimer) |
| { |
| IMG_UINT32 i; |
| |
| for (i = 0; i < MIN(gsFaultInfoLog.ui32NumWrites, RGXFWIF_HWINFO_MAX); i++) |
| { |
| if ((gsFaultInfoLog.asFaults[i].ui64CRTimer == ui64CRTimer) && |
| (gsFaultInfoLog.asFaults[i].sFaultDevVAddr.uiAddr == sFaultDevVAddr.uiAddr)) |
| { |
| return &gsFaultInfoLog.asFaults[i]; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function __AcquireNextFaultInfoElement |
| |
| @Description |
| |
| Gets a pointer to the next element in the fault info log |
| (requires the fault info lock be held) |
| |
| |
| @Return FAULT_INFO* Pointer to the next record for writing |
| |
| ******************************************************************************/ |
| |
| static FAULT_INFO *_AcquireNextFaultInfoElement(void) |
| { |
| IMG_UINT32 ui32Head = gsFaultInfoLog.ui32Head; |
| FAULT_INFO *psInfo = &gsFaultInfoLog.asFaults[ui32Head]; |
| |
| return psInfo; |
| } |
| |
| static void _CommitFaultInfo(PVRSRV_RGXDEV_INFO *psDevInfo, |
| FAULT_INFO *psInfo, |
| RGXMEM_PROCESS_INFO *psProcessInfo, |
| IMG_DEV_VIRTADDR sFaultDevVAddr, |
| IMG_UINT64 ui64CRTimer, |
| MMU_FAULT_DATA *psMMUFaultData) |
| { |
| IMG_UINT32 i, j; |
| |
| /* commit the page fault details */ |
| |
| psInfo->sProcessInfo = *psProcessInfo; |
| psInfo->sFaultDevVAddr = sFaultDevVAddr; |
| psInfo->ui64CRTimer = ui64CRTimer; |
| psInfo->ui64When = OSClockns64(); |
| if (psMMUFaultData != NULL) |
| { |
| OSDeviceMemCopy(&psInfo->sMMUFaultData, psMMUFaultData, sizeof(MMU_FAULT_DATA)); |
| } |
| |
| /* if the page fault was caused by the firmware then get information about |
| * which client application created the related allocations. |
| * |
| * Fill in the process info data for each query result. |
| */ |
| |
| if (psInfo->sProcessInfo.uiPID == RGXMEM_SERVER_PID_FIRMWARE) |
| { |
| for (i = 0; i < DEVICEMEM_HISTORY_QUERY_INDEX_COUNT; i++) |
| { |
| for (j = 0; j < DEVICEMEM_HISTORY_QUERY_OUT_MAX_RESULTS; j++) |
| { |
| IMG_BOOL bFound; |
| |
| RGXMEM_PROCESS_INFO *psProcInfo = &psInfo->asQueryOut[i].sResults[j].sProcessInfo; |
| bFound = RGXPCPIDToProcessInfo(psDevInfo, |
| psProcInfo->uiPID, |
| psProcInfo); |
| if (!bFound) |
| { |
| OSStringLCopy(psProcInfo->szProcessName, |
| "(unknown)", |
| sizeof(psProcInfo->szProcessName)); |
| } |
| } |
| } |
| } |
| |
| /* assert the faults circular buffer hasn't been moving and |
| * move the head along |
| */ |
| |
| PVR_ASSERT(psInfo == &gsFaultInfoLog.asFaults[gsFaultInfoLog.ui32Head]); |
| |
| if (gsFaultInfoLog.ui32Head < RGXFWIF_HWINFO_MAX - 1) |
| { |
| gsFaultInfoLog.ui32Head++; |
| } |
| else |
| { |
| /* wrap back to the first of the 'LAST' entries */ |
| gsFaultInfoLog.ui32Head = RGXFWIF_HWINFO_MAX_FIRST; |
| } |
| |
| gsFaultInfoLog.ui32NumWrites++; |
| |
| |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _PrintFaultInfo |
| |
| @Description |
| |
| Print all the details of a page fault from a FAULT_INFO structure |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psInfo - The page fault occurrence to print |
| @Input pui32Index - (optional) index value to include in the print output |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _PrintFaultInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| FAULT_INFO *psInfo, |
| const IMG_UINT32 *pui32Index) |
| { |
| IMG_UINT32 i; |
| IMG_UINT64 ui64Seconds, ui64Nanoseconds; |
| |
| IMG_PID uiPID; |
| |
| uiPID = (psInfo->sProcessInfo.uiPID == RGXMEM_SERVER_PID_FIRMWARE || psInfo->sProcessInfo.uiPID == RGXMEM_SERVER_PID_PM) ? |
| 0 : psInfo->sProcessInfo.uiPID; |
| |
| ConvertOSTimestampToSAndNS(psInfo->ui64When, &ui64Seconds, &ui64Nanoseconds); |
| |
| if (pui32Index) |
| { |
| PVR_DUMPDEBUG_LOG("(%u) Device memory history for page fault address" IMG_DEV_VIRTADDR_FMTSPEC |
| ", CRTimer: 0x%016" IMG_UINT64_FMTSPECx |
| ", PID: %u (%s, unregistered: %u) OS time: " |
| "%" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC, |
| *pui32Index, |
| psInfo->sFaultDevVAddr.uiAddr, |
| psInfo->ui64CRTimer, |
| uiPID, |
| psInfo->sProcessInfo.szProcessName, |
| psInfo->sProcessInfo.bUnregistered, |
| ui64Seconds, |
| ui64Nanoseconds); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("Device memory history for page fault address" IMG_DEV_VIRTADDR_FMTSPEC |
| ", PID: %u " |
| "(%s, unregistered: %u) OS time: " |
| "%" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC, |
| psInfo->sFaultDevVAddr.uiAddr, |
| uiPID, |
| psInfo->sProcessInfo.szProcessName, |
| psInfo->sProcessInfo.bUnregistered, |
| ui64Seconds, |
| ui64Nanoseconds); |
| } |
| |
| if (psInfo->sProcessInfo.uiPID != RGXMEM_SERVER_PID_PM) |
| { |
| for (i = DEVICEMEM_HISTORY_QUERY_INDEX_PRECEDING; i < DEVICEMEM_HISTORY_QUERY_INDEX_COUNT; i++) |
| { |
| const IMG_CHAR *pszWhich; |
| |
| switch (i) |
| { |
| case DEVICEMEM_HISTORY_QUERY_INDEX_PRECEDING: |
| pszWhich = "Preceding page"; |
| break; |
| case DEVICEMEM_HISTORY_QUERY_INDEX_FAULTED: |
| pszWhich = "Faulted page"; |
| break; |
| case DEVICEMEM_HISTORY_QUERY_INDEX_NEXT: |
| pszWhich = "Next page"; |
| break; |
| } |
| |
| PVR_DUMPDEBUG_LOG("%s:", pszWhich); |
| _PrintDevicememHistoryQueryOut(pfnDumpDebugPrintf, pvDumpDebugFile, |
| &psInfo->sProcessInfo, |
| &psInfo->asQueryOut[i]); |
| } |
| } |
| } |
| |
| static void _RecordFaultInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_DEV_VIRTADDR sFaultDevVAddr, |
| IMG_DEV_PHYADDR sPCDevPAddr, |
| IMG_UINT64 ui64CRTimer, |
| IMG_UINT32 ui32PageSizeBytes, |
| const IMG_CHAR *pszIndent, |
| MMU_FAULT_DATA *psMMUFaultData) |
| { |
| IMG_BOOL bFound = IMG_FALSE, bIsPMFault = IMG_FALSE; |
| RGXMEM_PROCESS_INFO sProcessInfo; |
| FAULT_INFO *psInfo; |
| |
| /* look to see if we have already processed this fault. |
| * if so then use the previously acquired information. |
| */ |
| OSLockAcquire(psDevInfo->hDebugFaultInfoLock); |
| psInfo = _QueryFaultInfo(pfnDumpDebugPrintf, pvDumpDebugFile, sFaultDevVAddr, ui64CRTimer); |
| |
| if (psInfo == NULL) |
| { |
| if (sPCDevPAddr.uiAddr != RGXFWIF_INVALID_PC_PHYADDR) |
| { |
| /* Check if this is PM fault */ |
| if (psMMUFaultData != NULL && psMMUFaultData->eType == MMU_FAULT_TYPE_PM) |
| { |
| bIsPMFault = IMG_TRUE; |
| bFound = IMG_TRUE; |
| } |
| else |
| { |
| /* look up the process details for the faulting page catalogue */ |
| bFound = RGXPCAddrToProcessInfo(psDevInfo, sPCDevPAddr, &sProcessInfo); |
| } |
| |
| if (bFound) |
| { |
| IMG_BOOL bHits; |
| |
| psInfo = _AcquireNextFaultInfoElement(); |
| |
| if (bIsPMFault) |
| { |
| sProcessInfo.uiPID = RGXMEM_SERVER_PID_PM; |
| OSStringNCopy(sProcessInfo.szProcessName, "PM", sizeof(sProcessInfo.szProcessName)); |
| sProcessInfo.szProcessName[sizeof(sProcessInfo.szProcessName) - 1] = '\0'; |
| sProcessInfo.bUnregistered = IMG_FALSE; |
| bHits = IMG_TRUE; |
| } |
| else |
| { |
| /* get any DevicememHistory data for the faulting address */ |
| bHits = _GetDevicememHistoryData(sProcessInfo.uiPID, |
| sFaultDevVAddr, |
| psInfo->asQueryOut, |
| ui32PageSizeBytes); |
| } |
| |
| if (bHits) |
| { |
| _CommitFaultInfo(psDevInfo, |
| psInfo, |
| &sProcessInfo, |
| sFaultDevVAddr, |
| ui64CRTimer, |
| psMMUFaultData); |
| } |
| else |
| { |
| /* no hits, so no data to present */ |
| PVR_DUMPDEBUG_LOG("%sNo matching Devmem History for fault address", pszIndent); |
| psInfo = NULL; |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%sCould not find PID for PC 0x%016" IMG_UINT64_FMTSPECx, pszIndent, sPCDevPAddr.uiAddr); |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%sPage fault not applicable to Devmem History", pszIndent); |
| } |
| } |
| |
| if (psInfo != NULL) |
| { |
| _PrintFaultInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psInfo, NULL); |
| } |
| |
| OSLockRelease(psDevInfo->hDebugFaultInfoLock); |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _DumpFWHWRHostView |
| |
| @Description |
| |
| Dump FW HWR fault status in human readable form. |
| |
| @Input ui32Index - Index of global Fault info |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Return void |
| |
| ******************************************************************************/ |
| static void _DumpFWHWRHostView(MMU_FAULT_DATA *psFaultData, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| MMU_FAULT_DATA *psOutFaultData) |
| { |
| MMU_LEVEL eTopLevel; |
| const IMG_CHAR szPageLevel[][4] = {"", "PTE", "PDE", "PCE" }; |
| const IMG_CHAR szPageError[][3] = {"", "PT", "PD", "PC" }; |
| |
| eTopLevel = psFaultData->eTopLevel; |
| |
| if (psFaultData->eType == MMU_FAULT_TYPE_UNKNOWN) |
| { |
| return; |
| } |
| else if (psFaultData->eType == MMU_FAULT_TYPE_PM) |
| { |
| PVR_DUMPDEBUG_LOG("PM faulted at PC address = 0x%016" IMG_UINT64_FMTSPECx, psFaultData->sLevelData[MMU_LEVEL_0].ui64Address); |
| } |
| else |
| { |
| MMU_LEVEL eCurrLevel; |
| PVR_ASSERT(eTopLevel < MMU_LEVEL_LAST); |
| |
| for (eCurrLevel = MMU_LEVEL_0; eCurrLevel <= eTopLevel; eCurrLevel++) |
| { |
| MMU_LEVEL eLevel = eTopLevel - eCurrLevel; |
| MMU_LEVEL_DATA *psMMULevelData = &psFaultData->sLevelData[eLevel]; |
| if (psMMULevelData->ui64Address) |
| { |
| if (psMMULevelData->uiBytesPerEntry == 4) |
| { |
| PVR_DUMPDEBUG_LOG("%s for index %d = 0x%08x and is %s", |
| szPageLevel[eLevel], |
| psMMULevelData->ui32Index, |
| (IMG_UINT) psMMULevelData->ui64Address, |
| psMMULevelData->psDebugStr); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%s for index %d = 0x%016" IMG_UINT64_FMTSPECx " and is %s", |
| szPageLevel[eLevel], |
| psMMULevelData->ui32Index, |
| psMMULevelData->ui64Address, |
| psMMULevelData->psDebugStr); |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%s index (%d) out of bounds (%d)", |
| szPageError[eLevel], |
| psMMULevelData->ui32Index, |
| psMMULevelData->ui32NumOfEntries); |
| break; |
| } |
| } |
| } |
| |
| if (psOutFaultData) |
| { |
| OSDeviceMemCopy(psOutFaultData, psFaultData, sizeof(MMU_FAULT_DATA)); |
| } |
| } |
| |
| static inline void _UpdateFaultInfo(MMU_FAULT_DATA *psDestData, MMU_FAULT_DATA *psSrcData) |
| { |
| OSDeviceMemCopy(psDestData, psSrcData, sizeof(MMU_FAULT_DATA)); |
| |
| /* Update count for next entry */ |
| if (gui32FaultIndex < RGXFWIF_HWINFO_MAX - 1) |
| { |
| gui32FaultIndex++; |
| } |
| else |
| { |
| gui32FaultIndex = RGXFWIF_HWINFO_MAX_FIRST; |
| } |
| } |
| |
| static void _HostFaultAnalysis(PVRSRV_RGXDEV_INFO *psDevInfo, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| IMG_UINT64 ui64MMUStatus, |
| IMG_BOOL bPMFault, |
| IMG_DEV_PHYADDR *psPCDevPAddr, |
| IMG_DEV_VIRTADDR *psFaultAddr, |
| IMG_UINT64 *pui64CRTimer, |
| MMU_FAULT_DATA *psFaultData) |
| { |
| IMG_UINT32 ui32Index = RGXFWIF_HWINFO_MAX; |
| IMG_UINT32 ui32LatestHWRNumber = 0; |
| IMG_UINT64 ui64LatestMMUStatus = 0; |
| IMG_UINT64 ui64LatestPCAddress = RGXFWIF_INVALID_PC_PHYADDR; |
| const IMG_CHAR *pszIndent = " "; |
| |
| /* |
| * Few cat bases are memory contexts used for PM or firmware. |
| * The rest are application contexts. |
| * |
| * It is not possible for the host to obtain the cat base address |
| * while the FW is running (since the cat bases are indirectly |
| * accessed), but in the case of the 'live' PC we can see if the |
| * FW has already logged it in the HWR log. |
| */ |
| |
| for (ui32Index = 0; ui32Index < RGXFWIF_HWINFO_MAX; ui32Index++) |
| { |
| RGX_HWRINFO *psHWRInfo = &psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32Index]; |
| |
| if (psHWRInfo->ui32HWRNumber > ui32LatestHWRNumber && psHWRInfo->eHWRType == RGX_HWRTYPE_MMUFAULT) |
| { |
| ui32LatestHWRNumber = psHWRInfo->ui32HWRNumber; |
| ui64LatestMMUStatus = psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus; |
| ui64LatestPCAddress = psHWRInfo->uHWRData.sMMUInfo.ui64PCAddress; |
| *pui64CRTimer = psHWRInfo->ui64CRTimer; |
| } |
| } |
| |
| if (ui64LatestMMUStatus == ui64MMUStatus && ui64LatestPCAddress != RGXFWIF_INVALID_PC_PHYADDR) |
| { |
| psPCDevPAddr->uiAddr = ui64LatestPCAddress; |
| PVR_DUMPDEBUG_LOG("%sLocated PC address: 0x%016" IMG_UINT64_FMTSPECx, pszIndent, psPCDevPAddr->uiAddr); |
| } |
| else |
| { |
| psPCDevPAddr->uiAddr = RGXFWIF_INVALID_PC_PHYADDR; |
| } |
| |
| if (psPCDevPAddr->uiAddr != RGXFWIF_INVALID_PC_PHYADDR) |
| { |
| if (!bPMFault) |
| { |
| PVR_DUMPDEBUG_LOG("%sChecking faulting address " IMG_DEV_VIRTADDR_FMTSPEC, pszIndent, psFaultAddr->uiAddr); |
| RGXCheckFaultAddress(psDevInfo, psFaultAddr, psPCDevPAddr, pfnDumpDebugPrintf, pvDumpDebugFile, psFaultData); |
| } |
| else |
| { |
| /* PM fault and we dump PC details only */ |
| psFaultData->eTopLevel = MMU_LEVEL_0; |
| psFaultData->eType = MMU_FAULT_TYPE_PM; |
| psFaultData->sLevelData[MMU_LEVEL_0].ui64Address = psPCDevPAddr->uiAddr; |
| } |
| |
| if ((GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_PAGE_FAULT_DEBUG_ENABLED) == 0) |
| { |
| _UpdateFaultInfo(&gsMMUFaultData[gui32FaultIndex], psFaultData); |
| } |
| } |
| } |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDumpRGXBIFBank |
| |
| @Description |
| |
| Dump BIF Bank state in human readable form. |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psDevInfo - RGX device info |
| @Input eBankID - BIF identifier |
| @Input ui64MMUStatus - MMU Status register value |
| @Input ui64ReqStatus - BIF request Status register value |
| @Input ui32HWRIndex - Index of FW HWR info if function is called |
| as a part of the debug dump summary else |
| RGXFWIF_HWINFO_MAX |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDumpRGXBIFBank(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXDBG_BIF_ID eBankID, |
| IMG_UINT64 ui64MMUStatus, |
| IMG_UINT64 ui64ReqStatus, |
| IMG_UINT32 ui32HWRIndex) |
| { |
| IMG_BOOL bExistingHWR = ui32HWRIndex < RGXFWIF_HWINFO_MAX; |
| IMG_CHAR *pszIndent = (bExistingHWR ? "" : " "); |
| |
| if (ui64MMUStatus == 0x0) |
| { |
| PVR_DUMPDEBUG_LOG("%s - OK", pszBIFNames[eBankID]); |
| } |
| else |
| { |
| IMG_DEV_VIRTADDR sFaultDevVAddr; |
| IMG_DEV_PHYADDR sPCDevPAddr = { 0 }; |
| IMG_UINT32 ui32PageSize; |
| IMG_UINT64 ui64CRTimer = 0; |
| IMG_UINT32 ui32PC = |
| (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT; |
| MMU_FAULT_DATA sFaultData = { 0 }; |
| |
| /* Bank 0 & 1 share the same fields */ |
| PVR_DUMPDEBUG_LOG("%s%s - FAULT:", |
| pszIndent, |
| pszBIFNames[eBankID]); |
| |
| /* MMU Status */ |
| { |
| IMG_UINT32 ui32MMUDataType = |
| (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_SHIFT; |
| |
| IMG_BOOL bROFault = (ui64MMUStatus & RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_EN) != 0; |
| IMG_BOOL bProtFault = (ui64MMUStatus & RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_EN) != 0; |
| |
| ui32PageSize = (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT; |
| |
| PVR_DUMPDEBUG_LOG("%s * MMU status (0x%016" IMG_UINT64_FMTSPECx "): PC = %d%s, Page Size = %d, MMU data type = %d%s%s.", |
| pszIndent, |
| ui64MMUStatus, |
| ui32PC, |
| (ui32PC < 0x8)?"":_RGXDecodePMPC(ui32PC), |
| ui32PageSize, |
| ui32MMUDataType, |
| (bROFault)?", Read Only fault":"", |
| (bProtFault)?", PM/META protection fault":""); |
| } |
| |
| /* Req Status */ |
| { |
| IMG_CHAR *pszTagID; |
| IMG_CHAR *pszTagSB; |
| IMG_CHAR aszScratch[RGX_DEBUG_STR_SIZE]; |
| IMG_BOOL bRead; |
| IMG_UINT32 ui32TagSB, ui32TagID; |
| IMG_UINT64 ui64Addr; |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, XE_MEMORY_HIERARCHY)) |
| { |
| bRead = (ui64ReqStatus & RGX_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_EN) != 0; |
| ui32TagSB = (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_SHIFT; |
| ui32TagID = (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_SHIFT; |
| } |
| else |
| { |
| bRead = (ui64ReqStatus & RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN) != 0; |
| ui32TagSB = (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT; |
| ui32TagID = (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT; |
| } |
| ui64Addr = ((ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_SHIFT) << |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSHIFT; |
| |
| _RGXDecodeBIFReqTags(psDevInfo, eBankID, ui32TagID, ui32TagSB, &pszTagID, &pszTagSB, &aszScratch[0], RGX_DEBUG_STR_SIZE); |
| |
| PVR_DUMPDEBUG_LOG("%s * Request (0x%016" IMG_UINT64_FMTSPECx |
| "): %s (%s), %s " IMG_DEV_VIRTADDR_FMTSPEC ".", |
| pszIndent, |
| ui64ReqStatus, |
| pszTagID, |
| pszTagSB, |
| (bRead)?"Reading from":"Writing to", |
| ui64Addr); |
| } |
| |
| /* Check if the host thinks this fault is valid */ |
| |
| sFaultDevVAddr.uiAddr = (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK); |
| |
| if (bExistingHWR) |
| { |
| /* Called from debug dump summary */ |
| sPCDevPAddr.uiAddr = psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].uHWRData.sBIFInfo.ui64PCAddress; |
| ui64CRTimer = psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].ui64CRTimer; |
| |
| PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016" IMG_UINT64_FMTSPECx, pszIndent, sPCDevPAddr.uiAddr); |
| if (psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].ui32HWRNumber < psDevInfo->psRGXFWIfHWRInfoBuf->ui32DDReqCount) |
| { |
| /* check if fault is already analysed from host */ |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_PAGE_FAULT_DEBUG_ENABLED) |
| { |
| _DumpFWHWRHostView(&(gsFaultInfoLog.asFaults[ui32HWRIndex].sMMUFaultData), |
| pfnDumpDebugPrintf, pvDumpDebugFile, &sFaultData); |
| } |
| else |
| { |
| _DumpFWHWRHostView(&gsMMUFaultData[ui32HWRIndex], |
| pfnDumpDebugPrintf, pvDumpDebugFile, &sFaultData); |
| } |
| } |
| } |
| else |
| { |
| /* Only the first 8 cat bases are application memory contexts which we can validate... */ |
| IMG_BOOL bPMFault = (ui32PC >= 8); |
| _HostFaultAnalysis(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, |
| ui64MMUStatus, bPMFault, &sPCDevPAddr, &sFaultDevVAddr, |
| &ui64CRTimer, &sFaultData); |
| } |
| |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_PAGE_FAULT_DEBUG_ENABLED) |
| { |
| _RecordFaultInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| sFaultDevVAddr, sPCDevPAddr, ui64CRTimer, |
| _PageSizeHWToBytes(ui32PageSize), pszIndent, |
| &sFaultData); |
| } |
| } |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDumpRGXMMUFaultStatus |
| |
| @Description |
| |
| Dump MMU Fault status in human readable form. |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psDevInfo - RGX device info |
| @Input ui64MMUStatus - MMU Status register value |
| @Input ui32HWRIndex - Index of FW HWR info if function is called |
| as a part of the debug dump summary else |
| RGXFWIF_HWINFO_MAX |
| @Input pszMetaOrCore - string representing call is for META or MMU core |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDumpRGXMMUFaultStatus(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT64 ui64MMUStatus, |
| IMG_UINT32 ui32HWRIndex, |
| const IMG_PCHAR pszMetaOrCore) |
| { |
| IMG_BOOL bExistingHWR = ui32HWRIndex < RGXFWIF_HWINFO_MAX; |
| IMG_CHAR *pszIndent = (!bExistingHWR ? "" : " "); |
| |
| if (ui64MMUStatus == 0x0) |
| { |
| PVR_DUMPDEBUG_LOG("%sMMU (%s) - OK", pszIndent, pszMetaOrCore); |
| } |
| else |
| { |
| IMG_UINT32 ui32PC = (ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_CONTEXT_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_CONTEXT_SHIFT; |
| IMG_UINT64 ui64Addr = ((ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_ADDRESS_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_ADDRESS_SHIFT) << 4; /* align shift */ |
| IMG_UINT32 ui32Requester = (ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_REQ_ID_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_REQ_ID_SHIFT; |
| IMG_UINT32 ui32SideBand = (ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_TAG_SB_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_TAG_SB_SHIFT; |
| IMG_UINT32 ui32MMULevel = (ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_LEVEL_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_LEVEL_SHIFT; |
| IMG_BOOL bRead = (ui64MMUStatus & RGX_CR_MMU_FAULT_STATUS_RNW_EN) != 0; |
| IMG_BOOL bFault = (ui64MMUStatus & RGX_CR_MMU_FAULT_STATUS_FAULT_EN) != 0; |
| IMG_BOOL bROFault = ((ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_TYPE_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_TYPE_SHIFT) == 0x2; |
| IMG_BOOL bProtFault = ((ui64MMUStatus & ~RGX_CR_MMU_FAULT_STATUS_TYPE_CLRMSK) >> |
| RGX_CR_MMU_FAULT_STATUS_TYPE_SHIFT) == 0x3; |
| IMG_CHAR aszScratch[RGX_DEBUG_STR_SIZE]; |
| IMG_CHAR *pszTagID; |
| IMG_CHAR *pszTagSB; |
| IMG_UINT64 ui64CRTimer = 0; |
| IMG_DEV_VIRTADDR sFaultDevVAddr; |
| IMG_DEV_PHYADDR sPCDevPAddr = { 0 }; |
| MMU_FAULT_DATA sFaultData; |
| memset(&sFaultData, 0, sizeof(MMU_FAULT_DATA)); |
| |
| _RGXDecodeMMUReqTags(psDevInfo, ui32Requester, ui32SideBand, bRead, &pszTagID, &pszTagSB, aszScratch, RGX_DEBUG_STR_SIZE); |
| |
| PVR_DUMPDEBUG_LOG("%sMMU (%s) - FAULT:", pszIndent, pszMetaOrCore); |
| PVR_DUMPDEBUG_LOG("%s * MMU status (0x%016" IMG_UINT64_FMTSPECx "): PC = %d, %s 0x%010" IMG_UINT64_FMTSPECx ", %s (%s)%s%s%s%s.", |
| pszIndent, |
| ui64MMUStatus, |
| ui32PC, |
| (bRead)?"Reading from":"Writing to", |
| ui64Addr, |
| pszTagID, |
| pszTagSB, |
| (bFault)?", Fault":"", |
| (bROFault)?", Read Only fault":"", |
| (bProtFault)?", PM/META protection fault":"", |
| _RGXDecodeMMULevel(ui32MMULevel)); |
| |
| /* Check if the host thinks this fault is valid */ |
| sFaultDevVAddr.uiAddr = ui64Addr; |
| |
| if (bExistingHWR) |
| { |
| /* Called from debug dump summary */ |
| sPCDevPAddr.uiAddr = psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].uHWRData.sMMUInfo.ui64PCAddress; |
| ui64CRTimer = psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].ui64CRTimer; |
| |
| PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016" IMG_UINT64_FMTSPECx, pszIndent, sPCDevPAddr.uiAddr); |
| if (psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex].ui32HWRNumber < psDevInfo->psRGXFWIfHWRInfoBuf->ui32DDReqCount) |
| { |
| /* check if Fault is already analysed from host */ |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_PAGE_FAULT_DEBUG_ENABLED) |
| { |
| _DumpFWHWRHostView(&(gsFaultInfoLog.asFaults[ui32HWRIndex].sMMUFaultData), |
| pfnDumpDebugPrintf, pvDumpDebugFile, &sFaultData); |
| } |
| else |
| { |
| _DumpFWHWRHostView(&gsMMUFaultData[ui32HWRIndex], |
| pfnDumpDebugPrintf, pvDumpDebugFile, &sFaultData); |
| } |
| } |
| } |
| else |
| { |
| IMG_BOOL bPMFault; |
| #if defined(SUPPORT_TRUSTED_DEVICE) |
| ui32PC = ui32PC - 1; |
| #endif |
| bPMFault = (ui32PC <= 8); |
| _HostFaultAnalysis(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, |
| ui64MMUStatus, bPMFault, &sPCDevPAddr, &sFaultDevVAddr, |
| &ui64CRTimer, &sFaultData); |
| } |
| if (GetInfoPageDebugFlagsKM() & DEBUG_FEATURE_PAGE_FAULT_DEBUG_ENABLED) |
| { |
| _RecordFaultInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| sFaultDevVAddr, sPCDevPAddr, ui64CRTimer, |
| _PageSizeHWToBytes(0), pszIndent, &sFaultData); |
| } |
| } |
| } |
| static_assert((RGX_CR_MMU_FAULT_STATUS_CONTEXT_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_CONTEXT_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_CONTEXT_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_CONTEXT_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_ADDRESS_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_ADDRESS_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_ADDRESS_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_ADDRESS_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TAG_SB_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_TAG_SB_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TAG_SB_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_TAG_SB_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_REQ_ID_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_REQ_ID_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_REQ_ID_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_REQ_ID_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_LEVEL_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_LEVEL_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_LEVEL_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_LEVEL_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_RNW_EN == RGX_CR_MMU_FAULT_STATUS_META_RNW_EN), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_FAULT_EN == RGX_CR_MMU_FAULT_STATUS_META_FAULT_EN), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TYPE_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_TYPE_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TYPE_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_TYPE_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TYPE_CLRMSK == RGX_CR_MMU_FAULT_STATUS_META_TYPE_CLRMSK), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| static_assert((RGX_CR_MMU_FAULT_STATUS_TYPE_SHIFT == RGX_CR_MMU_FAULT_STATUS_META_TYPE_SHIFT), |
| "RGX_CR_MMU_FAULT_STATUS_META mismatch!"); |
| |
| |
| |
| #if !defined(NO_HARDWARE) |
| static PVRSRV_ERROR _RGXMipsExtraDebug(PVRSRV_RGXDEV_INFO *psDevInfo, RGX_MIPS_STATE *psMIPSState) |
| { |
| void __iomem *pvRegsBaseKM = psDevInfo->pvRegsBaseKM; |
| IMG_UINT32 ui32RegRead; |
| IMG_UINT32 eError = PVRSRV_OK; |
| IMG_UINT32 *pui32NMIMemoryPointer; |
| IMG_UINT32 volatile *pui32SyncFlag; |
| IMG_DEVMEM_OFFSET_T uiNMIMemoryBootOffset; |
| |
| /* Map the FW data area to the kernel */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWDataMemDesc, |
| (void **)&pui32NMIMemoryPointer); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Failed to acquire NMI shared memory area (%s)", |
| __func__, |
| PVRSRVGetErrorString(eError))); |
| goto map_error_fail; |
| } |
| |
| /* Calculate offset to the boot/NMI data page */ |
| uiNMIMemoryBootOffset = RGXMIPSFW_GET_OFFSET_IN_DWORDS(RGXGetFWImageSectionOffset(NULL, MIPS_BOOT_DATA)); |
| |
| /* Jump to the NMI shared data area within the page above */ |
| pui32NMIMemoryPointer += uiNMIMemoryBootOffset + RGXMIPSFW_GET_OFFSET_IN_DWORDS(RGXMIPSFW_NMI_SHARED_DATA_BASE); |
| |
| /* Acquire the NMI operations lock */ |
| OSLockAcquire(psDevInfo->hNMILock); |
| |
| /* Make sure the synchronisation flag is set to 0 */ |
| pui32SyncFlag = &pui32NMIMemoryPointer[RGXMIPSFW_NMI_SYNC_FLAG_OFFSET]; |
| *pui32SyncFlag = 0; |
| OSWriteMemoryBarrier(); |
| (void) *pui32SyncFlag; |
| |
| /* Enable NMI issuing in the MIPS wrapper */ |
| OSWriteHWReg64(pvRegsBaseKM, |
| RGX_CR_MIPS_WRAPPER_NMI_ENABLE, |
| RGX_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_EN); |
| |
| /* Check the MIPS is not in error state already (e.g. it is booting or an NMI has already been requested) */ |
| ui32RegRead = OSReadHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_EXCEPTION_STATUS); |
| if ((ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_ERL_EN) || (ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_EN)) |
| { |
| |
| eError = PVRSRV_ERROR_MIPS_STATUS_UNAVAILABLE; |
| goto fail; |
| } |
| ui32RegRead = 0; |
| |
| /* Issue NMI */ |
| OSWriteHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_WRAPPER_NMI_EVENT, |
| RGX_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_EN); |
| |
| |
| /* Wait for NMI Taken to be asserted */ |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| ui32RegRead = OSReadHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_EXCEPTION_STATUS); |
| if (ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_EN) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| if ((ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_EN) == 0) |
| { |
| eError = PVRSRV_ERROR_MIPS_STATUS_UNAVAILABLE; |
| goto fail; |
| } |
| ui32RegRead = 0; |
| |
| /* Allow the firmware to proceed */ |
| *pui32SyncFlag = 1; |
| OSWriteMemoryBarrier(); |
| (void) *pui32SyncFlag; |
| |
| /* Wait for the FW to have finished the NMI routine */ |
| ui32RegRead = OSReadHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_EXCEPTION_STATUS); |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| ui32RegRead = OSReadHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_EXCEPTION_STATUS); |
| if (!(ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_ERL_EN)) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| if (ui32RegRead & RGX_CR_MIPS_EXCEPTION_STATUS_SI_ERL_EN) |
| { |
| eError = PVRSRV_ERROR_MIPS_STATUS_UNAVAILABLE; |
| goto fail; |
| } |
| ui32RegRead = 0; |
| |
| /* Copy state */ |
| OSDeviceMemCopy(psMIPSState, pui32NMIMemoryPointer + RGXMIPSFW_NMI_STATE_OFFSET, sizeof(*psMIPSState)); |
| |
| --(psMIPSState->ui32ErrorEPC); |
| --(psMIPSState->ui32EPC); |
| |
| /* Disable NMI issuing in the MIPS wrapper */ |
| OSWriteHWReg32(pvRegsBaseKM, |
| RGX_CR_MIPS_WRAPPER_NMI_ENABLE, |
| 0); |
| |
| fail: |
| /* Release the NMI operations lock */ |
| OSLockRelease(psDevInfo->hNMILock); |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWDataMemDesc); |
| map_error_fail: |
| return eError; |
| } |
| |
| /* Print decoded information from cause register */ |
| static void _RGXMipsDumpCauseDecode(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| IMG_UINT32 ui32Cause, |
| IMG_UINT32 ui32ErrorState) |
| { |
| #define INDENT " " |
| const IMG_UINT32 ui32ExcCode = RGXMIPSFW_C0_CAUSE_EXCCODE(ui32Cause); |
| const IMG_CHAR * const pszException = _GetMIPSExcString(ui32ExcCode); |
| |
| if (ui32ErrorState == RGXMIPSFW_NMI_ERROR_STATE_SET && |
| pszException != NULL) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Cause exception: %s", pszException); |
| } |
| |
| if (ui32Cause & RGXMIPSFW_C0_CAUSE_FDCIPENDING) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "FDC interrupt pending"); |
| } |
| |
| if (!(ui32Cause & RGXMIPSFW_C0_CAUSE_IV)) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Interrupt uses general interrupt vector"); |
| } |
| |
| if (ui32Cause & RGXMIPSFW_C0_CAUSE_PCIPENDING) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Performance Counter Interrupt pending"); |
| } |
| |
| /* Unusable Coproc exception */ |
| if (ui32ExcCode == 11) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Unusable Coprocessor: %d", RGXMIPSFW_C0_CAUSE_UNUSABLE_UNIT(ui32Cause)); |
| } |
| |
| #undef INDENT |
| } |
| |
| static IMG_BOOL _IsFWCodeException(IMG_UINT32 ui32ExcCode) |
| { |
| if (ui32ExcCode >= sizeof(apsMIPSExcCodes)/sizeof(MIPS_EXCEPTION_ENCODING)) |
| { |
| PVR_DPF((PVR_DBG_WARNING, |
| "Only %lu exceptions available in MIPS, %u is not a valid exception code", |
| (unsigned long)sizeof(apsMIPSExcCodes)/sizeof(MIPS_EXCEPTION_ENCODING), ui32ExcCode)); |
| return IMG_FALSE; |
| } |
| |
| return apsMIPSExcCodes[ui32ExcCode].bIsFatal; |
| } |
| |
| static void _RGXMipsDumpDebugDecode(PVRSRV_RGXDEV_INFO *psDevInfo, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| IMG_UINT32 ui32Debug, |
| IMG_UINT32 ui32DEPC) |
| { |
| const IMG_CHAR *pszDException = NULL; |
| IMG_UINT32 i; |
| #define INDENT " " |
| |
| if (!(ui32Debug & RGXMIPSFW_C0_DEBUG_DM)) |
| { |
| return; |
| } |
| |
| PVR_DUMPDEBUG_LOG("DEBUG :"); |
| |
| pszDException = _GetMIPSExcString(RGXMIPSFW_C0_DEBUG_EXCCODE(ui32Debug)); |
| |
| if (pszDException != NULL) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Debug exception: %s", pszDException); |
| } |
| |
| /* Check FW code corruption in case of known errors */ |
| if (_IsFWCodeException(RGXMIPSFW_C0_DEBUG_EXCCODE(ui32Debug))) |
| { |
| PVRSRV_ERROR eError; |
| eError = _ValidateFWImageForMIPS(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, INDENT); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Failed to validate any FW code corruption"); |
| } |
| } |
| |
| for (i = 0; i < ARRAY_SIZE(sMIPS_C0_DebugTable); ++i) |
| { |
| const RGXMIPSFW_C0_DEBUG_TBL_ENTRY * const psDebugEntry = &sMIPS_C0_DebugTable[i]; |
| |
| if (ui32Debug & psDebugEntry->ui32Mask) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "%s", psDebugEntry->pszExplanation); |
| } |
| } |
| #undef INDENT |
| PVR_DUMPDEBUG_LOG("DEPC :0x%08X", ui32DEPC); |
| } |
| |
| static inline void _GetMipsTLBPARanges(const RGX_MIPS_TLB_ENTRY *psTLBEntry, |
| const RGX_MIPS_REMAP_ENTRY *psRemapEntry0, |
| const RGX_MIPS_REMAP_ENTRY *psRemapEntry1, |
| IMG_UINT64 *pui64PA0Start, |
| IMG_UINT64 *pui64PA0End, |
| IMG_UINT64 *pui64PA1Start, |
| IMG_UINT64 *pui64PA1End) |
| { |
| IMG_BOOL bUseRemapOutput = (psRemapEntry0 != NULL && psRemapEntry1 != NULL) ? IMG_TRUE : IMG_FALSE; |
| IMG_UINT64 ui64PageSize = RGXMIPSFW_TLB_GET_PAGE_SIZE(psTLBEntry->ui32TLBPageMask); |
| |
| if ((psTLBEntry->ui32TLBLo0 & RGXMIPSFW_TLB_VALID) == 0) |
| { |
| /* Dummy values to fail the range checks later */ |
| *pui64PA0Start = -1ULL; |
| *pui64PA0End = -1ULL; |
| } |
| else if (bUseRemapOutput) |
| { |
| *pui64PA0Start = (IMG_UINT64)psRemapEntry0->ui32RemapAddrOut << 12; |
| *pui64PA0End = *pui64PA0Start + ui64PageSize - 1; |
| } |
| else |
| { |
| *pui64PA0Start = RGXMIPSFW_TLB_GET_PA(psTLBEntry->ui32TLBLo0); |
| *pui64PA0End = *pui64PA0Start + ui64PageSize - 1; |
| } |
| |
| if ((psTLBEntry->ui32TLBLo1 & RGXMIPSFW_TLB_VALID) == 0) |
| { |
| /* Dummy values to fail the range checks later */ |
| *pui64PA1Start = -1ULL; |
| *pui64PA1End = -1ULL; |
| } |
| else if (bUseRemapOutput) |
| { |
| *pui64PA1Start = (IMG_UINT64)psRemapEntry1->ui32RemapAddrOut << 12; |
| *pui64PA1End = *pui64PA1Start + ui64PageSize - 1; |
| } |
| else |
| { |
| *pui64PA1Start = RGXMIPSFW_TLB_GET_PA(psTLBEntry->ui32TLBLo1); |
| *pui64PA1End = *pui64PA1Start + ui64PageSize - 1; |
| } |
| } |
| |
| static void _CheckMipsTLBDuplicatePAs(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| const RGX_MIPS_TLB_ENTRY *psTLB, |
| const RGX_MIPS_REMAP_ENTRY *psRemap) |
| { |
| IMG_UINT64 ui64PA0StartI, ui64PA1StartI, ui64PA0StartJ, ui64PA1StartJ; |
| IMG_UINT64 ui64PA0EndI, ui64PA1EndI, ui64PA0EndJ, ui64PA1EndJ; |
| IMG_UINT32 i, j; |
| |
| #define RANGES_OVERLAP(start0,end0,start1,end1) ((start0) < (end1) && (start1) < (end0)) |
| |
| for (i = 0; i < RGXMIPSFW_NUMBER_OF_TLB_ENTRIES; i++) |
| { |
| _GetMipsTLBPARanges(&psTLB[i], |
| psRemap ? &psRemap[i] : NULL, |
| psRemap ? &psRemap[i + RGXMIPSFW_NUMBER_OF_TLB_ENTRIES] : NULL, |
| &ui64PA0StartI, &ui64PA0EndI, |
| &ui64PA1StartI, &ui64PA1EndI); |
| |
| for (j = i + 1; j < RGXMIPSFW_NUMBER_OF_TLB_ENTRIES; j++) |
| { |
| _GetMipsTLBPARanges(&psTLB[j], |
| psRemap ? &psRemap[j] : NULL, |
| psRemap ? &psRemap[j + RGXMIPSFW_NUMBER_OF_TLB_ENTRIES] : NULL, |
| &ui64PA0StartJ, &ui64PA0EndJ, |
| &ui64PA1StartJ, &ui64PA1EndJ); |
| |
| if (RANGES_OVERLAP(ui64PA0StartI, ui64PA0EndI, ui64PA0StartJ, ui64PA0EndJ) || |
| RANGES_OVERLAP(ui64PA0StartI, ui64PA0EndI, ui64PA1StartJ, ui64PA1EndJ) || |
| RANGES_OVERLAP(ui64PA1StartI, ui64PA1EndI, ui64PA0StartJ, ui64PA0EndJ) || |
| RANGES_OVERLAP(ui64PA1StartI, ui64PA1EndI, ui64PA1StartJ, ui64PA1EndJ) ) |
| { |
| PVR_DUMPDEBUG_LOG("Overlap between TLB entry %u and %u", i , j); |
| } |
| } |
| } |
| } |
| |
| static inline void _RGXMipsDumpTLBEntry(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| const RGX_MIPS_TLB_ENTRY *psTLBEntry, |
| const RGX_MIPS_REMAP_ENTRY *psRemapEntry0, |
| const RGX_MIPS_REMAP_ENTRY *psRemapEntry1, |
| IMG_UINT32 ui32Index) |
| { |
| IMG_BOOL bDumpRemapEntries = (psRemapEntry0 != NULL && psRemapEntry1 != NULL) ? IMG_TRUE : IMG_FALSE; |
| IMG_UINT64 ui64PA0 = RGXMIPSFW_TLB_GET_PA(psTLBEntry->ui32TLBLo0); |
| IMG_UINT64 ui64PA1 = RGXMIPSFW_TLB_GET_PA(psTLBEntry->ui32TLBLo1); |
| IMG_UINT64 ui64Remap0AddrOut = 0, ui64Remap1AddrOut = 0; |
| IMG_UINT32 ui32Remap0AddrIn = 0, ui32Remap1AddrIn = 0; |
| |
| static const IMG_CHAR * const apszPermissionInhibit[4] = |
| { |
| "", |
| "XI", |
| "RI", |
| "RIXI" |
| }; |
| |
| static const IMG_CHAR * const apszCoherencyTLB[8] = |
| { |
| "C", |
| "C", |
| " ", |
| "C", |
| "C", |
| "C", |
| "C", |
| " " |
| }; |
| |
| static const IMG_CHAR * const apszDirtyGlobalValid[8] = |
| { |
| " ", |
| " G", |
| " V ", |
| " VG", |
| "D ", |
| "D G", |
| "DV ", |
| "DVG" |
| }; |
| |
| if (bDumpRemapEntries) |
| { |
| /* RemapAddrIn is always 4k aligned and on 32 bit */ |
| ui32Remap0AddrIn = psRemapEntry0->ui32RemapAddrIn << 12; |
| ui32Remap1AddrIn = psRemapEntry1->ui32RemapAddrIn << 12; |
| |
| /* RemapAddrOut is always 4k aligned and on 32 or 36 bit */ |
| ui64Remap0AddrOut = (IMG_UINT64)psRemapEntry0->ui32RemapAddrOut << 12; |
| ui64Remap1AddrOut = (IMG_UINT64)psRemapEntry1->ui32RemapAddrOut << 12; |
| |
| /* If TLB and remap entries match, then merge them else, print them separately */ |
| if ((IMG_UINT32)ui64PA0 == ui32Remap0AddrIn && |
| (IMG_UINT32)ui64PA1 == ui32Remap1AddrIn) |
| { |
| ui64PA0 = ui64Remap0AddrOut; |
| ui64PA1 = ui64Remap1AddrOut; |
| bDumpRemapEntries = IMG_FALSE; |
| } |
| } |
| |
| PVR_DUMPDEBUG_LOG("%2u) VA 0x%08X (%3uk) -> PA0 0x%08" IMG_UINT64_FMTSPECx " %s%s%s, " |
| "PA1 0x%08" IMG_UINT64_FMTSPECx " %s%s%s", |
| ui32Index, |
| psTLBEntry->ui32TLBHi, |
| RGXMIPSFW_TLB_GET_PAGE_SIZE(psTLBEntry->ui32TLBPageMask), |
| ui64PA0, |
| apszPermissionInhibit[RGXMIPSFW_TLB_GET_INHIBIT(psTLBEntry->ui32TLBLo0)], |
| apszDirtyGlobalValid[RGXMIPSFW_TLB_GET_DGV(psTLBEntry->ui32TLBLo0)], |
| apszCoherencyTLB[RGXMIPSFW_TLB_GET_COHERENCY(psTLBEntry->ui32TLBLo0)], |
| ui64PA1, |
| apszPermissionInhibit[RGXMIPSFW_TLB_GET_INHIBIT(psTLBEntry->ui32TLBLo1)], |
| apszDirtyGlobalValid[RGXMIPSFW_TLB_GET_DGV(psTLBEntry->ui32TLBLo1)], |
| apszCoherencyTLB[RGXMIPSFW_TLB_GET_COHERENCY(psTLBEntry->ui32TLBLo1)]); |
| |
| if (bDumpRemapEntries) |
| { |
| PVR_DUMPDEBUG_LOG(" Remap %2u : IN 0x%08X (%3uk) => OUT 0x%08" IMG_UINT64_FMTSPECx, |
| ui32Index, |
| ui32Remap0AddrIn, |
| RGXMIPSFW_REMAP_GET_REGION_SIZE(psRemapEntry0->ui32RemapRegionSize), |
| ui64Remap0AddrOut); |
| |
| PVR_DUMPDEBUG_LOG(" Remap %2u : IN 0x%08X (%3uk) => OUT 0x%08" IMG_UINT64_FMTSPECx, |
| ui32Index + RGXMIPSFW_NUMBER_OF_TLB_ENTRIES, |
| ui32Remap1AddrIn, |
| RGXMIPSFW_REMAP_GET_REGION_SIZE(psRemapEntry1->ui32RemapRegionSize), |
| ui64Remap1AddrOut); |
| } |
| } |
| |
| #endif /* !defined(NO_HARDWARE) */ |
| |
| /* |
| Appends flags strings to a null-terminated string buffer - each flag |
| description string starts with a space. |
| */ |
| static void _Flags2Description(IMG_CHAR *sDesc, const IMG_FLAGS2DESC *psConvTable, IMG_UINT32 ui32TableSize, IMG_UINT32 ui32Flags) |
| { |
| IMG_UINT32 ui32Idx; |
| |
| for (ui32Idx = 0; ui32Idx < ui32TableSize; ui32Idx++) |
| { |
| if ((ui32Flags & psConvTable[ui32Idx].uiFlag) == psConvTable[ui32Idx].uiFlag) |
| { |
| strcat(sDesc, psConvTable[ui32Idx].pszLabel); |
| } |
| } |
| } |
| |
| /* |
| Writes flags strings to an uninitialised buffer. |
| */ |
| static void _GetFwFlagsDescription(IMG_CHAR *psDesc, IMG_UINT32 ui32RawFlags) |
| { |
| const IMG_CHAR *psCswLabel = "Ctx switch:"; |
| strcpy(psDesc, psCswLabel); |
| _Flags2Description(psDesc, asCSW2Description, ARRAY_SIZE(asCSW2Description), ui32RawFlags); |
| _Flags2Description(psDesc, asMisc2Description, ARRAY_SIZE(asMisc2Description), ui32RawFlags); |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDumpFWAssert |
| |
| @Description |
| |
| Dump FW assert strings when a thread asserts. |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psRGXFWIfTraceBufCtl - RGX FW trace buffer |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDumpFWAssert(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl) |
| { |
| IMG_CHAR *pszTraceAssertPath; |
| IMG_CHAR *pszTraceAssertInfo; |
| IMG_INT32 ui32TraceAssertLine; |
| IMG_UINT32 i; |
| |
| for (i = 0; i < RGXFW_THREAD_NUM; i++) |
| { |
| pszTraceAssertPath = psRGXFWIfTraceBufCtl->sTraceBuf[i].sAssertBuf.szPath; |
| pszTraceAssertInfo = psRGXFWIfTraceBufCtl->sTraceBuf[i].sAssertBuf.szInfo; |
| ui32TraceAssertLine = psRGXFWIfTraceBufCtl->sTraceBuf[i].sAssertBuf.ui32LineNum; |
| |
| /* print non-null assert strings */ |
| if (*pszTraceAssertInfo) |
| { |
| PVR_DUMPDEBUG_LOG("FW-T%d Assert: %s (%s:%d)", |
| i, pszTraceAssertInfo, pszTraceAssertPath, ui32TraceAssertLine); |
| } |
| } |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDumpFWFaults |
| |
| @Description |
| |
| Dump FW assert strings when a thread asserts. |
| |
| @Input pfnDumpDebugPrintf - The debug printf function |
| @Input pvDumpDebugFile - Optional file identifier to be passed to the |
| 'printf' function if required |
| @Input psRGXFWIfTraceBufCtl - RGX FW trace buffer |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDumpFWFaults(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl) |
| { |
| if (psRGXFWIfTraceBufCtl->ui32FWFaults > 0) |
| { |
| IMG_UINT32 ui32StartFault = psRGXFWIfTraceBufCtl->ui32FWFaults - RGXFWIF_FWFAULTINFO_MAX; |
| IMG_UINT32 ui32EndFault = psRGXFWIfTraceBufCtl->ui32FWFaults - 1; |
| IMG_UINT32 ui32Index; |
| |
| if (psRGXFWIfTraceBufCtl->ui32FWFaults < RGXFWIF_FWFAULTINFO_MAX) |
| { |
| ui32StartFault = 0; |
| } |
| |
| for (ui32Index = ui32StartFault; ui32Index <= ui32EndFault; ui32Index++) |
| { |
| RGX_FWFAULTINFO *psFaultInfo = &psRGXFWIfTraceBufCtl->sFaultInfo[ui32Index % RGXFWIF_FWFAULTINFO_MAX]; |
| IMG_UINT64 ui64Seconds, ui64Nanoseconds; |
| |
| /* Split OS timestamp in seconds and nanoseconds */ |
| ConvertOSTimestampToSAndNS(psFaultInfo->ui64OSTimer, &ui64Seconds, &ui64Nanoseconds); |
| |
| PVR_DUMPDEBUG_LOG("FW Fault %d: %s (%s:%d)", |
| ui32Index+1, psFaultInfo->sFaultBuf.szInfo, |
| psFaultInfo->sFaultBuf.szPath, |
| psFaultInfo->sFaultBuf.ui32LineNum); |
| PVR_DUMPDEBUG_LOG(" Data = 0x%08x, CRTimer = 0x%012"IMG_UINT64_FMTSPECx", OSTimer = %" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC, |
| psFaultInfo->ui32Data, |
| psFaultInfo->ui64CRTimer, |
| ui64Seconds, ui64Nanoseconds); |
| } |
| } |
| } |
| |
| static void _RGXDumpFWPoll(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl) |
| { |
| IMG_UINT32 i; |
| for (i = 0; i < RGXFW_THREAD_NUM; i++) |
| { |
| if (psRGXFWIfTraceBufCtl->aui32CrPollAddr[i]) |
| { |
| PVR_DUMPDEBUG_LOG("T%u polling %s (reg:0x%08X mask:0x%08X)", |
| i, |
| ((psRGXFWIfTraceBufCtl->aui32CrPollAddr[i] & RGXFW_POLL_TYPE_SET)?("set"):("unset")), |
| psRGXFWIfTraceBufCtl->aui32CrPollAddr[i] & ~RGXFW_POLL_TYPE_SET, |
| psRGXFWIfTraceBufCtl->aui32CrPollMask[i]); |
| } |
| } |
| |
| } |
| |
| static void _RGXDumpFWHWRInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl, |
| RGXFWIF_HWRINFOBUF *psHWInfoBuf, PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| IMG_BOOL bAnyLocked = IMG_FALSE; |
| IMG_UINT32 dm, i; |
| IMG_UINT32 ui32LineSize; |
| IMG_CHAR *pszLine, *pszTemp; |
| IMG_CHAR *apszDmNames[] = {"GP", "TDM", "TA", "3D", "CDM", |
| "RTU", "SHG", NULL }; |
| |
| const IMG_CHAR szMsgHeader[] = "Number of HWR: "; |
| const IMG_CHAR szMsgFalse[] = "FALSE("; |
| IMG_CHAR *pszLockupType = ""; |
| RGX_HWRINFO *psHWRInfo; |
| const IMG_UINT32 ui32MsgHeaderCharCount = ARRAY_SIZE(szMsgHeader) - 1; /* size includes the null */ |
| const IMG_UINT32 ui32MsgFalseCharCount = ARRAY_SIZE(szMsgFalse) - 1; |
| IMG_UINT32 ui32HWRRecoveryFlags; |
| IMG_UINT32 ui32ReadIndex; |
| |
| if (!(RGX_IS_FEATURE_SUPPORTED(psDevInfo, FASTRENDER_DM))) |
| { |
| apszDmNames[RGXFWIF_DM_TDM] = "2D"; |
| } |
| |
| for (dm = 0; dm < RGXFWIF_DM_MAX; dm++) |
| { |
| if (psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[dm] || |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[dm]) |
| { |
| bAnyLocked = IMG_TRUE; |
| break; |
| } |
| } |
| |
| if (!bAnyLocked && (psRGXFWIfTraceBufCtl->ui32HWRStateFlags & RGXFWIF_HWR_HARDWARE_OK) && !PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| /* No HWR situation, print nothing */ |
| return; |
| } |
| |
| if (PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| IMG_BOOL bAnyHWROccured = IMG_FALSE; |
| |
| for (dm = 0; (dm < RGXFWIF_DM_MAX) && (apszDmNames[dm] != NULL); dm++) |
| { |
| if (psRGXFWIfTraceBufCtl->aui32HwrDmRecoveredCount[dm] != 0 || |
| psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[dm] != 0 || |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[dm] !=0) |
| { |
| bAnyHWROccured = IMG_TRUE; |
| break; |
| } |
| } |
| |
| if (!bAnyHWROccured) |
| { |
| return; |
| } |
| } |
| |
| ui32LineSize = sizeof(IMG_CHAR) * ( |
| ui32MsgHeaderCharCount + |
| (RGXFWIF_DM_MAX * ( 4/*DM name + left parenthesis*/ + |
| 10/*UINT32 max num of digits*/ + |
| 1/*slash*/ + |
| 10/*UINT32 max num of digits*/ + |
| 3/*right parenthesis + comma + space*/)) + |
| ui32MsgFalseCharCount + 1 + (RGXFWIF_DM_MAX*6) + 1 |
| /* 'FALSE(' + ')' + (UINT16 max num + comma) per DM + \0 */ |
| ); |
| |
| pszLine = OSAllocMem(ui32LineSize); |
| if (pszLine == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Out of mem allocating line string (size: %d)", |
| __func__, |
| ui32LineSize)); |
| return; |
| } |
| |
| OSStringCopy(pszLine, szMsgHeader); |
| pszTemp = pszLine + ui32MsgHeaderCharCount; |
| |
| for (dm = 0; (dm < RGXFWIF_DM_MAX) && (apszDmNames[dm] != NULL); dm++) |
| { |
| pszTemp += OSSNPrintf(pszTemp, |
| 4 + 10 + 1 + 10 + 1 + 10 + 1 + 1 + 1 + 1 |
| /* (name + left parenthesis) + UINT32 + slash + UINT32 + plus + UINT32 + right parenthesis + comma + space + \0 */, |
| "%s(%u/%u+%u), ", |
| apszDmNames[dm], |
| psRGXFWIfTraceBufCtl->aui32HwrDmRecoveredCount[dm], |
| psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[dm], |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[dm]); |
| } |
| |
| OSStringCopy(pszTemp, szMsgFalse); |
| pszTemp += ui32MsgFalseCharCount; |
| |
| for (dm = 0; (dm < RGXFWIF_DM_MAX) && (apszDmNames[dm] != NULL); dm++) |
| { |
| pszTemp += OSSNPrintf(pszTemp, |
| 10 + 1 + 1 /* UINT32 max num + comma + \0 */, |
| (dm < RGXFWIF_DM_MAX-1 ? "%u," : "%u)"), |
| psRGXFWIfTraceBufCtl->aui32HwrDmFalseDetectCount[dm]); |
| } |
| |
| PVR_DUMPDEBUG_LOG("%s", pszLine); |
| |
| OSFreeMem(pszLine); |
| |
| /* Print out per HWR info */ |
| for (dm = 0; (dm < RGXFWIF_DM_MAX) && (apszDmNames[dm] != NULL); dm++) |
| { |
| if (dm == RGXFWIF_DM_GP) |
| { |
| PVR_DUMPDEBUG_LOG("DM %d (GP)", dm); |
| } |
| else |
| { |
| if (!PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| IMG_CHAR sPerDmHwrDescription[RGX_DEBUG_STR_SIZE]; |
| sPerDmHwrDescription[0] = '\0'; |
| |
| _Flags2Description(sPerDmHwrDescription, asDmState2Description, ARRAY_SIZE(asDmState2Description), psRGXFWIfTraceBufCtl->aui32HWRRecoveryFlags[dm]); |
| PVR_DUMPDEBUG_LOG("DM %d (HWRflags 0x%08x:%s)", dm, psRGXFWIfTraceBufCtl->aui32HWRRecoveryFlags[dm], sPerDmHwrDescription); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("DM %d", dm); |
| } |
| } |
| |
| ui32ReadIndex = 0; |
| for (i = 0 ; i < RGXFWIF_HWINFO_MAX ; i++) |
| { |
| psHWRInfo = &psHWInfoBuf->sHWRInfo[ui32ReadIndex]; |
| |
| if ((psHWRInfo->eDM == dm) && (psHWRInfo->ui32HWRNumber != 0)) |
| { |
| IMG_CHAR aui8RecoveryNum[10+10+1]; |
| IMG_UINT64 ui64Seconds, ui64Nanoseconds; |
| |
| /* Split OS timestamp in seconds and nanoseconds */ |
| ConvertOSTimestampToSAndNS(psHWRInfo->ui64OSTimer, &ui64Seconds, &ui64Nanoseconds); |
| |
| ui32HWRRecoveryFlags = psHWRInfo->ui32HWRRecoveryFlags; |
| if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_GUILTY_LOCKUP) { pszLockupType = ", Guilty Lockup"; } |
| else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_INNOCENT_LOCKUP) { pszLockupType = ", Innocent Lockup"; } |
| else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_GUILTY_OVERRUNING) { pszLockupType = ", Guilty Overrun"; } |
| else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_INNOCENT_OVERRUNING) { pszLockupType = ", Innocent Overrun"; } |
| else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_HARD_CONTEXT_SWITCH) { pszLockupType = ", Hard Context Switch"; } |
| |
| OSSNPrintf(aui8RecoveryNum, sizeof(aui8RecoveryNum), "Recovery %d:", psHWRInfo->ui32HWRNumber); |
| PVR_DUMPDEBUG_LOG(" %s PID = %u, frame = %d, HWRTData = 0x%08X, EventStatus = 0x%08X%s", |
| aui8RecoveryNum, |
| psHWRInfo->ui32PID, |
| psHWRInfo->ui32FrameNum, |
| psHWRInfo->ui32ActiveHWRTData, |
| psHWRInfo->ui32EventStatus, |
| pszLockupType); |
| pszTemp = &aui8RecoveryNum[0]; |
| while (*pszTemp != '\0') |
| { |
| *pszTemp++ = ' '; |
| } |
| |
| /* There's currently no time correlation for the Guest OSes on the Firmware so there's no point printing OS Timestamps on Guests */ |
| if (!PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| PVR_DUMPDEBUG_LOG(" %s CRTimer = 0x%012"IMG_UINT64_FMTSPECx", OSTimer = %" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC ", CyclesElapsed = %" IMG_INT64_FMTSPECd, |
| aui8RecoveryNum, |
| psHWRInfo->ui64CRTimer, |
| ui64Seconds, |
| ui64Nanoseconds, |
| (psHWRInfo->ui64CRTimer-psHWRInfo->ui64CRTimeOfKick)*256); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" %s CRTimer = 0x%012"IMG_UINT64_FMTSPECx", CyclesElapsed = %" IMG_INT64_FMTSPECd, |
| aui8RecoveryNum, |
| psHWRInfo->ui64CRTimer, |
| (psHWRInfo->ui64CRTimer-psHWRInfo->ui64CRTimeOfKick)*256); |
| } |
| |
| if (psHWRInfo->ui64CRTimeHWResetFinish != 0) |
| { |
| if (psHWRInfo->ui64CRTimeFreelistReady != 0) |
| { |
| PVR_DUMPDEBUG_LOG(" %s PreResetTimeInCycles = %" IMG_INT64_FMTSPECd ", HWResetTimeInCycles = %" IMG_INT64_FMTSPECd ", FreelistReconTimeInCycles = %" IMG_INT64_FMTSPECd ", TotalRecoveryTimeInCycles = %" IMG_INT64_FMTSPECd, |
| aui8RecoveryNum, |
| (psHWRInfo->ui64CRTimeHWResetStart-psHWRInfo->ui64CRTimer)*256, |
| (psHWRInfo->ui64CRTimeHWResetFinish-psHWRInfo->ui64CRTimeHWResetStart)*256, |
| (psHWRInfo->ui64CRTimeFreelistReady-psHWRInfo->ui64CRTimeHWResetFinish)*256, |
| (psHWRInfo->ui64CRTimeFreelistReady-psHWRInfo->ui64CRTimer)*256); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" %s PreResetTimeInCycles = %" IMG_INT64_FMTSPECd ", HWResetTimeInCycles = %" IMG_INT64_FMTSPECd ", TotalRecoveryTimeInCycles = %" IMG_INT64_FMTSPECd, |
| aui8RecoveryNum, |
| (psHWRInfo->ui64CRTimeHWResetStart-psHWRInfo->ui64CRTimer)*256, |
| (psHWRInfo->ui64CRTimeHWResetFinish-psHWRInfo->ui64CRTimeHWResetStart)*256, |
| (psHWRInfo->ui64CRTimeHWResetFinish-psHWRInfo->ui64CRTimer)*256); |
| } |
| } |
| |
| switch (psHWRInfo->eHWRType) |
| { |
| case RGX_HWRTYPE_BIF0FAULT: |
| case RGX_HWRTYPE_BIF1FAULT: |
| { |
| if (!(RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE))) |
| { |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXFWIF_HWRTYPE_BIF_BANK_GET(psHWRInfo->eHWRType), |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFMMUStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFReqStatus, |
| ui32ReadIndex); |
| } |
| } |
| break; |
| case RGX_HWRTYPE_TEXASBIF0FAULT: |
| { |
| if (!(RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE))) |
| { |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, CLUSTER_GROUPING)) |
| { |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_TEXAS_BIF, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFMMUStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFReqStatus, |
| ui32ReadIndex); |
| } |
| } |
| } |
| break; |
| case RGX_HWRTYPE_MMUFAULT: |
| { |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE)) |
| { |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus, |
| ui32ReadIndex, |
| "Core"); |
| } |
| } |
| break; |
| case RGX_HWRTYPE_MMUMETAFAULT: |
| { |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE)) |
| { |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus, |
| ui32ReadIndex, |
| "Meta"); |
| } |
| } |
| break; |
| |
| |
| case RGX_HWRTYPE_POLLFAILURE: |
| { |
| PVR_DUMPDEBUG_LOG(" T%u polling %s (reg:0x%08X mask:0x%08X last:0x%08X)", |
| psHWRInfo->uHWRData.sPollInfo.ui32ThreadNum, |
| ((psHWRInfo->uHWRData.sPollInfo.ui32CrPollAddr & RGXFW_POLL_TYPE_SET)?("set"):("unset")), |
| psHWRInfo->uHWRData.sPollInfo.ui32CrPollAddr & ~RGXFW_POLL_TYPE_SET, |
| psHWRInfo->uHWRData.sPollInfo.ui32CrPollMask, |
| psHWRInfo->uHWRData.sPollInfo.ui32CrPollLastValue); |
| } |
| break; |
| |
| case RGX_HWRTYPE_OVERRUN: |
| case RGX_HWRTYPE_UNKNOWNFAILURE: |
| { |
| /* Nothing to dump */ |
| } |
| break; |
| |
| default: |
| { |
| PVR_ASSERT(IMG_FALSE); |
| } |
| break; |
| } |
| } |
| |
| if (ui32ReadIndex == RGXFWIF_HWINFO_MAX_FIRST - 1) |
| ui32ReadIndex = psHWInfoBuf->ui32WriteIndex; |
| else |
| ui32ReadIndex = (ui32ReadIndex + 1) - (ui32ReadIndex / RGXFWIF_HWINFO_LAST_INDEX) * RGXFWIF_HWINFO_MAX_LAST; |
| } |
| } |
| } |
| |
| #if !defined(NO_HARDWARE) |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _CheckForPendingPage |
| |
| @Description |
| |
| Check if the MMU indicates it is blocked on a pending page |
| |
| @Input psDevInfo - RGX device info |
| |
| @Return IMG_BOOL - IMG_TRUE if there is a pending page |
| |
| ******************************************************************************/ |
| static INLINE IMG_BOOL _CheckForPendingPage(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| IMG_UINT32 ui32BIFMMUEntry; |
| |
| ui32BIFMMUEntry = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_MMU_ENTRY); |
| |
| if (ui32BIFMMUEntry & RGX_CR_BIF_MMU_ENTRY_PENDING_EN) |
| { |
| return IMG_TRUE; |
| } |
| else |
| { |
| return IMG_FALSE; |
| } |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _GetPendingPageInfo |
| |
| @Description |
| |
| Get information about the pending page from the MMU status registers |
| |
| @Input psDevInfo - RGX device info |
| @Output psDevVAddr - The device virtual address of the pending MMU address translation |
| @Output pui32CatBase - The page catalog base |
| @Output pui32DataType - The MMU entry data type |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static void _GetPendingPageInfo(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_DEV_VIRTADDR *psDevVAddr, |
| IMG_UINT32 *pui32CatBase, |
| IMG_UINT32 *pui32DataType) |
| { |
| IMG_UINT64 ui64BIFMMUEntryStatus; |
| |
| ui64BIFMMUEntryStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_MMU_ENTRY_STATUS); |
| |
| psDevVAddr->uiAddr = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_CLRMSK); |
| |
| *pui32CatBase = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_CLRMSK) >> |
| RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_SHIFT; |
| |
| *pui32DataType = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_CLRMSK) >> |
| RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_SHIFT; |
| } |
| |
| #endif |
| |
| void RGXDumpRGXDebugSummary(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_BOOL bRGXPoweredON) |
| { |
| IMG_CHAR *pszState, *pszReason; |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBuf = psDevInfo->psRGXFWIfTraceBuf; |
| IMG_UINT32 ui32OSid; |
| RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg; |
| /* space for the current clock speed and 3 previous */ |
| RGXFWIF_TIME_CORR asTimeCorrs[4]; |
| IMG_UINT32 ui32NumClockSpeedChanges; |
| |
| #if defined(NO_HARDWARE) |
| PVR_UNREFERENCED_PARAMETER(bRGXPoweredON); |
| #else |
| if ((bRGXPoweredON) && !PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE)) |
| { |
| |
| IMG_UINT64 ui64RegValMMUStatus; |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_MMU_FAULT_STATUS); |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, ui64RegValMMUStatus, RGXFWIF_HWINFO_MAX, "Core"); |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_MMU_FAULT_STATUS_META); |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, ui64RegValMMUStatus, RGXFWIF_HWINFO_MAX, "Meta"); |
| }else |
| { |
| IMG_UINT64 ui64RegValMMUStatus, ui64RegValREQStatus; |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_FAULT_BANK0_MMU_STATUS); |
| ui64RegValREQStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_FAULT_BANK0_REQ_STATUS); |
| |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_BIF0, ui64RegValMMUStatus, ui64RegValREQStatus, RGXFWIF_HWINFO_MAX); |
| |
| if (!(RGX_IS_FEATURE_SUPPORTED(psDevInfo, SINGLE_BIF))) |
| { |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_FAULT_BANK1_MMU_STATUS); |
| ui64RegValREQStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_FAULT_BANK1_REQ_STATUS); |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_BIF1, ui64RegValMMUStatus, ui64RegValREQStatus, RGXFWIF_HWINFO_MAX); |
| } |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, CLUSTER_GROUPING)) |
| { |
| IMG_UINT32 ui32PhantomCnt = RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, NUM_CLUSTERS) ? RGX_REQ_NUM_PHANTOMS(RGX_GET_FEATURE_VALUE(psDevInfo, NUM_CLUSTERS)) : 0; |
| |
| if (ui32PhantomCnt > 1) |
| { |
| IMG_UINT32 ui32Phantom; |
| for (ui32Phantom = 0; ui32Phantom < ui32PhantomCnt; ui32Phantom++) |
| { |
| /* This can't be done as it may interfere with the FW... */ |
| /*OSWriteHWReg64(RGX_CR_TEXAS_INDIRECT, ui32Phantom);*/ |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS); |
| ui64RegValREQStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS); |
| |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_TEXAS_BIF, ui64RegValMMUStatus, ui64RegValREQStatus, RGXFWIF_HWINFO_MAX); |
| } |
| }else |
| { |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS); |
| ui64RegValREQStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS); |
| |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_TEXAS_BIF, ui64RegValMMUStatus, ui64RegValREQStatus, RGXFWIF_HWINFO_MAX); |
| } |
| } |
| } |
| |
| if (_CheckForPendingPage(psDevInfo)) |
| { |
| IMG_UINT32 ui32CatBase; |
| IMG_UINT32 ui32DataType; |
| IMG_DEV_VIRTADDR sDevVAddr; |
| |
| PVR_DUMPDEBUG_LOG("MMU Pending page: Yes"); |
| |
| _GetPendingPageInfo(psDevInfo, &sDevVAddr, &ui32CatBase, &ui32DataType); |
| |
| if (ui32CatBase >= 8) |
| { |
| PVR_DUMPDEBUG_LOG("Cannot check address on PM cat base %u", ui32CatBase); |
| } |
| else |
| { |
| IMG_DEV_PHYADDR sPCDevPAddr; |
| |
| sPCDevPAddr.uiAddr = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_CAT_BASEN(ui32CatBase)); |
| |
| PVR_DUMPDEBUG_LOG("Checking device virtual address " IMG_DEV_VIRTADDR_FMTSPEC |
| " on cat base %u. PC Addr = 0x%" IMG_UINT64_FMTSPECx, |
| sDevVAddr.uiAddr, |
| ui32CatBase, |
| sPCDevPAddr.uiAddr); |
| RGXCheckFaultAddress(psDevInfo, &sDevVAddr, &sPCDevPAddr, |
| pfnDumpDebugPrintf, pvDumpDebugFile, NULL); |
| } |
| } |
| } |
| #endif /* NO_HARDWARE */ |
| |
| /* Firmware state */ |
| switch (OSAtomicRead(&psDevInfo->psDeviceNode->eHealthStatus)) |
| { |
| case PVRSRV_DEVICE_HEALTH_STATUS_OK: pszState = "OK"; break; |
| case PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING: pszState = "NOT RESPONDING"; break; |
| case PVRSRV_DEVICE_HEALTH_STATUS_DEAD: pszState = "DEAD"; break; |
| case PVRSRV_DEVICE_HEALTH_STATUS_FAULT: pszState = "FAULT"; break; |
| case PVRSRV_DEVICE_HEALTH_STATUS_UNDEFINED: pszState = "UNDEFINED"; break; |
| default: pszState = "UNKNOWN"; break; |
| } |
| |
| switch (OSAtomicRead(&psDevInfo->psDeviceNode->eHealthReason)) |
| { |
| case PVRSRV_DEVICE_HEALTH_REASON_NONE: pszReason = ""; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_ASSERTED: pszReason = " - Asserted"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_POLL_FAILING: pszReason = " - Poll failure"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_TIMEOUTS: pszReason = " - Global Event Object timeouts rising"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_QUEUE_CORRUPT: pszReason = " - KCCB offset invalid"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_QUEUE_STALLED: pszReason = " - KCCB stalled"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_IDLING: pszReason = " - Idling"; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_RESTARTING: pszReason = " - Restarting"; break; |
| default: pszReason = " - Unknown reason"; break; |
| } |
| |
| if (psRGXFWIfTraceBuf == NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX FW State: %s%s", pszState, pszReason); |
| |
| /* can't dump any more information */ |
| return; |
| } |
| |
| if (!PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| IMG_CHAR sHwrStateDescription[RGX_DEBUG_STR_SIZE]; |
| sHwrStateDescription[0] = '\0'; |
| |
| _Flags2Description(sHwrStateDescription, asHwrState2Description, ARRAY_SIZE(asHwrState2Description), psRGXFWIfTraceBuf->ui32HWRStateFlags); |
| PVR_DUMPDEBUG_LOG("RGX FW State: %s%s (HWRState 0x%08x:%s)", pszState, pszReason, psRGXFWIfTraceBuf->ui32HWRStateFlags, sHwrStateDescription); |
| PVR_DUMPDEBUG_LOG("RGX FW Power State: %s (APM %s: %d ok, %d denied, %d non-idle, %d retry, %d other, %d total. Latency: %u ms)", |
| pszPowStateName[psRGXFWIfTraceBuf->ePowState], |
| (psDevInfo->pvAPMISRData)?"enabled":"disabled", |
| psDevInfo->ui32ActivePMReqOk - psDevInfo->ui32ActivePMReqNonIdle, |
| psDevInfo->ui32ActivePMReqDenied, |
| psDevInfo->ui32ActivePMReqNonIdle, |
| psDevInfo->ui32ActivePMReqRetry, |
| psDevInfo->ui32ActivePMReqTotal - |
| psDevInfo->ui32ActivePMReqOk - |
| psDevInfo->ui32ActivePMReqDenied - |
| psDevInfo->ui32ActivePMReqRetry - |
| psDevInfo->ui32ActivePMReqNonIdle, |
| psDevInfo->ui32ActivePMReqTotal, |
| psRuntimeCfg->ui32ActivePMLatencyms); |
| |
| ui32NumClockSpeedChanges = (IMG_UINT32) OSAtomicRead(&psDevInfo->psDeviceNode->iNumClockSpeedChanges); |
| RGXGetTimeCorrData(psDevInfo->psDeviceNode, asTimeCorrs, ARRAY_SIZE(asTimeCorrs)); |
| |
| PVR_DUMPDEBUG_LOG("RGX DVFS: %u frequency changes. Current frequency: %u.%03u MHz (sampled at %" IMG_UINT64_FMTSPEC ")", |
| ui32NumClockSpeedChanges, |
| asTimeCorrs[0].ui32CoreClockSpeed / 1000000, |
| (asTimeCorrs[0].ui32CoreClockSpeed / 1000) % 1000, |
| asTimeCorrs[0].ui64OSTimeStamp); |
| if (ui32NumClockSpeedChanges > 0) |
| { |
| PVR_DUMPDEBUG_LOG(" Previous frequencies: %u.%03u, %u.%03u, %u.%03u MHz (Sampled at " |
| "%" IMG_UINT64_FMTSPEC ", %" IMG_UINT64_FMTSPEC ", %" IMG_UINT64_FMTSPEC ")", |
| asTimeCorrs[1].ui32CoreClockSpeed / 1000000, |
| (asTimeCorrs[1].ui32CoreClockSpeed / 1000) % 1000, |
| asTimeCorrs[2].ui32CoreClockSpeed / 1000000, |
| (asTimeCorrs[2].ui32CoreClockSpeed / 1000) % 1000, |
| asTimeCorrs[3].ui32CoreClockSpeed / 1000000, |
| (asTimeCorrs[3].ui32CoreClockSpeed / 1000) % 1000, |
| asTimeCorrs[1].ui64OSTimeStamp, |
| asTimeCorrs[2].ui64OSTimeStamp, |
| asTimeCorrs[3].ui64OSTimeStamp); |
| } |
| |
| for (ui32OSid = 0; ui32OSid < RGXFW_NUM_OS; ui32OSid++) |
| { |
| RGXFWIF_PER_OS_STATES sFwOsState = psRGXFWIfTraceBuf->sPerOsStateMirror[ui32OSid]; |
| static const IMG_CHAR * const apszFwOsStateName[4] = |
| { |
| "stopped", |
| "ready", |
| "active", |
| "offloading" |
| }; |
| |
| PVR_DUMPDEBUG_LOG("RGX FW OS %u - State: %s; Freelists: %s%s%s", ui32OSid, |
| apszFwOsStateName[sFwOsState.bfOsState], |
| (sFwOsState.bfFLOk) ? "Ok" : "Not Ok", |
| (sFwOsState.bfFLGrowPending) ? "; Grow Request Pending" : "", |
| (sFwOsState.bfIsolatedOS) ? "; Isolated;" : "" |
| ); |
| } |
| |
| _RGXDumpFWAssert(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf); |
| _RGXDumpFWFaults(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf); |
| _RGXDumpFWPoll(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("RGX FW State: Unavailable under Guest Mode of operation"); |
| PVR_DUMPDEBUG_LOG("RGX FW Power State: Unavailable under Guest Mode of operation"); |
| } |
| |
| _RGXDumpFWHWRInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf, psDevInfo->psRGXFWIfHWRInfoBuf, psDevInfo); |
| |
| #if defined(SUPPORT_RGXFW_STATS_FRAMEWORK) |
| /* Dump all non-zero values in lines of 8... */ |
| { |
| IMG_CHAR pszLine[(9*RGXFWIF_STATS_FRAMEWORK_LINESIZE)+1]; |
| IMG_UINT32 *pui32FWStatsBuf = psRGXFWIfTraceBuf->aui32FWStatsBuf; |
| IMG_UINT32 ui32Index1, ui32Index2; |
| |
| PVR_DUMPDEBUG_LOG("STATS[START]: RGXFWIF_STATS_FRAMEWORK_MAX=%d", RGXFWIF_STATS_FRAMEWORK_MAX); |
| for (ui32Index1 = 0; ui32Index1 < RGXFWIF_STATS_FRAMEWORK_MAX; ui32Index1 += RGXFWIF_STATS_FRAMEWORK_LINESIZE) |
| { |
| IMG_UINT32 ui32OrOfValues = 0; |
| IMG_CHAR *pszBuf = pszLine; |
| |
| /* Print all values in this line and skip if all zero... */ |
| for (ui32Index2 = 0; ui32Index2 < RGXFWIF_STATS_FRAMEWORK_LINESIZE; ui32Index2++) |
| { |
| ui32OrOfValues |= pui32FWStatsBuf[ui32Index1+ui32Index2]; |
| OSSNPrintf(pszBuf, 9 + 1, " %08x", pui32FWStatsBuf[ui32Index1+ui32Index2]); |
| pszBuf += 9; /* write over the '\0' */ |
| } |
| |
| if (ui32OrOfValues != 0) |
| { |
| PVR_DUMPDEBUG_LOG("STATS[%08x]:%s", ui32Index1, pszLine); |
| } |
| } |
| PVR_DUMPDEBUG_LOG("STATS[END]"); |
| } |
| #endif |
| } |
| |
| static void _RGXDumpMetaSPExtraDebugInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| /* List of extra META Slave Port debug registers */ |
| #define RGX_META_SP_EXTRA_DEBUG \ |
| X(RGX_CR_META_SP_MSLVCTRL0) \ |
| X(RGX_CR_META_SP_MSLVCTRL1) \ |
| X(RGX_CR_META_SP_MSLVDATAX) \ |
| X(RGX_CR_META_SP_MSLVIRQSTATUS) \ |
| X(RGX_CR_META_SP_MSLVIRQENABLE) \ |
| X(RGX_CR_META_SP_MSLVIRQLEVEL) |
| |
| IMG_UINT32 ui32Idx, ui32RegIdx; |
| IMG_UINT32 ui32RegVal; |
| IMG_UINT32 ui32RegAddr; |
| |
| const IMG_UINT32 aui32DebugRegAddr [] = { |
| #define X(A) A, |
| RGX_META_SP_EXTRA_DEBUG |
| #undef X |
| }; |
| |
| const IMG_CHAR* apszDebugRegName [] = { |
| #define X(A) #A, |
| RGX_META_SP_EXTRA_DEBUG |
| #undef X |
| }; |
| |
| const IMG_UINT32 aui32Debug2RegAddr [] = {0xA28, 0x0A30, 0x0A38}; |
| |
| PVR_DUMPDEBUG_LOG("META Slave Port extra debug:"); |
| |
| /* dump first set of Slave Port debug registers */ |
| for (ui32Idx = 0; ui32Idx < sizeof(aui32DebugRegAddr)/sizeof(IMG_UINT32); ui32Idx++) |
| { |
| const IMG_CHAR* pszRegName = apszDebugRegName[ui32Idx]; |
| |
| ui32RegAddr = aui32DebugRegAddr[ui32Idx]; |
| ui32RegVal = OSReadHWReg32(psDevInfo->pvRegsBaseKM, ui32RegAddr); |
| PVR_DUMPDEBUG_LOG(" * %s: 0x%8.8X", pszRegName, ui32RegVal); |
| } |
| |
| /* dump second set of Slave Port debug registers */ |
| for (ui32Idx = 0; ui32Idx < 4; ui32Idx++) |
| { |
| OSWriteHWReg32(psDevInfo->pvRegsBaseKM, 0xA20, ui32Idx); |
| ui32RegVal = OSReadHWReg32(psDevInfo->pvRegsBaseKM, 0xA20); |
| PVR_DUMPDEBUG_LOG(" * 0xA20[%d]: 0x%8.8X", ui32Idx, ui32RegVal); |
| |
| } |
| |
| for (ui32RegIdx = 0; ui32RegIdx < sizeof(aui32Debug2RegAddr)/sizeof(IMG_UINT32); ui32RegIdx++) |
| { |
| ui32RegAddr = aui32Debug2RegAddr[ui32RegIdx]; |
| for (ui32Idx = 0; ui32Idx < 2; ui32Idx++) |
| { |
| OSWriteHWReg32(psDevInfo->pvRegsBaseKM, ui32RegAddr, ui32Idx); |
| ui32RegVal = OSReadHWReg32(psDevInfo->pvRegsBaseKM, ui32RegAddr); |
| PVR_DUMPDEBUG_LOG(" * 0x%X[%d]: 0x%8.8X", ui32RegAddr, ui32Idx, ui32RegVal); |
| } |
| } |
| |
| } |
| |
| void RGXDumpDebugInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| PVR_DUMPDEBUG_LOG("------[ RGX Device: Start ]------"); |
| |
| RGXDebugRequestProcess(pfnDumpDebugPrintf, pvDumpDebugFile, |
| psDevInfo, DEBUG_REQUEST_VERBOSITY_MAX); |
| |
| PVR_DUMPDEBUG_LOG("------[ RGX Device: End ]------"); |
| } |
| |
| /* |
| * Array of all the Firmware Trace log IDs used to convert the trace data. |
| */ |
| typedef struct _TRACEBUF_LOG_ { |
| RGXFW_LOG_SFids eSFId; |
| const IMG_CHAR *pszName; |
| const IMG_CHAR *pszFmt; |
| IMG_UINT32 ui32ArgNum; |
| } TRACEBUF_LOG; |
| |
| static const TRACEBUF_LOG aLogDefinitions[] = |
| { |
| #define X(a, b, c, d, e) {RGXFW_LOG_CREATESFID(a,b,e), #c, d, e}, |
| RGXFW_LOG_SFIDLIST |
| #undef X |
| }; |
| |
| #define NARGS_MASK ~(0xF<<16) |
| static IMG_BOOL _FirmwareTraceIntegrityCheck(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile) |
| { |
| const TRACEBUF_LOG *psLogDef = &aLogDefinitions[0]; |
| IMG_BOOL bIntegrityOk = IMG_TRUE; |
| |
| /* |
| * For every log ID, check the format string and number of arguments is valid. |
| */ |
| while (psLogDef->eSFId != RGXFW_SF_LAST) |
| { |
| const TRACEBUF_LOG *psLogDef2; |
| const IMG_CHAR *pszString; |
| IMG_UINT32 ui32Count; |
| |
| /* |
| * Check the number of arguments matches the number of '%' in the string and |
| * check that no string uses %s which is not supported as it requires a |
| * pointer to memory that is not going to be valid. |
| */ |
| pszString = psLogDef->pszFmt; |
| ui32Count = 0; |
| |
| while (*pszString != '\0') |
| { |
| if (*pszString++ == '%') |
| { |
| ui32Count++; |
| if (*pszString == 's') |
| { |
| bIntegrityOk = IMG_FALSE; |
| PVR_DUMPDEBUG_LOG("Integrity Check FAIL: %s has an unsupported type not recognized (fmt: %%%c). Please fix.", |
| psLogDef->pszName, *pszString); |
| } |
| else if (*pszString == '%') |
| { |
| /* Double % is a printable % sign and not a format string... */ |
| ui32Count--; |
| } |
| } |
| } |
| |
| if (ui32Count != psLogDef->ui32ArgNum) |
| { |
| bIntegrityOk = IMG_FALSE; |
| PVR_DUMPDEBUG_LOG("Integrity Check FAIL: %s has %d arguments but only %d are specified. Please fix.", |
| psLogDef->pszName, ui32Count, psLogDef->ui32ArgNum); |
| } |
| |
| /* RGXDumpFirmwareTrace() has a hardcoded limit of supporting up to 20 arguments... */ |
| if (ui32Count > 20) |
| { |
| bIntegrityOk = IMG_FALSE; |
| PVR_DUMPDEBUG_LOG("Integrity Check FAIL: %s has %d arguments but a maximum of 20 are supported. Please fix.", |
| psLogDef->pszName, ui32Count); |
| } |
| |
| /* Check the id number is unique (don't take into account the number of arguments) */ |
| ui32Count = 0; |
| psLogDef2 = &aLogDefinitions[0]; |
| |
| while (psLogDef2->eSFId != RGXFW_SF_LAST) |
| { |
| if ((psLogDef->eSFId & NARGS_MASK) == (psLogDef2->eSFId & NARGS_MASK)) |
| { |
| ui32Count++; |
| } |
| psLogDef2++; |
| } |
| |
| if (ui32Count != 1) |
| { |
| bIntegrityOk = IMG_FALSE; |
| PVR_DUMPDEBUG_LOG("Integrity Check FAIL: %s id %x is not unique, there are %d more. Please fix.", |
| psLogDef->pszName, psLogDef->eSFId, ui32Count - 1); |
| } |
| |
| /* Move to the next log ID... */ |
| psLogDef++; |
| } |
| |
| return bIntegrityOk; |
| } |
| |
| void RGXDumpFirmwareTrace(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| static IMG_BOOL bIntegrityCheckPassed = IMG_FALSE; |
| |
| /* Check that the firmware trace is correctly defined... */ |
| if (!bIntegrityCheckPassed) |
| { |
| bIntegrityCheckPassed = _FirmwareTraceIntegrityCheck(pfnDumpDebugPrintf, pvDumpDebugFile); |
| if (!bIntegrityCheckPassed) |
| { |
| return; |
| } |
| } |
| |
| /* Dump FW trace information... */ |
| if (psRGXFWIfTraceBufCtl != NULL) |
| { |
| IMG_UINT32 tid; |
| IMG_UINT32 ui32TraceBufSizeInDWords = psRGXFWIfTraceBufCtl->ui32TraceBufSizeInDWords; |
| |
| /* Print the log type settings... */ |
| if (psRGXFWIfTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_GROUP_MASK) |
| { |
| PVR_DUMPDEBUG_LOG("Debug log type: %s ( " RGXFWIF_LOG_ENABLED_GROUPS_LIST_PFSPEC ")", |
| ((psRGXFWIfTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_TRACE)?("trace"):("tbi")), |
| RGXFWIF_LOG_ENABLED_GROUPS_LIST(psRGXFWIfTraceBufCtl->ui32LogType) |
| ); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("Debug log type: none"); |
| } |
| |
| /* Print the decoded log for each thread... */ |
| for (tid = 0; tid < RGXFW_THREAD_NUM; tid++) |
| { |
| IMG_UINT32 *pui32TraceBuf = psRGXFWIfTraceBufCtl->sTraceBuf[tid].pui32TraceBuffer; |
| IMG_UINT32 ui32TracePtr = psRGXFWIfTraceBufCtl->sTraceBuf[tid].ui32TracePointer; |
| IMG_UINT32 ui32Count = 0; |
| |
| if (pui32TraceBuf == NULL) |
| { |
| /* trace buffer not yet allocated */ |
| continue; |
| } |
| |
| while (ui32Count < ui32TraceBufSizeInDWords) |
| { |
| IMG_UINT32 ui32Data, ui32DataToId; |
| |
| /* Find the first valid log ID, skipping whitespace... */ |
| do |
| { |
| ui32Data = pui32TraceBuf[ui32TracePtr]; |
| ui32DataToId = idToStringID(ui32Data, SFs); |
| |
| /* If an unrecognized id is found it may be inconsistent data or a firmware trace error. */ |
| if (ui32DataToId == RGXFW_SF_LAST && RGXFW_LOG_VALIDID(ui32Data)) |
| { |
| PVR_DUMPDEBUG_LOG("WARNING: Unrecognized id (%x). From here on the trace might be wrong!", ui32Data); |
| } |
| |
| /* Update the trace pointer... */ |
| ui32TracePtr = (ui32TracePtr + 1) % ui32TraceBufSizeInDWords; |
| ui32Count++; |
| } while ((RGXFW_SF_LAST == ui32DataToId || ui32DataToId >= RGXFW_SF_FIRST) && |
| ui32Count < ui32TraceBufSizeInDWords); |
| |
| if (ui32Count < ui32TraceBufSizeInDWords) |
| { |
| IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN] = "%" IMG_UINT64_FMTSPEC ":T%u-%s> "; |
| IMG_UINT64 ui64Timestamp; |
| IMG_UINT uiLen; |
| |
| /* If we hit the ASSERT message then this is the end of the log... */ |
| if (ui32Data == RGXFW_SF_MAIN_ASSERT_FAILED) |
| { |
| PVR_DUMPDEBUG_LOG("ASSERTION %s failed at %s:%u", |
| psRGXFWIfTraceBufCtl->sTraceBuf[tid].sAssertBuf.szInfo, |
| psRGXFWIfTraceBufCtl->sTraceBuf[tid].sAssertBuf.szPath, |
| psRGXFWIfTraceBufCtl->sTraceBuf[tid].sAssertBuf.ui32LineNum); |
| break; |
| } |
| |
| /* |
| * Print the trace string and provide up to 20 arguments which |
| * printf function will be able to use. We have already checked |
| * that no string uses more than this. |
| */ |
| OSStringCopy(&szBuffer[OSStringLength(szBuffer)], SFs[ui32DataToId].psName); |
| uiLen = OSStringLength(szBuffer); |
| szBuffer[uiLen ? uiLen - 1 : 0] = '\0'; |
| ui64Timestamp = (IMG_UINT64)(pui32TraceBuf[(ui32TracePtr + 0) % ui32TraceBufSizeInDWords]) << 32 | |
| (IMG_UINT64)(pui32TraceBuf[(ui32TracePtr + 1) % ui32TraceBufSizeInDWords]); |
| PVR_DUMPDEBUG_LOG(szBuffer, ui64Timestamp, tid, groups[RGXFW_SF_GID(ui32Data)], |
| pui32TraceBuf[(ui32TracePtr + 2) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 3) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 4) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 5) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 6) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 7) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 8) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 9) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 10) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 11) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 12) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 13) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 14) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 15) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 16) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 17) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 18) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 19) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 20) % ui32TraceBufSizeInDWords], |
| pui32TraceBuf[(ui32TracePtr + 21) % ui32TraceBufSizeInDWords]); |
| |
| /* Update the trace pointer... */ |
| ui32TracePtr = (ui32TracePtr + 2 + RGXFW_SF_PARAMNUM(ui32Data)) % ui32TraceBufSizeInDWords; |
| ui32Count = (ui32Count + 2 + RGXFW_SF_PARAMNUM(ui32Data)); |
| } |
| } |
| } |
| } |
| } |
| |
| static const IMG_CHAR *_RGXGetDebugDevStateString(PVRSRV_DEVICE_STATE eDevState) |
| { |
| switch (eDevState) |
| { |
| case PVRSRV_DEVICE_STATE_INIT: |
| return "Initialising"; |
| case PVRSRV_DEVICE_STATE_ACTIVE: |
| return "Active"; |
| case PVRSRV_DEVICE_STATE_DEINIT: |
| return "De-initialising"; |
| case PVRSRV_DEVICE_STATE_BAD: |
| return "Bad"; |
| case PVRSRV_DEVICE_STATE_UNDEFINED: |
| PVR_ASSERT(!"Device has undefined state"); |
| __fallthrough; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| static const IMG_CHAR* _RGXGetDebugDevPowerStateString(PVRSRV_DEV_POWER_STATE ePowerState) |
| { |
| switch (ePowerState) |
| { |
| case PVRSRV_DEV_POWER_STATE_DEFAULT: return "DEFAULT"; |
| case PVRSRV_DEV_POWER_STATE_OFF: return "OFF"; |
| case PVRSRV_DEV_POWER_STATE_ON: return "ON"; |
| default: return "UNKNOWN"; |
| } |
| } |
| |
| PVRSRV_ERROR RGXDumpRGXRegisters(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| IMG_UINT32 ui32Meta = (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META)) ? RGX_GET_FEATURE_VALUE(psDevInfo, META) : 0; |
| IMG_UINT32 ui32TACycles, ui323DCycles, ui32TAOr3DCycles, ui32TAAnd3DCycles; |
| IMG_UINT32 ui32RegVal; |
| IMG_BOOL bFirmwarePerf; |
| IMG_BOOL bS7Infra = RGX_IS_FEATURE_SUPPORTED(psDevInfo, S7_TOP_INFRASTRUCTURE); |
| void __iomem *pvRegsBaseKM = psDevInfo->pvRegsBaseKM; |
| PVRSRV_ERROR eError; |
| RGXFWIF_INIT *psRGXFWInit = NULL; |
| |
| PVR_DUMPDEBUG_LOG("------[ RGX registers ]------"); |
| PVR_DUMPDEBUG_LOG("RGX Register Base Address (Linear): 0x%p", psDevInfo->pvRegsBaseKM); |
| PVR_DUMPDEBUG_LOG("RGX Register Base Address (Physical): 0x%08lX", (unsigned long)psDevInfo->sRegsPhysBase.uiAddr); |
| |
| /* Check if firmware perf was set at Init time */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc, (void**)&psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "Failed to acquire kernel FW IF Init struct")); |
| return eError; |
| } |
| bFirmwarePerf = (psRGXFWInit->eFirmwarePerf != FW_PERF_CONF_NONE); |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc); |
| |
| /* Helper macros to emit data */ |
| #define REG32_FMTSPEC "%-30s: 0x%08X" |
| #define REG64_FMTSPEC "%-30s: 0x%016" IMG_UINT64_FMTSPECx |
| #define DDLOG32(R) PVR_DUMPDEBUG_LOG(REG32_FMTSPEC, #R, OSReadHWReg32(pvRegsBaseKM, RGX_CR_##R)); |
| #define DDLOG64(R) PVR_DUMPDEBUG_LOG(REG64_FMTSPEC, #R, OSReadHWReg64(pvRegsBaseKM, RGX_CR_##R)); |
| #define DDLOG32_DPX(R) PVR_DUMPDEBUG_LOG(REG32_FMTSPEC, #R, OSReadHWReg32(pvRegsBaseKM, DPX_CR_##R)); |
| #define DDLOG64_DPX(R) PVR_DUMPDEBUG_LOG(REG64_FMTSPEC, #R, OSReadHWReg64(pvRegsBaseKM, DPX_CR_##R)); |
| #define DDLOGVAL32(S,V) PVR_DUMPDEBUG_LOG(REG32_FMTSPEC, S, V); |
| |
| #if defined(NO_HARDWARE) |
| /* OSReadHWReg variants don't use params passed in NoHW builds */ |
| PVR_UNREFERENCED_PARAMETER(pvRegsBaseKM); |
| #endif |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, PBVNC_COREID_REG)) |
| { |
| DDLOG64(CORE_ID); |
| } |
| else |
| { |
| DDLOG32(CORE_ID); |
| } |
| DDLOG32(CORE_REVISION); |
| DDLOG32(DESIGNER_REV_FIELD1); |
| DDLOG32(DESIGNER_REV_FIELD2); |
| DDLOG64(CHANGESET_NUMBER); |
| if (ui32Meta) |
| { |
| DDLOG32(META_SP_MSLVIRQSTATUS); |
| } |
| |
| DDLOG64(CLK_CTRL); |
| DDLOG64(CLK_STATUS); |
| DDLOG64(CLK_CTRL2); |
| DDLOG64(CLK_STATUS2); |
| |
| if (bS7Infra) |
| { |
| DDLOG64(CLK_XTPLUS_CTRL); |
| DDLOG64(CLK_XTPLUS_STATUS); |
| } |
| DDLOG32(EVENT_STATUS); |
| DDLOG64(TIMER); |
| if (bS7Infra) |
| { |
| DDLOG64(MMU_FAULT_STATUS); |
| DDLOG64(MMU_FAULT_STATUS_META); |
| } |
| else |
| { |
| DDLOG32(BIF_FAULT_BANK0_MMU_STATUS); |
| DDLOG64(BIF_FAULT_BANK0_REQ_STATUS); |
| DDLOG32(BIF_FAULT_BANK1_MMU_STATUS); |
| DDLOG64(BIF_FAULT_BANK1_REQ_STATUS); |
| } |
| DDLOG32(BIF_MMU_STATUS); |
| DDLOG32(BIF_MMU_ENTRY); |
| DDLOG64(BIF_MMU_ENTRY_STATUS); |
| |
| if (bS7Infra) |
| { |
| DDLOG32(BIF_JONES_OUTSTANDING_READ); |
| DDLOG32(BIF_BLACKPEARL_OUTSTANDING_READ); |
| DDLOG32(BIF_DUST_OUTSTANDING_READ); |
| } |
| else |
| { |
| if (!(RGX_IS_FEATURE_SUPPORTED(psDevInfo, XT_TOP_INFRASTRUCTURE))) |
| { |
| DDLOG32(BIF_STATUS_MMU); |
| DDLOG32(BIF_READS_EXT_STATUS); |
| DDLOG32(BIF_READS_INT_STATUS); |
| } |
| DDLOG32(BIFPM_STATUS_MMU); |
| DDLOG32(BIFPM_READS_EXT_STATUS); |
| DDLOG32(BIFPM_READS_INT_STATUS); |
| } |
| |
| if (RGX_IS_BRN_SUPPORTED(psDevInfo, 44871)) |
| { |
| PVR_DUMPDEBUG_LOG("Warning: BRN44871 is present"); |
| } |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, SLC_VIVT)) |
| { |
| DDLOG64(CONTEXT_MAPPING0); |
| DDLOG64(CONTEXT_MAPPING1); |
| DDLOG64(CONTEXT_MAPPING2); |
| DDLOG64(CONTEXT_MAPPING3); |
| DDLOG64(CONTEXT_MAPPING4); |
| } |
| else |
| { |
| DDLOG64(BIF_CAT_BASE_INDEX); |
| DDLOG64(BIF_CAT_BASE0); |
| DDLOG64(BIF_CAT_BASE1); |
| DDLOG64(BIF_CAT_BASE2); |
| DDLOG64(BIF_CAT_BASE3); |
| DDLOG64(BIF_CAT_BASE4); |
| DDLOG64(BIF_CAT_BASE5); |
| DDLOG64(BIF_CAT_BASE6); |
| DDLOG64(BIF_CAT_BASE7); |
| } |
| |
| DDLOG32(BIF_CTRL_INVAL); |
| DDLOG32(BIF_CTRL); |
| |
| DDLOG64(BIF_PM_CAT_BASE_VCE0); |
| DDLOG64(BIF_PM_CAT_BASE_TE0); |
| DDLOG64(BIF_PM_CAT_BASE_ALIST0); |
| DDLOG64(BIF_PM_CAT_BASE_VCE1); |
| DDLOG64(BIF_PM_CAT_BASE_TE1); |
| DDLOG64(BIF_PM_CAT_BASE_ALIST1); |
| |
| DDLOG32(PERF_TA_PHASE); |
| DDLOG32(PERF_TA_CYCLE); |
| DDLOG32(PERF_3D_PHASE); |
| DDLOG32(PERF_3D_CYCLE); |
| |
| ui32TACycles = OSReadHWReg32(pvRegsBaseKM, RGX_CR_PERF_TA_CYCLE); |
| ui323DCycles = OSReadHWReg32(pvRegsBaseKM, RGX_CR_PERF_3D_CYCLE); |
| ui32TAOr3DCycles = OSReadHWReg32(pvRegsBaseKM, RGX_CR_PERF_TA_OR_3D_CYCLE); |
| ui32TAAnd3DCycles = ((ui32TACycles + ui323DCycles) > ui32TAOr3DCycles) ? (ui32TACycles + ui323DCycles - ui32TAOr3DCycles) : 0; |
| DDLOGVAL32("PERF_TA_OR_3D_CYCLE", ui32TAOr3DCycles); |
| DDLOGVAL32("PERF_TA_AND_3D_CYCLE", ui32TAAnd3DCycles); |
| |
| DDLOG32(PERF_COMPUTE_PHASE); |
| DDLOG32(PERF_COMPUTE_CYCLE); |
| |
| DDLOG32(PM_PARTIAL_RENDER_ENABLE); |
| |
| DDLOG32(ISP_RENDER); |
| DDLOG64(TLA_STATUS); |
| DDLOG64(MCU_FENCE); |
| |
| DDLOG32(VDM_CONTEXT_STORE_STATUS); |
| DDLOG64(VDM_CONTEXT_STORE_TASK0); |
| DDLOG64(VDM_CONTEXT_STORE_TASK1); |
| DDLOG64(VDM_CONTEXT_STORE_TASK2); |
| DDLOG64(VDM_CONTEXT_RESUME_TASK0); |
| DDLOG64(VDM_CONTEXT_RESUME_TASK1); |
| DDLOG64(VDM_CONTEXT_RESUME_TASK2); |
| |
| DDLOG32(ISP_CTL); |
| DDLOG32(ISP_STATUS); |
| DDLOG32(MTS_INTCTX); |
| DDLOG32(MTS_BGCTX); |
| DDLOG32(MTS_BGCTX_COUNTED_SCHEDULE); |
| DDLOG32(MTS_SCHEDULE); |
| DDLOG32(MTS_GPU_INT_STATUS); |
| |
| DDLOG32(CDM_CONTEXT_STORE_STATUS); |
| DDLOG64(CDM_CONTEXT_PDS0); |
| DDLOG64(CDM_CONTEXT_PDS1); |
| DDLOG64(CDM_TERMINATE_PDS); |
| DDLOG64(CDM_TERMINATE_PDS1); |
| |
| if (RGX_IS_ERN_SUPPORTED(psDevInfo, 47025)) |
| { |
| DDLOG64(CDM_CONTEXT_LOAD_PDS0); |
| DDLOG64(CDM_CONTEXT_LOAD_PDS1); |
| } |
| |
| if (bS7Infra) |
| { |
| DDLOG32(JONES_IDLE); |
| } |
| |
| DDLOG32(SIDEKICK_IDLE); |
| |
| if (!bS7Infra) |
| { |
| DDLOG32(SLC_IDLE); |
| DDLOG32(SLC_STATUS0); |
| DDLOG64(SLC_STATUS1); |
| |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, SLC_BANKS) && RGX_GET_FEATURE_VALUE(psDevInfo, SLC_BANKS)) |
| { |
| DDLOG64(SLC_STATUS2); |
| } |
| |
| DDLOG32(SLC_CTRL_BYPASS); |
| DDLOG64(SLC_CTRL_MISC); |
| } |
| else |
| { |
| DDLOG32(SLC3_IDLE); |
| DDLOG64(SLC3_STATUS); |
| DDLOG32(SLC3_FAULT_STOP_STATUS); |
| } |
| |
| if (ui32Meta) |
| { |
| IMG_BOOL bIsT0Enabled = IMG_FALSE, bIsFWFaulted = IMG_FALSE; |
| |
| /* Forcing bit 6 of MslvCtrl1 to 0 to avoid internal reg read going through the core */ |
| OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVCTRL1, 0x0); |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_T0ENABLE_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T0 TXENABLE", ui32RegVal); |
| if (ui32RegVal & META_CR_TXENABLE_ENABLE_BIT) |
| { |
| bIsT0Enabled = IMG_TRUE; |
| } |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_T0STATUS_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T0 TXSTATUS", ui32RegVal); |
| |
| /* check for FW fault */ |
| if (((ui32RegVal >> 20) & 0x3) == 0x2) |
| { |
| bIsFWFaulted = IMG_TRUE; |
| } |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_T0DEFR_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T0 TXDEFR", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR0_PC, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T0 PC", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR0_PCX, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T0 PCX", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR0_SP, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T0 SP", ui32RegVal); |
| |
| |
| if ((ui32Meta == MTP218) || (ui32Meta == MTP219)) |
| { |
| eError = RGXReadWithSP(psDevInfo, META_CR_T1ENABLE_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T1 TXENABLE", ui32RegVal); |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_T1STATUS_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T1 TXSTATUS", ui32RegVal); |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_T1DEFR_OFFSET, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("T1 TXDEFR", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR1_PC, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T1 PC", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR1_PCX, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T1 PCX", ui32RegVal); |
| |
| eError = RGXReadMetaCoreReg(psDevInfo, META_CR_THR1_SP, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadMetaCoreReg", _METASPError); |
| DDLOGVAL32("T1 SP", ui32RegVal); |
| } |
| |
| if (bFirmwarePerf) |
| { |
| eError = RGXReadWithSP(psDevInfo, META_CR_PERF_COUNT0, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("PERF_COUNT0", ui32RegVal); |
| |
| eError = RGXReadWithSP(psDevInfo, META_CR_PERF_COUNT1, &ui32RegVal); |
| PVR_LOGG_IF_ERROR(eError, "RGXReadWithSP", _METASPError); |
| DDLOGVAL32("PERF_COUNT1", ui32RegVal); |
| } |
| |
| if (bIsT0Enabled & bIsFWFaulted) |
| { |
| PVRSRV_ERROR eError; |
| eError = _ValidateFWImageForMETA(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DUMPDEBUG_LOG("Failed to validate any FW code corruption"); |
| } |
| } |
| else if (bIsFWFaulted) |
| { |
| PVR_DUMPDEBUG_LOG("Skipping FW code memory corruption checking as META is disabled"); |
| } |
| } |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, MIPS)) |
| { |
| DDLOG32(MIPS_ADDR_REMAP1_CONFIG1); |
| DDLOG64(MIPS_ADDR_REMAP1_CONFIG2); |
| DDLOG32(MIPS_ADDR_REMAP2_CONFIG1); |
| DDLOG64(MIPS_ADDR_REMAP2_CONFIG2); |
| DDLOG32(MIPS_ADDR_REMAP3_CONFIG1); |
| DDLOG64(MIPS_ADDR_REMAP3_CONFIG2); |
| DDLOG32(MIPS_ADDR_REMAP4_CONFIG1); |
| DDLOG64(MIPS_ADDR_REMAP4_CONFIG2); |
| DDLOG32(MIPS_ADDR_REMAP5_CONFIG1); |
| DDLOG64(MIPS_ADDR_REMAP5_CONFIG2); |
| DDLOG64(MIPS_WRAPPER_CONFIG); |
| DDLOG32(MIPS_EXCEPTION_STATUS); |
| |
| #if !defined(NO_HARDWARE) |
| { |
| RGX_MIPS_STATE sMIPSState = {0}; |
| |
| eError = _RGXMipsExtraDebug(psDevInfo, &sMIPSState); |
| PVR_DUMPDEBUG_LOG("---- [ MIPS internal state ] ----"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DUMPDEBUG_LOG("MIPS extra debug not available"); |
| } |
| else |
| { |
| DDLOGVAL32("PC", sMIPSState.ui32ErrorEPC); |
| DDLOGVAL32("STATUS_REGISTER", sMIPSState.ui32StatusRegister); |
| DDLOGVAL32("CAUSE_REGISTER", sMIPSState.ui32CauseRegister); |
| _RGXMipsDumpCauseDecode(pfnDumpDebugPrintf, pvDumpDebugFile, |
| sMIPSState.ui32CauseRegister, sMIPSState.ui32ErrorState); |
| DDLOGVAL32("BAD_REGISTER", sMIPSState.ui32BadRegister); |
| DDLOGVAL32("EPC", sMIPSState.ui32EPC); |
| DDLOGVAL32("SP", sMIPSState.ui32SP); |
| DDLOGVAL32("BAD_INSTRUCTION", sMIPSState.ui32BadInstr); |
| _RGXMipsDumpDebugDecode(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, |
| sMIPSState.ui32Debug, sMIPSState.ui32DEPC); |
| |
| { |
| IMG_UINT32 ui32Idx; |
| |
| IMG_BOOL bCheckBRN63553WA = |
| RGX_IS_BRN_SUPPORTED(psDevInfo, 63553) && |
| (OSReadHWReg32(pvRegsBaseKM, RGX_CR_MIPS_ADDR_REMAP5_CONFIG1) == (0x0 | RGX_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_EN)); |
| |
| IMG_BOOL bUseRemapRanges = RGX_GET_FEATURE_VALUE(psDevInfo, PHYS_BUS_WIDTH) > 32; |
| |
| PVR_DUMPDEBUG_LOG("TLB :"); |
| |
| for (ui32Idx = 0; ui32Idx < ARRAY_SIZE(sMIPSState.asTLB); ui32Idx++) |
| { |
| RGX_MIPS_REMAP_ENTRY *psRemapEntry0 = NULL; |
| RGX_MIPS_REMAP_ENTRY *psRemapEntry1 = NULL; |
| |
| if (bUseRemapRanges) |
| { |
| psRemapEntry0 = &sMIPSState.asRemap[ui32Idx]; |
| psRemapEntry1 = &sMIPSState.asRemap[ui32Idx+16]; |
| } |
| |
| |
| _RGXMipsDumpTLBEntry(pfnDumpDebugPrintf, |
| pvDumpDebugFile, |
| &sMIPSState.asTLB[ui32Idx], |
| psRemapEntry0, |
| psRemapEntry1, |
| ui32Idx); |
| |
| if (bCheckBRN63553WA) |
| { |
| const RGX_MIPS_TLB_ENTRY *psTLBEntry = &sMIPSState.asTLB[ui32Idx]; |
| |
| #define BRN63553_TLB_IS_NUL(X) (((X) & RGXMIPSFW_TLB_VALID) && (RGXMIPSFW_TLB_GET_PA(X) == 0x0)) |
| |
| if (BRN63553_TLB_IS_NUL(psTLBEntry->ui32TLBLo0) || BRN63553_TLB_IS_NUL(psTLBEntry->ui32TLBLo1)) |
| { |
| PVR_DUMPDEBUG_LOG("BRN63553 WA present with a valid TLB entry mapping address 0x0."); |
| } |
| } |
| } |
| |
| /* This implicitly also checks for overlaps between memory and regbank addresses */ |
| _CheckMipsTLBDuplicatePAs(pfnDumpDebugPrintf, |
| pvDumpDebugFile, |
| sMIPSState.asTLB, |
| bUseRemapRanges ? sMIPSState.asRemap : NULL); |
| |
| if (bUseRemapRanges) |
| { |
| /* Dump unmapped address if it was dumped in FW, otherwise it will be 0 */ |
| if (sMIPSState.ui32UnmappedAddress) |
| { |
| PVR_DUMPDEBUG_LOG("Remap unmapped address => 0x%08X", |
| sMIPSState.ui32UnmappedAddress); |
| } |
| } |
| } |
| } |
| PVR_DUMPDEBUG_LOG("--------------------------------"); |
| } |
| #endif |
| } |
| |
| return PVRSRV_OK; |
| |
| _METASPError: |
| PVR_DPF((PVR_DBG_ERROR, "Dump Slave Port debug information")); |
| _RGXDumpMetaSPExtraDebugInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo); |
| |
| return eError; |
| } |
| |
| void RGXDebugRequestProcess(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32VerbLevel) |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode; |
| RGXFWIF_INIT *psRGXFWInit = NULL; |
| PVRSRV_DEV_POWER_STATE ePowerState; |
| IMG_BOOL bRGXPoweredON; |
| const IMG_CHAR *Bit32 = "32 Bit", *Bit64 = "64 Bit"; |
| IMG_UINT8 ui8FwOsCount; |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| |
| eError = PVRSRVPowerLock(psDeviceNode); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: failed to acquire lock (%s)", |
| __func__, |
| PVRSRVGetErrorString(eError))); |
| return; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc, (void**)&psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "Failed to acquire kernel FW IF Init struct")); |
| goto ExitUnlock; |
| } |
| |
| ui8FwOsCount = psRGXFWInit->sRGXCompChecks.sInitOptions.ui8OsCountSupport; |
| |
| eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Error retrieving RGX power state. No debug info dumped.", |
| __func__)); |
| goto Exit; |
| } |
| |
| bRGXPoweredON = (ePowerState == PVRSRV_DEV_POWER_STATE_ON); |
| PVR_DUMPDEBUG_LOG("------[ Driver Info ]------"); |
| PVR_DUMP_DRIVER_INFO("UM", psPVRSRVData->sDriverInfo.sUMBuildInfo); |
| PVR_DUMP_DRIVER_INFO("KM", psPVRSRVData->sDriverInfo.sKMBuildInfo); |
| if (psRGXFWInit->sRGXCompChecks.bUpdated) |
| { |
| PVR_DUMP_FIRMWARE_INFO(psRGXFWInit->sRGXCompChecks); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("FW info: UNINITIALIZED"); |
| } |
| PVR_DUMPDEBUG_LOG("Comparison of UM/KM components: %s", (psPVRSRVData->sDriverInfo.bIsNoMatch) ? ("MISMATCH") : ("MATCHING")); |
| |
| PVR_DUMPDEBUG_LOG("KM Arch: %s", (psPVRSRVData->sDriverInfo.ui8KMBitArch & BUILD_ARCH_64BIT)? |
| Bit64 : Bit32); |
| |
| if (!PVRSRV_VZ_MODE_IS(DRIVER_MODE_NATIVE)) |
| { |
| PVR_DUMPDEBUG_LOG("Driver Mode: %s", (PVRSRV_VZ_MODE_IS(DRIVER_MODE_HOST))?"Host":"Guest"); |
| } |
| |
| if ((PVRSRV_VZ_MODE_IS(DRIVER_MODE_NATIVE) && (ui8FwOsCount > 1)) || |
| (PVRSRV_VZ_MODE_IS(DRIVER_MODE_HOST) && (ui8FwOsCount != RGXFW_NUM_OS))) |
| { |
| PVR_DUMPDEBUG_LOG("Mismatch between the number of Operating Systems supported by KM driver (%d) and FW (%d)", |
| (PVRSRV_VZ_MODE_IS(DRIVER_MODE_NATIVE)) ? (1) : (RGXFW_NUM_OS), ui8FwOsCount); |
| } |
| |
| if (psPVRSRVData->sDriverInfo.ui8UMSupportedArch) |
| { |
| if ((psPVRSRVData->sDriverInfo.ui8UMSupportedArch & BUILD_ARCH_BOTH) == |
| BUILD_ARCH_BOTH) |
| { |
| PVR_DUMPDEBUG_LOG("UM Connected Clients Arch: %s and %s", Bit64, Bit32); |
| |
| }else |
| { |
| PVR_DUMPDEBUG_LOG("UM Connected Clients: %s",(psPVRSRVData->sDriverInfo.ui8UMSupportedArch & |
| BUILD_ARCH_64BIT)? Bit64 : Bit32); |
| } |
| } |
| |
| PVR_DUMPDEBUG_LOG("------[ RGX Summary ]------"); |
| PVR_DUMPDEBUG_LOG("RGX BVNC: %d.%d.%d.%d", psDevInfo->sDevFeatureCfg.ui32B, \ |
| psDevInfo->sDevFeatureCfg.ui32V, \ |
| psDevInfo->sDevFeatureCfg.ui32N, \ |
| psDevInfo->sDevFeatureCfg.ui32C); |
| PVR_DUMPDEBUG_LOG("RGX Device State: %s", _RGXGetDebugDevStateString(psDeviceNode->eDevState)); |
| PVR_DUMPDEBUG_LOG("RGX Power State: %s", _RGXGetDebugDevPowerStateString(ePowerState)); |
| |
| RGXDumpRGXDebugSummary(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, bRGXPoweredON); |
| |
| if ((bRGXPoweredON) && !PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| |
| eError = RGXDumpRGXRegisters(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: RGXDumpRGXRegisters failed (%s)", |
| __func__, |
| PVRSRVGetErrorString(eError))); |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" (!) %s. No registers dumped", PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST) ? "Guest Mode of operation" : "RGX power is down"); |
| } |
| |
| /* Dump out the kernel CCB. */ |
| { |
| RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| |
| if (psKCCBCtl != NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX Kernel CCB WO:0x%X RO:0x%X", |
| psKCCBCtl->ui32WriteOffset, |
| psKCCBCtl->ui32ReadOffset); |
| } |
| } |
| |
| /* Dump out the firmware CCB. */ |
| { |
| RGXFWIF_CCB_CTL *psFCCBCtl = psDevInfo->psFirmwareCCBCtl; |
| |
| if (psFCCBCtl != NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX Firmware CCB WO:0x%X RO:0x%X", |
| psFCCBCtl->ui32WriteOffset, |
| psFCCBCtl->ui32ReadOffset); |
| } |
| } |
| |
| #if defined(SUPPORT_WORKLOAD_ESTIMATION) |
| /* Dump out the Workload estimation CCB. */ |
| { |
| RGXFWIF_CCB_CTL *psWorkEstCCBCtl = psDevInfo->psWorkEstFirmwareCCBCtl; |
| |
| if (psWorkEstCCBCtl != NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX WorkEst CCB WO:0x%X RO:0x%X", |
| psWorkEstCCBCtl->ui32WriteOffset, |
| psWorkEstCCBCtl->ui32ReadOffset); |
| } |
| } |
| #endif |
| |
| |
| if (psRGXFWIfTraceBufCtl != NULL) |
| { |
| #if defined(PVRSRV_SYNC_CHECKPOINT_CCB) |
| /* Dump out the checkpoint CCB offsets. */ |
| { |
| RGXFWIF_CCB_CTL *psCheckpointCCBCtl = psDevInfo->psCheckpointCCBCtl; |
| |
| if (psCheckpointCCBCtl != NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX Checkpoint CCB WO:0x%X RO:0x%X (Check State: FW=%#X, HOST=%#X)", |
| psCheckpointCCBCtl->ui32WriteOffset, |
| psCheckpointCCBCtl->ui32ReadOffset, |
| psRGXFWIfTraceBufCtl->ui32FWSyncCheckMark, |
| psRGXFWIfTraceBufCtl->ui32HostSyncCheckMark); |
| } |
| } |
| #endif /* defined(PVRSRV_SYNC_CHECKPOINT_CCB) */ |
| |
| /* Dump the KCCB commands executed */ |
| PVR_DUMPDEBUG_LOG("RGX Kernel CCB commands executed = %d", |
| psRGXFWIfTraceBufCtl->ui32KCCBCmdsExecuted); |
| |
| #if defined(PVRSRV_STALLED_CCB_ACTION) |
| /* Check flag indicates support for SLR Log (for compatibility) */ |
| if (psRGXFWIfTraceBufCtl->ui32TracebufFlags & RGXFWIF_TRACEBUFCFG_SLR_LOG) |
| { |
| /* Dump the number of times we have performed a forced UFO update, |
| * and (if non-zero) the timestamp of the most recent occurrence/ |
| */ |
| PVR_DUMPDEBUG_LOG("RGX SLR: Forced UFO updates requested = %d", |
| psRGXFWIfTraceBufCtl->ui32ForcedUpdatesRequested); |
| if (psRGXFWIfTraceBufCtl->ui32ForcedUpdatesRequested > 0) |
| { |
| IMG_UINT8 ui8Idx; |
| IMG_UINT64 ui64Seconds, ui64Nanoseconds; |
| |
| if (psRGXFWIfTraceBufCtl->ui64LastForcedUpdateTime > 0ULL) |
| { |
| ConvertOSTimestampToSAndNS(psRGXFWIfTraceBufCtl->ui64LastForcedUpdateTime, &ui64Seconds, &ui64Nanoseconds); |
| PVR_DUMPDEBUG_LOG("RGX SLR: (most recent forced update was around %" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC ")", |
| ui64Seconds, ui64Nanoseconds); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("RGX SLR: (unable to force update as fence contained no sync checkpoints)"); |
| } |
| /* Dump SLR log */ |
| if (psRGXFWIfTraceBufCtl->sSLRLogFirst.aszCCBName[0]) |
| { |
| ConvertOSTimestampToSAndNS(psRGXFWIfTraceBufCtl->sSLRLogFirst.ui64Timestamp, &ui64Seconds, &ui64Nanoseconds); |
| PVR_DUMPDEBUG_LOG("RGX SLR:{%" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC |
| "} Fence found on context 0x%x '%s' has %d UFOs", |
| ui64Seconds, ui64Nanoseconds, |
| psRGXFWIfTraceBufCtl->sSLRLogFirst.ui32FWCtxAddr, |
| psRGXFWIfTraceBufCtl->sSLRLogFirst.aszCCBName, |
| psRGXFWIfTraceBufCtl->sSLRLogFirst.ui32NumUFOs); |
| } |
| for (ui8Idx=0; ui8Idx<PVR_SLR_LOG_ENTRIES;ui8Idx++) |
| { |
| if (psRGXFWIfTraceBufCtl->sSLRLog[ui8Idx].aszCCBName[0]) |
| { |
| ConvertOSTimestampToSAndNS(psRGXFWIfTraceBufCtl->sSLRLog[ui8Idx].ui64Timestamp, &ui64Seconds, &ui64Nanoseconds); |
| PVR_DUMPDEBUG_LOG("RGX SLR:[%" IMG_UINT64_FMTSPEC ".%09" IMG_UINT64_FMTSPEC |
| "] Fence found on context 0x%x '%s' has %d UFOs", |
| ui64Seconds, ui64Nanoseconds, |
| psRGXFWIfTraceBufCtl->sSLRLog[ui8Idx].ui32FWCtxAddr, |
| psRGXFWIfTraceBufCtl->sSLRLog[ui8Idx].aszCCBName, |
| psRGXFWIfTraceBufCtl->sSLRLog[ui8Idx].ui32NumUFOs); |
| } |
| } |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("RGX SLR: Unsupported"); |
| } |
| #else |
| PVR_DUMPDEBUG_LOG("RGX SLR: Disabled"); |
| #endif |
| |
| /* Dump the IRQ info for threads or OS IDs */ |
| if (!PVRSRV_VZ_MODE_IS(DRIVER_MODE_GUEST)) |
| { |
| IMG_UINT32 ui32idx; |
| |
| for_each_irq_cnt(ui32idx) |
| { |
| IMG_UINT32 ui32IrqCnt; |
| |
| get_irq_cnt_val(ui32IrqCnt, ui32idx, psDevInfo); |
| if (ui32IrqCnt) |
| if (ui32IrqCnt) |
| { |
| PVR_DUMPDEBUG_LOG(MSG_IRQ_CNT_TYPE "%u: FW IRQ count = %u", ui32idx, ui32IrqCnt); |
| #if defined(RGX_FW_IRQ_OS_COUNTERS) |
| if (ui32idx == RGXFW_HYPERVISOR_OS) |
| #endif |
| { |
| PVR_DUMPDEBUG_LOG("Last sampled IRQ count in LISR = %u", psDevInfo->aui32SampleIRQCount[ui32idx]); |
| } |
| } |
| } |
| } |
| } |
| |
| /* Dump the FW config flags */ |
| { |
| RGXFWIF_OS_CONFIG *psOSConfig = psDevInfo->psFWIfOSConfig; |
| IMG_CHAR sFwFlagsDescription[MAX_FW_DESCRIPTION_LENGTH]; |
| |
| if (!psOSConfig) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: OS Config is not mapped into CPU space", |
| __func__)); |
| goto Exit; |
| } |
| |
| _GetFwFlagsDescription(sFwFlagsDescription, psOSConfig->ui32ConfigFlags); |
| PVR_DUMPDEBUG_LOG("FW OS config flags = 0x%X (%s)", psOSConfig->ui32ConfigFlags, sFwFlagsDescription); |
| } |
| |
| if (DD_VERB_LVL_ENABLED(ui32VerbLevel, DEBUG_REQUEST_VERBOSITY_MEDIUM)) |
| { |
| IMG_INT tid; |
| /* Dump FW trace information */ |
| if (psRGXFWIfTraceBufCtl != NULL) |
| { |
| for (tid = 0 ; tid < RGXFW_THREAD_NUM ; tid++) |
| { |
| IMG_UINT32 i; |
| IMG_BOOL bPrevLineWasZero = IMG_FALSE; |
| IMG_BOOL bLineIsAllZeros = IMG_FALSE; |
| IMG_UINT32 ui32CountLines = 0; |
| IMG_UINT32 *pui32TraceBuffer; |
| IMG_CHAR *pszLine; |
| |
| if (psRGXFWIfTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_GROUP_MASK) |
| { |
| PVR_DUMPDEBUG_LOG("Debug log type: %s ( " RGXFWIF_LOG_ENABLED_GROUPS_LIST_PFSPEC ")", |
| ((psRGXFWIfTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_TRACE)?("trace"):("tbi")), |
| RGXFWIF_LOG_ENABLED_GROUPS_LIST(psRGXFWIfTraceBufCtl->ui32LogType) |
| ); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("Debug log type: none"); |
| } |
| |
| pui32TraceBuffer = psRGXFWIfTraceBufCtl->sTraceBuf[tid].pui32TraceBuffer; |
| |
| /* Skip if trace buffer is not allocated */ |
| if (pui32TraceBuffer == NULL) |
| { |
| PVR_DUMPDEBUG_LOG("RGX FW thread %d: Trace buffer not yet allocated",tid); |
| continue; |
| } |
| |
| /* Max number of DWords to be printed per line, in debug dump output */ |
| #define PVR_DD_FW_TRACEBUF_LINESIZE 30U |
| /* each element in the line is 8 characters plus a space. The '+ 1' is because of the final trailing '\0'. */ |
| pszLine = OSAllocMem(9 * PVR_DD_FW_TRACEBUF_LINESIZE + 1); |
| if (pszLine == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Out of mem allocating line string (size: %d)", |
| __func__, |
| 9 * PVR_DD_FW_TRACEBUF_LINESIZE + 1)); |
| goto Exit; |
| } |
| |
| PVR_DUMPDEBUG_LOG("------[ RGX FW thread %d trace START ]------", tid); |
| PVR_DUMPDEBUG_LOG("FWT[traceptr]: %X", psRGXFWIfTraceBufCtl->sTraceBuf[tid].ui32TracePointer); |
| PVR_DUMPDEBUG_LOG("FWT[tracebufsize]: %X", psRGXFWIfTraceBufCtl->ui32TraceBufSizeInDWords); |
| |
| for (i = 0; i < psRGXFWIfTraceBufCtl->ui32TraceBufSizeInDWords; i += PVR_DD_FW_TRACEBUF_LINESIZE) |
| { |
| IMG_UINT32 k = 0; |
| IMG_UINT32 ui32Line = 0x0; |
| IMG_UINT32 ui32LineOffset = i*sizeof(IMG_UINT32); |
| IMG_CHAR *pszBuf = pszLine; |
| |
| for (k = 0; k < PVR_DD_FW_TRACEBUF_LINESIZE; k++) |
| { |
| if ((i + k) >= psRGXFWIfTraceBufCtl->ui32TraceBufSizeInDWords) |
| { |
| /* Stop reading when the index goes beyond trace buffer size. This condition is |
| * hit during printing the last line in DD when ui32TraceBufSizeInDWords is not |
| * a multiple of PVR_DD_FW_TRACEBUF_LINESIZE */ |
| break; |
| } |
| |
| ui32Line |= pui32TraceBuffer[i + k]; |
| |
| /* prepare the line to print it. The '+1' is because of the trailing '\0' added */ |
| OSSNPrintf(pszBuf, 9 + 1, " %08x", pui32TraceBuffer[i + k]); |
| pszBuf += 9; /* write over the '\0' */ |
| } |
| |
| bLineIsAllZeros = (ui32Line == 0x0); |
| |
| if (bLineIsAllZeros) |
| { |
| if (bPrevLineWasZero) |
| { |
| ui32CountLines++; |
| } |
| else |
| { |
| bPrevLineWasZero = IMG_TRUE; |
| ui32CountLines = 1; |
| PVR_DUMPDEBUG_LOG("FWT[%08x]: 00000000 ... 00000000", ui32LineOffset); |
| } |
| } |
| else |
| { |
| if (bPrevLineWasZero && ui32CountLines > 1) |
| { |
| PVR_DUMPDEBUG_LOG("FWT[...]: %d lines were all zero", ui32CountLines); |
| } |
| bPrevLineWasZero = IMG_FALSE; |
| |
| PVR_DUMPDEBUG_LOG("FWT[%08x]:%s", ui32LineOffset, pszLine); |
| } |
| |
| } |
| if (bPrevLineWasZero) |
| { |
| PVR_DUMPDEBUG_LOG("FWT[END]: %d lines were all zero", ui32CountLines); |
| } |
| |
| PVR_DUMPDEBUG_LOG("------[ RGX FW thread %d trace END ]------", tid); |
| |
| OSFreeMem(pszLine); |
| } |
| |
| if (RGX_IS_FEATURE_VALUE_SUPPORTED(psDevInfo, META)) |
| { |
| RGXFWIF_OS_CONFIG *psOSConfig = psDevInfo->psFWIfOSConfig; |
| |
| if (!psOSConfig) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: OS Config is not mapped into CPU space", |
| __func__)); |
| goto Exit; |
| } |
| |
| if ((psOSConfig->ui32ConfigFlags & RGXFWIF_INICFG_METAT1_DUMMY) != 0) |
| { |
| IMG_UINT32 *pui32T1PCX = &psRGXFWIfTraceBufCtl->ui32T1PCX[0]; |
| IMG_UINT32 ui32T1PCXWOff = psRGXFWIfTraceBufCtl->ui32T1PCXWOff; |
| IMG_UINT32 i = ui32T1PCXWOff; |
| |
| PVR_DUMPDEBUG_LOG("------[ FW Thread 1 PCX list (most recent first) ]------"); |
| do |
| { |
| PVR_DUMPDEBUG_LOG(" 0x%08x", pui32T1PCX[i]); |
| i = (i == 0) ? (RGXFWIF_MAX_PCX - 1) : (i - 1); |
| |
| } while (i != ui32T1PCXWOff); |
| |
| PVR_DUMPDEBUG_LOG("------[ FW Thread 1 PCX list [END] ]------"); |
| } |
| |
| } |
| } |
| |
| { |
| if (DD_VERB_LVL_ENABLED(ui32VerbLevel, DEBUG_REQUEST_VERBOSITY_HIGH)) |
| { |
| PVR_DUMPDEBUG_LOG("------[ Full CCB Status ]------"); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("------[ Stalled FWCtxs ]------"); |
| } |
| |
| DumpTransferCtxtsInfo(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, ui32VerbLevel); |
| |
| DumpRenderCtxtsInfo(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, ui32VerbLevel); |
| |
| DumpKickSyncCtxtsInfo(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, ui32VerbLevel); |
| |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, COMPUTE)) |
| { |
| DumpComputeCtxtsInfo(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, ui32VerbLevel); |
| } |
| if (RGX_IS_FEATURE_SUPPORTED(psDevInfo, FASTRENDER_DM)) |
| { |
| DumpTDMTransferCtxtsInfo(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile, ui32VerbLevel); |
| } |
| } |
| } |
| |
| Exit: |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc); |
| ExitUnlock: |
| PVRSRVPowerUnlock(psDeviceNode); |
| } |
| |
| /****************************************************************************** |
| End of file (rgxdebug.c) |
| ******************************************************************************/ |