/*************************************************************************/ /*!
|
@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 "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"
|
#if !defined(PVRSRV_GPUVIRT_GUESTDRV)
|
#include "rgxfw_log_helper.h"
|
#endif
|
|
#include "rgxta3d.h"
|
#include "rgxcompute.h"
|
#include "rgxtransfer.h"
|
#include "rgxray.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 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;
|
|
#if !defined(PVRSRV_GPUVIRT_GUESTDRV)
|
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
|
};
|
#endif
|
|
#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;
|
}
|
|
|
#if defined(SUPPORT_EXTRA_METASP_DEBUG)
|
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,
|
&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;
|
}
|
|
PVRSRV_ERROR ValidateFWImageWithSP(PVRSRV_RGXDEV_INFO *psDevInfo)
|
{
|
#if !defined(NO_HARDWARE) && defined(DEBUG) && !defined(PVRSRV_GPUVIRT_GUESTDRV) && !defined(SUPPORT_TRUSTED_DEVICE)
|
RGXFWIF_DEV_VIRTADDR sFWAddr;
|
PVRSRV_ERROR eError;
|
|
#define VALIDATEFWIMAGEWITHSP_NUM_CHECKS (1U)
|
static IMG_UINT32 ui32NumChecks = 0;
|
|
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 !defined(SUPPORT_TRUSTED_DEVICE)
|
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;
|
}
|
#endif
|
|
#else
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
#endif
|
|
return PVRSRV_OK;
|
}
|
#endif /* defined(SUPPORT_EXTRA_METASP_DEBUG) */
|
|
|
|
/*
|
Guest drivers have the following limitations:
|
- Cannot perform general device management (including debug)
|
- Cannot touch the hardware except OSID kick registers
|
- Guest driver do not support Firmware Trace log
|
*/
|
#if defined(PVRSRV_GPUVIRT_GUESTDRV)
|
void RGXDebugRequestProcess(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
void *pvDumpDebugFile,
|
PVRSRV_RGXDEV_INFO *psDevInfo,
|
IMG_UINT32 ui32VerbLevel)
|
{
|
PVR_UNREFERENCED_PARAMETER(pfnDumpDebugPrintf);
|
PVR_UNREFERENCED_PARAMETER(pvDumpDebugFile);
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
PVR_UNREFERENCED_PARAMETER(ui32VerbLevel);
|
}
|
|
void RGXDumpDebugInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
void *pvDumpDebugFile,
|
PVRSRV_RGXDEV_INFO *psDevInfo)
|
{
|
PVR_UNREFERENCED_PARAMETER(psDevInfo);
|
PVR_UNREFERENCED_PARAMETER(pfnDumpDebugPrintf);
|
PVR_UNREFERENCED_PARAMETER(pvDumpDebugFile);
|
}
|
#else
|
/*!
|
*******************************************************************************
|
|
@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
|
{
|
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 us)",
|
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%016llX): 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%016llX): %s (%s), %s 0x%010llX.",
|
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%016llX", pszIndent, sPCDevPAddr.uiAddr);
|
}
|
else
|
{
|
sPCDevPAddr.uiAddr = RGXFWIF_INVALID_PC_PHYADDR;
|
}
|
}
|
else
|
{
|
PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016llX", pszIndent, ui64PCAddress);
|
sPCDevPAddr.uiAddr = ui64PCAddress;
|
}
|
|
if (bSummary)
|
{
|
PVR_DUMPDEBUG_LOG("%sChecking faulting address 0x%010llX", 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%016llX): PC = %d, %s 0x%010llX, %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%016llX", pszIndent, sPCDevPAddr.uiAddr);
|
}
|
}
|
else
|
{
|
sPCDevPAddr.uiAddr = RGXFWIF_INVALID_PC_PHYADDR;
|
}
|
}
|
else
|
{
|
PVR_DUMPDEBUG_LOG("%sFW logged fault using PC Address: 0x%016llX",
|
pszIndent, ui64PCAddress);
|
sPCDevPAddr.uiAddr = ui64PCAddress;
|
}
|
|
if (bSummary && sPCDevPAddr.uiAddr != 0)
|
{
|
PVR_DUMPDEBUG_LOG("%sChecking faulting address 0x%010llX",
|
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 */
|
OSFlushCPUCacheRangeKM(PMR_DeviceNode(psPMR),
|
pui32NMIPageBasePointer,
|
pui32NMIPageBasePointer + RGXMIPSFW_PAGE_SIZE/(sizeof(IMG_UINT32)),
|
sCPUPhyAddrStart,
|
sCPUPhyAddrEnd);
|
|
/* 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 */
|
OSFlushCPUCacheRangeKM(PMR_DeviceNode(psPMR),
|
pui32NMIPageBasePointer,
|
pui32NMIPageBasePointer + RGXMIPSFW_PAGE_SIZE/(sizeof(IMG_UINT32)),
|
sCPUPhyAddrStart,
|
sCPUPhyAddrEnd);
|
|
/* 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] =
|
{
|
"",
|
", V",
|
", G",
|
", GV",
|
", D",
|
", DV",
|
", DG",
|
", 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) */
|
|
/*!
|
*******************************************************************************
|
|
@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(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
|
{
|
PVR_DUMPDEBUG_LOG("DM %d (HWRflags 0x%08x)", dm, psRGXFWIfTraceBufCtl->aui32HWRRecoveryFlags[dm]);
|
}
|
|
ui32ReadIndex = 0;
|
for(i = 0 ; i < RGXFWIF_HWINFO_MAX ; i++)
|
{
|
psHWRInfo = &psHWInfoBuf->sHWRInfo[ui32ReadIndex];
|
|
if((psHWRInfo->eDM == dm) && (psHWRInfo->ui32HWRNumber != 0))
|
{
|
IMG_CHAR aui8RecoveryNum[10+10+1];
|
IMG_UINT64 ui64Seconds, ui64Nanoseconds;
|
|
/* Split OS timestamp in seconds and nanoseconds */
|
ConvertOSTimestampToSAndNS(psHWRInfo->ui64OSTimer, &ui64Seconds, &ui64Nanoseconds);
|
|
ui32HWRRecoveryFlags = psHWRInfo->ui32HWRRecoveryFlags;
|
if(ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_GUILTY_LOCKUP) { pszLockupType = ", Guilty Lockup"; }
|
else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_INNOCENT_LOCKUP) { pszLockupType = ", Innocent Lockup"; }
|
else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_GUILTY_OVERRUNING) { pszLockupType = ", Guilty Overrun"; }
|
else if (ui32HWRRecoveryFlags & RGXFWIF_DM_STATE_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%012llX, OSTimer = %llu.%09llu, CyclesElapsed = %lld",
|
aui8RecoveryNum,
|
psHWRInfo->ui64CRTimer,
|
ui64Seconds,
|
ui64Nanoseconds,
|
(psHWRInfo->ui64CRTimer-psHWRInfo->ui64CRTimeOfKick)*256);
|
if (psHWRInfo->ui64CRTimeHWResetFinish != 0)
|
{
|
if (psHWRInfo->ui64CRTimeFreelistReady != 0)
|
{
|
PVR_DUMPDEBUG_LOG(" %s PreResetTimeInCycles = %lld, HWResetTimeInCycles = %lld, FreelistReconTimeInCycles = %lld, TotalRecoveryTimeInCycles = %lld",
|
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 = %lld, HWResetTimeInCycles = %lld, TotalRecoveryTimeInCycles = %lld",
|
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)",
|
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);
|
}
|
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;
|
|
#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_GET_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%llX",
|
(unsigned long long) sDevVAddr.uiAddr,
|
ui32CatBase,
|
(unsigned long long) 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;
|
}
|
|
PVR_DUMPDEBUG_LOG("RGX FW State: %s%s (HWRState 0x%08x)", pszState, pszReason, psRGXFWIfTraceBuf->ui32HWRStateFlags);
|
PVR_DUMPDEBUG_LOG("RGX FW Power State: %s (APM %s: %d ok, %d denied, %d other, %d total)",
|
pszPowStateName[psRGXFWIfTraceBuf->ePowState],
|
(psDevInfo->pvAPMISRData)?"enabled":"disabled",
|
psDevInfo->ui32ActivePMReqOk,
|
psDevInfo->ui32ActivePMReqDenied,
|
psDevInfo->ui32ActivePMReqTotal - psDevInfo->ui32ActivePMReqOk - psDevInfo->ui32ActivePMReqDenied,
|
psDevInfo->ui32ActivePMReqTotal);
|
|
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)", 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"
|
);
|
}
|
_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;
|
|
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");
|
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_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
|
PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode;
|
PVRSRV_ERROR 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;
|
|
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("------[ 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_INIT *psRGXFWInit;
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc,
|
(void **)&psRGXFWInit);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"RGXDebugRequestProcess: Failed to acquire kernel fw if ctl (%u)",
|
eError));
|
goto Exit;
|
}
|
|
PVR_DUMPDEBUG_LOG("RGX FW config flags = 0x%X", psRGXFWInit->ui32ConfigFlags);
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
|
}
|
|
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_INIT *psRGXFWInit;
|
|
eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc,
|
(void **)&psRGXFWInit);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"RGXDebugRequestProcess: Failed to acquire kernel fw if ctl (%u)",
|
eError));
|
goto Exit;
|
}
|
|
if ((psRGXFWInit->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] ]------");
|
}
|
|
DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
|
}
|
}
|
|
{
|
#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_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);
|
}
|
#endif
|
|
/*
|
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)
|
******************************************************************************/
|