| /*************************************************************************/ /*! |
| @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 "rgxdefs_km.h" |
| #include "rgxdevice.h" |
| #include "rgxmem.h" |
| #include "allocmem.h" |
| #include "cache_km.h" |
| #include "osfunc.h" |
| |
| #include "lists.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 "devicemem.h" |
| #include "devicemem_pdump.h" |
| #include "devicemem_utils.h" |
| #include "rgx_fwif.h" |
| #include "rgx_fwif_sf.h" |
| #include "rgxfw_log_helper.h" |
| |
| #include "rgxta3d.h" |
| #include "rgxcompute.h" |
| #include "rgxtransfer.h" |
| #include "rgxtdmtransfer.h" |
| #include "rgxray.h" |
| #include "rgxtimecorr.h" |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| #include "devicemem_history_server.h" |
| #endif |
| #include "rgx_bvnc_defs_km.h" |
| #define PVR_DUMP_DRIVER_INFO(x, y) \ |
| PVR_DUMPDEBUG_LOG("%s info: " \ |
| "BuildOptions: 0x%08x " \ |
| "BuildVersion: %d.%d " \ |
| "BuildRevision: %8d " \ |
| "BuildType: %s", \ |
| (x), \ |
| (y).ui32BuildOptions, \ |
| PVRVERSION_UNPACK_MAJ((y).ui32BuildVersion), \ |
| PVRVERSION_UNPACK_MIN((y).ui32BuildVersion), \ |
| (y).ui32BuildRevision, \ |
| (BUILD_TYPE_DEBUG == (y).ui32BuildType) ? "debug" : "release") |
| |
| |
| #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 |
| }; |
| |
| typedef struct _IMG_FLAGS2DESC_ |
| { |
| IMG_UINT32 uiFlag; |
| IMG_CHAR *pszLabel; |
| } IMG_FLAGS2DESC; |
| |
| 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; "} |
| }; |
| |
| const IMG_FLAGS2DESC asMisc2Description[] = |
| { |
| {RGXFWIF_INICFG_USE_EXTENDED, "Use extended; "}, |
| {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_SHG_BYPASS_EN, "SHG Bypass; "}, |
| {RGXFWIF_INICFG_RTU_BYPASS_EN, "RTU Bypass; "}, |
| {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; "} |
| }; |
| |
| 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; "}, |
| }; |
| |
| 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; "}, |
| }; |
| |
| #if !defined(NO_HARDWARE) |
| /* Translation of MIPS exception encoding */ |
| static const IMG_CHAR * const apszMIPSExcCodes[32] = |
| { |
| "Interrupt", |
| "TLB modified exception", |
| "TLB exception (load/instruction fetch)", |
| "TLB exception (store)", |
| "Address error exception (load/instruction fetch)", |
| "Address error exception (store)", |
| "Bus error exception (instruction fetch)", |
| "Bus error exception (load/store)", |
| "Syscall exception", |
| "Breakpoint exception", |
| "Reserved instruction exception", |
| "Coprocessor Unusable exception", |
| "Arithmetic Overflow exception", |
| "Trap exception", |
| NULL, |
| NULL, |
| "Implementation-Specific Exception 1 (COP2)", |
| "CorExtend Unusable", |
| "Coprocessor 2 exceptions", |
| "TLB Read-Inhibit", |
| "TLB Execute-Inhibit", |
| NULL, |
| NULL, |
| "Reference to WatchHi/WatchLo address", |
| "Machine check", |
| NULL, |
| "DSP Module State Disabled exception", |
| NULL, |
| NULL, |
| NULL, |
| /* Can only happen in MIPS debug mode */ |
| "Parity error", |
| NULL |
| }; |
| #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 |
| |
| IMG_UINT32 RGXReadWithSP(IMG_UINT32 ui32FWAddr) |
| { |
| PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_DEVICE_NODE *psDeviceNode = psPVRSRVData->psDeviceNodeList; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| IMG_UINT32 ui32Value = 0; |
| PVRSRV_ERROR eError; |
| |
| eError = RGXReadMETAAddr(psDevInfo, ui32FWAddr, &ui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXReadWithSP error: %s", PVRSRVGetErrorStringKM(eError))); |
| } |
| |
| return ui32Value; |
| } |
| |
| void RGXWriteWithSP(IMG_UINT32 ui32FWAddr, IMG_UINT32 ui32Value) |
| { |
| PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_DEVICE_NODE *psDeviceNode = psPVRSRVData->psDeviceNodeList; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| PVRSRV_ERROR eError; |
| |
| eError = RGXWriteMETAAddr(psDevInfo, ui32FWAddr, ui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXWriteMETAAddr error: %s", PVRSRVGetErrorStringKM(eError))); |
| } |
| } |
| |
| #if defined(SUPPORT_EXTRA_METASP_DEBUG) |
| #if !defined(NO_HARDWARE) && !defined(SUPPORT_TRUSTED_DEVICE) |
| static PVRSRV_ERROR _ValidateFWImageWithSP(PVRSRV_RGXDEV_INFO *psDevInfo, |
| DEVMEM_MEMDESC *psMemDesc, |
| RGXFWIF_DEV_VIRTADDR *psFWAddr, |
| const IMG_CHAR *pszDesc) |
| { |
| PMR *psFWImagePMR; |
| IMG_UINT32 *pui32HostCodeAddr; |
| PVRSRV_ERROR eError; |
| IMG_UINT32 ui32FWCodeAddr, ui32FWImageLen, ui32Value, i; |
| IMG_HANDLE hFWImage; |
| |
| eError = DevmemServerGetImportHandle(psMemDesc, |
| (void **)&psFWImagePMR); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "ValidateFWImageWithSP: Error getting %s PMR (%u)", |
| pszDesc, |
| eError)); |
| return eError; |
| } |
| |
| /* Get a pointer to the FW code and the allocation size */ |
| eError = PMRAcquireKernelMappingData(psFWImagePMR, |
| 0, |
| 0, /* Map whole PMR */ |
| (void**)&pui32HostCodeAddr, |
| (size_t*)&ui32FWImageLen, |
| &hFWImage); |
| if(eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "ValidateFWImageWithSP: Acquire mapping for %s failed (%u)", |
| pszDesc, |
| eError)); |
| return eError; |
| } |
| |
| ui32FWCodeAddr = psFWAddr->ui32Addr; |
| ui32FWImageLen /= sizeof(IMG_UINT32); /* Byte -> 32 bit words */ |
| |
| for (i = 0; i < ui32FWImageLen; i++) |
| { |
| eError = RGXReadMETAAddr(psDevInfo, ui32FWCodeAddr, &ui32Value); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "ValidateFWImageWithSP error: %s", |
| PVRSRVGetErrorStringKM(eError))); |
| goto validatefwimage_release; |
| } |
| |
| PVR_DPF((PVR_DBG_VERBOSE, |
| "0x%x: CPU 0x%08x, FW 0x%08x", |
| i * 4, pui32HostCodeAddr[i], ui32Value)); |
| |
| if (pui32HostCodeAddr[i] != ui32Value) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "ValidateFWImageWithSP: Mismatch while validating %s at offset 0x%x: CPU 0x%08x, FW 0x%08x", |
| pszDesc, |
| i * 4, pui32HostCodeAddr[i], ui32Value)); |
| eError = PVRSRV_ERROR_FW_IMAGE_MISMATCH; |
| goto validatefwimage_release; |
| } |
| |
| ui32FWCodeAddr += 4; |
| } |
| |
| PVR_DPF((PVR_DBG_ERROR, |
| "ValidateFWImageWithSP: Match between Host and Meta views of the %s", |
| pszDesc)); |
| |
| validatefwimage_release: |
| PMRReleaseKernelMappingData(psFWImagePMR, hFWImage); |
| |
| return eError; |
| } |
| #endif |
| |
| PVRSRV_ERROR ValidateFWImageWithSP(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| #if !defined(NO_HARDWARE) && !defined(SUPPORT_TRUSTED_DEVICE) |
| RGXFWIF_DEV_VIRTADDR sFWAddr; |
| PVRSRV_ERROR eError; |
| |
| #define VALIDATEFWIMAGEWITHSP_NUM_CHECKS (1U) |
| static IMG_UINT32 ui32NumChecks = 0; |
| PVRSRV_VZ_RET_IF_MODE(DRIVER_MODE_GUEST, PVRSRV_OK); |
| |
| if (ui32NumChecks == VALIDATEFWIMAGEWITHSP_NUM_CHECKS) |
| { |
| return PVRSRV_OK; |
| } |
| ui32NumChecks++; |
| |
| if (psDevInfo->pvRegsBaseKM == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "ValidateFWImageWithSP: RGX registers not mapped yet!")); |
| return PVRSRV_ERROR_BAD_MAPPING; |
| } |
| |
| sFWAddr.ui32Addr = RGXFW_BOOTLDR_META_ADDR; |
| eError = _ValidateFWImageWithSP(psDevInfo, |
| psDevInfo->psRGXFWCodeMemDesc, |
| &sFWAddr, |
| "FW code"); |
| if (eError != PVRSRV_OK) return eError; |
| |
| if (0 != psDevInfo->sDevFeatureCfg.ui32MCMS) |
| { |
| RGXSetFirmwareAddress(&sFWAddr, |
| psDevInfo->psRGXFWCorememMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| eError = _ValidateFWImageWithSP(psDevInfo, |
| psDevInfo->psRGXFWCorememMemDesc, |
| &sFWAddr, |
| "FW coremem code"); |
| if (eError != PVRSRV_OK) return eError; |
| } |
| |
| #else |
| PVR_UNREFERENCED_PARAMETER(psDevInfo); |
| #endif |
| |
| return PVRSRV_OK; |
| } |
| #endif /* defined(SUPPORT_EXTRA_METASP_DEBUG) */ |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDecodePMPC |
| |
| @Description |
| |
| Return the name for the PM managed Page Catalogues |
| |
| @Input ui32PC - Page Catalogue number |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static IMG_CHAR* _RGXDecodePMPC(IMG_UINT32 ui32PC) |
| { |
| 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 _DPXDecodeBIFReqTags |
| |
| @Description |
| |
| Decode the BIF Tag ID and sideband data fields from DPX_CR_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 |
| |
| ******************************************************************************/ |
| static void _DPXDecodeBIFReqTags(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(eBankID == RGXDBG_DPX_BIF); |
| PVR_ASSERT(ppszTagID != NULL); |
| |
| PVR_UNREFERENCED_PARAMETER(ui32TagSB); |
| PVR_UNREFERENCED_PARAMETER(pszScratchBuf); |
| PVR_UNREFERENCED_PARAMETER(ui32ScratchBufSize); |
| |
| switch (ui32TagID) |
| { |
| case 0x0: |
| { |
| pszTagID = "MMU"; |
| break; |
| } |
| case 0x1: |
| { |
| pszTagID = "RS_READ"; |
| break; |
| } |
| case 0x2: |
| { |
| pszTagID = "RS_WRITE"; |
| break; |
| } |
| case 0x3: |
| { |
| pszTagID = "RQ"; |
| break; |
| } |
| case 0x4: |
| { |
| pszTagID = "PU"; |
| break; |
| } |
| } /* switch(TagID) */ |
| |
| *ppszTagID = pszTagID; |
| *ppszTagSB = pszTagSB; |
| } |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @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 |
| |
| ******************************************************************************/ |
| 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 ((psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) && (eBankID == RGXDBG_DPX_BIF)) |
| { |
| _DPXDecodeBIFReqTags(eBankID, ui32TagID, ui32TagSB, ppszTagID, ppszTagSB, pszScratchBuf, ui32ScratchBufSize); |
| return; |
| } |
| |
| switch (ui32TagID) |
| { |
| case 0x0: |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (eBankID == RGXDBG_BIF0) |
| { |
| pszTagID = "VRDM"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Control Stream"; break; |
| case 0x1: pszTagSB = "SHF State"; break; |
| case 0x2: pszTagSB = "Index Data"; break; |
| case 0x4: pszTagSB = "Call Stack"; break; |
| case 0x8: pszTagSB = "Context State"; break; |
| } |
| } |
| else |
| { |
| pszTagID = "MMU"; |
| switch (ui32TagSB) |
| { |
| case 0x0: pszTagSB = "Table"; break; |
| case 0x1: pszTagSB = "Directory"; break; |
| case 0x2: pszTagSB = "Catalogue"; break; |
| } |
| } |
| }else |
| { |
| 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: |
| { |
| if ((psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) && (eBankID == RGXDBG_BIF0)) |
| { |
| pszTagID = "SHF"; |
| }else |
| { |
| pszTagID = "HOST"; |
| } |
| break; |
| } |
| case 0x3: |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (eBankID == RGXDBG_BIF0) |
| { |
| pszTagID = "SHG"; |
| } |
| } |
| else if (0 == (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_MIPS_BIT_MASK)) |
| { |
| 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 (psDevInfo->sDevFeatureCfg.ui64ErnsBrns & HW_ERN_57596_BIT_MASK) |
| { |
| 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: |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_CLUSTER_GROUPING_BIT_MASK) |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (eBankID == RGXDBG_TEXAS_BIF) |
| { |
| pszTagID = "PBE"; |
| } |
| else |
| { |
| pszTagID = "RPM"; |
| } |
| }else{ |
| pszTagID = "PBE"; |
| } |
| }else |
| { |
| pszTagID = "PBE"; |
| break; |
| } |
| break; |
| } |
| case 0x6: |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_CLUSTER_GROUPING_BIT_MASK) |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (eBankID == RGXDBG_TEXAS_BIF) |
| { |
| pszTagID = "ISP"; |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "ZLS"; break; |
| case 0x20: pszTagSB = "Occlusion Query"; break; |
| } |
| }else |
| { |
| pszTagID = "FBA"; |
| } |
| }else |
| { |
| pszTagID = "ISP"; |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "ZLS"; break; |
| case 0x20: pszTagSB = "Occlusion Query"; break; |
| } |
| } |
| }else |
| { |
| pszTagID = "ISP"; |
| switch (ui32TagSB) |
| { |
| case 0x00: pszTagSB = "ZLS"; break; |
| case 0x20: pszTagSB = "Occlusion Query"; break; |
| } |
| } |
| break; |
| } |
| case 0x7: |
| { |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_CLUSTER_GROUPING_BIT_MASK) |
| { |
| 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 (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_PBE2_IN_XE_BIT_MASK/*RGX_FEATURE_SIMPLE_INTERNAL_PARAMETER_FORMAT_BIT_MASK*/) |
| { |
| 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(6 > psDevInfo->sDevFeatureCfg.ui32NumClusters) |
| { |
| pszGroupEnc = "PDSRW"; break; |
| }else if(6 == psDevInfo->sDevFeatureCfg.ui32NumClusters) |
| { |
| pszGroupEnc = "UPUC_USC"; break; |
| } |
| case 0x6: |
| if(6 == psDevInfo->sDevFeatureCfg.ui32NumClusters) |
| { |
| pszGroupEnc = "TPUC_USC"; break; |
| } |
| case 0x7: |
| if(6 == psDevInfo->sDevFeatureCfg.ui32NumClusters) |
| { |
| 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 (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_XT_TOP_INFRASTRUCTURE_BIT_MASK) |
| { |
| 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 IMG_CHAR* _RGXDecodeMMULevel(IMG_UINT32 ui32MMULevel) |
| { |
| 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((psDevInfo->sDevFeatureCfg.ui64ErnsBrns & HW_ERN_50539_BIT_MASK) || \ |
| (psDevInfo->sDevFeatureCfg.ui32FBCDCArch >= 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(psDevInfo->sDevFeatureCfg.ui64ErnsBrns & HW_ERN_50539_BIT_MASK) |
| { |
| 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); |
| } |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| |
| 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: %llu us ago (OS time %llu.%09llu s)", |
| ui32Index, |
| psResult->szString, |
| (unsigned long long) psResult->sBaseDevVAddr.uiAddr, |
| (unsigned long long) psResult->uiSize, |
| psResult->bMap ? "Map": "Unmap", |
| (unsigned long long) OSDivide64r64(psResult->ui64Age, 1000, &ui32Remainder), |
| (unsigned long long) ui64Seconds, |
| (unsigned long long) ui64Nanoseconds); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" [%u] Name: %s Base address: " IMG_DEV_VIRTADDR_FMTSPEC |
| " Size: " IMG_DEVMEM_SIZE_FMTSPEC |
| " Operation: %s Modified: %llu us ago (OS time %llu.%09llu) PID: %u (%s)", |
| ui32Index, |
| psResult->szString, |
| (unsigned long long) psResult->sBaseDevVAddr.uiAddr, |
| (unsigned long long) psResult->uiSize, |
| psResult->bMap ? "Map": "Unmap", |
| (unsigned long long) OSDivide64r64(psResult->ui64Age, 1000, &ui32Remainder), |
| (unsigned long long) ui64Seconds, |
| (unsigned long long) ui64Nanoseconds, |
| (unsigned int) 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; |
| 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) |
| { |
| IMG_UINT32 i, j; |
| |
| /* commit the page fault details */ |
| |
| psInfo->sProcessInfo = *psProcessInfo; |
| psInfo->sFaultDevVAddr = sFaultDevVAddr; |
| psInfo->ui64CRTimer = ui64CRTimer; |
| psInfo->ui64When = OSClockns64(); |
| |
| /* 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) |
| { |
| OSStringNCopy(psProcInfo->szProcessName, |
| "(unknown)", |
| sizeof(psProcInfo->szProcessName) - 1); |
| psProcInfo->szProcessName[sizeof(psProcInfo->szProcessName) - 1] = '\0'; |
| } |
| } |
| } |
| } |
| |
| /* 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) ? 0 : psInfo->sProcessInfo.uiPID; |
| |
| ConvertOSTimestampToSAndNS(psInfo->ui64When, &ui64Seconds, &ui64Nanoseconds); |
| |
| if(pui32Index) |
| { |
| PVR_DUMPDEBUG_LOG("(%u) Device memory history for page fault address 0x%010llX, CRTimer: 0x%016llX, " |
| "PID: %u (%s, unregistered: %u) OS time: %llu.%09llu", |
| *pui32Index, |
| (unsigned long long) psInfo->sFaultDevVAddr.uiAddr, |
| psInfo->ui64CRTimer, |
| (unsigned int) uiPID, |
| psInfo->sProcessInfo.szProcessName, |
| psInfo->sProcessInfo.bUnregistered, |
| (unsigned long long) ui64Seconds, |
| (unsigned long long) ui64Nanoseconds); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("Device memory history for page fault address 0x%010llX, PID: %u " |
| "(%s, unregistered: %u) OS time: %llu.%09llu", |
| (unsigned long long) psInfo->sFaultDevVAddr.uiAddr, |
| (unsigned int) uiPID, |
| psInfo->sProcessInfo.szProcessName, |
| psInfo->sProcessInfo.bUnregistered, |
| (unsigned long long) ui64Seconds, |
| (unsigned long long) ui64Nanoseconds); |
| } |
| |
| 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]); |
| } |
| } |
| |
| #endif |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @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 ui64PCAddress - Page catalogue base address of faulting access |
| @Input ui64CRTimer - RGX CR timer value at time of page fault |
| @Input bSummary - Flag to check whether the function is called |
| as a part of the debug dump summary or |
| as a part of a HWR log |
| @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_UINT64 ui64PCAddress, |
| IMG_UINT64 ui64CRTimer, |
| IMG_BOOL bSummary) |
| { |
| IMG_CHAR *pszIndent = (bSummary ? "" : " "); |
| |
| if (ui64MMUStatus == 0x0) |
| { |
| PVR_DUMPDEBUG_LOG("%s - OK", pszBIFNames[eBankID]); |
| } |
| else |
| { |
| IMG_DEV_VIRTADDR sFaultDevVAddr; |
| IMG_DEV_PHYADDR sPCDevPAddr = { 0 }; |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| IMG_BOOL bFound = IMG_FALSE; |
| RGXMEM_PROCESS_INFO sProcessInfo; |
| IMG_UINT32 ui32PageSizeBytes; |
| FAULT_INFO *psInfo; |
| #endif |
| /* Bank 0 & 1 share the same fields */ |
| PVR_DUMPDEBUG_LOG("%s%s - FAULT:", |
| pszIndent, |
| pszBIFNames[eBankID]); |
| |
| /* MMU Status */ |
| { |
| IMG_UINT32 ui32PC = |
| (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT; |
| |
| IMG_UINT32 ui32PageSize = |
| (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT; |
| |
| 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; |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| ui32PageSizeBytes = _PageSizeHWToBytes(ui32PageSize); |
| #endif |
| |
| 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 = (ui64ReqStatus & RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN) != 0; |
| IMG_UINT32 ui32TagSB = |
| (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT; |
| IMG_UINT32 ui32TagID = |
| (ui64ReqStatus & ~RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT; |
| IMG_UINT64 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; |
| |
| /* RNW bit offset is different. The TAG_SB, TAG_ID and address fields are the same. */ |
| if( (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) && (eBankID == RGXDBG_DPX_BIF)) |
| { |
| bRead = (ui64ReqStatus & DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_EN) != 0; |
| } |
| |
| _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 (bSummary) |
| { |
| IMG_UINT32 ui32PC = |
| (ui64MMUStatus & ~RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK) >> |
| RGX_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT; |
| |
| /* Only the first 8 cat bases are application memory contexts which we can validate... */ |
| if (ui32PC < 8) |
| { |
| sPCDevPAddr.uiAddr = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_CAT_BASEN(ui32PC)); |
| PVR_DUMPDEBUG_LOG("%sAcquired live PC address: 0x%016" |
| IMG_UINT64_FMTSPECX, pszIndent, sPCDevPAddr.uiAddr); |
| } |
| else |
| { |
| sPCDevPAddr.uiAddr = RGXFWIF_INVALID_PC_PHYADDR; |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016" |
| IMG_UINT64_FMTSPECX, pszIndent, ui64PCAddress); |
| sPCDevPAddr.uiAddr = ui64PCAddress; |
| } |
| |
| if (bSummary) |
| { |
| PVR_DUMPDEBUG_LOG("%sChecking faulting address "IMG_DEV_VIRTADDR_FMTSPEC, |
| pszIndent, sFaultDevVAddr.uiAddr); |
| RGXCheckFaultAddress(psDevInfo, &sFaultDevVAddr, &sPCDevPAddr, |
| pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| |
| /* 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) |
| { |
| /* look up the process details for the faulting page catalogue */ |
| bFound = RGXPCAddrToProcessInfo(psDevInfo, sPCDevPAddr, &sProcessInfo); |
| |
| if(bFound) |
| { |
| IMG_BOOL bHits; |
| |
| psInfo = _AcquireNextFaultInfoElement(); |
| |
| /* get any DevicememHistory data for the faulting address */ |
| bHits = _GetDevicememHistoryData(sProcessInfo.uiPID, |
| sFaultDevVAddr, |
| psInfo->asQueryOut, |
| ui32PageSizeBytes); |
| |
| if(bHits) |
| { |
| _CommitFaultInfo(psDevInfo, |
| psInfo, |
| &sProcessInfo, |
| sFaultDevVAddr, |
| ui64CRTimer); |
| } |
| 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%016llX", 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); |
| #endif |
| |
| } |
| |
| } |
| |
| |
| /*! |
| ******************************************************************************* |
| |
| @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 ui64PCAddress - Page catalogue base address of faulting access |
| @Input ui64CRTimer - RGX CR timer value at time of page fault |
| @Input bIsMetaMMUStatus - Is the status from MMU_FAULT_STATUS or MMU_FAULT_STATUS_META. |
| @Input bSummary - Flag to check whether the function is called |
| as a part of the debug dump summary or |
| as a part of a HWR log |
| @Return void |
| |
| ******************************************************************************/ |
| static void _RGXDumpRGXMMUFaultStatus(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT64 ui64MMUStatus, |
| IMG_UINT64 ui64PCAddress, |
| IMG_UINT64 ui64CRTimer, |
| IMG_BOOL bIsMetaMMUStatus, |
| IMG_BOOL bSummary) |
| { |
| IMG_CHAR *pszMetaOrCore = (bIsMetaMMUStatus ? "Meta" : "Core"); |
| IMG_CHAR *pszIndent = (bSummary ? "" : " "); |
| |
| 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_DEV_VIRTADDR sFaultDevVAddr; |
| IMG_DEV_PHYADDR sPCDevPAddr = { 0 }; |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| IMG_BOOL bFound = IMG_FALSE; |
| RGXMEM_PROCESS_INFO sProcessInfo; |
| IMG_UINT32 ui32PageSizeBytes = _PageSizeHWToBytes(0); |
| FAULT_INFO *psInfo; |
| #endif |
| |
| _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 (bSummary) |
| { |
| /* |
| * The first 7 or 8 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. |
| */ |
| #if defined(SUPPORT_TRUSTED_DEVICE) |
| if (ui32PC > 7) |
| #else |
| if (ui32PC > 6) |
| #endif |
| { |
| IMG_UINT32 ui32LatestHWRNumber = 0; |
| IMG_UINT64 ui64LatestMMUStatus = 0; |
| IMG_UINT64 ui64LatestPCAddress = 0; |
| IMG_UINT32 ui32HWRIndex; |
| |
| for (ui32HWRIndex = 0 ; ui32HWRIndex < RGXFWIF_HWINFO_MAX ; ui32HWRIndex++) |
| { |
| RGX_HWRINFO *psHWRInfo = &psDevInfo->psRGXFWIfHWRInfoBuf->sHWRInfo[ui32HWRIndex]; |
| |
| if (psHWRInfo->ui32HWRNumber > ui32LatestHWRNumber && |
| psHWRInfo->eHWRType == RGX_HWRTYPE_MMUFAULT) |
| { |
| ui32LatestHWRNumber = psHWRInfo->ui32HWRNumber; |
| ui64LatestMMUStatus = psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus; |
| ui64LatestPCAddress = psHWRInfo->uHWRData.sMMUInfo.ui64PCAddress; |
| } |
| } |
| |
| if (ui64LatestMMUStatus == ui64MMUStatus && ui64LatestPCAddress != 0) |
| { |
| sPCDevPAddr.uiAddr = ui64LatestPCAddress; |
| PVR_DUMPDEBUG_LOG("%sLocated PC address: 0x%016" IMG_UINT64_FMTSPECX, pszIndent, sPCDevPAddr.uiAddr); |
| } |
| } |
| else |
| { |
| sPCDevPAddr.uiAddr = RGXFWIF_INVALID_PC_PHYADDR; |
| } |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016" IMG_UINT64_FMTSPECX, |
| pszIndent, ui64PCAddress); |
| sPCDevPAddr.uiAddr = ui64PCAddress; |
| } |
| |
| if (bSummary && sPCDevPAddr.uiAddr != 0) |
| { |
| PVR_DUMPDEBUG_LOG("%sChecking faulting address " IMG_DEV_VIRTADDR_FMTSPEC, |
| pszIndent, sFaultDevVAddr.uiAddr); |
| RGXCheckFaultAddress(psDevInfo, &sFaultDevVAddr, &sPCDevPAddr, |
| pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| |
| #if defined(SUPPORT_PAGE_FAULT_DEBUG) |
| /* 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) |
| { |
| /* look up the process details for the faulting page catalogue */ |
| bFound = RGXPCAddrToProcessInfo(psDevInfo, sPCDevPAddr, &sProcessInfo); |
| |
| if(bFound) |
| { |
| IMG_BOOL bHits; |
| |
| psInfo = _AcquireNextFaultInfoElement(); |
| |
| /* get any DevicememHistory data for the faulting address */ |
| bHits = _GetDevicememHistoryData(sProcessInfo.uiPID, |
| sFaultDevVAddr, |
| psInfo->asQueryOut, |
| ui32PageSizeBytes); |
| |
| if(bHits) |
| { |
| _CommitFaultInfo(psDevInfo, |
| psInfo, |
| &sProcessInfo, |
| sFaultDevVAddr, |
| ui64CRTimer); |
| } |
| 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%016llX", |
| 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); |
| #endif |
| } |
| } |
| 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, PVRSRV_DEVICE_CONFIG *psDevConfig, RGX_MIPS_STATE *psMIPSState) |
| { |
| void *pvRegsBaseKM = psDevInfo->pvRegsBaseKM; |
| IMG_UINT32 ui32RegRead; |
| IMG_UINT32 eError = PVRSRV_OK; |
| /* This pointer contains a kernel mapping of a particular memory area shared |
| between the driver and the firmware. This area is used for exchanging info |
| about the internal state of the MIPS*/ |
| IMG_UINT32 *pui32NMIMemoryPointer; |
| IMG_UINT32 *pui32NMIPageBasePointer; |
| IMG_BOOL bValid; |
| IMG_CPU_PHYADDR sCPUPhyAddrStart; |
| IMG_CPU_PHYADDR sCPUPhyAddrEnd; |
| PMR *psPMR = (PMR *)(psDevInfo->psRGXFWDataMemDesc->psImport->hPMR); |
| |
| /* Map the FW code area to the kernel */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWDataMemDesc, |
| (void **)&pui32NMIMemoryPointer); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"_RGXMipsExtraDebug: Failed to acquire NMI shared memory area (%u)", eError)); |
| goto map_error_fail; |
| } |
| |
| eError = PMR_CpuPhysAddr(psPMR, |
| RGXMIPSFW_LOG2_PAGE_SIZE, |
| 1, |
| RGXMIPSFW_BOOT_NMI_DATA_BASE_PAGE * RGXMIPSFW_PAGE_SIZE, |
| &sCPUPhyAddrStart, |
| &bValid); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXBootldrDataInit: PMR_CpuPhysAddr failed (%u)", |
| eError)); |
| return eError; |
| } |
| |
| sCPUPhyAddrEnd.uiAddr = sCPUPhyAddrStart.uiAddr + RGXMIPSFW_PAGE_SIZE; |
| |
| /* Jump to the boot/NMI data page */ |
| pui32NMIMemoryPointer += RGXMIPSFW_GET_OFFSET_IN_DWORDS(RGXMIPSFW_BOOT_NMI_DATA_BASE_PAGE * RGXMIPSFW_PAGE_SIZE); |
| pui32NMIPageBasePointer = pui32NMIMemoryPointer; |
| |
| /* Jump to the NMI shared data area within the page above */ |
| pui32NMIMemoryPointer += RGXMIPSFW_GET_OFFSET_IN_DWORDS(RGXMIPSFW_NMI_SHARED_DATA_BASE); |
| |
| /* Acquire the NMI operations lock */ |
| OSLockAcquire(psDevInfo->hNMILock); |
| |
| /* Make sure the synchronization flag is set to 0 */ |
| pui32NMIMemoryPointer[RGXMIPSFW_NMI_SYNC_FLAG_OFFSET] = 0; |
| |
| /* Flush out the dirty locations of the NMI page */ |
| CacheOpExecKM(PMR_DeviceNode(psPMR), |
| pui32NMIPageBasePointer, |
| pui32NMIPageBasePointer + RGXMIPSFW_PAGE_SIZE/(sizeof(IMG_UINT32)), |
| sCPUPhyAddrStart, |
| sCPUPhyAddrEnd, |
| PVRSRV_CACHE_OP_FLUSH); |
| |
| /* 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 */ |
| pui32NMIMemoryPointer[RGXMIPSFW_NMI_SYNC_FLAG_OFFSET] = 1; |
| |
| /* Flush out the dirty locations of the NMI page */ |
| CacheOpExecKM(PMR_DeviceNode(psPMR), |
| pui32NMIPageBasePointer, |
| pui32NMIPageBasePointer + RGXMIPSFW_PAGE_SIZE/(sizeof(IMG_UINT32)), |
| sCPUPhyAddrStart, |
| sCPUPhyAddrEnd, |
| PVRSRV_CACHE_OP_FLUSH); |
| |
| /* 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) |
| { |
| #define INDENT " " |
| const IMG_UINT32 ui32ExcCode = RGXMIPSFW_C0_CAUSE_EXCCODE(ui32Cause); |
| const IMG_CHAR * const pszException = apszMIPSExcCodes[ui32ExcCode]; |
| |
| if (pszException != NULL) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Cause exception: %s", pszException); |
| } |
| |
| /* IP Bits */ |
| { |
| IMG_UINT32 ui32HWIRQStatus = RGXMIPSFW_C0_CAUSE_PENDING_HWIRQ(ui32Cause); |
| IMG_UINT32 i; |
| |
| for (i = 0; i < RGXMIPSFW_C0_NBHWIRQ; ++i) |
| { |
| if (ui32HWIRQStatus & (1 << i)) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Hardware interrupt %d pending", i); |
| /* Can there be more than one HW irq pending or should we break? */ |
| } |
| } |
| } |
| |
| 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 special 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)); |
| } |
| |
| if (ui32Cause & RGXMIPSFW_C0_CAUSE_TIPENDING) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Timer Interrupt pending"); |
| } |
| |
| #undef INDENT |
| } |
| |
| static void _RGXMipsDumpDebugDecode(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)) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Debug Mode is OFF"); |
| return; |
| } |
| |
| pszDException = apszMIPSExcCodes[RGXMIPSFW_C0_DEBUG_EXCCODE(ui32Debug)]; |
| |
| if (pszDException != NULL) |
| { |
| PVR_DUMPDEBUG_LOG(INDENT "Debug exception: %s", pszDException); |
| } |
| |
| for (i = 0; i < IMG_ARR_NUM_ELEMS(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 _RGXMipsDumpTLBEntry(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, void *pvDumpDebugFile, const RGX_MIPS_TLB_ENTRY *psEntry, IMG_UINT32 ui32Index) |
| { |
| #define INDENT " " |
| #define DUMP_TLB_LO(ENTRY_LO, ENTRY_NUM) \ |
| PVR_DUMPDEBUG_LOG(INDENT "EntryLo" #ENTRY_NUM \ |
| ":%s PFN = 0x%05X, %s%s", \ |
| apszPermissionInhibit[RGXMIPSFW_TLB_GET_INHIBIT(ENTRY_LO)], \ |
| RGXMIPSFW_TLB_GET_PFN(ENTRY_LO), \ |
| apszCoherencyTBL[RGXMIPSFW_TLB_GET_COHERENCY(ENTRY_LO)], \ |
| apszDirtyGlobalValid[RGXMIPSFW_TLB_GET_DGV(ENTRY_LO)]) |
| |
| static const IMG_CHAR * const apszPermissionInhibit[4] = |
| { |
| "", |
| " XI,", |
| " RI,", |
| " RI/XI," |
| }; |
| |
| static const IMG_CHAR * const apszCoherencyTBL[8] = |
| { |
| "Cacheable", |
| "Cacheable", |
| "Uncached", |
| "Cacheable", |
| "Cacheable", |
| "Cacheable", |
| "Cacheable", |
| "Uncached" |
| }; |
| |
| static const IMG_CHAR * const apszDirtyGlobalValid[8] = |
| { |
| "", |
| ", G", |
| ", V", |
| ", GV", |
| ", D", |
| ", DG", |
| ", DV", |
| ", DGV" |
| }; |
| |
| PVR_DUMPDEBUG_LOG("Entry %u, Page Mask: 0x%04X, EntryHi: VPN2 = 0x%05X", ui32Index, RGXMIPSFW_TLB_GET_MASK(psEntry->ui32TLBPageMask), |
| RGXMIPSFW_TLB_GET_VPN2(psEntry->ui32TLBHi)); |
| |
| DUMP_TLB_LO(psEntry->ui32TLBLo0, 0); |
| |
| DUMP_TLB_LO(psEntry->ui32TLBLo1, 1); |
| |
| #undef DUMP_TLB_LO |
| } |
| |
| #endif /* defined(RGX_FEATURE_MIPS) && !defined(NO_HARDWARE) */ |
| |
| static void _Flags2Description(IMG_CHAR *psDesc, 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(psDesc, psConvTable[ui32Idx].pszLabel); |
| } |
| } |
| } |
| |
| static void _GetFwFlagsDescription(IMG_CHAR *psDesc, IMG_UINT32 ui32RawFlags) |
| { |
| const IMG_CHAR *psCswLabel = "Ctx switch: "; |
| strcat(psDesc, psCswLabel); |
| _Flags2Description(psDesc, asCSW2Description, IMG_ARR_NUM_ELEMS(asCSW2Description), ui32RawFlags); |
| _Flags2Description(psDesc, asMisc2Description, IMG_ARR_NUM_ELEMS(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); |
| } |
| } |
| } |
| |
| 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, 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 *pszMsgHeader = "Number of HWR: "; |
| IMG_CHAR *pszLockupType = ""; |
| RGXFWIF_HWRINFOBUF *psHWInfoBuf = psDevInfo->psRGXFWIfHWRInfoBuf; |
| RGX_HWRINFO *psHWRInfo; |
| IMG_UINT32 ui32MsgHeaderSize = OSStringLength(pszMsgHeader); |
| IMG_UINT32 ui32HWRRecoveryFlags; |
| IMG_UINT32 ui32ReadIndex; |
| |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_FASTRENDER_DM_BIT_MASK)) |
| { |
| apszDmNames[RGXFWIF_DM_TDM] = "2D("; |
| } |
| |
| for (dm = 0; dm < psDevInfo->sDevFeatureCfg.ui32MAXDMCount; dm++) |
| { |
| if (psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[dm] || |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[dm]) |
| { |
| bAnyLocked = IMG_TRUE; |
| break; |
| } |
| } |
| |
| if (!bAnyLocked && (psRGXFWIfTraceBufCtl->ui32HWRStateFlags & RGXFWIF_HWR_HARDWARE_OK)) |
| { |
| /* No HWR situation, print nothing */ |
| return; |
| } |
| |
| ui32LineSize = sizeof(IMG_CHAR) * ( ui32MsgHeaderSize + |
| (psDevInfo->sDevFeatureCfg.ui32MAXDMCount*( 4/*DM name + left parenthesis*/ + |
| 10/*UINT32 max num of digits*/ + |
| 1/*slash*/ + |
| 10/*UINT32 max num of digits*/ + |
| 3/*right parenthesis + comma + space*/)) + |
| 7 + (psDevInfo->sDevFeatureCfg.ui32MAXDMCount*6)/* FALSE() + (UINT16 max num + comma) per DM */ + |
| 1/* \0 */); |
| |
| pszLine = OSAllocMem(ui32LineSize); |
| if (pszLine == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"_RGXDumpRGXDebugSummary: Out of mem allocating line string (size: %d)", ui32LineSize)); |
| return; |
| } |
| |
| OSStringCopy(pszLine,pszMsgHeader); |
| pszTemp = pszLine + ui32MsgHeaderSize; |
| |
| for (dm = 0; (dm < psDevInfo->sDevFeatureCfg.ui32MAXDMCount) && (apszDmNames[dm] != NULL); dm++) |
| { |
| OSStringCopy(pszTemp,apszDmNames[dm]); |
| pszTemp += OSStringLength(apszDmNames[dm]); |
| pszTemp += OSSNPrintf(pszTemp, |
| 10 + 1 + 10 + 1 + 10 + 1 + 1 + 1 + 1 /* UINT32 + slash + UINT32 + plus + UINT32 + right parenthesis + comma + space + \0 */, |
| "%u/%u+%u), ", |
| psRGXFWIfTraceBufCtl->aui32HwrDmRecoveredCount[dm], |
| psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[dm], |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[dm]); |
| } |
| |
| OSStringCopy(pszTemp, "FALSE("); |
| pszTemp += 6; |
| |
| for (dm = 0; (dm < psDevInfo->sDevFeatureCfg.ui32MAXDMCount) && (apszDmNames[dm] != NULL); dm++) |
| { |
| pszTemp += OSSNPrintf(pszTemp, |
| 10 + 1 + 1 /* UINT32 max num + comma + \0 */, |
| (dm < psDevInfo->sDevFeatureCfg.ui32MAXDMCount-1 ? "%u," : "%u)"), |
| psRGXFWIfTraceBufCtl->aui32HwrDmFalseDetectCount[dm]); |
| } |
| |
| PVR_DUMPDEBUG_LOG("%s", pszLine); |
| |
| OSFreeMem(pszLine); |
| |
| /* Print out per HWR info */ |
| for (dm = 0; (dm < psDevInfo->sDevFeatureCfg.ui32MAXDMCount) && (apszDmNames[dm] != NULL); dm++) |
| { |
| if (dm == RGXFWIF_DM_GP) |
| { |
| PVR_DUMPDEBUG_LOG("DM %d (GP)", dm); |
| } |
| else |
| { |
| IMG_CHAR sPerDmHwrDescription[RGX_DEBUG_STR_SIZE] = ""; |
| |
| _Flags2Description(sPerDmHwrDescription, asDmState2Description, IMG_ARR_NUM_ELEMS(asDmState2Description), psRGXFWIfTraceBufCtl->aui32HWRRecoveryFlags[dm]); |
| PVR_DUMPDEBUG_LOG("DM %d (HWRflags 0x%08x: %s)", dm, psRGXFWIfTraceBufCtl->aui32HWRRecoveryFlags[dm], sPerDmHwrDescription); |
| } |
| |
| 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_GUILTY_LOCKUP) { pszLockupType = ", Innocent Overrun"; } |
| |
| OSSNPrintf(aui8RecoveryNum, sizeof(aui8RecoveryNum), "Recovery %d:", psHWRInfo->ui32HWRNumber); |
| PVR_DUMPDEBUG_LOG(" %s PID = %d, 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++ = ' '; |
| } |
| 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); |
| 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(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK)) |
| { |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXFWIF_HWRTYPE_BIF_BANK_GET(psHWRInfo->eHWRType), |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFMMUStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFReqStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64PCAddress, |
| psHWRInfo->ui64CRTimer, |
| IMG_FALSE); |
| } |
| } |
| break; |
| case RGX_HWRTYPE_TEXASBIF0FAULT: |
| { |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK)) |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_CLUSTER_GROUPING_BIT_MASK) |
| { |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_TEXAS_BIF, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFMMUStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFReqStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64PCAddress, |
| psHWRInfo->ui64CRTimer, |
| IMG_FALSE); |
| } |
| } |
| } |
| break; |
| case RGX_HWRTYPE_DPXMMUFAULT: |
| { |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK)) |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_DPX_BIF, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFMMUStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64BIFReqStatus, |
| psHWRInfo->uHWRData.sBIFInfo.ui64PCAddress, |
| psHWRInfo->ui64CRTimer, |
| IMG_FALSE); |
| } |
| } |
| } |
| break; |
| case RGX_HWRTYPE_MMUFAULT: |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK) |
| { |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus, |
| psHWRInfo->uHWRData.sMMUInfo.ui64PCAddress, |
| psHWRInfo->ui64CRTimer, |
| IMG_FALSE, |
| IMG_FALSE); |
| } |
| } |
| break; |
| |
| case RGX_HWRTYPE_MMUMETAFAULT: |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK) |
| { |
| |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, |
| psHWRInfo->uHWRData.sMMUInfo.ui64MMUStatus, |
| psHWRInfo->uHWRData.sMMUInfo.ui64PCAddress, |
| psHWRInfo->ui64CRTimer, |
| IMG_TRUE, |
| IMG_FALSE); |
| } |
| } |
| 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 |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function _RGXDumpRGXDebugSummary |
| |
| @Description |
| |
| Dump a summary in human readable form with the RGX state |
| |
| @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 bRGXPoweredON - IMG_TRUE if RGX device is on |
| |
| @Return void |
| |
| ******************************************************************************/ |
| static 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; |
| IMG_CHAR sHwrStateDescription[RGX_DEBUG_STR_SIZE] = ""; |
| 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) |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK) |
| { |
| |
| IMG_UINT64 ui64RegValMMUStatus; |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_MMU_FAULT_STATUS); |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, ui64RegValMMUStatus, 0, 0, IMG_FALSE, IMG_TRUE); |
| |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_MMU_FAULT_STATUS_META); |
| _RGXDumpRGXMMUFaultStatus(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, ui64RegValMMUStatus, 0, 0, IMG_TRUE, IMG_TRUE); |
| }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, 0, 0, IMG_TRUE); |
| |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_SINGLE_BIF_BIT_MASK)) |
| { |
| 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, 0, 0, IMG_TRUE); |
| } |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_CLUSTER_GROUPING_BIT_MASK) |
| { |
| IMG_UINT32 ui32PhantomCnt = RGX_REQ_NUM_PHANTOMS(psDevInfo->sDevFeatureCfg.ui32NumClusters); |
| |
| 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, 0, 0, IMG_TRUE); |
| } |
| }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, 0, 0, IMG_TRUE); |
| } |
| } |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| ui64RegValMMUStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, DPX_CR_BIF_FAULT_BANK_MMU_STATUS); |
| ui64RegValREQStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, DPX_CR_BIF_FAULT_BANK_REQ_STATUS); |
| _RGXDumpRGXBIFBank(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, RGXDBG_DPX_BIF, ui64RegValMMUStatus, ui64RegValREQStatus, 0, 0, IMG_TRUE); |
| } |
| |
| } |
| |
| 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); |
| } |
| } |
| } |
| #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; |
| default: pszState = "UNKNOWN"; break; |
| } |
| |
| switch (OSAtomicRead(&psDevInfo->psDeviceNode->eHealthReason)) |
| { |
| case PVRSRV_DEVICE_HEALTH_REASON_NONE: pszReason = ""; break; |
| case PVRSRV_DEVICE_HEALTH_REASON_ASSERTED: pszReason = " - FW Assert"; 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; |
| 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; |
| } |
| |
| _Flags2Description(sHwrStateDescription, asHwrState2Description, IMG_ARR_NUM_ELEMS(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 other, %d total. Latency: %u ms)", |
| pszPowStateName[psRGXFWIfTraceBuf->ePowState], |
| (psDevInfo->pvAPMISRData)?"enabled":"disabled", |
| psDevInfo->ui32ActivePMReqOk, |
| psDevInfo->ui32ActivePMReqDenied, |
| psDevInfo->ui32ActivePMReqTotal - psDevInfo->ui32ActivePMReqOk - psDevInfo->ui32ActivePMReqDenied, |
| psDevInfo->ui32ActivePMReqTotal, |
| psRuntimeCfg->ui32ActivePMLatencyms); |
| |
| ui32NumClockSpeedChanges = (IMG_UINT32) OSAtomicRead(&psDevInfo->psDeviceNode->iNumClockSpeedChanges); |
| RGXGetTimeCorrData(psDevInfo->psDeviceNode, asTimeCorrs, IMG_ARR_NUM_ELEMS(asTimeCorrs)); |
| |
| PVR_DUMPDEBUG_LOG("RGX DVFS: %u frequency changes. Current frequency: %u MHz (sampled at %llx)", |
| ui32NumClockSpeedChanges, |
| asTimeCorrs[0].ui32CoreClockSpeed / 1000000, |
| (unsigned long long) asTimeCorrs[0].ui64OSTimeStamp); |
| if(ui32NumClockSpeedChanges > 0) |
| { |
| PVR_DUMPDEBUG_LOG(" Previous frequencies: %u, %u, %u MHz (Sampled at %llx, %llx, %llx)", |
| asTimeCorrs[1].ui32CoreClockSpeed / 1000000, |
| asTimeCorrs[2].ui32CoreClockSpeed / 1000000, |
| asTimeCorrs[3].ui32CoreClockSpeed / 1000000, |
| (unsigned long long) asTimeCorrs[1].ui64OSTimeStamp, |
| (unsigned long long) asTimeCorrs[2].ui64OSTimeStamp, |
| (unsigned long long) asTimeCorrs[3].ui64OSTimeStamp); |
| } |
| |
| for (ui32OSid = 0; ui32OSid < RGXFW_NUM_OS; ui32OSid++) |
| { |
| IMG_UINT32 ui32OSStateFlags = psRGXFWIfTraceBuf->ui32OSStateFlags[ui32OSid]; |
| |
| PVR_DUMPDEBUG_LOG("RGX FW OS %u State: 0x%08x (Active: %s%s, Freelists: %s, Grow Request Pending: %s)", ui32OSid, ui32OSStateFlags, |
| ((ui32OSStateFlags & RGXFW_OS_STATE_ACTIVE_OS) != 0)?"Yes":"No", |
| ((ui32OSStateFlags & RGXFW_OS_STATE_OFFLOADING) != 0)?"- offloading":"", |
| ((ui32OSStateFlags & RGXFW_OS_STATE_FREELIST_OK) != 0)?"Ok":"Not Ok", |
| ((ui32OSStateFlags & RGXFW_OS_STATE_GROW_REQUEST_PENDING) != 0)?"Yes":"No" |
| ); |
| } |
| _RGXDumpFWAssert(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf); |
| |
| _RGXDumpFWPoll(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf); |
| |
| _RGXDumpFWHWRInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psRGXFWIfTraceBuf, psDevInfo); |
| } |
| |
| 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) |
| { |
| IMG_UINT32 i; |
| PVRSRV_VZ_RETN_IF_MODE(DRIVER_MODE_GUEST); |
| |
| for(i=0;i<=DEBUG_REQUEST_VERBOSITY_MAX;i++) |
| { |
| RGXDebugRequestProcess(pfnDumpDebugPrintf, pvDumpDebugFile, |
| psDevInfo, i); |
| } |
| } |
| |
| /* |
| * Array of all the Firmware Trace log IDs used to convert the trace data. |
| */ |
| typedef struct _TRACEBUF_LOG_ { |
| RGXFW_LOG_SFids eSFId; |
| IMG_CHAR *pszName; |
| IMG_CHAR *pszFmt; |
| IMG_UINT32 ui32ArgNum; |
| } TRACEBUF_LOG; |
| |
| static 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) |
| { |
| 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) |
| { |
| IMG_UINT32 ui32Count; |
| IMG_CHAR *pszString; |
| TRACEBUF_LOG *psLogDef2; |
| |
| /* |
| * 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; |
| |
| /* 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 < RGXFW_TRACE_BUFFER_SIZE) |
| { |
| IMG_UINT32 ui32Data, ui32DataToId; |
| |
| /* Find the first valid log ID, skipping whitespace... */ |
| do |
| { |
| ui32Data = pui32TraceBuf[ui32TracePtr]; |
| ui32DataToId = idToStringID(ui32Data); |
| |
| /* If an unrecognized id is found check if it is valid, if it is tracebuf needs updating. */ |
| if (ui32DataToId == RGXFW_SF_LAST && RGXFW_LOG_VALIDID(ui32Data)) |
| { |
| PVR_DUMPDEBUG_LOG("ERROR: Unrecognized id (%x). From here on the trace might be wrong!", ui32Data); |
| return; |
| } |
| |
| /* Update the trace pointer... */ |
| ui32TracePtr = (ui32TracePtr + 1) % RGXFW_TRACE_BUFFER_SIZE; |
| ui32Count++; |
| } while ((RGXFW_SF_LAST == ui32DataToId || ui32DataToId >= RGXFW_SF_FIRST) && |
| ui32Count < RGXFW_TRACE_BUFFER_SIZE); |
| |
| if (ui32Count < RGXFW_TRACE_BUFFER_SIZE) |
| { |
| IMG_CHAR szBuffer[PVR_MAX_DEBUG_MESSAGE_LEN] = "%llu: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].name); |
| uiLen = OSStringLength(szBuffer); |
| szBuffer[uiLen ? uiLen - 1 : 0] = '\0'; |
| ui64Timestamp = (IMG_UINT64)(pui32TraceBuf[(ui32TracePtr + 0) % RGXFW_TRACE_BUFFER_SIZE]) << 32 | |
| (IMG_UINT64)(pui32TraceBuf[(ui32TracePtr + 1) % RGXFW_TRACE_BUFFER_SIZE]); |
| PVR_DUMPDEBUG_LOG(szBuffer, ui64Timestamp, tid, groups[RGXFW_SF_GID(ui32Data)], |
| pui32TraceBuf[(ui32TracePtr + 2) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 3) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 4) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 5) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 6) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 7) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 8) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 9) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 10) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 11) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 12) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 13) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 14) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 15) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 16) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 17) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 18) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 19) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 20) % RGXFW_TRACE_BUFFER_SIZE], |
| pui32TraceBuf[(ui32TracePtr + 21) % RGXFW_TRACE_BUFFER_SIZE]); |
| |
| /* Update the trace pointer... */ |
| ui32TracePtr = (ui32TracePtr + 2 + RGXFW_SF_PARAMNUM(ui32Data)) % RGXFW_TRACE_BUFFER_SIZE; |
| 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_UNDEFINED: |
| PVR_ASSERT(!"Device has undefined state"); |
| /* fallthrough */ |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| static 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"; |
| } |
| } |
| |
| 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; |
| PVRSRV_VZ_RETN_IF_MODE(DRIVER_MODE_GUEST); |
| |
| eError = PVRSRVPowerLock(psDeviceNode); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXDebugRequestProcess : failed to acquire lock, error:0x%x", eError)); |
| return; |
| } |
| |
| switch (ui32VerbLevel) |
| { |
| case DEBUG_REQUEST_VERBOSITY_LOW : |
| { |
| PVRSRV_DEV_POWER_STATE ePowerState; |
| IMG_BOOL bRGXPoweredON; |
| IMG_CHAR *Bit32 = "32 Bit", *Bit64 = "64 Bit"; |
| |
| eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXDebugRequestProcess: Error retrieving RGX power state. No debug info dumped.")); |
| goto Exit; |
| } |
| |
| bRGXPoweredON = (ePowerState == PVRSRV_DEV_POWER_STATE_ON); |
| if(psPVRSRVData->sDriverInfo.bIsNoMatch) |
| { |
| PVR_DUMPDEBUG_LOG("------[ Driver Info ]------"); |
| PVR_DUMP_DRIVER_INFO("UM", psPVRSRVData->sDriverInfo.sUMBuildInfo); |
| PVR_DUMP_DRIVER_INFO("KM", psPVRSRVData->sDriverInfo.sKMBuildInfo); |
| } |
| |
| PVR_DUMPDEBUG_LOG("KM Arch: %s", (psPVRSRVData->sDriverInfo.ui8KMBitArch & BUILD_ARCH_64BIT)? |
| Bit64 : Bit32); |
| |
| 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) |
| { |
| |
| 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); |
| |
| if(psDevInfo->sDevFeatureCfg.ui32META) |
| { |
| /* 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 = RGXRunScript(psDevInfo, psDevInfo->psScripts->asDbgCommands, RGX_MAX_DEBUG_COMMANDS, PDUMP_FLAGS_CONTINUOUS, pfnDumpDebugPrintf, pvDumpDebugFile); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXDebugRequestProcess: RGXRunScript failed (%d)", eError)); |
| if(psDevInfo->sDevFeatureCfg.ui32META) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"Dump Slave Port debug information")); |
| _RGXDumpMetaSPExtraDebugInfo(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo); |
| } |
| } |
| #if !defined(NO_HARDWARE) |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_MIPS_BIT_MASK) |
| { |
| RGX_MIPS_STATE sMIPSState; |
| PVRSRV_ERROR eError; |
| OSCachedMemSet((void *)&sMIPSState, 0x00, sizeof(RGX_MIPS_STATE)); |
| eError = _RGXMipsExtraDebug(psDevInfo, psDeviceNode->psDevConfig, &sMIPSState); |
| PVR_DUMPDEBUG_LOG("---- [ MIPS internal state ] ----"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DUMPDEBUG_LOG("MIPS extra debug not available"); |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG("PC :0x%08X", sMIPSState.ui32ErrorEPC); |
| PVR_DUMPDEBUG_LOG("STATUS_REGISTER :0x%08X", sMIPSState.ui32StatusRegister); |
| PVR_DUMPDEBUG_LOG("CAUSE_REGISTER :0x%08X", sMIPSState.ui32CauseRegister); |
| _RGXMipsDumpCauseDecode(pfnDumpDebugPrintf, pvDumpDebugFile, sMIPSState.ui32CauseRegister); |
| PVR_DUMPDEBUG_LOG("BAD_REGISTER :0x%08X", sMIPSState.ui32BadRegister); |
| PVR_DUMPDEBUG_LOG("EPC :0x%08X", sMIPSState.ui32EPC); |
| PVR_DUMPDEBUG_LOG("SP :0x%08X", sMIPSState.ui32SP); |
| PVR_DUMPDEBUG_LOG("BAD_INSTRUCTION :0x%08X", sMIPSState.ui32BadInstr); |
| PVR_DUMPDEBUG_LOG("DEBUG :"); |
| _RGXMipsDumpDebugDecode(pfnDumpDebugPrintf, pvDumpDebugFile, sMIPSState.ui32Debug, sMIPSState.ui32DEPC); |
| |
| { |
| IMG_UINT32 ui32Idx; |
| |
| PVR_DUMPDEBUG_LOG("TLB :"); |
| for (ui32Idx = 0; |
| ui32Idx < IMG_ARR_NUM_ELEMS(sMIPSState.asTLB); |
| ++ui32Idx) |
| { |
| _RGXMipsDumpTLBEntry(pfnDumpDebugPrintf, pvDumpDebugFile, &sMIPSState.asTLB[ui32Idx], ui32Idx); |
| } |
| } |
| } |
| PVR_DUMPDEBUG_LOG("--------------------------------"); |
| } |
| #endif |
| } |
| else |
| { |
| PVR_DUMPDEBUG_LOG(" (!) RGX power is down. No registers dumped"); |
| } |
| |
| /* 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); |
| } |
| } |
| |
| /* Dump the KCCB commands executed */ |
| { |
| PVR_DUMPDEBUG_LOG("RGX Kernel CCB commands executed = %d", |
| psDevInfo->psRGXFWIfTraceBuf->ui32KCCBCmdsExecuted); |
| } |
| |
| /* Dump the IRQ info for threads*/ |
| { |
| IMG_UINT32 ui32TID; |
| |
| for (ui32TID = 0; ui32TID < RGXFW_THREAD_NUM; ui32TID++) |
| { |
| PVR_DUMPDEBUG_LOG("RGX FW thread %u: FW IRQ count = %u, Last sampled IRQ count in LISR = %u", |
| ui32TID, |
| psDevInfo->psRGXFWIfTraceBuf->aui32InterruptCount[ui32TID], |
| psDevInfo->aui32SampleIRQCount[ui32TID]); |
| } |
| } |
| |
| /* 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,"RGXDebugRequestProcess: OS Config is not mapped into CPU space")); |
| goto Exit; |
| } |
| |
| _GetFwFlagsDescription(sFwFlagsDescription, psOSConfig->ui32ConfigFlags); |
| PVR_DUMPDEBUG_LOG("FW OS config flags = 0x%X (%s)", psOSConfig->ui32ConfigFlags, sFwFlagsDescription); |
| } |
| |
| break; |
| |
| } |
| case DEBUG_REQUEST_VERBOSITY_MEDIUM : |
| { |
| IMG_INT tid; |
| /* Dump FW trace information */ |
| if (psDevInfo->psRGXFWIfTraceBuf != NULL) |
| { |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| |
| 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; |
| } |
| |
| /* each element in the line is 8 characters plus a space. The '+1' is because of the final trailing '\0'. */ |
| pszLine = OSAllocMem(9*RGXFW_TRACE_BUFFER_LINESIZE+1); |
| if (pszLine == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXDebugRequestProcess: Out of mem allocating line string (size: %d)", 9*RGXFW_TRACE_BUFFER_LINESIZE)); |
| 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", RGXFW_TRACE_BUFFER_SIZE); |
| |
| for (i = 0; i < RGXFW_TRACE_BUFFER_SIZE; i += RGXFW_TRACE_BUFFER_LINESIZE) |
| { |
| IMG_UINT32 k = 0; |
| IMG_UINT32 ui32Line = 0x0; |
| IMG_UINT32 ui32LineOffset = i*sizeof(IMG_UINT32); |
| IMG_CHAR *pszBuf = pszLine; |
| |
| for (k = 0; k < RGXFW_TRACE_BUFFER_LINESIZE; k++) |
| { |
| 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(psDevInfo->sDevFeatureCfg.ui32META) |
| { |
| RGXFWIF_OS_CONFIG *psOSConfig = psDevInfo->psFWIfOSConfig; |
| |
| if (!psOSConfig) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXDebugRequestProcess: OS Config is not mapped into CPU space")); |
| goto Exit; |
| } |
| |
| if ((psOSConfig->ui32ConfigFlags & RGXFWIF_INICFG_METAT1_DUMMY) != 0) |
| { |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| 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 defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) || defined(PVRSRV_ENABLE_FULL_CCB_DUMP) |
| PVR_DUMPDEBUG_LOG("------[ Full CCB Status ]------"); |
| #else |
| PVR_DUMPDEBUG_LOG("------[ Stalled FWCtxs ]------"); |
| #endif |
| CheckForStalledTransferCtxt(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile); |
| CheckForStalledRenderCtxt(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile); |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_COMPUTE_BIT_MASK) |
| { |
| CheckForStalledComputeCtxt(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_FASTRENDER_DM_BIT_MASK) |
| { |
| CheckForStalledTDMTransferCtxt(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| CheckForStalledRayCtxt(psDevInfo, pfnDumpDebugPrintf, pvDumpDebugFile); |
| } |
| } |
| break; |
| } |
| case DEBUG_REQUEST_VERBOSITY_HIGH: |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_DEV_POWER_STATE ePowerState; |
| IMG_BOOL bRGXPoweredON; |
| |
| eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXDebugRequestProcess: Error retrieving RGX power state. No debug info dumped.")); |
| return; |
| } |
| |
| bRGXPoweredON = (ePowerState == PVRSRV_DEV_POWER_STATE_ON); |
| |
| PVR_DUMPDEBUG_LOG("------[ Debug summary ]------"); |
| |
| _RGXDumpRGXDebugSummary(pfnDumpDebugPrintf, pvDumpDebugFile, psDevInfo, bRGXPoweredON); |
| } |
| default: |
| break; |
| } |
| |
| Exit: |
| PVRSRVPowerUnlock(psDeviceNode); |
| } |
| |
| /* |
| RGXPanic |
| */ |
| void RGXPanic(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| PVR_LOG(("RGX panic")); |
| PVRSRVDebugRequest(psDevInfo->psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, |
| NULL, NULL); |
| OSPanic(); |
| } |
| |
| |
| /****************************************************************************** |
| End of file (rgxdebug.c) |
| ******************************************************************************/ |