/*************************************************************************/ /*! @Title Device specific initialisation routines @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved @License Dual MIT/GPLv2 The contents of this file are subject to the MIT license as set out below. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 2 ("GPL") in which case the provisions of GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of GPL, and not to allow others to use your version of this file under the terms of the MIT license, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by GPL as set out in the file called "GPL-COPYING" included in this distribution. If you do not delete the provisions above, a recipient may use your version of this file under the terms of either the MIT license or GPL. This License is also included in this distribution in the file called "MIT-COPYING". EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ #include #include "sgxdefs.h" #include "sgxmmu.h" #include "services_headers.h" #include "buffer_manager.h" #include "sgxapi_km.h" #include "sgxinfo.h" #include "sgx_mkif_km.h" #include "sgxconfig.h" #include "sysconfig.h" #include "pvr_bridge_km.h" #include "sgx_bridge_km.h" #include "pdump_km.h" #include "ra.h" #include "mmu.h" #include "handle.h" #include "perproc.h" #include "sgxutils.h" #include "pvrversion.h" #include "sgx_options.h" #include "lists.h" #include "srvkm.h" #include "ttrace.h" IMG_UINT32 g_ui32HostIRQCountSample = 0; extern int powering_down; #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) static const IMG_CHAR *SGXUKernelStatusString(IMG_UINT32 code) { switch(code) { #define MKTC_ST(x) \ case x: \ return #x; #include "sgx_ukernel_status_codes.h" default: return "(Unknown)"; } } #endif /* defined(PVRSRV_USSE_EDM_STATUS_DEBUG) */ #define VAR(x) #x /* PRQA S 0881 11 */ /* ignore 'order of evaluation' warning */ #define CHECK_SIZE(NAME) \ { \ if (psSGXStructSizes->ui32Sizeof_##NAME != psDevInfo->sSGXStructSizes.ui32Sizeof_##NAME) \ { \ PVR_DPF((PVR_DBG_ERROR, "SGXDevInitCompatCheck: Size check failed for SGXMKIF_%s (client) = %d bytes, (ukernel) = %d bytes\n", \ VAR(NAME), \ psDevInfo->sSGXStructSizes.ui32Sizeof_##NAME, \ psSGXStructSizes->ui32Sizeof_##NAME )); \ bStructSizesFailed = IMG_TRUE; \ } \ } #if defined (SYS_USING_INTERRUPTS) IMG_BOOL SGX_ISRHandler(IMG_VOID *pvData); #endif static PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext); #if defined(PDUMP) static PVRSRV_ERROR SGXResetPDump(PVRSRV_DEVICE_NODE *psDeviceNode); #endif /*! ******************************************************************************* @Function SGXCommandComplete @Description SGX command complete handler @Input psDeviceNode - SGX device node @Return none ******************************************************************************/ static IMG_VOID SGXCommandComplete(PVRSRV_DEVICE_NODE *psDeviceNode) { #if defined(OS_SUPPORTS_IN_LISR) if (OSInLISR(psDeviceNode->psSysData)) { /* * We shouldn't call SGXScheduleProcessQueuesKM in an * LISR, as it may attempt to power up SGX. * We assume that the LISR will schedule the MISR, which * will test the following flag, and call * SGXScheduleProcessQueuesKM if the flag is set. */ psDeviceNode->bReProcessDeviceCommandComplete = IMG_TRUE; } else { SGXScheduleProcessQueuesKM(psDeviceNode); } #else SGXScheduleProcessQueuesKM(psDeviceNode); #endif } /*! ******************************************************************************* @Function DeinitDevInfo @Description Deinits DevInfo @Input none @Return none ******************************************************************************/ static IMG_UINT32 DeinitDevInfo(PVRSRV_SGXDEV_INFO *psDevInfo) { if (psDevInfo->psKernelCCBInfo != IMG_NULL) { /* Free CCB info. */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO), psDevInfo->psKernelCCBInfo, IMG_NULL); } return PVRSRV_OK; } /*! ******************************************************************************* @Function InitDevInfo @Description Loads DevInfo @Input psDeviceNode @Return PVRSRV_ERROR ******************************************************************************/ static PVRSRV_ERROR InitDevInfo(PVRSRV_PER_PROCESS_DATA *psPerProc, PVRSRV_DEVICE_NODE *psDeviceNode, #if defined (SUPPORT_SID_INTERFACE) SGX_BRIDGE_INIT_INFO_KM *psInitInfo) #else SGX_BRIDGE_INIT_INFO *psInitInfo) #endif { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; PVRSRV_ERROR eError; PVRSRV_SGX_CCB_INFO *psKernelCCBInfo = IMG_NULL; PVR_UNREFERENCED_PARAMETER(psPerProc); psDevInfo->sScripts = psInitInfo->sScripts; psDevInfo->psKernelCCBMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBMemInfo; psDevInfo->psKernelCCB = (PVRSRV_SGX_KERNEL_CCB *) psDevInfo->psKernelCCBMemInfo->pvLinAddrKM; psDevInfo->psKernelCCBCtlMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBCtlMemInfo; psDevInfo->psKernelCCBCtl = (PVRSRV_SGX_CCB_CTL *) psDevInfo->psKernelCCBCtlMemInfo->pvLinAddrKM; psDevInfo->psKernelCCBEventKickerMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCCBEventKickerMemInfo; psDevInfo->pui32KernelCCBEventKicker = (IMG_UINT32 *)psDevInfo->psKernelCCBEventKickerMemInfo->pvLinAddrKM; psDevInfo->psKernelSGXHostCtlMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXHostCtlMemInfo; psDevInfo->psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psKernelSGXHostCtlMemInfo->pvLinAddrKM; psDevInfo->psKernelSGXTA3DCtlMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXTA3DCtlMemInfo; #if defined(FIX_HW_BRN_31272) || defined(FIX_HW_BRN_31780) || defined(FIX_HW_BRN_33920) psDevInfo->psKernelSGXPTLAWriteBackMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXPTLAWriteBackMemInfo; #endif psDevInfo->psKernelSGXMiscMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelSGXMiscMemInfo; #if defined(SGX_SUPPORT_HWPROFILING) psDevInfo->psKernelHWProfilingMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWProfilingMemInfo; #endif #if defined(SUPPORT_SGX_HWPERF) psDevInfo->psKernelHWPerfCBMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelHWPerfCBMemInfo; #endif psDevInfo->psKernelTASigBufferMemInfo = psInitInfo->hKernelTASigBufferMemInfo; psDevInfo->psKernel3DSigBufferMemInfo = psInitInfo->hKernel3DSigBufferMemInfo; #if defined(FIX_HW_BRN_29702) psDevInfo->psKernelCFIMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelCFIMemInfo; #endif #if defined(FIX_HW_BRN_29823) psDevInfo->psKernelDummyTermStreamMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelDummyTermStreamMemInfo; #endif #if defined(SGX_FEATURE_VDM_CONTEXT_SWITCH) && \ defined(FIX_HW_BRN_33657) && defined(SUPPORT_SECURE_33657_FIX) psDevInfo->psKernelVDMStateUpdateBufferMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelVDMStateUpdateBufferMemInfo; #endif #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) psDevInfo->psKernelEDMStatusBufferMemInfo = (PVRSRV_KERNEL_MEM_INFO *)psInitInfo->hKernelEDMStatusBufferMemInfo; #endif /* * Assign client-side build options for later verification */ psDevInfo->ui32ClientBuildOptions = psInitInfo->ui32ClientBuildOptions; /* * Assign microkernel IF structure sizes for later verification */ psDevInfo->sSGXStructSizes = psInitInfo->sSGXStructSizes; /* Setup the kernel version of the CCB control */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGX_CCB_INFO), (IMG_VOID **)&psKernelCCBInfo, 0, "SGX Circular Command Buffer Info"); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"InitDevInfo: Failed to alloc memory")); goto failed_allockernelccb; } OSMemSet(psKernelCCBInfo, 0, sizeof(PVRSRV_SGX_CCB_INFO)); psKernelCCBInfo->psCCBMemInfo = psDevInfo->psKernelCCBMemInfo; psKernelCCBInfo->psCCBCtlMemInfo = psDevInfo->psKernelCCBCtlMemInfo; psKernelCCBInfo->psCommands = psDevInfo->psKernelCCB->asCommands; psKernelCCBInfo->pui32WriteOffset = &psDevInfo->psKernelCCBCtl->ui32WriteOffset; psKernelCCBInfo->pui32ReadOffset = &psDevInfo->psKernelCCBCtl->ui32ReadOffset; psDevInfo->psKernelCCBInfo = psKernelCCBInfo; /* Copy the USE code addresses for the host kick. */ OSMemCopy(psDevInfo->aui32HostKickAddr, psInitInfo->aui32HostKickAddr, SGXMKIF_CMD_MAX * sizeof(psDevInfo->aui32HostKickAddr[0])); psDevInfo->bForcePTOff = IMG_FALSE; psDevInfo->ui32CacheControl = psInitInfo->ui32CacheControl; psDevInfo->ui32EDMTaskReg0 = psInitInfo->ui32EDMTaskReg0; psDevInfo->ui32EDMTaskReg1 = psInitInfo->ui32EDMTaskReg1; psDevInfo->ui32ClkGateCtl = psInitInfo->ui32ClkGateCtl; psDevInfo->ui32ClkGateCtl2 = psInitInfo->ui32ClkGateCtl2; psDevInfo->ui32ClkGateStatusReg = psInitInfo->ui32ClkGateStatusReg; psDevInfo->ui32ClkGateStatusMask = psInitInfo->ui32ClkGateStatusMask; #if defined(SGX_FEATURE_MP) psDevInfo->ui32MasterClkGateStatusReg = psInitInfo->ui32MasterClkGateStatusReg; psDevInfo->ui32MasterClkGateStatusMask = psInitInfo->ui32MasterClkGateStatusMask; psDevInfo->ui32MasterClkGateStatus2Reg = psInitInfo->ui32MasterClkGateStatus2Reg; psDevInfo->ui32MasterClkGateStatus2Mask = psInitInfo->ui32MasterClkGateStatus2Mask; #endif /* SGX_FEATURE_MP */ /* Initialise Dev Data */ OSMemCopy(&psDevInfo->asSGXDevData, &psInitInfo->asInitDevData, sizeof(psDevInfo->asSGXDevData)); return PVRSRV_OK; failed_allockernelccb: DeinitDevInfo(psDevInfo); return eError; } static PVRSRV_ERROR SGXRunScript(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_INIT_COMMAND *psScript, IMG_UINT32 ui32NumInitCommands) { IMG_UINT32 ui32PC; SGX_INIT_COMMAND *psComm; for (ui32PC = 0, psComm = psScript; ui32PC < ui32NumInitCommands; ui32PC++, psComm++) { switch (psComm->eOp) { case SGX_INIT_OP_WRITE_HW_REG: { OSWriteHWReg(psDevInfo->pvRegsBaseKM, psComm->sWriteHWReg.ui32Offset, psComm->sWriteHWReg.ui32Value); PDUMPCOMMENT("SGXRunScript: Write HW reg operation"); PDUMPREG(SGX_PDUMPREG_NAME, psComm->sWriteHWReg.ui32Offset, psComm->sWriteHWReg.ui32Value); break; } case SGX_INIT_OP_READ_HW_REG: { OSReadHWReg(psDevInfo->pvRegsBaseKM, psComm->sReadHWReg.ui32Offset); #if defined(PDUMP) PDUMPCOMMENT("SGXRunScript: Read HW reg operation"); PDumpRegRead(SGX_PDUMPREG_NAME, psComm->sReadHWReg.ui32Offset, PDUMP_FLAGS_CONTINUOUS); #endif break; } #if defined(PDUMP) case SGX_INIT_OP_PDUMP_HW_REG: { PDUMPCOMMENT("SGXRunScript: Dump HW reg operation"); PDUMPREG(SGX_PDUMPREG_NAME, psComm->sPDumpHWReg.ui32Offset, psComm->sPDumpHWReg.ui32Value); break; } #endif case SGX_INIT_OP_HALT: { return PVRSRV_OK; } case SGX_INIT_OP_ILLEGAL: /* FALLTHROUGH */ default: { PVR_DPF((PVR_DBG_ERROR,"SGXRunScript: PC %d: Illegal command: %d", ui32PC, psComm->eOp)); return PVRSRV_ERROR_UNKNOWN_SCRIPT_OPERATION; } } } return PVRSRV_ERROR_UNKNOWN_SCRIPT_OPERATION; } #if defined(SUPPORT_MEMORY_TILING) static PVRSRV_ERROR SGX_AllocMemTilingRangeInt(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Start, IMG_UINT32 ui32End, IMG_UINT32 ui32TilingStride, IMG_UINT32 *pui32RangeIndex) { IMG_UINT32 i; IMG_UINT32 ui32Offset; IMG_UINT32 ui32Val; /* HW supports 10 ranges */ for(i=0; i < SGX_BIF_NUM_TILING_RANGES; i++) { if((psDevInfo->ui32MemTilingUsage & (1U << i)) == 0) { /* mark in use */ psDevInfo->ui32MemTilingUsage |= 1U << i; /* output range index if the caller wants it */ if(pui32RangeIndex != IMG_NULL) { *pui32RangeIndex = i; } goto RangeAllocated; } } PVR_DPF((PVR_DBG_ERROR,"SGX_AllocMemTilingRange: all tiling ranges in use")); return PVRSRV_ERROR_EXCEEDED_HW_LIMITS; RangeAllocated: /* An improperly aligned range could cause BIF not to tile some memory which is intended to be tiled, * or cause BIF to tile some memory which is not intended to be. */ if(ui32Start & ~SGX_BIF_TILING_ADDR_MASK) { PVR_DPF((PVR_DBG_WARNING,"SGX_AllocMemTilingRangeInt: Tiling range start (0x%08X) fails" "alignment test", ui32Start)); } if((ui32End + 0x00001000) & ~SGX_BIF_TILING_ADDR_MASK) { PVR_DPF((PVR_DBG_WARNING,"SGX_AllocMemTilingRangeInt: Tiling range end (0x%08X) fails" "alignment test", ui32End)); } ui32Offset = EUR_CR_BIF_TILE0 + (i<<2); ui32Val = ((ui32TilingStride << EUR_CR_BIF_TILE0_CFG_SHIFT) & EUR_CR_BIF_TILE0_CFG_MASK) | (((ui32End>>SGX_BIF_TILING_ADDR_LSB) << EUR_CR_BIF_TILE0_MAX_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MAX_ADDRESS_MASK) | (((ui32Start>>SGX_BIF_TILING_ADDR_LSB) << EUR_CR_BIF_TILE0_MIN_ADDRESS_SHIFT) & EUR_CR_BIF_TILE0_MIN_ADDRESS_MASK) | (EUR_CR_BIF_TILE0_ENABLE << EUR_CR_BIF_TILE0_CFG_SHIFT); OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); #if defined(SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS) ui32Offset = EUR_CR_BIF_TILE0_ADDR_EXT + (i<<2); ui32Val = (((ui32End>>SGX_BIF_TILING_EXT_ADDR_LSB) << EUR_CR_BIF_TILE0_ADDR_EXT_MAX_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MAX_MASK) | (((ui32Start>>SGX_BIF_TILING_EXT_ADDR_LSB) << EUR_CR_BIF_TILE0_ADDR_EXT_MIN_SHIFT) & EUR_CR_BIF_TILE0_ADDR_EXT_MIN_MASK); OSWriteHWReg(psDevInfo->pvRegsBaseKM, ui32Offset, ui32Val); PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); #endif /* SGX_FEATURE_BIF_WIDE_TILING_AND_4K_ADDRESS */ return PVRSRV_OK; } #endif /* SUPPORT_MEMORY_TILING */ /*! ******************************************************************************* @Function SGXInitialise @Description (client invoked) chip-reset and initialisation @Input pvDeviceNode - device info. structure @Input bHardwareRecovery - true if recovering powered hardware, false if powering up @Return PVRSRV_ERROR ******************************************************************************/ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bHardwareRecovery) { PVRSRV_ERROR eError; PVRSRV_KERNEL_MEM_INFO *psSGXHostCtlMemInfo = psDevInfo->psKernelSGXHostCtlMemInfo; SGXMKIF_HOST_CTL *psSGXHostCtl = psSGXHostCtlMemInfo->pvLinAddrKM; static IMG_BOOL bFirstTime = IMG_TRUE; #if defined(PDUMP) IMG_BOOL bPDumpIsSuspended = PDumpIsSuspended(); #endif /* PDUMP */ #if defined(SGX_FEATURE_MP) /* Slave core clocks must be enabled during reset */ #else SGXInitClocks(psDevInfo, PDUMP_FLAGS_CONTINUOUS); #endif /* SGX_FEATURE_MP */ /* Part 1 of the initialisation script runs before resetting SGX. */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX initialisation script part 1\n"); eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart1, SGX_MAX_INIT_COMMANDS); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXInitialise: SGXRunScript (part 1) failed (%d)", eError)); return eError; } PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "End of SGX initialisation script part 1\n"); /* Reset the chip */ psDevInfo->ui32NumResets++; #if !defined(SGX_FEATURE_MP) bHardwareRecovery |= bFirstTime; #endif /* SGX_FEATURE_MP */ SGXReset(psDevInfo, bHardwareRecovery, PDUMP_FLAGS_CONTINUOUS); #if defined(EUR_CR_POWER) #if defined(SGX531) /* Disable half the pipes. 531 has 2 pipes within a 4 pipe framework, so the 2 redundant pipes must be disabled even though they do not exist. */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_POWER, 1); PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_POWER, 1); #else /* set the default pipe count (all fully enabled) */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_POWER, 0); PDUMPREG(SGX_PDUMPREG_NAME, EUR_CR_POWER, 0); #endif #endif /* Initialise the kernel CCB event kicker value */ *psDevInfo->pui32KernelCCBEventKicker = 0; #if defined(PDUMP) if (!bPDumpIsSuspended) { psDevInfo->ui32KernelCCBEventKickerDumpVal = 0; PDUMPMEM(&psDevInfo->ui32KernelCCBEventKickerDumpVal, psDevInfo->psKernelCCBEventKickerMemInfo, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); } #endif /* PDUMP */ #if defined(SUPPORT_MEMORY_TILING) { /* Initialise EUR_CR_BIF_TILE registers for any tiling heaps */ DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = psDevInfo->pvDeviceMemoryHeap; IMG_UINT32 i; psDevInfo->ui32MemTilingUsage = 0; for(i=0; iui32HeapCount; i++) { if(psDeviceMemoryHeap[i].ui32XTileStride > 0) { /* Set up the HW control registers */ eError = SGX_AllocMemTilingRangeInt( psDevInfo, psDeviceMemoryHeap[i].sDevVAddrBase.uiAddr, psDeviceMemoryHeap[i].sDevVAddrBase.uiAddr + psDeviceMemoryHeap[i].ui32HeapSize, psDeviceMemoryHeap[i].ui32XTileStride, NULL); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "Unable to allocate SGX BIF tiling range for heap: %s", psDeviceMemoryHeap[i].pszName)); break; } } } } #endif /* Part 2 of the initialisation script runs after resetting SGX. */ PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX initialisation script part 2\n"); eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asInitCommandsPart2, SGX_MAX_INIT_COMMANDS); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXInitialise: SGXRunScript (part 2) failed (%d)", eError)); return eError; } PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "End of SGX initialisation script part 2\n"); /* Record the system timestamp for the microkernel */ psSGXHostCtl->ui32HostClock = OSClockus(); psSGXHostCtl->ui32InitStatus = 0; #if defined(PDUMP) PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Reset the SGX microkernel initialisation status\n"); PDUMPMEM(IMG_NULL, psSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32InitStatus), sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Initialise the microkernel\n"); #endif /* PDUMP */ #if defined(SGX_FEATURE_MULTI_EVENT_KICK) OSWriteMemoryBarrier(); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK2, 0), EUR_CR_EVENT_KICK2_NOW_MASK); #else *psDevInfo->pui32KernelCCBEventKicker = (*psDevInfo->pui32KernelCCBEventKicker + 1) & 0xFF; OSWriteMemoryBarrier(); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), EUR_CR_EVENT_KICK_NOW_MASK); #endif /* SGX_FEATURE_MULTI_EVENT_KICK */ OSMemoryBarrier(); #if defined(PDUMP) /* Dump the host kick. */ if (!bPDumpIsSuspended) { #if defined(SGX_FEATURE_MULTI_EVENT_KICK) PDUMPREG(SGX_PDUMPREG_NAME, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK2, 0), EUR_CR_EVENT_KICK2_NOW_MASK); #else psDevInfo->ui32KernelCCBEventKickerDumpVal = 1; PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "First increment of the SGX event kicker value\n"); PDUMPMEM(&psDevInfo->ui32KernelCCBEventKickerDumpVal, psDevInfo->psKernelCCBEventKickerMemInfo, 0, sizeof(IMG_UINT32), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); PDUMPREG(SGX_PDUMPREG_NAME, SGX_MP_CORE_SELECT(EUR_CR_EVENT_KICK, 0), EUR_CR_EVENT_KICK_NOW_MASK); #endif /* SGX_FEATURE_MULTI_EVENT_KICK */ } #endif /* PDUMP */ #if !defined(NO_HARDWARE) /* Wait for the microkernel to finish initialising. */ if (PollForValueKM(&psSGXHostCtl->ui32InitStatus, PVRSRV_USSE_EDM_INIT_COMPLETE, PVRSRV_USSE_EDM_INIT_COMPLETE, MAX_HW_TIME_US, MAX_HW_TIME_US/WAIT_TRY_COUNT, IMG_FALSE) != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "SGXInitialise: Wait for uKernel initialisation failed")); SGXDumpDebugInfo(psDevInfo, IMG_FALSE); PVR_DBG_BREAK; return PVRSRV_ERROR_RETRY; } #endif /* NO_HARDWARE */ #if defined(PDUMP) PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Wait for the SGX microkernel initialisation to complete"); PDUMPMEMPOL(psSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32InitStatus), PVRSRV_USSE_EDM_INIT_COMPLETE, PVRSRV_USSE_EDM_INIT_COMPLETE, PDUMP_POLL_OPERATOR_EQUAL, PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psSGXHostCtlMemInfo)); #endif /* PDUMP */ PVR_ASSERT(psDevInfo->psKernelCCBCtl->ui32ReadOffset == psDevInfo->psKernelCCBCtl->ui32WriteOffset); bFirstTime = IMG_FALSE; return PVRSRV_OK; } /*! ******************************************************************************* @Function SGXDeinitialise @Description (client invoked) chip-reset and deinitialisation @Input hDevCookie - device info. handle @Return PVRSRV_ERROR ******************************************************************************/ PVRSRV_ERROR SGXDeinitialise(IMG_HANDLE hDevCookie) { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *) hDevCookie; PVRSRV_ERROR eError; /* Did SGXInitialise map the SGX registers in? */ if (psDevInfo->pvRegsBaseKM == IMG_NULL) { return PVRSRV_OK; } eError = SGXRunScript(psDevInfo, psDevInfo->sScripts.asDeinitCommands, SGX_MAX_DEINIT_COMMANDS); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXDeinitialise: SGXRunScript failed (%d)", eError)); return eError; } return PVRSRV_OK; } /*! ******************************************************************************* @Function DevInitSGXPart1 @Description Reset and initialise Chip @Input pvDeviceNode - device info. structure @Return PVRSRV_ERROR ******************************************************************************/ static PVRSRV_ERROR DevInitSGXPart1 (IMG_VOID *pvDeviceNode) { IMG_HANDLE hDevMemHeap = IMG_NULL; PVRSRV_SGXDEV_INFO *psDevInfo; IMG_HANDLE hKernelDevMemContext; IMG_DEV_PHYADDR sPDDevPAddr; IMG_UINT32 i; PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)pvDeviceNode; DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap; PVRSRV_ERROR eError; /* pdump info about the core */ PDUMPCOMMENT("SGX Core Version Information: %s", SGX_CORE_FRIENDLY_NAME); #if defined(SGX_FEATURE_MP) #if !defined(SGX_FEATURE_MP_PLUS) PDUMPCOMMENT("SGX Multi-processor: %d cores", SGX_FEATURE_MP_CORE_COUNT); #else PDUMPCOMMENT("SGX Multi-processor: %d TA cores, %d 3D cores", SGX_FEATURE_MP_CORE_COUNT_TA, SGX_FEATURE_MP_CORE_COUNT_3D); #endif #endif /* SGX_FEATURE_MP */ #if (SGX_CORE_REV == 0) PDUMPCOMMENT("SGX Core Revision Information: head RTL"); #else PDUMPCOMMENT("SGX Core Revision Information: %d", SGX_CORE_REV); #endif #if defined(SGX_FEATURE_SYSTEM_CACHE) PDUMPCOMMENT("SGX System Level Cache is present\r\n"); #if defined(SGX_BYPASS_SYSTEM_CACHE) PDUMPCOMMENT("SGX System Level Cache is bypassed\r\n"); #endif /* SGX_BYPASS_SYSTEM_CACHE */ #endif /* SGX_FEATURE_SYSTEM_CACHE */ PDUMPCOMMENT("SGX Initialisation Part 1"); /* Allocate device control block */ if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGXDEV_INFO), (IMG_VOID **)&psDevInfo, IMG_NULL, "SGX Device Info") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart1 : Failed to alloc memory for DevInfo")); return (PVRSRV_ERROR_OUT_OF_MEMORY); } OSMemSet (psDevInfo, 0, sizeof(PVRSRV_SGXDEV_INFO)); /* setup info from jdisplayconfig.h (variations controlled by build) */ psDevInfo->eDeviceType = DEV_DEVICE_TYPE; psDevInfo->eDeviceClass = DEV_DEVICE_CLASS; /* Initialize SGX idle status */ psDevInfo->bSGXIdle = IMG_TRUE; /* Store the devinfo as its needed by dynamically enumerated systems called from BM */ psDeviceNode->pvDevice = (IMG_PVOID)psDevInfo; /* get heap info from the devnode */ psDevInfo->ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount; psDevInfo->pvDeviceMemoryHeap = (IMG_VOID*)psDeviceMemoryHeap; /* create the kernel memory context */ hKernelDevMemContext = BM_CreateContext(psDeviceNode, &sPDDevPAddr, IMG_NULL, IMG_NULL); if (hKernelDevMemContext == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart1: Failed BM_CreateContext")); return PVRSRV_ERROR_OUT_OF_MEMORY; } psDevInfo->sKernelPDDevPAddr = sPDDevPAddr; /* create the kernel, shared and shared_exported heaps */ for(i=0; isDevMemoryInfo.ui32HeapCount; i++) { switch(psDeviceMemoryHeap[i].DevMemHeapType) { case DEVICE_MEMORY_HEAP_KERNEL: case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { /* Shared PB heap could be zero size */ if (psDeviceMemoryHeap[i].ui32HeapSize > 0) { hDevMemHeap = BM_CreateHeap (hKernelDevMemContext, &psDeviceMemoryHeap[i]); /* in the case of kernel context heaps just store the heap handle in the heap info structure */ psDeviceMemoryHeap[i].hDevMemHeap = hDevMemHeap; } break; } } } #if defined(PDUMP) if(hDevMemHeap) { /* set up the MMU pdump info */ psDevInfo->sMMUAttrib = *((BM_HEAP*)hDevMemHeap)->psMMUAttrib; } #endif eError = MMU_BIFResetPDAlloc(psDevInfo); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGX : Failed to alloc memory for BIF reset")); return eError; } return PVRSRV_OK; } /*! ******************************************************************************* @Function SGXGetInfoForSrvinitKM @Description Get SGX related information necessary for initilisation server @Input hDevHandle - device handle psInitInfo - pointer to structure for returned information @Output psInitInfo - pointer to structure containing returned information @Return PVRSRV_ERROR ******************************************************************************/ IMG_EXPORT #if defined (SUPPORT_SID_INTERFACE) PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle, PVRSRV_HEAP_INFO_KM *pasHeapInfo, IMG_DEV_PHYADDR *psPDDevPAddr) #else PVRSRV_ERROR SGXGetInfoForSrvinitKM(IMG_HANDLE hDevHandle, SGX_BRIDGE_INFO_FOR_SRVINIT *psInitInfo) #endif { PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_SGXDEV_INFO *psDevInfo; PVRSRV_ERROR eError; PDUMPCOMMENT("SGXGetInfoForSrvinit"); psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevHandle; psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; #if defined (SUPPORT_SID_INTERFACE) *psPDDevPAddr = psDevInfo->sKernelPDDevPAddr; eError = PVRSRVGetDeviceMemHeapsKM(hDevHandle, pasHeapInfo); #else psInitInfo->sPDDevPAddr = psDevInfo->sKernelPDDevPAddr; eError = PVRSRVGetDeviceMemHeapsKM(hDevHandle, &psInitInfo->asHeapInfo[0]); #endif if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXGetInfoForSrvinit: PVRSRVGetDeviceMemHeapsKM failed (%d)", eError)); return eError; } return eError; } /*! ******************************************************************************* @Function DevInitSGXPart2KM @Description Reset and initialise Chip @Input pvDeviceNode - device info. structure @Return PVRSRV_ERROR ******************************************************************************/ IMG_EXPORT PVRSRV_ERROR DevInitSGXPart2KM (PVRSRV_PER_PROCESS_DATA *psPerProc, IMG_HANDLE hDevHandle, #if defined (SUPPORT_SID_INTERFACE) SGX_BRIDGE_INIT_INFO_KM *psInitInfo) #else SGX_BRIDGE_INIT_INFO *psInitInfo) #endif { PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_SGXDEV_INFO *psDevInfo; PVRSRV_ERROR eError; SGX_DEVICE_MAP *psSGXDeviceMap; PVRSRV_DEV_POWER_STATE eDefaultPowerState; PDUMPCOMMENT("SGX Initialisation Part 2"); psDeviceNode = (PVRSRV_DEVICE_NODE *)hDevHandle; psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; /* Init devinfo */ eError = InitDevInfo(psPerProc, psDeviceNode, psInitInfo); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart2KM: Failed to load EDM program")); goto failed_init_dev_info; } eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, (IMG_VOID**)&psSGXDeviceMap); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart2KM: Failed to get device memory map!")); return PVRSRV_ERROR_INIT_FAILURE; } /* Registers already mapped? */ if (psSGXDeviceMap->pvRegsCpuVBase) { psDevInfo->pvRegsBaseKM = psSGXDeviceMap->pvRegsCpuVBase; } else { /* Map Regs */ psDevInfo->pvRegsBaseKM = OSMapPhysToLin(psSGXDeviceMap->sRegsCpuPBase, psSGXDeviceMap->ui32RegsSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, IMG_NULL); if (!psDevInfo->pvRegsBaseKM) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart2KM: Failed to map in regs\n")); return PVRSRV_ERROR_BAD_MAPPING; } } psDevInfo->ui32RegSize = psSGXDeviceMap->ui32RegsSize; psDevInfo->sRegsPhysBase = psSGXDeviceMap->sRegsSysPBase; #if defined(SGX_FEATURE_HOST_PORT) if (psSGXDeviceMap->ui32Flags & SGX_HOSTPORT_PRESENT) { /* Map Host Port */ psDevInfo->pvHostPortBaseKM = OSMapPhysToLin(psSGXDeviceMap->sHPCpuPBase, psSGXDeviceMap->ui32HPSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, IMG_NULL); if (!psDevInfo->pvHostPortBaseKM) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart2KM: Failed to map in host port\n")); return PVRSRV_ERROR_BAD_MAPPING; } psDevInfo->ui32HPSize = psSGXDeviceMap->ui32HPSize; psDevInfo->sHPSysPAddr = psSGXDeviceMap->sHPSysPBase; } #endif/* #ifdef SGX_FEATURE_HOST_PORT */ #if defined (SYS_USING_INTERRUPTS) /* Set up ISR callback information. */ psDeviceNode->pvISRData = psDeviceNode; /* ISR handler address was set up earlier */ PVR_ASSERT(psDeviceNode->pfnDeviceISR == SGX_ISRHandler); #endif /* SYS_USING_INTERRUPTS */ /* Prevent the microkernel being woken up before there is something to do. */ psDevInfo->psSGXHostCtl->ui32PowerStatus |= PVRSRV_USSE_EDM_POWMAN_NO_WORK; eDefaultPowerState = PVRSRV_DEV_POWER_STATE_OFF; /* Register the device with the power manager. */ eError = PVRSRVRegisterPowerDevice (psDeviceNode->sDevId.ui32DeviceIndex, &SGXPrePowerState, &SGXPostPowerState, &SGXPreClockSpeedChange, &SGXPostClockSpeedChange, (IMG_HANDLE)psDeviceNode, PVRSRV_DEV_POWER_STATE_OFF, eDefaultPowerState); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevInitSGXPart2KM: failed to register device with power manager")); return eError; } #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) /* map the external system cache control registers into the SGX MMU */ psDevInfo->ui32ExtSysCacheRegsSize = psSGXDeviceMap->ui32ExtSysCacheRegsSize; psDevInfo->sExtSysCacheRegsDevPBase = psSGXDeviceMap->sExtSysCacheRegsDevPBase; eError = MMU_MapExtSystemCacheRegs(psDeviceNode); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXInitialise : Failed to map external system cache registers")); return eError; } #endif /* SUPPORT_EXTERNAL_SYSTEM_CACHE */ /* Initialise the Kernel CCB */ OSMemSet(psDevInfo->psKernelCCB, 0, sizeof(PVRSRV_SGX_KERNEL_CCB)); OSMemSet(psDevInfo->psKernelCCBCtl, 0, sizeof(PVRSRV_SGX_CCB_CTL)); OSMemSet(psDevInfo->pui32KernelCCBEventKicker, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker)); PDUMPCOMMENT("Initialise Kernel CCB"); PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBMemInfo, 0, sizeof(PVRSRV_SGX_KERNEL_CCB), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBMemInfo)); PDUMPCOMMENT("Initialise Kernel CCB Control"); PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBCtlMemInfo, 0, sizeof(PVRSRV_SGX_CCB_CTL), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBCtlMemInfo)); PDUMPCOMMENT("Initialise Kernel CCB Event Kicker"); PDUMPMEM(IMG_NULL, psDevInfo->psKernelCCBEventKickerMemInfo, 0, sizeof(*psDevInfo->pui32KernelCCBEventKicker), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelCCBEventKickerMemInfo)); return PVRSRV_OK; failed_init_dev_info: return eError; } /*! ******************************************************************************* @Function DevDeInitSGX @Description Reset and deinitialise Chip @Input pvDeviceNode - device info. structure @Return PVRSRV_ERROR ******************************************************************************/ static PVRSRV_ERROR DevDeInitSGX (IMG_VOID *pvDeviceNode) { PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)pvDeviceNode; PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; PVRSRV_ERROR eError; IMG_UINT32 ui32Heap; DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; SGX_DEVICE_MAP *psSGXDeviceMap; if (!psDevInfo) { /* Can happen if DevInitSGX failed */ PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Null DevInfo")); return PVRSRV_OK; } #if defined(SUPPORT_HW_RECOVERY) if (psDevInfo->hTimer) { eError = OSRemoveTimer(psDevInfo->hTimer); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Failed to remove timer")); return eError; } psDevInfo->hTimer = IMG_NULL; } #endif /* SUPPORT_HW_RECOVERY */ #if defined(SUPPORT_EXTERNAL_SYSTEM_CACHE) /* unmap the external system cache control registers */ eError = MMU_UnmapExtSystemCacheRegs(psDeviceNode); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Failed to unmap ext system cache registers")); return eError; } #endif /* SUPPORT_EXTERNAL_SYSTEM_CACHE */ MMU_BIFResetPDFree(psDevInfo); /* DeinitDevInfo the DevInfo */ DeinitDevInfo(psDevInfo); /* Destroy heaps. */ psDeviceMemoryHeap = (DEVICE_MEMORY_HEAP_INFO *)psDevInfo->pvDeviceMemoryHeap; for(ui32Heap=0; ui32HeapsDevMemoryInfo.ui32HeapCount; ui32Heap++) { switch(psDeviceMemoryHeap[ui32Heap].DevMemHeapType) { case DEVICE_MEMORY_HEAP_KERNEL: case DEVICE_MEMORY_HEAP_SHARED: case DEVICE_MEMORY_HEAP_SHARED_EXPORTED: { if (psDeviceMemoryHeap[ui32Heap].hDevMemHeap != IMG_NULL) { BM_DestroyHeap(psDeviceMemoryHeap[ui32Heap].hDevMemHeap); } break; } } } /* Destroy the kernel context. */ eError = BM_DestroyContext(psDeviceNode->sDevMemoryInfo.pBMKernelContext, IMG_NULL); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX : Failed to destroy kernel context")); return eError; } /* remove the device from the power manager */ eError = PVRSRVRemovePowerDevice (((PVRSRV_DEVICE_NODE*)pvDeviceNode)->sDevId.ui32DeviceIndex); if (eError != PVRSRV_OK) { return eError; } eError = SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, (IMG_VOID**)&psSGXDeviceMap); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"DevDeInitSGX: Failed to get device memory map!")); return eError; } /* Only unmap the registers if they were mapped here */ if (!psSGXDeviceMap->pvRegsCpuVBase) { /* UnMap Regs */ if (psDevInfo->pvRegsBaseKM != IMG_NULL) { OSUnMapPhysToLin(psDevInfo->pvRegsBaseKM, psDevInfo->ui32RegSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, IMG_NULL); } } #if defined(SGX_FEATURE_HOST_PORT) if (psSGXDeviceMap->ui32Flags & SGX_HOSTPORT_PRESENT) { /* unMap Host Port */ if (psDevInfo->pvHostPortBaseKM != IMG_NULL) { OSUnMapPhysToLin(psDevInfo->pvHostPortBaseKM, psDevInfo->ui32HPSize, PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, IMG_NULL); } } #endif /* #ifdef SGX_FEATURE_HOST_PORT */ /* DeAllocate devinfo */ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(PVRSRV_SGXDEV_INFO), psDevInfo, 0); psDeviceNode->pvDevice = IMG_NULL; if (psDeviceMemoryHeap != IMG_NULL) { /* Free the device memory heap info. */ OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(DEVICE_MEMORY_HEAP_INFO) * SGX_MAX_HEAP_ID, psDeviceMemoryHeap, 0); } return PVRSRV_OK; } #if defined(RESTRICTED_REGISTERS) && defined(SGX_FEATURE_MP) /*! ******************************************************************************* @Function SGXDumpMasterDebugReg @Description Dump a single SGX debug register value @Input psDevInfo - SGX device info @Input pszName - string used for logging @Input ui32RegAddr - SGX register offset @Return IMG_VOID ******************************************************************************/ static IMG_VOID SGXDumpMasterDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_CHAR *pszName, IMG_UINT32 ui32RegAddr) { IMG_UINT32 ui32RegVal; ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, ui32RegAddr); PVR_LOG(("(HYD) %s%08X", pszName, ui32RegVal)); } #endif /* defined(RESTRICTED_REGISTERS) */ /*! ******************************************************************************* @Function SGXDumpDebugReg @Description Dump a single SGX debug register value @Input psDevInfo - SGX device info @Input ui32CoreNum - processor number @Input pszName - string used for logging @Input ui32RegAddr - SGX register offset @Return IMG_VOID ******************************************************************************/ static IMG_VOID SGXDumpDebugReg (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_UINT32 ui32CoreNum, IMG_CHAR *pszName, IMG_UINT32 ui32RegAddr) { IMG_UINT32 ui32RegVal; ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(ui32RegAddr, ui32CoreNum)); PVR_LOG(("(P%u) %s%08X", ui32CoreNum, pszName, ui32RegVal)); } #if defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) || defined(FIX_HW_BRN_31620) static INLINE IMG_UINT32 GetDirListBaseReg(IMG_UINT32 ui32Index) { if (ui32Index == 0) { return EUR_CR_BIF_DIR_LIST_BASE0; } else { return (EUR_CR_BIF_DIR_LIST_BASE1 + ((ui32Index - 1) * 0x4)); } } #endif void dsscomp_kdump(void); /*! ******************************************************************************* @Function SGXDumpDebugInfo @Description Dump useful debugging info @Input psDevInfo - SGX device info @Input bDumpSGXRegs - Whether to dump SGX debug registers. Must not be done when SGX is not powered. @Return IMG_VOID ******************************************************************************/ IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO *psDevInfo, IMG_BOOL bDumpSGXRegs) { IMG_UINT32 ui32CoreNum; dsscomp_kdump(); PVR_LOG(("SGX debug (%s)", PVRVERSION_STRING)); if (bDumpSGXRegs) { PVR_DPF((PVR_DBG_ERROR,"SGX Register Base Address (Linear): 0x%08X", (IMG_UINTPTR_T)psDevInfo->pvRegsBaseKM)); PVR_DPF((PVR_DBG_ERROR,"SGX Register Base Address (Physical): 0x%08X", psDevInfo->sRegsPhysBase.uiAddr)); SGXDumpDebugReg(psDevInfo, 0, "EUR_CR_CORE_ID: ", EUR_CR_CORE_ID); SGXDumpDebugReg(psDevInfo, 0, "EUR_CR_CORE_REVISION: ", EUR_CR_CORE_REVISION); #if defined(RESTRICTED_REGISTERS) && defined(SGX_FEATURE_MP) SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_BIF_INT_STAT: ", EUR_CR_MASTER_BIF_INT_STAT); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_BIF_FAULT: ",EUR_CR_MASTER_BIF_FAULT); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_CLKGATESTATUS2: ",EUR_CR_MASTER_CLKGATESTATUS2 ); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_PIM_STATUS: ",EUR_CR_MASTER_VDM_PIM_STATUS); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_BIF_BANK_SET: ",EUR_CR_MASTER_BIF_BANK_SET); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_EVENT_STATUS: ",EUR_CR_MASTER_EVENT_STATUS); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_EVENT_STATUS2: ",EUR_CR_MASTER_EVENT_STATUS2); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_MP_PRIMITIVE: ",EUR_CR_MASTER_MP_PRIMITIVE); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_DPM_DPLIST_STATUS: ",EUR_CR_MASTER_DPM_DPLIST_STATUS); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_DPM_PROACTIVE_PIM_SPEC: ",EUR_CR_MASTER_DPM_PROACTIVE_PIM_SPEC); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_PAGE_MANAGEOP: ",EUR_CR_MASTER_DPM_PAGE_MANAGEOP); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_STORE_SNAPSHOT: ",EUR_CR_MASTER_VDM_CONTEXT_STORE_SNAPSHOT); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_LOAD_STATUS: ",EUR_CR_MASTER_VDM_CONTEXT_LOAD_STATUS); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_STORE_STREAM: ",EUR_CR_MASTER_VDM_CONTEXT_STORE_STREAM); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_STORE_STATUS: ",EUR_CR_MASTER_VDM_CONTEXT_STORE_STATUS); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_STORE_STATE0: ",EUR_CR_MASTER_VDM_CONTEXT_STORE_STATE0); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_CONTEXT_STORE_STATE1: ",EUR_CR_MASTER_VDM_CONTEXT_STORE_STATE1); SGXDumpMasterDebugReg(psDevInfo, "EUR_CR_MASTER_VDM_WAIT_FOR_KICK: ",EUR_CR_MASTER_VDM_WAIT_FOR_KICK); #endif for (ui32CoreNum = 0; ui32CoreNum < SGX_FEATURE_MP_CORE_COUNT_3D; ui32CoreNum++) { /* Dump HW event status */ SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_STATUS: ", EUR_CR_EVENT_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_STATUS2: ", EUR_CR_EVENT_STATUS2); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_CTRL: ", EUR_CR_BIF_CTRL); #if defined(EUR_CR_BIF_BANK0) SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_BANK0: ", EUR_CR_BIF_BANK0); #endif SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_INT_STAT: ", EUR_CR_BIF_INT_STAT); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_FAULT: ", EUR_CR_BIF_FAULT); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_MEM_REQ_STAT: ", EUR_CR_BIF_MEM_REQ_STAT); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_CLKGATECTL: ", EUR_CR_CLKGATECTL); #if defined(EUR_CR_PDS_PC_BASE) SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_PDS_PC_BASE: ", EUR_CR_PDS_PC_BASE); #endif #if defined(RESTRICTED_REGISTERS) SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_BIF_BANK_SET: ", EUR_CR_BIF_BANK_SET); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_CLKGATECTL: ", EUR_CR_CLKGATECTL); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_CLKGATESTATUS: ", EUR_CR_CLKGATESTATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_MTE_CTRL: ", EUR_CR_MTE_CTRL); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_EXEC: ", EUR_CR_EVENT_OTHER_PDS_EXEC); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_DATA: ", EUR_CR_EVENT_OTHER_PDS_DATA); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_EVENT_OTHER_PDS_INFO: ", EUR_CR_EVENT_OTHER_PDS_INFO); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_ZLS_PAGE_THRESHOLD: ", EUR_CR_DPM_ZLS_PAGE_THRESHOLD); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_GLOBAL_LIST: ", EUR_CR_DPM_TA_GLOBAL_LIST); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_STATE_CONTEXT_ID: ", EUR_CR_DPM_STATE_CONTEXT_ID); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_CONTEXT_PB_BASE: ", EUR_CR_DPM_CONTEXT_PB_BASE); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS1: ", EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS1); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_3D_FREE_LIST_STATUS1: ", EUR_CR_DPM_3D_FREE_LIST_STATUS1); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS2: ", EUR_CR_DPM_TA_ALLOC_FREE_LIST_STATUS2); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_3D_FREE_LIST_STATUS2: ", EUR_CR_DPM_3D_FREE_LIST_STATUS2); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_ABORT_STATUS_MTILE: ", EUR_CR_DPM_ABORT_STATUS_MTILE); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_PAGE_STATUS: ", EUR_CR_DPM_PAGE_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_PAGE: ", EUR_CR_DPM_PAGE); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_GLOBAL_PAGE_STATUS: ", EUR_CR_DPM_GLOBAL_PAGE_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_LOAD_STATUS: ", EUR_CR_VDM_CONTEXT_LOAD_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATUS: ", EUR_CR_VDM_CONTEXT_STORE_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_TASK_KICK_STATUS: ", EUR_CR_VDM_TASK_KICK_STATUS); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATE0: ", EUR_CR_VDM_CONTEXT_STORE_STATE0); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_VDM_CONTEXT_STORE_STATE1: ", EUR_CR_VDM_CONTEXT_STORE_STATE1); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_REQUESTING: ", EUR_CR_DPM_REQUESTING); SGXDumpDebugReg(psDevInfo, ui32CoreNum, "EUR_CR_DPM_REQUESTING: ", EUR_CR_DPM_REQUESTING); #endif } #if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && !defined(FIX_HW_BRN_31620) { IMG_UINT32 ui32RegVal; IMG_UINT32 ui32PDDevPAddr; /* If there was a SGX pagefault check the page table too see if the host thinks the fault is correct */ ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_INT_STAT); if (ui32RegVal & EUR_CR_BIF_INT_STAT_PF_N_RW_MASK) { ui32RegVal = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_FAULT); ui32RegVal &= EUR_CR_BIF_FAULT_ADDR_MASK; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_DIR_LIST_BASE0); ui32PDDevPAddr &= EUR_CR_BIF_DIR_LIST_BASE0_ADDR_MASK; MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32RegVal); } } #else { IMG_UINT32 ui32FaultAddress; IMG_UINT32 ui32Bank0; IMG_UINT32 ui32DirListIndex; IMG_UINT32 ui32PDDevPAddr; ui32FaultAddress = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_FAULT); ui32FaultAddress = ui32FaultAddress & EUR_CR_BIF_FAULT_ADDR_MASK; ui32Bank0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_BANK0); /* Check the EDM's's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_EDM_MASK) >> EUR_CR_BIF_BANK0_INDEX_EDM_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking EDM memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); /* Check the TA's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_TA_MASK) >> EUR_CR_BIF_BANK0_INDEX_TA_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking TA memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); /* Check the 3D's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_3D_MASK) >> EUR_CR_BIF_BANK0_INDEX_3D_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking 3D memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); #if defined(EUR_CR_BIF_BANK0_INDEX_2D_MASK) /* Check the 2D's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_2D_MASK) >> EUR_CR_BIF_BANK0_INDEX_2D_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking 2D memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); #endif #if defined(EUR_CR_BIF_BANK0_INDEX_PTLA_MASK) /* Check the 2D's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_PTLA_MASK) >> EUR_CR_BIF_BANK0_INDEX_PTLA_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking PTLA memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); #endif #if defined(EUR_CR_BIF_BANK0_INDEX_HOST_MASK) /* Check the Host's memory context */ ui32DirListIndex = (ui32Bank0 & EUR_CR_BIF_BANK0_INDEX_HOST_MASK) >> EUR_CR_BIF_BANK0_INDEX_HOST_SHIFT; ui32PDDevPAddr = OSReadHWReg(psDevInfo->pvRegsBaseKM, GetDirListBaseReg(ui32DirListIndex)); PVR_LOG(("Checking Host memory context (index = %d, PD = 0x%08x)", ui32DirListIndex, ui32PDDevPAddr)); MMU_CheckFaultAddr(psDevInfo, ui32PDDevPAddr, ui32FaultAddress); #endif } #endif } /* Dump out the outstanding queue items. */ QueueDumpDebugInfo(); { /* Dump out the Host control. */ SGXMKIF_HOST_CTL *psSGXHostCtl = psDevInfo->psSGXHostCtl; IMG_UINT32 *pui32HostCtlBuffer = (IMG_UINT32 *)psSGXHostCtl; IMG_UINT32 ui32LoopCounter; if (psSGXHostCtl->ui32AssertFail != 0) { PVR_LOG(("SGX Microkernel assert fail: 0x%08X", psSGXHostCtl->ui32AssertFail)); psSGXHostCtl->ui32AssertFail = 0; } PVR_LOG(("SGX Host control:")); for (ui32LoopCounter = 0; ui32LoopCounter < sizeof(*psDevInfo->psSGXHostCtl) / sizeof(*pui32HostCtlBuffer); ui32LoopCounter += 4) { PVR_LOG(("\t(HC-%X) 0x%08X 0x%08X 0x%08X 0x%08X", ui32LoopCounter * sizeof(*pui32HostCtlBuffer), pui32HostCtlBuffer[ui32LoopCounter + 0], pui32HostCtlBuffer[ui32LoopCounter + 1], pui32HostCtlBuffer[ui32LoopCounter + 2], pui32HostCtlBuffer[ui32LoopCounter + 3])); } } { /* Dump out the TA/3D control. */ IMG_UINT32 *pui32TA3DCtlBuffer = psDevInfo->psKernelSGXTA3DCtlMemInfo->pvLinAddrKM; IMG_UINT32 ui32LoopCounter; PVR_LOG(("SGX TA/3D control:")); for (ui32LoopCounter = 0; ui32LoopCounter < psDevInfo->psKernelSGXTA3DCtlMemInfo->uAllocSize / sizeof(*pui32TA3DCtlBuffer); ui32LoopCounter += 4) { PVR_LOG(("\t(T3C-%X) 0x%08X 0x%08X 0x%08X 0x%08X", ui32LoopCounter * sizeof(*pui32TA3DCtlBuffer), pui32TA3DCtlBuffer[ui32LoopCounter + 0], pui32TA3DCtlBuffer[ui32LoopCounter + 1], pui32TA3DCtlBuffer[ui32LoopCounter + 2], pui32TA3DCtlBuffer[ui32LoopCounter + 3])); } } #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) { IMG_UINT32 *pui32MKTraceBuffer = psDevInfo->psKernelEDMStatusBufferMemInfo->pvLinAddrKM; IMG_UINT32 ui32LastStatusCode, ui32WriteOffset; ui32LastStatusCode = *pui32MKTraceBuffer; pui32MKTraceBuffer++; ui32WriteOffset = *pui32MKTraceBuffer; pui32MKTraceBuffer++; PVR_LOG(("Last SGX microkernel status code: %08X %s", ui32LastStatusCode, SGXUKernelStatusString(ui32LastStatusCode))); #if defined(PVRSRV_DUMP_MK_TRACE) /* Dump the raw microkernel trace buffer to the log. */ { IMG_UINT32 ui32LoopCounter; for (ui32LoopCounter = 0; ui32LoopCounter < SGXMK_TRACE_BUFFER_SIZE; ui32LoopCounter++) { IMG_UINT32 *pui32BufPtr; pui32BufPtr = pui32MKTraceBuffer + (((ui32WriteOffset + ui32LoopCounter) % SGXMK_TRACE_BUFFER_SIZE) * 4); PVR_LOG(("\t(MKT-%X) %08X %08X %08X %08X %s", ui32LoopCounter, pui32BufPtr[2], pui32BufPtr[3], pui32BufPtr[1], pui32BufPtr[0], SGXUKernelStatusString(pui32BufPtr[0]))); } } #endif /* PVRSRV_DUMP_MK_TRACE */ } #endif /* PVRSRV_USSE_EDM_STATUS_DEBUG */ { /* Dump out the kernel CCB. */ PVR_LOG(("SGX Kernel CCB WO:0x%X RO:0x%X", psDevInfo->psKernelCCBCtl->ui32WriteOffset, psDevInfo->psKernelCCBCtl->ui32ReadOffset)); #if defined(PVRSRV_DUMP_KERNEL_CCB) { IMG_UINT32 ui32LoopCounter; for (ui32LoopCounter = 0; ui32LoopCounter < sizeof(psDevInfo->psKernelCCB->asCommands) / sizeof(psDevInfo->psKernelCCB->asCommands[0]); ui32LoopCounter++) { SGXMKIF_COMMAND *psCommand = &psDevInfo->psKernelCCB->asCommands[ui32LoopCounter]; PVR_LOG(("\t(KCCB-%X) %08X %08X - %08X %08X %08X %08X", ui32LoopCounter, psCommand->ui32ServiceAddress, psCommand->ui32CacheControl, psCommand->ui32Data[0], psCommand->ui32Data[1], psCommand->ui32Data[2], psCommand->ui32Data[3])); } } #endif /* PVRSRV_DUMP_KERNEL_CCB */ } #if defined (TTRACE) PVRSRVDumpTimeTraceBuffers(); #endif } #if defined(SYS_USING_INTERRUPTS) || defined(SUPPORT_HW_RECOVERY) /*! ******************************************************************************* @Function HWRecoveryResetSGX @Description Resets SGX Note: may be called from an ISR so should not call pdump. @Input psDevInfo - dev info @Input ui32Component - core component to reset @Return IMG_VOID ******************************************************************************/ static IMG_VOID HWRecoveryResetSGX (PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32Component, IMG_UINT32 ui32CallerID) { PVRSRV_ERROR eError; PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psSGXHostCtl; #if defined(SUPPORT_HWRECOVERY_TRACE_LIMIT) static IMG_UINT32 ui32Clockinus = 0; static IMG_UINT32 ui32HWRecoveryCount=0; IMG_UINT32 ui32TempClockinus=0; #endif PVR_UNREFERENCED_PARAMETER(ui32Component); /* Debug dumps associated with HWR can be long. Delay system suspend */ SysLockSystemSuspend(); /* Ensure that hardware recovery is serialised with any power transitions. */ eError = PVRSRVPowerLock(ui32CallerID, IMG_FALSE); if(eError != PVRSRV_OK) { /* Unable to obtain lock because there is already a power transition in progress. */ PVR_DPF((PVR_DBG_WARNING,"HWRecoveryResetSGX: Power transition in progress")); return; } psSGXHostCtl->ui32InterruptClearFlags |= PVRSRV_USSE_EDM_INTERRUPT_HWR; PVR_LOG(("HWRecoveryResetSGX: SGX Hardware Recovery triggered")); #if defined(SUPPORT_HWRECOVERY_TRACE_LIMIT) /* * The following defines are system specific and should be defined in * the corresponding sysconfig.h file. The values indicated are examples only. SYS_SGX_HWRECOVERY_TRACE_RESET_TIME_PERIOD 5000000 //(5 Seconds) SYS_SGX_MAX_HWRECOVERY_OCCURANCE_COUNT 5 */ ui32TempClockinus = OSClockus(); if((ui32TempClockinus-ui32Clockinus) < SYS_SGX_HWRECOVERY_TRACE_RESET_TIME_PERIOD){ ui32HWRecoveryCount++; if(SYS_SGX_MAX_HWRECOVERY_OCCURANCE_COUNT <= ui32HWRecoveryCount){ OSPanic(); } }else{ ui32Clockinus = ui32TempClockinus; SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); ui32HWRecoveryCount = 0; } #else SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); #endif /* Suspend pdumping. */ PDUMPSUSPEND(); /* Reset and re-initialise SGX. */ eError = SGXInitialise(psDevInfo, IMG_TRUE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"HWRecoveryResetSGX: SGXInitialise failed (%d)", eError)); } /* Resume pdumping. */ PDUMPRESUME(); PVRSRVPowerUnlock(ui32CallerID); SysUnlockSystemSuspend(); /* Send a dummy kick so that we start processing again */ SGXScheduleProcessQueuesKM(psDeviceNode); /* Flush any old commands from the queues. */ PVRSRVProcessQueues(IMG_TRUE); } #endif /* #if defined(SYS_USING_INTERRUPTS) || defined(SUPPORT_HW_RECOVERY) */ #if defined(SUPPORT_HW_RECOVERY) /*! ****************************************************************************** @Function SGXOSTimer @Description Timer function for SGX @Input pvData - private data @Return PVRSRV_ERROR ******************************************************************************/ IMG_VOID SGXOSTimer(IMG_VOID *pvData) { PVRSRV_DEVICE_NODE *psDeviceNode = pvData; PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; static IMG_UINT32 ui32EDMTasks = 0; static IMG_UINT32 ui32LockupCounter = 0; /* To prevent false positives */ static IMG_UINT32 ui32OpenCLDelayCounter = 0; static IMG_UINT32 ui32NumResets = 0; #if defined(FIX_HW_BRN_31093) static IMG_BOOL bBRN31093Inval = IMG_FALSE; #endif IMG_UINT32 ui32CurrentEDMTasks; IMG_UINT32 ui32CurrentOpenCLDelayCounter=0; IMG_BOOL bLockup = IMG_FALSE; IMG_BOOL bPoweredDown; /* increment a timestamp */ psDevInfo->ui32TimeStamp++; #if defined(NO_HARDWARE) bPoweredDown = IMG_TRUE; #else bPoweredDown = (SGXIsDevicePowered(psDeviceNode)) ? IMG_FALSE : IMG_TRUE; #endif /* NO_HARDWARE */ /* * Check whether EDM timer tasks are getting scheduled. If not, assume * that SGX has locked up and reset the chip. */ /* Check whether the timer should be running */ if (bPoweredDown) { ui32LockupCounter = 0; #if defined(FIX_HW_BRN_31093) bBRN31093Inval = IMG_FALSE; #endif } else { /* The PDS timer should be running. */ ui32CurrentEDMTasks = OSReadHWReg(psDevInfo->pvRegsBaseKM, psDevInfo->ui32EDMTaskReg0); if (psDevInfo->ui32EDMTaskReg1 != 0) { ui32CurrentEDMTasks ^= OSReadHWReg(psDevInfo->pvRegsBaseKM, psDevInfo->ui32EDMTaskReg1); } if ((ui32CurrentEDMTasks == ui32EDMTasks) && (psDevInfo->ui32NumResets == ui32NumResets)) { ui32LockupCounter++; if (ui32LockupCounter == 3) { ui32LockupCounter = 0; ui32CurrentOpenCLDelayCounter = (psDevInfo->psSGXHostCtl)->ui32OpenCLDelayCount; if(0 != ui32CurrentOpenCLDelayCounter) { if(ui32OpenCLDelayCounter != ui32CurrentOpenCLDelayCounter){ ui32OpenCLDelayCounter = ui32CurrentOpenCLDelayCounter; }else{ ui32OpenCLDelayCounter -= 1; (psDevInfo->psSGXHostCtl)->ui32OpenCLDelayCount = ui32OpenCLDelayCounter; } goto SGX_NoUKernel_LockUp; } #if defined(FIX_HW_BRN_31093) if (bBRN31093Inval == IMG_FALSE) { /* It could be a BIF hang so do a INVAL_PTE */ #if defined(FIX_HW_BRN_29997) IMG_UINT32 ui32BIFCtrl; /* Pause the BIF before issuing the invalidate */ ui32BIFCtrl = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl | EUR_CR_BIF_CTRL_PAUSE_MASK); /* delay for 200 clocks */ SGXWaitClocks(psDevInfo, 200); #endif /* Flag that we have attempt to un-block the BIF */ bBRN31093Inval = IMG_TRUE; OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL_INVAL, EUR_CR_BIF_CTRL_INVAL_PTE_MASK); /* delay for 200 clocks */ SGXWaitClocks(psDevInfo, 200); #if defined(FIX_HW_BRN_29997) /* un-pause the BIF by restoring the BIF_CTRL */ OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BIF_CTRL, ui32BIFCtrl); #endif } else #endif { PVR_DPF((PVR_DBG_ERROR, "SGXOSTimer() detected SGX lockup (0x%x tasks)", ui32EDMTasks)); bLockup = IMG_TRUE; (psDevInfo->psSGXHostCtl)->ui32OpenCLDelayCount = 0; } } } else { #if defined(FIX_HW_BRN_31093) bBRN31093Inval = IMG_FALSE; #endif ui32LockupCounter = 0; ui32EDMTasks = ui32CurrentEDMTasks; ui32NumResets = psDevInfo->ui32NumResets; } } SGX_NoUKernel_LockUp: if (bLockup) { SGXMKIF_HOST_CTL *psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psSGXHostCtl; /* increment the counter so we know the host detected the lockup */ psSGXHostCtl->ui32HostDetectedLockups ++; /* Reset the chip and process the queues. */ HWRecoveryResetSGX(psDeviceNode, 0, ISR_ID); } } #endif /* defined(SUPPORT_HW_RECOVERY) */ #if defined(SYS_USING_INTERRUPTS) /* SGX ISR Handler */ IMG_BOOL SGX_ISRHandler (IMG_VOID *pvData) { IMG_BOOL bInterruptProcessed = IMG_FALSE; /* Real Hardware */ { IMG_UINT32 ui32EventStatus = 0, ui32EventEnable = 0; IMG_UINT32 ui32EventClear = 0; #if defined(SGX_FEATURE_DATA_BREAKPOINTS) IMG_UINT32 ui32EventStatus2, ui32EventEnable2; #endif IMG_UINT32 ui32EventClear2 = 0; PVRSRV_DEVICE_NODE *psDeviceNode; PVRSRV_SGXDEV_INFO *psDevInfo; /* check for null pointers */ if(pvData == IMG_NULL) { PVR_DPF((PVR_DBG_ERROR, "SGX_ISRHandler: Invalid params\n")); return bInterruptProcessed; } psDeviceNode = (PVRSRV_DEVICE_NODE *)pvData; psDevInfo = (PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice; if(!powering_down) { ui32EventStatus = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS); ui32EventEnable = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_ENABLE); } /* test only the unmasked bits */ ui32EventStatus &= ui32EventEnable; #if defined(SGX_FEATURE_DATA_BREAKPOINTS) if(!powering_down) { ui32EventStatus2 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_STATUS2); ui32EventEnable2 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_ENABLE2); } /* test only the unmasked bits */ ui32EventStatus2 &= ui32EventEnable2; #endif /* defined(SGX_FEATURE_DATA_BREAKPOINTS) */ /* Thought: is it better to insist that the bit assignment in the "clear" register(s) matches that of the "status" register(s)? It would greatly simplify this LISR */ if (ui32EventStatus & EUR_CR_EVENT_STATUS_SW_EVENT_MASK) { ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_SW_EVENT_MASK; } #if defined(SGX_FEATURE_DATA_BREAKPOINTS) if (ui32EventStatus2 & EUR_CR_EVENT_STATUS2_DATA_BREAKPOINT_UNTRAPPED_MASK) { ui32EventClear2 |= EUR_CR_EVENT_HOST_CLEAR2_DATA_BREAKPOINT_UNTRAPPED_MASK; } if (ui32EventStatus2 & EUR_CR_EVENT_STATUS2_DATA_BREAKPOINT_TRAPPED_MASK) { ui32EventClear2 |= EUR_CR_EVENT_HOST_CLEAR2_DATA_BREAKPOINT_TRAPPED_MASK; } #endif /* defined(SGX_FEATURE_DATA_BREAKPOINTS) */ if (ui32EventClear || ui32EventClear2) { bInterruptProcessed = IMG_TRUE; /* Clear master interrupt bit */ ui32EventClear |= EUR_CR_EVENT_HOST_CLEAR_MASTER_INTERRUPT_MASK; /* clear the events */ if(!powering_down) { OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR, ui32EventClear); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR2, ui32EventClear2); } /* Sample the current count from the uKernel _after_ we've cleared the interrupt. */ g_ui32HostIRQCountSample = psDevInfo->psSGXHostCtl->ui32InterruptCount; } } return bInterruptProcessed; } /* SGX MISR Handler */ static IMG_VOID SGX_MISRHandler (IMG_VOID *pvData) { PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE *)pvData; PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO*)psDeviceNode->pvDevice; SGXMKIF_HOST_CTL *psSGXHostCtl = (SGXMKIF_HOST_CTL *)psDevInfo->psSGXHostCtl; if (((psSGXHostCtl->ui32InterruptFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR) != 0UL) && ((psSGXHostCtl->ui32InterruptClearFlags & PVRSRV_USSE_EDM_INTERRUPT_HWR) == 0UL)) { HWRecoveryResetSGX(psDeviceNode, 0, ISR_ID); } #if defined(OS_SUPPORTS_IN_LISR) if (psDeviceNode->bReProcessDeviceCommandComplete) { SGXScheduleProcessQueuesKM(psDeviceNode); } #endif SGXTestActivePowerEvent(psDeviceNode, ISR_ID); } #endif /* #if defined (SYS_USING_INTERRUPTS) */ #if defined(SUPPORT_MEMORY_TILING) IMG_INTERNAL PVRSRV_ERROR SGX_AllocMemTilingRange(PVRSRV_DEVICE_NODE *psDeviceNode, PVRSRV_KERNEL_MEM_INFO *psMemInfo, IMG_UINT32 ui32XTileStride, IMG_UINT32 *pui32RangeIndex) { return SGX_AllocMemTilingRangeInt(psDeviceNode->pvDevice, psMemInfo->sDevVAddr.uiAddr, psMemInfo->sDevVAddr.uiAddr + ((IMG_UINT32) psMemInfo->uAllocSize) + SGX_MMU_PAGE_SIZE - 1, ui32XTileStride, pui32RangeIndex); } IMG_INTERNAL PVRSRV_ERROR SGX_FreeMemTilingRange(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_UINT32 ui32RangeIndex) { PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; IMG_UINT32 ui32Offset; IMG_UINT32 ui32Val; if(ui32RangeIndex >= 10) { PVR_DPF((PVR_DBG_ERROR,"SGX_FreeMemTilingRange: invalid Range index ")); return PVRSRV_ERROR_INVALID_PARAMS; } /* clear the usage bit */ psDevInfo->ui32MemTilingUsage &= ~(1<pvRegsBaseKM, ui32Offset, ui32Val); PDUMPREG(SGX_PDUMPREG_NAME, ui32Offset, ui32Val); return PVRSRV_OK; } #endif /* defined(SUPPORT_MEMORY_TILING) */ static IMG_VOID SGXCacheInvalidate(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; #if defined(SGX_FEATURE_MP) psDevInfo->ui32CacheControl |= SGXMKIF_CC_INVAL_BIF_SL; #else PVR_UNREFERENCED_PARAMETER(psDevInfo); #endif /* SGX_FEATURE_MP */ } /*! ******************************************************************************* @Function SGXRegisterDevice @Description Registers the device with the system @Input: psDeviceNode - device node @Return PVRSRV_ERROR : ******************************************************************************/ PVRSRV_ERROR SGXRegisterDevice (PVRSRV_DEVICE_NODE *psDeviceNode) { DEVICE_MEMORY_INFO *psDevMemoryInfo; DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; /* setup details that never change */ psDeviceNode->sDevId.eDeviceType = DEV_DEVICE_TYPE; psDeviceNode->sDevId.eDeviceClass = DEV_DEVICE_CLASS; #if defined(PDUMP) { /* memory space names are set up in system code */ SGX_DEVICE_MAP *psSGXDeviceMemMap; SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE_SGX, (IMG_VOID**)&psSGXDeviceMemMap); psDeviceNode->sDevId.pszPDumpDevName = psSGXDeviceMemMap->pszPDumpDevName; PVR_ASSERT(psDeviceNode->sDevId.pszPDumpDevName != IMG_NULL); } psDeviceNode->sDevId.pszPDumpRegName = SGX_PDUMPREG_NAME; #endif /* PDUMP */ psDeviceNode->pfnInitDevice = &DevInitSGXPart1; psDeviceNode->pfnDeInitDevice = &DevDeInitSGX; psDeviceNode->pfnInitDeviceCompatCheck = &SGXDevInitCompatCheck; #if defined(PDUMP) psDeviceNode->pfnPDumpInitDevice = &SGXResetPDump; psDeviceNode->pfnMMUGetContextID = &MMU_GetPDumpContextID; #endif /* MMU callbacks */ psDeviceNode->pfnMMUInitialise = &MMU_Initialise; psDeviceNode->pfnMMUFinalise = &MMU_Finalise; psDeviceNode->pfnMMUInsertHeap = &MMU_InsertHeap; psDeviceNode->pfnMMUCreate = &MMU_Create; psDeviceNode->pfnMMUDelete = &MMU_Delete; psDeviceNode->pfnMMUAlloc = &MMU_Alloc; psDeviceNode->pfnMMUFree = &MMU_Free; psDeviceNode->pfnMMUMapPages = &MMU_MapPages; psDeviceNode->pfnMMUMapShadow = &MMU_MapShadow; psDeviceNode->pfnMMUUnmapPages = &MMU_UnmapPages; psDeviceNode->pfnMMUMapScatter = &MMU_MapScatter; psDeviceNode->pfnMMUGetPhysPageAddr = &MMU_GetPhysPageAddr; psDeviceNode->pfnMMUGetPDDevPAddr = &MMU_GetPDDevPAddr; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) psDeviceNode->pfnMMUIsHeapShared = &MMU_IsHeapShared; #endif #if defined(FIX_HW_BRN_31620) psDeviceNode->pfnMMUGetCacheFlushRange = &MMU_GetCacheFlushRange; psDeviceNode->pfnMMUGetPDPhysAddr = &MMU_GetPDPhysAddr; #else psDeviceNode->pfnMMUGetCacheFlushRange = IMG_NULL; psDeviceNode->pfnMMUGetPDPhysAddr = IMG_NULL; #endif psDeviceNode->pfnMMUMapPagesSparse = &MMU_MapPagesSparse; psDeviceNode->pfnMMUMapShadowSparse = &MMU_MapShadowSparse; #if defined (SYS_USING_INTERRUPTS) /* SGX ISR handler */ psDeviceNode->pfnDeviceISR = SGX_ISRHandler; psDeviceNode->pfnDeviceMISR = SGX_MISRHandler; #endif #if defined(SUPPORT_MEMORY_TILING) psDeviceNode->pfnAllocMemTilingRange = SGX_AllocMemTilingRange; psDeviceNode->pfnFreeMemTilingRange = SGX_FreeMemTilingRange; #endif /* SGX command complete handler */ psDeviceNode->pfnDeviceCommandComplete = &SGXCommandComplete; psDeviceNode->pfnCacheInvalidate = SGXCacheInvalidate; /* and setup the device's memory map: */ psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; /* size of address space */ psDevMemoryInfo->ui32AddressSpaceSizeLog2 = SGX_FEATURE_ADDRESS_SPACE_SIZE; /* flags, backing store details to be specified by system */ psDevMemoryInfo->ui32Flags = 0; /* device memory heap info about each heap in a device address space */ if(OSAllocMem( PVRSRV_OS_PAGEABLE_HEAP, sizeof(DEVICE_MEMORY_HEAP_INFO) * SGX_MAX_HEAP_ID, (IMG_VOID **)&psDevMemoryInfo->psDeviceMemoryHeap, 0, "Array of Device Memory Heap Info") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR,"SGXRegisterDevice : Failed to alloc memory for DEVICE_MEMORY_HEAP_INFO")); return (PVRSRV_ERROR_OUT_OF_MEMORY); } OSMemSet(psDevMemoryInfo->psDeviceMemoryHeap, 0, sizeof(DEVICE_MEMORY_HEAP_INFO) * SGX_MAX_HEAP_ID); psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; /* setup heaps Note: backing store to be setup by system (defaults to UMA) */ /************* general ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_GENERAL_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_GENERAL_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "General"; psDeviceMemoryHeap->pszBSName = "General BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; #if !defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) /* specify the mapping heap ID for this device */ psDevMemoryInfo->ui32MappingHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); #endif psDeviceMemoryHeap++;/* advance to the next heap */ #if defined(SUPPORT_MEMORY_TILING) /************* VPB tiling ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_VPB_TILED_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_VPB_TILED_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_VPB_TILED_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "VPB Tiled"; psDeviceMemoryHeap->pszBSName = "VPB Tiled BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap->ui32XTileStride = SGX_VPB_TILED_HEAP_STRIDE; PVR_DPF((PVR_DBG_WARNING, "VPB tiling heap tiling stride = 0x%x", psDeviceMemoryHeap->ui32XTileStride)); psDeviceMemoryHeap++;/* advance to the next heap */ #endif #if defined(SUPPORT_ION) /************* Ion Heap ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_ION_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_ION_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_ION_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "Ion"; psDeviceMemoryHeap->pszBSName = "Ion BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* specify the ion heap ID for this device */ psDevMemoryInfo->ui32IonHeapID = SGX_ION_HEAP_ID; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ #endif /************* TA data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_TADATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_TADATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_TADATA_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->pszName = "TA Data"; psDeviceMemoryHeap->pszBSName = "TA Data BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* kernel code ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_CODE_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_KERNEL_CODE_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_KERNEL_CODE_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->pszName = "Kernel Code"; psDeviceMemoryHeap->pszBSName = "Kernel Code BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* Kernel Video Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_KERNEL_DATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_KERNEL_DATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_KERNEL_DATA_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->pszName = "KernelData"; psDeviceMemoryHeap->pszBSName = "KernelData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* PixelShaderUSSE ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PIXELSHADER_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PIXELSHADER_HEAP_BASE; /* The actual size of the pixel and vertex shader heap must be such that all addresses are within range of the one of the USSE code base registers, but the addressable range is hardware-dependent. SGX_PIXELSHADER_HEAP_SIZE is defined to be the maximum possible size to ensure that the heap layout is consistent across all SGXs. */ psDeviceMemoryHeap->ui32HeapSize = ((10 << SGX_USE_CODE_SEGMENT_RANGE_BITS) - 0x00001000); PVR_ASSERT(psDeviceMemoryHeap->ui32HeapSize <= SGX_PIXELSHADER_HEAP_SIZE); psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "PixelShaderUSSE"; psDeviceMemoryHeap->pszBSName = "PixelShaderUSSE BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* VertexShaderUSSE ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_VERTEXSHADER_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_VERTEXSHADER_HEAP_BASE; /* See comment above with PixelShaderUSSE ui32HeapSize */ psDeviceMemoryHeap->ui32HeapSize = ((4 << SGX_USE_CODE_SEGMENT_RANGE_BITS) - 0x00001000); PVR_ASSERT(psDeviceMemoryHeap->ui32HeapSize <= SGX_VERTEXSHADER_HEAP_SIZE); psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "VertexShaderUSSE"; psDeviceMemoryHeap->pszBSName = "VertexShaderUSSE BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* PDS Pixel Code/Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSPIXEL_CODEDATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PDSPIXEL_CODEDATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PDSPIXEL_CODEDATA_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "PDSPixelCodeData"; psDeviceMemoryHeap->pszBSName = "PDSPixelCodeData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* PDS Vertex Code/Data ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PDSVERTEX_CODEDATA_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PDSVERTEX_CODEDATA_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PDSVERTEX_CODEDATA_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "PDSVertexCodeData"; psDeviceMemoryHeap->pszBSName = "PDSVertexCodeData BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* CacheCoherent ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SYNCINFO_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_SYNCINFO_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_SYNCINFO_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->pszName = "CacheCoherent"; psDeviceMemoryHeap->pszBSName = "CacheCoherent BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; /* set the sync heap id */ psDevMemoryInfo->ui32SyncHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); psDeviceMemoryHeap++;/* advance to the next heap */ /************* Shared 3D Parameters ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_SHARED_3DPARAMETERS_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_SHARED_3DPARAMETERS_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_SHARED_3DPARAMETERS_HEAP_SIZE; psDeviceMemoryHeap->pszName = "Shared 3DParameters"; psDeviceMemoryHeap->pszBSName = "Shared 3DParameters BS"; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ /************* Percontext 3D Parameters ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_PERCONTEXT_3DPARAMETERS_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_PERCONTEXT_3DPARAMETERS_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_PERCONTEXT_3DPARAMETERS_HEAP_SIZE; psDeviceMemoryHeap->pszName = "Percontext 3DParameters"; psDeviceMemoryHeap->pszBSName = "Percontext 3DParameters BS"; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) /************* General Mapping ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_GENERAL_MAPPING_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_GENERAL_MAPPING_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_GENERAL_MAPPING_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_MULTI_PROCESS; psDeviceMemoryHeap->pszName = "GeneralMapping"; psDeviceMemoryHeap->pszBSName = "GeneralMapping BS"; #if defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) /* if((2D hardware is enabled) && (multi-mem contexts enabled) && (BRN23410 is present)) - then don't make the heap per-context otherwise the TA and 2D requestors must always be aligned to the same address space which could affect performance */ psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; #else /* defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) */ psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_PERCONTEXT; #endif /* defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) && defined(FIX_HW_BRN_23410) */ /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; /* specify the mapping heap ID for this device */ psDevMemoryInfo->ui32MappingHeapID = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); psDeviceMemoryHeap++;/* advance to the next heap */ #endif /* #if defined(SUPPORT_SGX_GENERAL_MAPPING_HEAP) */ #if defined(SGX_FEATURE_2D_HARDWARE) /************* 2D HW Heap ***************/ psDeviceMemoryHeap->ui32HeapID = HEAP_ID( PVRSRV_DEVICE_TYPE_SGX, SGX_2D_HEAP_ID); psDeviceMemoryHeap->sDevVAddrBase.uiAddr = SGX_2D_HEAP_BASE; psDeviceMemoryHeap->ui32HeapSize = SGX_2D_HEAP_SIZE; psDeviceMemoryHeap->ui32Attribs = PVRSRV_HAP_WRITECOMBINE | PVRSRV_MEM_RAM_BACKED_ALLOCATION | PVRSRV_HAP_SINGLE_PROCESS; psDeviceMemoryHeap->pszName = "2D"; psDeviceMemoryHeap->pszBSName = "2D BS"; psDeviceMemoryHeap->DevMemHeapType = DEVICE_MEMORY_HEAP_SHARED_EXPORTED; /* set the default (4k). System can override these as required */ psDeviceMemoryHeap->ui32DataPageSize = SGX_MMU_PAGE_SIZE; psDeviceMemoryHeap++;/* advance to the next heap */ #endif /* #if defined(SGX_FEATURE_2D_HARDWARE) */ /* set the heap count */ psDevMemoryInfo->ui32HeapCount = (IMG_UINT32)(psDeviceMemoryHeap - psDevMemoryInfo->psDeviceMemoryHeap); return PVRSRV_OK; } #if defined(PDUMP) static PVRSRV_ERROR SGXResetPDump(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *)(psDeviceNode->pvDevice); psDevInfo->psKernelCCBInfo->ui32CCBDumpWOff = 0; PVR_DPF((PVR_DBG_MESSAGE, "Reset pdump CCB write offset.")); return PVRSRV_OK; } #endif /* PDUMP */ /*! ******************************************************************************* @Function SGXGetClientInfoKM @Description Gets the client information @Input hDevCookie @Output psClientInfo @Return PVRSRV_ERROR : ******************************************************************************/ IMG_EXPORT PVRSRV_ERROR SGXGetClientInfoKM(IMG_HANDLE hDevCookie, SGX_CLIENT_INFO* psClientInfo) { PVRSRV_SGXDEV_INFO *psDevInfo = (PVRSRV_SGXDEV_INFO *)((PVRSRV_DEVICE_NODE *)hDevCookie)->pvDevice; /* If this is the first client to connect to SGX perform initialisation */ psDevInfo->ui32ClientRefCount++; /* Copy information to the client info. */ psClientInfo->ui32ProcessID = OSGetCurrentProcessIDKM(); /* Copy requested information. */ OSMemCopy(&psClientInfo->asDevData, &psDevInfo->asSGXDevData, sizeof(psClientInfo->asDevData)); /* just return OK */ return PVRSRV_OK; } /*! ******************************************************************************* @Function SGXPanic @Description Called when an unrecoverable situation is detected. Dumps SGX debug information and tells the OS to panic. @Input psDevInfo - SGX device info @Return IMG_VOID ******************************************************************************/ IMG_VOID SGXPanic(PVRSRV_SGXDEV_INFO *psDevInfo) { PVR_LOG(("SGX panic")); SGXDumpDebugInfo(psDevInfo, IMG_FALSE); OSPanic(); } /*! ******************************************************************************* @Function SGXDevInitCompatCheck @Description Check compatibility of host driver and microkernel (DDK and build options) for SGX devices at services/device initialisation @Input psDeviceNode - device node @Return PVRSRV_ERROR - depending on mismatch found ******************************************************************************/ PVRSRV_ERROR SGXDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode) { PVRSRV_ERROR eError; PVRSRV_SGXDEV_INFO *psDevInfo; IMG_UINT32 ui32BuildOptions, ui32BuildOptionsMismatch; #if !defined(NO_HARDWARE) PPVRSRV_KERNEL_MEM_INFO psMemInfo; PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; /*!< internal misc info for ukernel */ PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; /*!< microkernel structure sizes */ IMG_BOOL bStructSizesFailed; /* Exceptions list for core rev check, format is pairs of (hw rev, sw rev) */ IMG_BOOL bCheckCoreRev; const IMG_UINT32 aui32CoreRevExceptions[] = { 0x10100, 0x10101 }; const IMG_UINT32 ui32NumCoreExceptions = sizeof(aui32CoreRevExceptions) / (2*sizeof(IMG_UINT32)); IMG_UINT i; #endif /* Ensure it's a SGX device */ if(psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_SGX) { PVR_LOG(("(FAIL) SGXInit: Device not of type SGX")); eError = PVRSRV_ERROR_INVALID_PARAMS; goto chk_exit; } psDevInfo = psDeviceNode->pvDevice; /* * 1. Check kernel-side and client-side build options * 2. Ensure ukernel DDK version and driver DDK version are compatible * 3. Check ukernel build options against kernel-side build options */ /* * Check KM build options against client-side host driver */ ui32BuildOptions = (SGX_BUILD_OPTIONS); if (ui32BuildOptions != psDevInfo->ui32ClientBuildOptions) { ui32BuildOptionsMismatch = ui32BuildOptions ^ psDevInfo->ui32ClientBuildOptions; if ( (psDevInfo->ui32ClientBuildOptions & ui32BuildOptionsMismatch) != 0) { PVR_LOG(("(FAIL) SGXInit: Mismatch in client-side and KM driver build options; " "extra options present in client-side driver: (0x%x). Please check sgx_options.h", psDevInfo->ui32ClientBuildOptions & ui32BuildOptionsMismatch )); } if ( (ui32BuildOptions & ui32BuildOptionsMismatch) != 0) { PVR_LOG(("(FAIL) SGXInit: Mismatch in client-side and KM driver build options; " "extra options present in KM: (0x%x). Please check sgx_options.h", ui32BuildOptions & ui32BuildOptionsMismatch )); } eError = PVRSRV_ERROR_BUILD_MISMATCH; goto chk_exit; } else { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: Client-side and KM driver build options match. [ OK ]")); } #if !defined (NO_HARDWARE) psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; /* Clear state (not strictly necessary since this is the first call) */ psSGXMiscInfoInt = psMemInfo->pvLinAddrKM; psSGXMiscInfoInt->ui32MiscInfoFlags = 0; psSGXMiscInfoInt->ui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_GET_STRUCT_SIZES; eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode, IMG_NULL); /* * Validate DDK version */ if(eError != PVRSRV_OK) { PVR_LOG(("(FAIL) SGXInit: Unable to validate device DDK version")); goto chk_exit; } psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; if( (psSGXFeatures->ui32DDKVersion != ((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) | PVRVERSION_BRANCH) ) || (psSGXFeatures->ui32DDKBuild != PVRVERSION_BUILD) ) { PVR_LOG(("(FAIL) SGXInit: Incompatible driver DDK revision (%d)/device DDK revision (%d).", PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild)); eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH; goto chk_exit; } else { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: driver DDK (%d) and device DDK (%d) match. [ OK ]", PVRVERSION_BUILD, psSGXFeatures->ui32DDKBuild)); } /* * Check hardware core revision is compatible with the one in software */ if (psSGXFeatures->ui32CoreRevSW == 0) { /* Head core revision cannot be checked. */ PVR_LOG(("SGXInit: HW core rev (%x) check skipped.", psSGXFeatures->ui32CoreRev)); } else { /* For some cores the hw/sw core revisions are expected not to match. For these * exceptional cases the core rev compatibility check should be skipped. */ bCheckCoreRev = IMG_TRUE; for(i=0; iui32CoreRev==aui32CoreRevExceptions[i]) && (psSGXFeatures->ui32CoreRevSW==aui32CoreRevExceptions[i+1]) ) { PVR_LOG(("SGXInit: HW core rev (%x), SW core rev (%x) check skipped.", psSGXFeatures->ui32CoreRev, psSGXFeatures->ui32CoreRevSW)); bCheckCoreRev = IMG_FALSE; } } if (bCheckCoreRev) { if (psSGXFeatures->ui32CoreRev != psSGXFeatures->ui32CoreRevSW) { PVR_LOG(("(FAIL) SGXInit: Incompatible HW core rev (%x) and SW core rev (%x).", psSGXFeatures->ui32CoreRev, psSGXFeatures->ui32CoreRevSW)); eError = PVRSRV_ERROR_BUILD_MISMATCH; goto chk_exit; } else { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: HW core rev (%x) and SW core rev (%x) match. [ OK ]", psSGXFeatures->ui32CoreRev, psSGXFeatures->ui32CoreRevSW)); } } } /* * Check ukernel structure sizes are the same as those in the driver */ psSGXStructSizes = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXStructSizes; bStructSizesFailed = IMG_FALSE; CHECK_SIZE(HOST_CTL); CHECK_SIZE(COMMAND); #if defined(SGX_FEATURE_2D_HARDWARE) CHECK_SIZE(2DCMD); CHECK_SIZE(2DCMD_SHARED); #endif CHECK_SIZE(CMDTA); CHECK_SIZE(CMDTA_SHARED); CHECK_SIZE(TRANSFERCMD); CHECK_SIZE(TRANSFERCMD_SHARED); CHECK_SIZE(3DREGISTERS); CHECK_SIZE(HWPBDESC); CHECK_SIZE(HWRENDERCONTEXT); CHECK_SIZE(HWRENDERDETAILS); CHECK_SIZE(HWRTDATA); CHECK_SIZE(HWRTDATASET); CHECK_SIZE(HWTRANSFERCONTEXT); if (bStructSizesFailed == IMG_TRUE) { PVR_LOG(("(FAIL) SGXInit: Mismatch in SGXMKIF structure sizes.")); eError = PVRSRV_ERROR_BUILD_MISMATCH; goto chk_exit; } else { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: SGXMKIF structure sizes match. [ OK ]")); } /* * Check ukernel build options against KM host driver */ ui32BuildOptions = psSGXFeatures->ui32BuildOptions; if (ui32BuildOptions != (SGX_BUILD_OPTIONS)) { ui32BuildOptionsMismatch = ui32BuildOptions ^ (SGX_BUILD_OPTIONS); if ( ((SGX_BUILD_OPTIONS) & ui32BuildOptionsMismatch) != 0) { PVR_LOG(("(FAIL) SGXInit: Mismatch in driver and microkernel build options; " "extra options present in driver: (0x%x). Please check sgx_options.h", (SGX_BUILD_OPTIONS) & ui32BuildOptionsMismatch )); } if ( (ui32BuildOptions & ui32BuildOptionsMismatch) != 0) { PVR_LOG(("(FAIL) SGXInit: Mismatch in driver and microkernel build options; " "extra options present in microkernel: (0x%x). Please check sgx_options.h", ui32BuildOptions & ui32BuildOptionsMismatch )); } eError = PVRSRV_ERROR_BUILD_MISMATCH; goto chk_exit; } else { PVR_DPF((PVR_DBG_MESSAGE, "SGXInit: Driver and microkernel build options match. [ OK ]")); } #endif // NO_HARDWARE eError = PVRSRV_OK; chk_exit: #if defined(IGNORE_SGX_INIT_COMPATIBILITY_CHECK) return PVRSRV_OK; #else return eError; #endif } /* * @Function SGXGetMiscInfoUkernel * * @Description Returns misc info (e.g. SGX build info/flags) from microkernel * * @Input psDevInfo : device info from init phase * @Input psDeviceNode : device node, used for scheduling ukernel to query SGX features * * @Return PVRSRV_ERROR : * */ static PVRSRV_ERROR SGXGetMiscInfoUkernel(PVRSRV_SGXDEV_INFO *psDevInfo, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext) { PVRSRV_ERROR eError; SGXMKIF_COMMAND sCommandData; /* CCB command data */ PVRSRV_SGX_MISCINFO_INFO *psSGXMiscInfoInt; /*!< internal misc info for ukernel */ PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; /*!< sgx features for client */ SGX_MISCINFO_STRUCT_SIZES *psSGXStructSizes; /*!< internal info: microkernel structure sizes */ PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; if (! psMemInfo->pvLinAddrKM) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoUkernel: Invalid address.")); return PVRSRV_ERROR_INVALID_PARAMS; } psSGXMiscInfoInt = psMemInfo->pvLinAddrKM; psSGXFeatures = &psSGXMiscInfoInt->sSGXFeatures; psSGXStructSizes = &psSGXMiscInfoInt->sSGXStructSizes; psSGXMiscInfoInt->ui32MiscInfoFlags &= ~PVRSRV_USSE_MISCINFO_READY; /* Reset SGX features */ OSMemSet(psSGXFeatures, 0, sizeof(*psSGXFeatures)); OSMemSet(psSGXStructSizes, 0, sizeof(*psSGXStructSizes)); /* set up buffer address for SGX features in CCB */ sCommandData.ui32Data[1] = psMemInfo->sDevVAddr.uiAddr; /* device V addr of output buffer */ PDUMPCOMMENT("Microkernel kick for SGXGetMiscInfo"); eError = SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_CMD_GETMISCINFO, &sCommandData, KERNEL_ID, 0, hDevMemContext, IMG_FALSE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoUkernel: SGXScheduleCCBCommandKM failed.")); return eError; } /* FIXME: DWORD value to determine code path in ukernel? * E.g. could use getMiscInfo to obtain register values for diagnostics? */ #if !defined(NO_HARDWARE) { IMG_BOOL bExit; bExit = IMG_FALSE; LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { if ((psSGXMiscInfoInt->ui32MiscInfoFlags & PVRSRV_USSE_MISCINFO_READY) != 0) { bExit = IMG_TRUE; break; } } END_LOOP_UNTIL_TIMEOUT(); /*if the loop exited because a timeout*/ if (!bExit) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoUkernel: Timeout occurred waiting for misc info.")); return PVRSRV_ERROR_TIMEOUT; } } #endif /* NO_HARDWARE */ return PVRSRV_OK; } /* * @Function SGXGetMiscInfoKM * * @Description Returns miscellaneous SGX info * * @Input psDevInfo : device info from init phase * @Input psDeviceNode : device node, used for scheduling ukernel to query SGX features * * @Output psMiscInfo : query request plus user-mode mem for holding returned data * * @Return PVRSRV_ERROR : * */ IMG_EXPORT PVRSRV_ERROR SGXGetMiscInfoKM(PVRSRV_SGXDEV_INFO *psDevInfo, SGX_MISC_INFO *psMiscInfo, PVRSRV_DEVICE_NODE *psDeviceNode, IMG_HANDLE hDevMemContext) { PVRSRV_ERROR eError; PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; IMG_UINT32 *pui32MiscInfoFlags = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->ui32MiscInfoFlags; /* Reset the misc info state flags */ *pui32MiscInfoFlags = 0; #if !defined(SUPPORT_SGX_EDM_MEMORY_DEBUG) PVR_UNREFERENCED_PARAMETER(hDevMemContext); #endif switch(psMiscInfo->eRequest) { #if defined(SGX_FEATURE_DATA_BREAKPOINTS) case SGX_MISC_INFO_REQUEST_SET_BREAKPOINT: { IMG_UINT32 ui32MaskDM; IMG_UINT32 ui32CtrlWEnable; IMG_UINT32 ui32CtrlREnable; IMG_UINT32 ui32CtrlTrapEnable; IMG_UINT32 ui32RegVal; IMG_UINT32 ui32StartRegVal; IMG_UINT32 ui32EndRegVal; SGXMKIF_COMMAND sCommandData; /* Set or Clear BP? */ if(psMiscInfo->uData.sSGXBreakpointInfo.bBPEnable) { /* set the break point */ IMG_DEV_VIRTADDR sBPDevVAddr = psMiscInfo->uData.sSGXBreakpointInfo.sBPDevVAddr; IMG_DEV_VIRTADDR sBPDevVAddrEnd = psMiscInfo->uData.sSGXBreakpointInfo.sBPDevVAddrEnd; /* BP address */ ui32StartRegVal = sBPDevVAddr.uiAddr & EUR_CR_BREAKPOINT0_START_ADDRESS_MASK; ui32EndRegVal = sBPDevVAddrEnd.uiAddr & EUR_CR_BREAKPOINT0_END_ADDRESS_MASK; ui32MaskDM = psMiscInfo->uData.sSGXBreakpointInfo.ui32DataMasterMask; ui32CtrlWEnable = psMiscInfo->uData.sSGXBreakpointInfo.bWrite; ui32CtrlREnable = psMiscInfo->uData.sSGXBreakpointInfo.bRead; ui32CtrlTrapEnable = psMiscInfo->uData.sSGXBreakpointInfo.bTrapped; /* normal data BP */ ui32RegVal = ((ui32MaskDM<uData.sSGXBreakpointInfo.ui32BPIndex; sCommandData.ui32Data[1] = ui32StartRegVal; sCommandData.ui32Data[2] = ui32EndRegVal; sCommandData.ui32Data[3] = ui32RegVal; /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; PDUMPCOMMENT("Microkernel kick for setting a data breakpoint"); eError = SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_CMD_DATABREAKPOINT, &sCommandData, KERNEL_ID, 0, hDevMemContext, IMG_FALSE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoKM: SGXScheduleCCBCommandKM failed.")); return eError; } #if defined(NO_HARDWARE) /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; #else { IMG_BOOL bExit; bExit = IMG_FALSE; LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { if (psDevInfo->psSGXHostCtl->ui32BPSetClearSignal != 0) { bExit = IMG_TRUE; /* clear signal flags */ psDevInfo->psSGXHostCtl->ui32BPSetClearSignal = 0; break; } } END_LOOP_UNTIL_TIMEOUT(); /*if the loop exited because a timeout*/ if (!bExit) { PVR_DPF((PVR_DBG_ERROR, "SGXGetMiscInfoKM: Timeout occurred waiting BP set/clear")); return PVRSRV_ERROR_TIMEOUT; } } #endif /* NO_HARDWARE */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_POLL_BREAKPOINT: { /* This request checks to see whether a breakpoint has been trapped. If so, it returns the number of the breakpoint number that was trapped in ui32BPIndex, sTrappedBPDevVAddr to the address which was trapped, and sets bTrappedBP. Otherwise, bTrappedBP will be false, and other fields should be ignored. */ /* The uKernel is not used, since if we are stopped on a breakpoint, it is not possible to guarantee that the uKernel would be able to run */ #if !defined(NO_HARDWARE) #if defined(SGX_FEATURE_MP) IMG_BOOL bTrappedBPMaster; IMG_UINT32 ui32CoreNum, ui32TrappedBPCoreNum; #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) IMG_UINT32 ui32PipeNum, ui32TrappedBPPipeNum; /* ui32PipeNum is the pipe number plus 1, or 0 to represent "partition" */ #define NUM_PIPES_PLUS_ONE (SGX_FEATURE_PERPIPE_BKPT_REGS_NUMPIPES+1) #endif IMG_BOOL bTrappedBPAny; #endif /* defined(SGX_FEATURE_MP) */ IMG_BOOL bFoundOne; #if defined(SGX_FEATURE_MP) ui32TrappedBPCoreNum = 0; bTrappedBPMaster = !!(EUR_CR_MASTER_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT)); bTrappedBPAny = bTrappedBPMaster; #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32TrappedBPPipeNum = 0; /* just to keep the (incorrect) compiler happy */ #endif for (ui32CoreNum = 0; ui32CoreNum < SGX_FEATURE_MP_CORE_COUNT_3D; ui32CoreNum++) { #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) /* FIXME: this macro makes the assumption that the PARTITION regs are the same distance before the PIPE0 regs as the PIPE1 regs are after it, _and_ assumes that the fields in the partition regs are in the same place in the pipe regs. Need to validate these assumptions, or assert them */ #define SGX_MP_CORE_PIPE_SELECT(r,c,p) \ ((SGX_MP_CORE_SELECT(EUR_CR_PARTITION_##r,c) + p*(EUR_CR_PIPE0_##r-EUR_CR_PARTITION_##r))) for (ui32PipeNum = 0; ui32PipeNum < NUM_PIPES_PLUS_ONE; ui32PipeNum++) { bFoundOne = 0 != (EUR_CR_PARTITION_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT, ui32CoreNum, ui32PipeNum))); if (bFoundOne) { bTrappedBPAny = IMG_TRUE; ui32TrappedBPCoreNum = ui32CoreNum; ui32TrappedBPPipeNum = ui32PipeNum; } } #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ bFoundOne = !!(EUR_CR_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum))); if (bFoundOne) { bTrappedBPAny = IMG_TRUE; ui32TrappedBPCoreNum = ui32CoreNum; } #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ } psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP = bTrappedBPAny; #else /* defined(SGX_FEATURE_MP) */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) #error Not yet considered the case for per-pipe regs in non-mp case #endif psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP = 0 != (EUR_CR_BREAKPOINT_TRAPPED_MASK & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT)); #endif /* defined(SGX_FEATURE_MP) */ if (psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBP) { IMG_UINT32 ui32Info0, ui32Info1; #if defined(SGX_FEATURE_MP) #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0:SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP_INFO0, ui32TrappedBPCoreNum, ui32TrappedBPPipeNum)); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1:SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP_INFO1, ui32TrappedBPCoreNum, ui32TrappedBPPipeNum)); #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO0:SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP_INFO0, ui32TrappedBPCoreNum)); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, bTrappedBPMaster?EUR_CR_MASTER_BREAKPOINT_TRAP_INFO1:SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP_INFO1, ui32TrappedBPCoreNum)); #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ #else /* defined(SGX_FEATURE_MP) */ ui32Info0 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT_TRAP_INFO0); ui32Info1 = OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_BREAKPOINT_TRAP_INFO1); #endif /* defined(SGX_FEATURE_MP) */ #ifdef SGX_FEATURE_PERPIPE_BKPT_REGS psMiscInfo->uData.sSGXBreakpointInfo.ui32BPIndex = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_NUMBER_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_NUMBER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.sTrappedBPDevVAddr.uiAddr = ui32Info0 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPBurstLength = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_SIZE_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBPRead = !!(ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_RNW_MASK); psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPDataMaster = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_DATA_MASTER_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_DATA_MASTER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPTag = (ui32Info1 & EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_TAG_MASK) >> EUR_CR_PARTITION_BREAKPOINT_TRAP_INFO1_TAG_SHIFT; #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ psMiscInfo->uData.sSGXBreakpointInfo.ui32BPIndex = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_NUMBER_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_NUMBER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.sTrappedBPDevVAddr.uiAddr = ui32Info0 & EUR_CR_BREAKPOINT_TRAP_INFO0_ADDRESS_MASK; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPBurstLength = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_SIZE_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_SIZE_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.bTrappedBPRead = !!(ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_RNW_MASK); psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPDataMaster = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_DATA_MASTER_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_DATA_MASTER_SHIFT; psMiscInfo->uData.sSGXBreakpointInfo.ui32TrappedBPTag = (ui32Info1 & EUR_CR_BREAKPOINT_TRAP_INFO1_TAG_MASK) >> EUR_CR_BREAKPOINT_TRAP_INFO1_TAG_SHIFT; #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ #if defined(SGX_FEATURE_MP) #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) /* mp, per-pipe regbanks */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = bTrappedBPMaster?65535:(ui32TrappedBPCoreNum + (ui32TrappedBPPipeNum<<10)); #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ /* mp, regbanks unsplit */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = bTrappedBPMaster?65535:ui32TrappedBPCoreNum; #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ #else /* defined(SGX_FEATURE_MP) */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) /* non-mp, per-pipe regbanks */ #error non-mp perpipe regs not yet supported #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ /* non-mp */ psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum = 65534; #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ #endif /* defined(SGX_FEATURE_MP) */ } #endif /* !defined(NO_HARDWARE) */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_RESUME_BREAKPOINT: { /* This request resumes from the currently trapped breakpoint. */ /* Core number must be supplied */ /* Polls for notify to be acknowledged by h/w */ #if !defined(NO_HARDWARE) #if defined(SGX_FEATURE_MP) IMG_UINT32 ui32CoreNum; IMG_BOOL bMaster; #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) IMG_UINT32 ui32PipeNum; #endif #endif /* defined(SGX_FEATURE_MP) */ IMG_UINT32 ui32OldSeqNum, ui32NewSeqNum; #if defined(SGX_FEATURE_MP) #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32PipeNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum >> 10; ui32CoreNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum & 1023; bMaster = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum > 32767; #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32CoreNum = psMiscInfo->uData.sSGXBreakpointInfo.ui32CoreNum; bMaster = ui32CoreNum > SGX_FEATURE_MP_CORE_COUNT_3D; #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ if (bMaster) { /* master */ /* EUR_CR_MASTER_BREAKPOINT_TRAPPED_MASK | EUR_CR_MASTER_BREAKPOINT_SEQNUM_MASK */ ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT); OSWriteHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT_TRAP, EUR_CR_MASTER_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_MASTER_BREAKPOINT_TRAP_CONTINUE_MASK); do { ui32NewSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, EUR_CR_MASTER_BREAKPOINT); } while (ui32OldSeqNum == ui32NewSeqNum); } else #endif /* defined(SGX_FEATURE_MP) */ { /* core */ #if defined(SGX_FEATURE_PERPIPE_BKPT_REGS) ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT, ui32CoreNum, ui32PipeNum)); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT_TRAP, ui32CoreNum, ui32PipeNum), EUR_CR_PARTITION_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_PARTITION_BREAKPOINT_TRAP_CONTINUE_MASK); do { ui32NewSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_PIPE_SELECT(BREAKPOINT, ui32CoreNum, ui32PipeNum)); } while (ui32OldSeqNum == ui32NewSeqNum); #else /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ ui32OldSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum)); OSWriteHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT_TRAP, ui32CoreNum), EUR_CR_BREAKPOINT_TRAP_WRNOTIFY_MASK | EUR_CR_BREAKPOINT_TRAP_CONTINUE_MASK); do { ui32NewSeqNum = 0x1c & OSReadHWReg(psDevInfo->pvRegsBaseKM, SGX_MP_CORE_SELECT(EUR_CR_BREAKPOINT, ui32CoreNum)); } while (ui32OldSeqNum == ui32NewSeqNum); #endif /* defined(SGX_FEATURE_PERPIPE_BKPT_REGS) */ } #endif /* !defined(NO_HARDWARE) */ return PVRSRV_OK; } #endif /* SGX_FEATURE_DATA_BREAKPOINTS) */ case SGX_MISC_INFO_REQUEST_CLOCKSPEED: { psMiscInfo->uData.ui32SGXClockSpeed = psDevInfo->ui32CoreClockSpeed; return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_ACTIVEPOWER: { psMiscInfo->uData.sActivePower.ui32NumActivePowerEvents = psDevInfo->psSGXHostCtl->ui32NumActivePowerEvents; return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_LOCKUPS: { #if defined(SUPPORT_HW_RECOVERY) psMiscInfo->uData.sLockups.ui32uKernelDetectedLockups = psDevInfo->psSGXHostCtl->ui32uKernelDetectedLockups; psMiscInfo->uData.sLockups.ui32HostDetectedLockups = psDevInfo->psSGXHostCtl->ui32HostDetectedLockups; #else psMiscInfo->uData.sLockups.ui32uKernelDetectedLockups = 0; psMiscInfo->uData.sLockups.ui32HostDetectedLockups = 0; #endif return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_SPM: { /* this is dealt with in UM */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_SGXREV: { PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; // PPVRSRV_KERNEL_MEM_INFO psMemInfo = psDevInfo->psKernelSGXMiscMemInfo; eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode, hDevMemContext); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "An error occurred in SGXGetMiscInfoUkernel: %d\n", eError)); return eError; } psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; /* Debug output */ PVR_DPF((PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: Core 0x%x, sw ID 0x%x, sw Rev 0x%x\n", psSGXFeatures->ui32CoreRev, psSGXFeatures->ui32CoreIdSW, psSGXFeatures->ui32CoreRevSW)); PVR_DPF((PVR_DBG_MESSAGE, "SGXGetMiscInfoKM: DDK version 0x%x, DDK build 0x%x\n", psSGXFeatures->ui32DDKVersion, psSGXFeatures->ui32DDKBuild)); /* done! */ return PVRSRV_OK; } case SGX_MISC_INFO_REQUEST_DRIVER_SGXREV: { PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; /* Reset the misc information to prevent * confusion with values returned from the ukernel */ OSMemSet(psMemInfo->pvLinAddrKM, 0, sizeof(PVRSRV_SGX_MISCINFO_INFO)); psSGXFeatures->ui32DDKVersion = (PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8) | PVRVERSION_BRANCH; psSGXFeatures->ui32DDKBuild = PVRVERSION_BUILD; /* Also report the kernel module build options -- used in SGXConnectionCheck() */ psSGXFeatures->ui32BuildOptions = (SGX_BUILD_OPTIONS); #if defined(PVRSRV_USSE_EDM_STATUS_DEBUG) /* Report the EDM status buffer location in memory */ psSGXFeatures->sDevVAEDMStatusBuffer = psDevInfo->psKernelEDMStatusBufferMemInfo->sDevVAddr; psSGXFeatures->pvEDMStatusBuffer = psDevInfo->psKernelEDMStatusBufferMemInfo->pvLinAddrKM; #endif /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; return PVRSRV_OK; } #if defined(SUPPORT_SGX_EDM_MEMORY_DEBUG) case SGX_MISC_INFO_REQUEST_MEMREAD: case SGX_MISC_INFO_REQUEST_MEMCOPY: { PVRSRV_ERROR eError; PVRSRV_SGX_MISCINFO_FEATURES *psSGXFeatures; PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemSrc; /* user-defined mem read */ PVRSRV_SGX_MISCINFO_MEMACCESS *psSGXMemDest; /* user-defined mem write */ { /* Set the mem read flag; src is user-defined */ *pui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_MEMREAD; psSGXMemSrc = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXMemAccessSrc; if(psMiscInfo->sDevVAddrSrc.uiAddr != 0) { psSGXMemSrc->sDevVAddr = psMiscInfo->sDevVAddrSrc; /* src address */ } else { return PVRSRV_ERROR_INVALID_PARAMS; } } if( psMiscInfo->eRequest == SGX_MISC_INFO_REQUEST_MEMCOPY) { /* Set the mem write flag; dest is user-defined */ *pui32MiscInfoFlags |= PVRSRV_USSE_MISCINFO_MEMWRITE; psSGXMemDest = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXMemAccessDest; if(psMiscInfo->sDevVAddrDest.uiAddr != 0) { psSGXMemDest->sDevVAddr = psMiscInfo->sDevVAddrDest; /* dest address */ } else { return PVRSRV_ERROR_INVALID_PARAMS; } } /* Get physical address of PD for memory read (may need to switch context in microkernel) */ if(psMiscInfo->hDevMemContext != IMG_NULL) { SGXGetMMUPDAddrKM( (IMG_HANDLE)psDeviceNode, hDevMemContext, &psSGXMemSrc->sPDDevPAddr); /* Single app will always use the same src and dest mem context */ psSGXMemDest->sPDDevPAddr = psSGXMemSrc->sPDDevPAddr; } else { return PVRSRV_ERROR_INVALID_PARAMS; } /* Submit the task to the ukernel */ eError = SGXGetMiscInfoUkernel(psDevInfo, psDeviceNode); if(eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "An error occurred in SGXGetMiscInfoUkernel: %d\n", eError)); return eError; } psSGXFeatures = &((PVRSRV_SGX_MISCINFO_INFO*)(psMemInfo->pvLinAddrKM))->sSGXFeatures; #if !defined(SGX_FEATURE_MULTIPLE_MEM_CONTEXTS) if(*pui32MiscInfoFlags & PVRSRV_USSE_MISCINFO_MEMREAD_FAIL) { return PVRSRV_ERROR_INVALID_MISCINFO; } #endif /* Copy SGX features into misc info struct, to return to client */ psMiscInfo->uData.sSGXFeatures = *psSGXFeatures; return PVRSRV_OK; } #endif /* SUPPORT_SGX_EDM_MEMORY_DEBUG */ #if defined(SUPPORT_SGX_HWPERF) case SGX_MISC_INFO_REQUEST_SET_HWPERF_STATUS: { PVRSRV_SGX_MISCINFO_SET_HWPERF_STATUS *psSetHWPerfStatus = &psMiscInfo->uData.sSetHWPerfStatus; const IMG_UINT32 ui32ValidFlags = PVRSRV_SGX_HWPERF_STATUS_RESET_COUNTERS | PVRSRV_SGX_HWPERF_STATUS_GRAPHICS_ON | PVRSRV_SGX_HWPERF_STATUS_PERIODIC_ON | PVRSRV_SGX_HWPERF_STATUS_MK_EXECUTION_ON; SGXMKIF_COMMAND sCommandData = {0}; /* Check for valid flags */ if ((psSetHWPerfStatus->ui32NewHWPerfStatus & ~ui32ValidFlags) != 0) { return PVRSRV_ERROR_INVALID_PARAMS; } #if defined(PDUMP) PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "SGX ukernel HWPerf status %u\n", psSetHWPerfStatus->ui32NewHWPerfStatus); #endif /* PDUMP */ /* Copy the new group selector(s) to the host ctl for the ukernel */ #if defined(SGX_FEATURE_EXTENDED_PERF_COUNTERS) OSMemCopy(&psDevInfo->psSGXHostCtl->aui32PerfGroup[0], &psSetHWPerfStatus->aui32PerfGroup[0], sizeof(psDevInfo->psSGXHostCtl->aui32PerfGroup)); OSMemCopy(&psDevInfo->psSGXHostCtl->aui32PerfBit[0], &psSetHWPerfStatus->aui32PerfBit[0], sizeof(psDevInfo->psSGXHostCtl->aui32PerfBit)); psDevInfo->psSGXHostCtl->ui32PerfCounterBitSelect = psSetHWPerfStatus->ui32PerfCounterBitSelect; psDevInfo->psSGXHostCtl->ui32PerfSumMux = psSetHWPerfStatus->ui32PerfSumMux; #if defined(PDUMP) PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, aui32PerfGroup), sizeof(psDevInfo->psSGXHostCtl->aui32PerfGroup), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, aui32PerfBit), sizeof(psDevInfo->psSGXHostCtl->aui32PerfBit), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32PerfCounterBitSelect), sizeof(psDevInfo->psSGXHostCtl->ui32PerfCounterBitSelect), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32PerfSumMux), sizeof(psDevInfo->psSGXHostCtl->ui32PerfSumMux), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); #endif /* PDUMP */ #else psDevInfo->psSGXHostCtl->ui32PerfGroup = psSetHWPerfStatus->ui32PerfGroup; #if defined(PDUMP) PDUMPMEM(IMG_NULL, psDevInfo->psKernelSGXHostCtlMemInfo, offsetof(SGXMKIF_HOST_CTL, ui32PerfGroup), sizeof(psDevInfo->psSGXHostCtl->ui32PerfGroup), PDUMP_FLAGS_CONTINUOUS, MAKEUNIQUETAG(psDevInfo->psKernelSGXHostCtlMemInfo)); #endif /* PDUMP */ #endif /* SGX_FEATURE_EXTENDED_PERF_COUNTERS */ /* Kick the ukernel to update the hardware state */ sCommandData.ui32Data[0] = psSetHWPerfStatus->ui32NewHWPerfStatus; eError = SGXScheduleCCBCommandKM(psDeviceNode, SGXMKIF_CMD_SETHWPERFSTATUS, &sCommandData, KERNEL_ID, 0, hDevMemContext, IMG_FALSE); return eError; } #endif /* SUPPORT_SGX_HWPERF */ case SGX_MISC_INFO_DUMP_DEBUG_INFO: { PVR_LOG(("User requested SGX debug info")); /* Dump SGX debug data to the kernel log. */ SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_FALSE); return PVRSRV_OK; } case SGX_MISC_INFO_DUMP_DEBUG_INFO_FORCE_REGS: { PVR_LOG(("User requested SGX debug info")); /* Dump SGX debug data to the kernel log. */ SGXDumpDebugInfo(psDeviceNode->pvDevice, IMG_TRUE); return PVRSRV_OK; } #if defined(DEBUG) /* Don't allow user-mode to reboot the device in production drivers */ case SGX_MISC_INFO_PANIC: { PVR_LOG(("User requested SGX panic")); SGXPanic(psDeviceNode->pvDevice); return PVRSRV_OK; } #endif default: { /* switch statement fell though, so: */ return PVRSRV_ERROR_INVALID_PARAMS; } } } IMG_EXPORT PVRSRV_ERROR SGXReadHWPerfCBKM(IMG_HANDLE hDevHandle, IMG_UINT32 ui32ArraySize, PVRSRV_SGX_HWPERF_CB_ENTRY *psClientHWPerfEntry, IMG_UINT32 *pui32DataCount, IMG_UINT32 *pui32ClockSpeed, IMG_UINT32 *pui32HostTimeStamp) { PVRSRV_ERROR eError = PVRSRV_OK; PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle; PVRSRV_SGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; SGXMKIF_HWPERF_CB *psHWPerfCB = psDevInfo->psKernelHWPerfCBMemInfo->pvLinAddrKM; IMG_UINT i; for (i = 0; psHWPerfCB->ui32Woff != psHWPerfCB->ui32Roff && i < ui32ArraySize; i++) { SGXMKIF_HWPERF_CB_ENTRY *psMKPerfEntry = &psHWPerfCB->psHWPerfCBData[psHWPerfCB->ui32Roff]; psClientHWPerfEntry[i].ui32FrameNo = psMKPerfEntry->ui32FrameNo; psClientHWPerfEntry[i].ui32PID = psMKPerfEntry->ui32PID; psClientHWPerfEntry[i].ui32RTData = psMKPerfEntry->ui32RTData; psClientHWPerfEntry[i].ui32Type = psMKPerfEntry->ui32Type; psClientHWPerfEntry[i].ui32Ordinal = psMKPerfEntry->ui32Ordinal; psClientHWPerfEntry[i].ui32Info = psMKPerfEntry->ui32Info; psClientHWPerfEntry[i].ui32Clocksx16 = SGXConvertTimeStamp(psDevInfo, psMKPerfEntry->ui32TimeWraps, psMKPerfEntry->ui32Time); OSMemCopy(&psClientHWPerfEntry[i].ui32Counters[0][0], &psMKPerfEntry->ui32Counters[0][0], sizeof(psMKPerfEntry->ui32Counters)); OSMemCopy(&psClientHWPerfEntry[i].ui32MiscCounters[0][0], &psMKPerfEntry->ui32MiscCounters[0][0], sizeof(psMKPerfEntry->ui32MiscCounters)); psHWPerfCB->ui32Roff = (psHWPerfCB->ui32Roff + 1) & (SGXMKIF_HWPERF_CB_SIZE - 1); } *pui32DataCount = i; *pui32ClockSpeed = psDevInfo->ui32CoreClockSpeed; *pui32HostTimeStamp = OSClockus(); return eError; } /****************************************************************************** End of file (sgxinit.c) ******************************************************************************/