| /*************************************************************************/ /*! |
| @File |
| @Title Rogue firmware utility routines |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description Rogue firmware utility routines |
| @License Dual MIT/GPLv2 |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| Alternatively, the contents of this file may be used under the terms of |
| the GNU General Public License Version 2 ("GPL") in which case the provisions |
| of GPL are applicable instead of those above. |
| |
| If you wish to allow use of your version of this file only under the terms of |
| GPL, and not to allow others to use your version of this file under the terms |
| of the MIT license, indicate your decision by deleting the provisions above |
| and replace them with the notice and other provisions required by GPL as set |
| out in the file called "GPL-COPYING" included in this distribution. If you do |
| not delete the provisions above, a recipient may use your version of this file |
| under the terms of either the MIT license or GPL. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS |
| PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
| BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ /**************************************************************************/ |
| |
| #include <stddef.h> |
| |
| #include "lists.h" |
| |
| #include "rgxdefs_km.h" |
| #include "rgx_fwif_km.h" |
| #include "pdump_km.h" |
| #include "osfunc.h" |
| #include "cache_km.h" |
| #include "allocmem.h" |
| #include "devicemem.h" |
| #include "devicemem_pdump.h" |
| #include "devicemem_server.h" |
| |
| #include "pvr_debug.h" |
| #include "pvr_notifier.h" |
| #include "rgxfwutils.h" |
| #include "rgx_options.h" |
| #include "rgx_fwif.h" |
| #include "rgx_fwif_alignchecks.h" |
| #include "rgx_fwif_resetframework.h" |
| #include "rgx_pdump_panics.h" |
| #include "rgxheapconfig.h" |
| #include "pvrsrv.h" |
| #if defined(SUPPORT_PVRSRV_GPUVIRT) |
| #include "rgxfwutils_vz.h" |
| #endif |
| #include "rgxdebug.h" |
| #include "rgxhwperf.h" |
| #include "rgxccb.h" |
| #include "rgxcompute.h" |
| #include "rgxtransfer.h" |
| #include "rgxpower.h" |
| #include "rgxray.h" |
| #if defined(SUPPORT_DISPLAY_CLASS) |
| #include "dc_server.h" |
| #endif |
| #include "rgxmem.h" |
| #include "rgxta3d.h" |
| #include "rgxutils.h" |
| #include "sync_internal.h" |
| #include "sync.h" |
| #include "tlstream.h" |
| #include "devicemem_server_utils.h" |
| #include "htbuffer.h" |
| #include "rgx_bvnc_defs_km.h" |
| |
| #if defined(SUPPORT_TRUSTED_DEVICE) |
| #include "physmem_osmem.h" |
| #endif |
| |
| #ifdef __linux__ |
| #include <linux/kernel.h> // sprintf |
| #include <linux/string.h> // strncpy, strlen |
| #include "rogue_trace_events.h" |
| #else |
| #include <stdio.h> |
| #include <string.h> |
| #endif |
| #if defined(PVRSRV_ENABLE_PROCESS_STATS) |
| #include "process_stats.h" |
| #endif |
| |
| #if defined(SUPPORT_WORKLOAD_ESTIMATION) |
| #include "rgxworkest.h" |
| #endif |
| |
| #if defined(SUPPORT_PDVFS) |
| #include "rgxpdvfs.h" |
| #endif |
| |
| /* Kernel CCB length */ |
| /* Reducing the size of the KCCB in an attempt to avoid flooding and overflowing the FW kick queue |
| * in the case of multiple OSes */ |
| #define RGXFWIF_KCCB_NUMCMDS_LOG2_GPUVIRT_ONLY (6) |
| #define RGXFWIF_KCCB_NUMCMDS_LOG2_FEAT_GPU_VIRTUALISATION (7) |
| |
| |
| /* Firmware CCB length */ |
| #if defined(SUPPORT_PDVFS) |
| #define RGXFWIF_FWCCB_NUMCMDS_LOG2 (8) |
| #else |
| #define RGXFWIF_FWCCB_NUMCMDS_LOG2 (5) |
| #endif |
| |
| /* Workload Estimation Firmware CCB length */ |
| #define RGXFWIF_WORKEST_FWCCB_NUMCMDS_LOG2 (7) |
| |
| typedef struct |
| { |
| RGXFWIF_KCCB_CMD sKCCBcmd; |
| DLLIST_NODE sListNode; |
| PDUMP_FLAGS_T uiPdumpFlags; |
| PVRSRV_RGXDEV_INFO *psDevInfo; |
| RGXFWIF_DM eDM; |
| } RGX_DEFERRED_KCCB_CMD; |
| |
| #if defined(PDUMP) |
| /* ensure PIDs are 32-bit because a 32-bit PDump load is generated for the |
| * PID filter example entries |
| */ |
| static_assert(sizeof(IMG_PID) == sizeof(IMG_UINT32), |
| "FW PID filtering assumes the IMG_PID type is 32-bits wide as it " |
| "generates WRW commands for loading the PID values"); |
| #endif |
| |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| static PVRSRV_ERROR _AllocateSLC3Fence(PVRSRV_RGXDEV_INFO* psDevInfo, RGXFWIF_INIT* psRGXFWInit) |
| { |
| PVRSRV_ERROR eError; |
| DEVMEM_MEMDESC** ppsSLC3FenceMemDesc = &psDevInfo->psSLC3FenceMemDesc; |
| IMG_UINT32 ui32CacheLineSize = GET_ROGUE_CACHE_LINE_SIZE(psDevInfo->sDevFeatureCfg.ui32CacheLineSize); |
| |
| PVR_DPF_ENTERED; |
| |
| eError = DevmemAllocate(psDevInfo->psFirmwareHeap, |
| 1, |
| ui32CacheLineSize, |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_FW_LOCAL, |
| "SLC3 Fence WA", |
| ppsSLC3FenceMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF_RETURN_RC(eError); |
| } |
| |
| /* |
| We need to map it so the heap for this allocation |
| is set |
| */ |
| eError = DevmemMapToDevice(*ppsSLC3FenceMemDesc, |
| psDevInfo->psFirmwareHeap, |
| &psRGXFWInit->sSLC3FenceDevVAddr); |
| if (eError != PVRSRV_OK) |
| { |
| DevmemFwFree(psDevInfo, *ppsSLC3FenceMemDesc); |
| *ppsSLC3FenceMemDesc = NULL; |
| } |
| |
| PVR_DPF_RETURN_RC1(eError, *ppsSLC3FenceMemDesc); |
| } |
| |
| static void _FreeSLC3Fence(PVRSRV_RGXDEV_INFO* psDevInfo) |
| { |
| DEVMEM_MEMDESC* psSLC3FenceMemDesc = psDevInfo->psSLC3FenceMemDesc; |
| |
| if (psSLC3FenceMemDesc) |
| { |
| DevmemReleaseDevVirtAddr(psSLC3FenceMemDesc); |
| DevmemFree(psSLC3FenceMemDesc); |
| } |
| } |
| #endif |
| |
| static void __MTSScheduleWrite(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32Value) |
| { |
| /* ensure memory is flushed before kicking MTS */ |
| OSWriteMemoryBarrier(); |
| |
| OSWriteHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_MTS_SCHEDULE, ui32Value); |
| |
| /* ensure the MTS kick goes through before continuing */ |
| OSMemoryBarrier(); |
| } |
| |
| |
| /*! |
| ******************************************************************************* |
| @Function RGXFWSetupSignatureChecks |
| @Description |
| @Input psDevInfo |
| |
| @Return PVRSRV_ERROR |
| ******************************************************************************/ |
| static PVRSRV_ERROR RGXFWSetupSignatureChecks(PVRSRV_RGXDEV_INFO* psDevInfo, |
| DEVMEM_MEMDESC** ppsSigChecksMemDesc, |
| IMG_UINT32 ui32SigChecksBufSize, |
| RGXFWIF_SIGBUF_CTL* psSigBufCtl, |
| const IMG_CHAR* pszBufferName) |
| { |
| PVRSRV_ERROR eError; |
| DEVMEM_FLAGS_T uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| /* Allocate memory for the checks */ |
| PDUMPCOMMENT("Allocate memory for %s signature checks", pszBufferName); |
| eError = DevmemFwAllocate(psDevInfo, |
| ui32SigChecksBufSize, |
| uiMemAllocFlags, |
| "FwSignatureChecks", |
| ppsSigChecksMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %d bytes for signature checks (%u)", |
| ui32SigChecksBufSize, |
| eError)); |
| return eError; |
| } |
| |
| /* Prepare the pointer for the fw to access that memory */ |
| RGXSetFirmwareAddress(&psSigBufCtl->sBuffer, |
| *ppsSigChecksMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| DevmemPDumpLoadMem( *ppsSigChecksMemDesc, |
| 0, |
| ui32SigChecksBufSize, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| psSigBufCtl->ui32LeftSizeInRegs = ui32SigChecksBufSize / sizeof(IMG_UINT32); |
| |
| return PVRSRV_OK; |
| } |
| |
| #if defined(RGXFW_ALIGNCHECKS) |
| /*! |
| ******************************************************************************* |
| @Function RGXFWSetupAlignChecks |
| @Description This functions allocates and fills memory needed for the |
| aligns checks of the UM and KM structures shared with the |
| firmware. The format of the data in the memory is as follows: |
| <number of elements in the KM array> |
| <array of KM structures' sizes and members' offsets> |
| <number of elements in the UM array> |
| <array of UM structures' sizes and members' offsets> |
| The UM array is passed from the user side. If the |
| SUPPORT_KERNEL_SRVINIT macro is defined the firmware is |
| is responsible for filling this part of the memory. If that |
| happens the check of the UM structures will be performed |
| by the host driver on client's connect. |
| If the macro is not defined the client driver fills the memory |
| and the firmware checks for the alignment of all structures. |
| @Input psDevInfo |
| |
| @Return PVRSRV_ERROR |
| ******************************************************************************/ |
| static PVRSRV_ERROR RGXFWSetupAlignChecks(PVRSRV_RGXDEV_INFO* psDevInfo, |
| RGXFWIF_DEV_VIRTADDR *psAlignChecksDevFW, |
| IMG_UINT32 *pui32RGXFWAlignChecks, |
| IMG_UINT32 ui32RGXFWAlignChecksArrLength) |
| { |
| IMG_UINT32 aui32RGXFWAlignChecksKM[] = { RGXFW_ALIGN_CHECKS_INIT_KM }; |
| IMG_UINT32 ui32RGXFWAlingChecksTotal; |
| IMG_UINT32* paui32AlignChecks; |
| PVRSRV_ERROR eError; |
| |
| #if defined(SUPPORT_KERNEL_SRVINIT) |
| /* In this case we don't know the number of elements in UM array. |
| * We have to assume something so we assume RGXFW_ALIGN_CHECKS_UM_MAX. */ |
| PVR_ASSERT(ui32RGXFWAlignChecksArrLength == 0); |
| ui32RGXFWAlingChecksTotal = sizeof(aui32RGXFWAlignChecksKM) |
| + RGXFW_ALIGN_CHECKS_UM_MAX * sizeof(IMG_UINT32) |
| + 2 * sizeof(IMG_UINT32); |
| #else |
| /* '2 * sizeof(IMG_UINT32)' if for sizes of km and um arrays. */ |
| PVR_ASSERT(ui32RGXFWAlignChecksArrLength != 0); |
| ui32RGXFWAlingChecksTotal = sizeof(aui32RGXFWAlignChecksKM) |
| + ui32RGXFWAlignChecksArrLength * sizeof(IMG_UINT32) |
| + 2 * sizeof(IMG_UINT32); |
| #endif |
| |
| /* Allocate memory for the checks */ |
| PDUMPCOMMENT("Allocate memory for alignment checks"); |
| eError = DevmemFwAllocate(psDevInfo, |
| ui32RGXFWAlingChecksTotal, |
| PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| #if defined(SUPPORT_KERNEL_SRVINIT) |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| #endif |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | PVRSRV_MEMALLOCFLAG_UNCACHED, |
| "FwAlignmentChecks", |
| &psDevInfo->psRGXFWAlignChecksMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %d bytes for alignment checks (%u)", |
| ui32RGXFWAlingChecksTotal, |
| eError)); |
| goto failAlloc; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWAlignChecksMemDesc, |
| (void **)&paui32AlignChecks); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel addr for alignment checks (%u)", |
| eError)); |
| goto failAqCpuAddr; |
| } |
| |
| /* Copy the values */ |
| #if defined(SUPPORT_KERNEL_SRVINIT) |
| *paui32AlignChecks++ = sizeof(aui32RGXFWAlignChecksKM)/sizeof(IMG_UINT32); |
| OSDeviceMemCopy(paui32AlignChecks, &aui32RGXFWAlignChecksKM[0], sizeof(aui32RGXFWAlignChecksKM)); |
| paui32AlignChecks += sizeof(aui32RGXFWAlignChecksKM)/sizeof(IMG_UINT32); |
| |
| *paui32AlignChecks = 0; |
| #else |
| *paui32AlignChecks++ = sizeof(aui32RGXFWAlignChecksKM)/sizeof(IMG_UINT32); |
| OSDeviceMemCopy(paui32AlignChecks, &aui32RGXFWAlignChecksKM[0], sizeof(aui32RGXFWAlignChecksKM)); |
| paui32AlignChecks += sizeof(aui32RGXFWAlignChecksKM)/sizeof(IMG_UINT32); |
| |
| *paui32AlignChecks++ = ui32RGXFWAlignChecksArrLength; |
| OSDeviceMemCopy(paui32AlignChecks, pui32RGXFWAlignChecks, ui32RGXFWAlignChecksArrLength * sizeof(IMG_UINT32)); |
| #endif |
| |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWAlignChecksMemDesc, |
| 0, |
| ui32RGXFWAlingChecksTotal, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| /* Prepare the pointer for the fw to access that memory */ |
| RGXSetFirmwareAddress(psAlignChecksDevFW, |
| psDevInfo->psRGXFWAlignChecksMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| return PVRSRV_OK; |
| |
| |
| |
| |
| failAqCpuAddr: |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWAlignChecksMemDesc); |
| psDevInfo->psRGXFWAlignChecksMemDesc = NULL; |
| failAlloc: |
| |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| static void RGXFWFreeAlignChecks(PVRSRV_RGXDEV_INFO* psDevInfo) |
| { |
| if (psDevInfo->psRGXFWAlignChecksMemDesc != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWAlignChecksMemDesc); |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWAlignChecksMemDesc); |
| psDevInfo->psRGXFWAlignChecksMemDesc = NULL; |
| } |
| } |
| #endif |
| |
| |
| void RGXSetFirmwareAddress(RGXFWIF_DEV_VIRTADDR *ppDest, |
| DEVMEM_MEMDESC *psSrc, |
| IMG_UINT32 uiExtraOffset, |
| IMG_UINT32 ui32Flags) |
| { |
| PVRSRV_ERROR eError; |
| IMG_DEV_VIRTADDR psDevVirtAddr; |
| PVRSRV_DEVICE_NODE *psDeviceNode; |
| IMG_UINT64 ui64ErnsBrns = 0; |
| PVRSRV_RGXDEV_INFO *psDevInfo; |
| |
| psDeviceNode = (PVRSRV_DEVICE_NODE *) DevmemGetConnection(psSrc); |
| psDevInfo = (PVRSRV_RGXDEV_INFO *)psDeviceNode->pvDevice; |
| ui64ErnsBrns = psDevInfo->sDevFeatureCfg.ui64ErnsBrns; |
| |
| if(psDevInfo->sDevFeatureCfg.ui32META) |
| { |
| IMG_UINT32 ui32Offset; |
| IMG_BOOL bCachedInMETA; |
| DEVMEM_FLAGS_T uiDevFlags; |
| IMG_UINT32 uiGPUCacheMode; |
| |
| eError = DevmemAcquireDevVirtAddr(psSrc, &psDevVirtAddr); |
| PVR_ASSERT(eError == PVRSRV_OK); |
| |
| /* Convert to an address in META memmap */ |
| ui32Offset = psDevVirtAddr.uiAddr + uiExtraOffset - RGX_FIRMWARE_HEAP_BASE ; |
| |
| /* Check in the devmem flags whether this memory is cached/uncached */ |
| DevmemGetFlags(psSrc, &uiDevFlags); |
| |
| /* Honour the META cache flags */ |
| bCachedInMETA = (PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) & uiDevFlags) != 0; |
| |
| /* Honour the SLC cache flags */ |
| uiGPUCacheMode = DevmemDeviceCacheMode(psDeviceNode, uiDevFlags); |
| |
| ui32Offset += RGXFW_SEGMMU_DATA_BASE_ADDRESS; |
| |
| if (bCachedInMETA) |
| { |
| ui32Offset |= RGXFW_SEGMMU_DATA_META_CACHED; |
| } |
| else |
| { |
| ui32Offset |= RGXFW_SEGMMU_DATA_META_UNCACHED; |
| } |
| |
| if (PVRSRV_CHECK_GPU_CACHED(uiGPUCacheMode)) |
| { |
| ui32Offset |= RGXFW_SEGMMU_DATA_VIVT_SLC_CACHED; |
| } |
| else |
| { |
| ui32Offset |= RGXFW_SEGMMU_DATA_VIVT_SLC_UNCACHED; |
| } |
| ppDest->ui32Addr = ui32Offset; |
| }else |
| { |
| eError = DevmemAcquireDevVirtAddr(psSrc, &psDevVirtAddr); |
| PVR_ASSERT(eError == PVRSRV_OK); |
| ppDest->ui32Addr = (IMG_UINT32)((psDevVirtAddr.uiAddr + uiExtraOffset) & 0xFFFFFFFF); |
| } |
| |
| if (ui32Flags & RFW_FWADDR_NOREF_FLAG) |
| { |
| DevmemReleaseDevVirtAddr(psSrc); |
| } |
| |
| } |
| |
| void RGXSetMetaDMAAddress(RGXFWIF_DMA_ADDR *psDest, |
| DEVMEM_MEMDESC *psSrcMemDesc, |
| RGXFWIF_DEV_VIRTADDR *psSrcFWDevVAddr, |
| IMG_UINT32 uiOffset) |
| { |
| PVRSRV_ERROR eError; |
| IMG_DEV_VIRTADDR sDevVirtAddr; |
| |
| eError = DevmemAcquireDevVirtAddr(psSrcMemDesc, &sDevVirtAddr); |
| PVR_ASSERT(eError == PVRSRV_OK); |
| |
| psDest->psDevVirtAddr.uiAddr = sDevVirtAddr.uiAddr; |
| psDest->psDevVirtAddr.uiAddr += uiOffset; |
| psDest->pbyFWAddr.ui32Addr = psSrcFWDevVAddr->ui32Addr; |
| |
| DevmemReleaseDevVirtAddr(psSrcMemDesc); |
| } |
| |
| |
| void RGXUnsetFirmwareAddress(DEVMEM_MEMDESC *psSrc) |
| { |
| DevmemReleaseDevVirtAddr(psSrc); |
| } |
| |
| struct _RGX_SERVER_COMMON_CONTEXT_ { |
| PVRSRV_RGXDEV_INFO *psDevInfo; |
| DEVMEM_MEMDESC *psFWCommonContextMemDesc; |
| PRGXFWIF_FWCOMMONCONTEXT sFWCommonContextFWAddr; |
| DEVMEM_MEMDESC *psFWMemContextMemDesc; |
| DEVMEM_MEMDESC *psFWFrameworkMemDesc; |
| DEVMEM_MEMDESC *psContextStateMemDesc; |
| RGX_CLIENT_CCB *psClientCCB; |
| DEVMEM_MEMDESC *psClientCCBMemDesc; |
| DEVMEM_MEMDESC *psClientCCBCtrlMemDesc; |
| IMG_BOOL bCommonContextMemProvided; |
| IMG_UINT32 ui32ContextID; |
| DLLIST_NODE sListNode; |
| RGXFWIF_CONTEXT_RESET_REASON eLastResetReason; |
| IMG_UINT32 ui32LastResetJobRef; |
| }; |
| |
| PVRSRV_ERROR FWCommonContextAllocate(CONNECTION_DATA *psConnection, |
| PVRSRV_DEVICE_NODE *psDeviceNode, |
| RGX_CCB_REQUESTOR_TYPE eRGXCCBRequestor, |
| RGXFWIF_DM eDM, |
| DEVMEM_MEMDESC *psAllocatedMemDesc, |
| IMG_UINT32 ui32AllocatedOffset, |
| DEVMEM_MEMDESC *psFWMemContextMemDesc, |
| DEVMEM_MEMDESC *psContextStateMemDesc, |
| IMG_UINT32 ui32CCBAllocSize, |
| IMG_UINT32 ui32Priority, |
| RGX_COMMON_CONTEXT_INFO *psInfo, |
| RGX_SERVER_COMMON_CONTEXT **ppsServerCommonContext) |
| { |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| RGX_SERVER_COMMON_CONTEXT *psServerCommonContext; |
| RGXFWIF_FWCOMMONCONTEXT *psFWCommonContext; |
| IMG_UINT32 ui32FWCommonContextOffset; |
| IMG_UINT8 *pui8Ptr; |
| PVRSRV_ERROR eError; |
| |
| /* |
| Allocate all the resources that are required |
| */ |
| psServerCommonContext = OSAllocMem(sizeof(*psServerCommonContext)); |
| if (psServerCommonContext == NULL) |
| { |
| eError = PVRSRV_ERROR_OUT_OF_MEMORY; |
| goto fail_alloc; |
| } |
| |
| psServerCommonContext->psDevInfo = psDevInfo; |
| |
| if (psAllocatedMemDesc) |
| { |
| PDUMPCOMMENT("Using existing MemDesc for Rogue firmware %s context (offset = %d)", |
| aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT], |
| ui32AllocatedOffset); |
| ui32FWCommonContextOffset = ui32AllocatedOffset; |
| psServerCommonContext->psFWCommonContextMemDesc = psAllocatedMemDesc; |
| psServerCommonContext->bCommonContextMemProvided = IMG_TRUE; |
| } |
| else |
| { |
| /* Allocate device memory for the firmware context */ |
| PDUMPCOMMENT("Allocate Rogue firmware %s context", aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT]); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(*psFWCommonContext), |
| RGX_FWCOMCTX_ALLOCFLAGS, |
| "FwContext", |
| &psServerCommonContext->psFWCommonContextMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s : Failed to allocate firmware %s context (%s)", |
| __FUNCTION__, |
| aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT], |
| PVRSRVGetErrorStringKM(eError))); |
| goto fail_contextalloc; |
| } |
| ui32FWCommonContextOffset = 0; |
| psServerCommonContext->bCommonContextMemProvided = IMG_FALSE; |
| } |
| |
| /* Record this context so we can refer to it if the FW needs to tell us it was reset. */ |
| psServerCommonContext->eLastResetReason = RGXFWIF_CONTEXT_RESET_REASON_NONE; |
| psServerCommonContext->ui32LastResetJobRef = 0; |
| psServerCommonContext->ui32ContextID = psDevInfo->ui32CommonCtxtCurrentID++; |
| |
| /* Allocate the client CCB */ |
| eError = RGXCreateCCB(psDevInfo, |
| ui32CCBAllocSize, |
| psConnection, |
| eRGXCCBRequestor, |
| psServerCommonContext, |
| &psServerCommonContext->psClientCCB, |
| &psServerCommonContext->psClientCCBMemDesc, |
| &psServerCommonContext->psClientCCBCtrlMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: failed to create CCB for %s context(%s)", |
| __FUNCTION__, |
| aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT], |
| PVRSRVGetErrorStringKM(eError))); |
| goto fail_allocateccb; |
| } |
| |
| /* |
| Temporarily map the firmware context to the kernel and init it |
| */ |
| eError = DevmemAcquireCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc, |
| (void **)&pui8Ptr); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to map firmware %s context (%s)to CPU", |
| __FUNCTION__, |
| aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT], |
| PVRSRVGetErrorStringKM(eError))); |
| goto fail_cpuvirtacquire; |
| } |
| |
| psFWCommonContext = (RGXFWIF_FWCOMMONCONTEXT *) (pui8Ptr + ui32FWCommonContextOffset); |
| psFWCommonContext->eDM = eDM; |
| |
| /* Set the firmware CCB device addresses in the firmware common context */ |
| RGXSetFirmwareAddress(&psFWCommonContext->psCCB, |
| psServerCommonContext->psClientCCBMemDesc, |
| 0, RFW_FWADDR_FLAG_NONE); |
| RGXSetFirmwareAddress(&psFWCommonContext->psCCBCtl, |
| psServerCommonContext->psClientCCBCtrlMemDesc, |
| 0, RFW_FWADDR_FLAG_NONE); |
| |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_META_DMA_BIT_MASK) |
| { |
| RGXSetMetaDMAAddress(&psFWCommonContext->sCCBMetaDMAAddr, |
| psServerCommonContext->psClientCCBMemDesc, |
| &psFWCommonContext->psCCB, |
| 0); |
| } |
| |
| /* Set the memory context device address */ |
| psServerCommonContext->psFWMemContextMemDesc = psFWMemContextMemDesc; |
| RGXSetFirmwareAddress(&psFWCommonContext->psFWMemContext, |
| psFWMemContextMemDesc, |
| 0, RFW_FWADDR_FLAG_NONE); |
| |
| /* Set the framework register updates address */ |
| psServerCommonContext->psFWFrameworkMemDesc = psInfo->psFWFrameworkMemDesc; |
| if (psInfo->psFWFrameworkMemDesc != NULL) |
| { |
| RGXSetFirmwareAddress(&psFWCommonContext->psRFCmd, |
| psInfo->psFWFrameworkMemDesc, |
| 0, RFW_FWADDR_FLAG_NONE); |
| } |
| else |
| { |
| /* This should never be touched in this contexts without a framework |
| * memdesc, but ensure it is zero so we see crashes if it is. |
| */ |
| psFWCommonContext->psRFCmd.ui32Addr = 0; |
| } |
| |
| psFWCommonContext->ui32Priority = ui32Priority; |
| psFWCommonContext->ui32PrioritySeqNum = 0; |
| |
| if(psInfo->psMCUFenceAddr != NULL) |
| { |
| psFWCommonContext->ui64MCUFenceAddr = psInfo->psMCUFenceAddr->uiAddr; |
| } |
| |
| if((psDevInfo->sDevFeatureCfg.ui32CtrlStreamFormat == 2) && \ |
| (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_SIGNAL_SNOOPING_BIT_MASK)) |
| { |
| if (eDM == RGXFWIF_DM_CDM) |
| { |
| if(psInfo->psResumeSignalAddr != NULL) |
| { |
| psFWCommonContext->ui64ResumeSignalAddr = psInfo->psResumeSignalAddr->uiAddr; |
| } |
| } |
| } |
| |
| /* Store a references to Server Common Context and PID for notifications back from the FW. */ |
| psFWCommonContext->ui32ServerCommonContextID = psServerCommonContext->ui32ContextID; |
| psFWCommonContext->ui32PID = OSGetCurrentClientProcessIDKM(); |
| |
| /* Set the firmware GPU context state buffer */ |
| psServerCommonContext->psContextStateMemDesc = psContextStateMemDesc; |
| if (psContextStateMemDesc) |
| { |
| RGXSetFirmwareAddress(&psFWCommonContext->psContextState, |
| psContextStateMemDesc, |
| 0, |
| RFW_FWADDR_FLAG_NONE); |
| } |
| |
| /* |
| * Dump the created context |
| */ |
| PDUMPCOMMENT("Dump %s context", aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT]); |
| DevmemPDumpLoadMem(psServerCommonContext->psFWCommonContextMemDesc, |
| ui32FWCommonContextOffset, |
| sizeof(*psFWCommonContext), |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| /* We've finished the setup so release the CPU mapping */ |
| DevmemReleaseCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc); |
| |
| /* Map this allocation into the FW */ |
| RGXSetFirmwareAddress(&psServerCommonContext->sFWCommonContextFWAddr, |
| psServerCommonContext->psFWCommonContextMemDesc, |
| ui32FWCommonContextOffset, |
| RFW_FWADDR_FLAG_NONE); |
| |
| #if defined(LINUX) |
| { |
| IMG_UINT32 ui32FWAddr = 0; |
| switch (eDM) { |
| case RGXFWIF_DM_TA: |
| ui32FWAddr = (IMG_UINT32) ((uintptr_t) IMG_CONTAINER_OF((void *) ((uintptr_t) |
| psServerCommonContext->sFWCommonContextFWAddr.ui32Addr), RGXFWIF_FWRENDERCONTEXT, sTAContext)); |
| case RGXFWIF_DM_3D: |
| ui32FWAddr = (IMG_UINT32) ((uintptr_t) IMG_CONTAINER_OF((void *) ((uintptr_t) |
| psServerCommonContext->sFWCommonContextFWAddr.ui32Addr), RGXFWIF_FWRENDERCONTEXT, s3DContext)); |
| default: |
| ui32FWAddr = psServerCommonContext->sFWCommonContextFWAddr.ui32Addr; |
| } |
| |
| trace_rogue_create_fw_context(OSGetCurrentClientProcessNameKM(), |
| aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT], |
| ui32FWAddr); |
| } |
| #endif |
| /*Add the node to the list when finalised */ |
| dllist_add_to_tail(&(psDevInfo->sCommonCtxtListHead), &(psServerCommonContext->sListNode)); |
| |
| *ppsServerCommonContext = psServerCommonContext; |
| return PVRSRV_OK; |
| |
| fail_allocateccb: |
| DevmemReleaseCpuVirtAddr(psServerCommonContext->psFWCommonContextMemDesc); |
| fail_cpuvirtacquire: |
| RGXUnsetFirmwareAddress(psServerCommonContext->psFWCommonContextMemDesc); |
| if (!psServerCommonContext->bCommonContextMemProvided) |
| { |
| DevmemFwFree(psDevInfo, psServerCommonContext->psFWCommonContextMemDesc); |
| psServerCommonContext->psFWCommonContextMemDesc = NULL; |
| } |
| fail_contextalloc: |
| OSFreeMem(psServerCommonContext); |
| fail_alloc: |
| return eError; |
| } |
| |
| void FWCommonContextFree(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext) |
| { |
| |
| /* Remove the context from the list of all contexts. */ |
| dllist_remove_node(&psServerCommonContext->sListNode); |
| |
| /* |
| Unmap the context itself and then all it's resources |
| */ |
| |
| /* Unmap the FW common context */ |
| RGXUnsetFirmwareAddress(psServerCommonContext->psFWCommonContextMemDesc); |
| /* Umap context state buffer (if there was one) */ |
| if (psServerCommonContext->psContextStateMemDesc) |
| { |
| RGXUnsetFirmwareAddress(psServerCommonContext->psContextStateMemDesc); |
| } |
| /* Unmap the framework buffer */ |
| if (psServerCommonContext->psFWFrameworkMemDesc) |
| { |
| RGXUnsetFirmwareAddress(psServerCommonContext->psFWFrameworkMemDesc); |
| } |
| /* Unmap client CCB and CCB control */ |
| RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBCtrlMemDesc); |
| RGXUnsetFirmwareAddress(psServerCommonContext->psClientCCBMemDesc); |
| /* Unmap the memory context */ |
| RGXUnsetFirmwareAddress(psServerCommonContext->psFWMemContextMemDesc); |
| |
| /* Destroy the client CCB */ |
| RGXDestroyCCB(psServerCommonContext->psDevInfo, psServerCommonContext->psClientCCB); |
| |
| |
| /* Free the FW common context (if there was one) */ |
| if (!psServerCommonContext->bCommonContextMemProvided) |
| { |
| DevmemFwFree(psServerCommonContext->psDevInfo, |
| psServerCommonContext->psFWCommonContextMemDesc); |
| psServerCommonContext->psFWCommonContextMemDesc = NULL; |
| } |
| /* Free the hosts representation of the common context */ |
| OSFreeMem(psServerCommonContext); |
| } |
| |
| PRGXFWIF_FWCOMMONCONTEXT FWCommonContextGetFWAddress(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext) |
| { |
| return psServerCommonContext->sFWCommonContextFWAddr; |
| } |
| |
| RGX_CLIENT_CCB *FWCommonContextGetClientCCB(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext) |
| { |
| return psServerCommonContext->psClientCCB; |
| } |
| |
| RGXFWIF_CONTEXT_RESET_REASON FWCommonContextGetLastResetReason(RGX_SERVER_COMMON_CONTEXT *psServerCommonContext, |
| IMG_UINT32 *pui32LastResetJobRef) |
| { |
| RGXFWIF_CONTEXT_RESET_REASON eLastResetReason; |
| |
| PVR_ASSERT(psServerCommonContext != NULL); |
| PVR_ASSERT(pui32LastResetJobRef != NULL); |
| |
| /* Take the most recent reason & job ref and reset for next time... */ |
| eLastResetReason = psServerCommonContext->eLastResetReason; |
| *pui32LastResetJobRef = psServerCommonContext->ui32LastResetJobRef; |
| psServerCommonContext->eLastResetReason = RGXFWIF_CONTEXT_RESET_REASON_NONE; |
| psServerCommonContext->ui32LastResetJobRef = 0; |
| |
| return eLastResetReason; |
| } |
| |
| /*! |
| ******************************************************************************* |
| @Function RGXFreeKernelCCB |
| @Description Free the kernel CCB |
| @Input psDevInfo |
| |
| @Return PVRSRV_ERROR |
| ******************************************************************************/ |
| static void RGXFreeKernelCCB(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| if (psDevInfo->psKernelCCBMemDesc != NULL) |
| { |
| if (psDevInfo->psKernelCCB != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psKernelCCBMemDesc); |
| psDevInfo->psKernelCCB = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psKernelCCBMemDesc); |
| psDevInfo->psKernelCCBMemDesc = NULL; |
| } |
| if (psDevInfo->psKernelCCBCtlMemDesc != NULL) |
| { |
| if (psDevInfo->psKernelCCBCtl != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psKernelCCBCtlMemDesc); |
| psDevInfo->psKernelCCBCtl = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psKernelCCBCtlMemDesc); |
| psDevInfo->psKernelCCBCtlMemDesc = NULL; |
| } |
| } |
| |
| /*! |
| ******************************************************************************* |
| @Function RGXSetupKernelCCB |
| @Description Allocate and initialise the kernel CCB |
| @Input psDevInfo |
| @Input psRGXFWInit |
| @Input ui32NumCmdsLog2 |
| @Input ui32CmdSize |
| |
| @Return PVRSRV_ERROR |
| ******************************************************************************/ |
| static PVRSRV_ERROR RGXSetupKernelCCB(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_INIT *psRGXFWInit, |
| IMG_UINT32 ui32NumCmdsLog2, |
| IMG_UINT32 ui32CmdSize) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_CCB_CTL *psKCCBCtl; |
| DEVMEM_FLAGS_T uiCCBCtlMemAllocFlags, uiCCBMemAllocFlags; |
| IMG_UINT32 ui32kCCBSize = (1U << ui32NumCmdsLog2); |
| |
| |
| /* |
| * FIXME: the write offset need not be writeable by the firmware, indeed may |
| * not even be needed for reading. Consider moving it to its own data |
| * structure. |
| */ |
| uiCCBCtlMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| /* Allocation flags for Kernel CCB */ |
| uiCCBMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| /* |
| * Allocate memory for the kernel CCB control. |
| */ |
| PDUMPCOMMENT("Allocate memory for kernel CCB control"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_CCB_CTL), |
| uiCCBCtlMemAllocFlags, |
| "FwKernelCCBControl", |
| &psDevInfo->psKernelCCBCtlMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupKernelCCB: Failed to allocate kernel CCB ctl (%u)", eError)); |
| goto fail; |
| } |
| |
| /* |
| * Allocate memory for the kernel CCB. |
| * (this will reference further command data in non-shared CCBs) |
| */ |
| PDUMPCOMMENT("Allocate memory for kernel CCB"); |
| eError = DevmemFwAllocate(psDevInfo, |
| ui32kCCBSize * ui32CmdSize, |
| uiCCBMemAllocFlags, |
| "FwKernelCCB", |
| &psDevInfo->psKernelCCBMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupKernelCCB: Failed to allocate kernel CCB (%u)", eError)); |
| goto fail; |
| } |
| |
| /* |
| * Map the kernel CCB control to the kernel. |
| */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psKernelCCBCtlMemDesc, |
| (void **)&psDevInfo->psKernelCCBCtl); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupKernelCCB: Failed to acquire cpu kernel CCB Ctl (%u)", eError)); |
| goto fail; |
| } |
| |
| /* |
| * Map the kernel CCB to the kernel. |
| */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psKernelCCBMemDesc, |
| (void **)&psDevInfo->psKernelCCB); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupKernelCCB: Failed to acquire cpu kernel CCB (%u)", eError)); |
| goto fail; |
| } |
| |
| /* |
| * Initialise the kernel CCB control. |
| */ |
| psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| psKCCBCtl->ui32WriteOffset = 0; |
| psKCCBCtl->ui32ReadOffset = 0; |
| psKCCBCtl->ui32WrapMask = ui32kCCBSize - 1; |
| psKCCBCtl->ui32CmdSize = ui32CmdSize; |
| |
| /* |
| * Set-up RGXFWIfCtl pointers to access the kCCB |
| */ |
| RGXSetFirmwareAddress(&psRGXFWInit->psKernelCCBCtl, |
| psDevInfo->psKernelCCBCtlMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->psKernelCCB, |
| psDevInfo->psKernelCCBMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| /* |
| * Pdump the kernel CCB control. |
| */ |
| PDUMPCOMMENT("Initialise kernel CCB ctl"); |
| DevmemPDumpLoadMem(psDevInfo->psKernelCCBCtlMemDesc, 0, sizeof(RGXFWIF_CCB_CTL), 0); |
| |
| return PVRSRV_OK; |
| |
| fail: |
| RGXFreeKernelCCB(psDevInfo); |
| |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| /*! |
| ******************************************************************************* |
| @Function RGXFreeFirmwareCCB |
| @Description Free the firmware CCB |
| @Input psDevInfo |
| @Input ppsFirmwareCCBCtl |
| @Input ppsFirmwareCCBCtlMemDesc |
| @Input ppui8FirmwareCCB |
| @Input ppsFirmwareCCBMemDesc |
| |
| @Return void |
| ******************************************************************************/ |
| static void RGXFreeFirmwareCCB(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_CCB_CTL **ppsFirmwareCCBCtl, |
| DEVMEM_MEMDESC **ppsFirmwareCCBCtlMemDesc, |
| IMG_UINT8 **ppui8FirmwareCCB, |
| DEVMEM_MEMDESC **ppsFirmwareCCBMemDesc) |
| { |
| if (*ppsFirmwareCCBMemDesc != NULL) |
| { |
| if (*ppui8FirmwareCCB != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(*ppsFirmwareCCBMemDesc); |
| *ppui8FirmwareCCB = NULL; |
| } |
| DevmemFwFree(psDevInfo, *ppsFirmwareCCBMemDesc); |
| *ppsFirmwareCCBMemDesc = NULL; |
| } |
| if (*ppsFirmwareCCBCtlMemDesc != NULL) |
| { |
| if (*ppsFirmwareCCBCtl != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(*ppsFirmwareCCBCtlMemDesc); |
| *ppsFirmwareCCBCtl = NULL; |
| } |
| DevmemFwFree(psDevInfo, *ppsFirmwareCCBCtlMemDesc); |
| *ppsFirmwareCCBCtlMemDesc = NULL; |
| } |
| } |
| |
| #define INPUT_STR_SIZE_MAX 13 |
| #define APPEND_STR_SIZE 7 |
| #define COMBINED_STR_LEN_MAX (INPUT_STR_SIZE_MAX + APPEND_STR_SIZE + 1) |
| |
| /*! |
| ******************************************************************************* |
| @Function RGXSetupFirmwareCCB |
| @Description Allocate and initialise a Firmware CCB |
| @Input psDevInfo |
| @Input ppsFirmwareCCBCtl |
| @Input ppsFirmwareCCBCtlMemDesc |
| @Input ppui8FirmwareCCB |
| @Input ppsFirmwareCCBMemDesc |
| @Input psFirmwareCCBCtlFWAddr |
| @Input psFirmwareCCBFWAddr |
| @Input ui32NumCmdsLog2 |
| @Input ui32CmdSize |
| @Input pszName Must be less than or equal to |
| INPUT_STR_SIZE_MAX |
| @Return PVRSRV_ERROR |
| ******************************************************************************/ |
| static PVRSRV_ERROR RGXSetupFirmwareCCB(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_CCB_CTL **ppsFirmwareCCBCtl, |
| DEVMEM_MEMDESC **ppsFirmwareCCBCtlMemDesc, |
| IMG_UINT8 **ppui8FirmwareCCB, |
| DEVMEM_MEMDESC **ppsFirmwareCCBMemDesc, |
| PRGXFWIF_CCB_CTL *psFirmwareCCBCtlFWAddr, |
| PRGXFWIF_CCB *psFirmwareCCBFWAddr, |
| IMG_UINT32 ui32NumCmdsLog2, |
| IMG_UINT32 ui32CmdSize, |
| IMG_PCHAR pszName) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_CCB_CTL *psFWCCBCtl; |
| DEVMEM_FLAGS_T uiCCBCtlMemAllocFlags, uiCCBMemAllocFlags; |
| IMG_UINT32 ui32FWCCBSize = (1U << ui32NumCmdsLog2); |
| IMG_CHAR sCCBCtlName[COMBINED_STR_LEN_MAX] = ""; |
| IMG_CHAR sAppend[] = "Control"; |
| |
| /* |
| * FIXME: the write offset need not be writeable by the host, indeed may |
| * not even be needed for reading. Consider moving it to its own data |
| * structure. |
| */ |
| uiCCBCtlMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| /* Allocation flags for Firmware CCB */ |
| uiCCBMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| PVR_ASSERT(strlen(sCCBCtlName) == 0); |
| PVR_ASSERT(strlen(sAppend) == APPEND_STR_SIZE); |
| PVR_ASSERT(strlen(pszName) <= INPUT_STR_SIZE_MAX); |
| |
| /* Append "Control" to the name for the control struct. */ |
| strncat(sCCBCtlName, pszName, INPUT_STR_SIZE_MAX); |
| strncat(sCCBCtlName, sAppend, APPEND_STR_SIZE); |
| |
| /* |
| Allocate memory for the Firmware CCB control. |
| */ |
| PDUMPCOMMENT("Allocate memory for %s", sCCBCtlName); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_CCB_CTL), |
| uiCCBCtlMemAllocFlags, |
| sCCBCtlName, |
| ppsFirmwareCCBCtlMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmwareCCB: Failed to allocate %s (%u)", sCCBCtlName, eError)); |
| goto fail; |
| } |
| |
| /* |
| Allocate memory for the Firmware CCB. |
| (this will reference further command data in non-shared CCBs) |
| */ |
| PDUMPCOMMENT("Allocate memory for %s", pszName); |
| eError = DevmemFwAllocate(psDevInfo, |
| ui32FWCCBSize * ui32CmdSize, |
| uiCCBMemAllocFlags, |
| pszName, |
| ppsFirmwareCCBMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmwareCCB: Failed to allocate %s (%u)", pszName, eError)); |
| goto fail; |
| } |
| |
| /* |
| Map the Firmware CCB control to the kernel. |
| */ |
| eError = DevmemAcquireCpuVirtAddr(*ppsFirmwareCCBCtlMemDesc, |
| (void **)ppsFirmwareCCBCtl); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmwareCCB: Failed to acquire cpu %s (%u)", sCCBCtlName, eError)); |
| goto fail; |
| } |
| |
| /* |
| Map the firmware CCB to the kernel. |
| */ |
| eError = DevmemAcquireCpuVirtAddr(*ppsFirmwareCCBMemDesc, |
| (void **)ppui8FirmwareCCB); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmwareCCB: Failed to acquire cpu %s (%u)", pszName, eError)); |
| goto fail; |
| } |
| |
| /* |
| * Initialise the firmware CCB control. |
| */ |
| psFWCCBCtl = *ppsFirmwareCCBCtl; |
| psFWCCBCtl->ui32WriteOffset = 0; |
| psFWCCBCtl->ui32ReadOffset = 0; |
| psFWCCBCtl->ui32WrapMask = ui32FWCCBSize - 1; |
| psFWCCBCtl->ui32CmdSize = ui32CmdSize; |
| |
| /* |
| * Set-up RGXFWIfCtl pointers to access the kCCBs |
| */ |
| RGXSetFirmwareAddress(psFirmwareCCBCtlFWAddr, |
| *ppsFirmwareCCBCtlMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| RGXSetFirmwareAddress(psFirmwareCCBFWAddr, |
| *ppsFirmwareCCBMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| /* |
| * Pdump the kernel CCB control. |
| */ |
| PDUMPCOMMENT("Initialise %s", sCCBCtlName); |
| DevmemPDumpLoadMem(*ppsFirmwareCCBCtlMemDesc, |
| 0, |
| sizeof(RGXFWIF_CCB_CTL), |
| 0); |
| |
| return PVRSRV_OK; |
| |
| fail: |
| RGXFreeFirmwareCCB(psDevInfo, |
| ppsFirmwareCCBCtl, |
| ppsFirmwareCCBCtlMemDesc, |
| ppui8FirmwareCCB, |
| ppsFirmwareCCBMemDesc); |
| |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| static void RGXSetupFaultReadRegisterRollback(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| PMR *psPMR; |
| |
| if (psDevInfo->psRGXFaultAddressMemDesc) |
| { |
| if (DevmemServerGetImportHandle(psDevInfo->psRGXFaultAddressMemDesc,(void **)&psPMR) == PVRSRV_OK) |
| { |
| PMRUnlockSysPhysAddresses(psPMR); |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFaultAddressMemDesc); |
| psDevInfo->psRGXFaultAddressMemDesc = NULL; |
| } |
| } |
| |
| static PVRSRV_ERROR RGXSetupFaultReadRegister(PVRSRV_DEVICE_NODE *psDeviceNode, RGXFWIF_INIT *psRGXFWInit) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| IMG_UINT32 *pui32MemoryVirtAddr; |
| IMG_UINT32 i; |
| size_t ui32PageSize; |
| DEVMEM_FLAGS_T uiMemAllocFlags; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| PMR *psPMR; |
| |
| ui32PageSize = OSGetPageSize(); |
| |
| /* Allocate page of memory to use for page faults on non-blocking memory transactions */ |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED; |
| |
| psDevInfo->psRGXFaultAddressMemDesc = NULL; |
| eError = DevmemFwAllocateExportable(psDeviceNode, |
| ui32PageSize, |
| ui32PageSize, |
| uiMemAllocFlags, |
| "FwExFaultAddress", |
| &psDevInfo->psRGXFaultAddressMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"Failed to allocate mem for fault address (%u)", |
| eError)); |
| goto failFaultAddressDescAlloc; |
| } |
| |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFaultAddressMemDesc, |
| (void **)&pui32MemoryVirtAddr); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire mem for fault address (%u)", |
| eError)); |
| goto failFaultAddressDescAqCpuVirt; |
| } |
| |
| for (i = 0; i < ui32PageSize/sizeof(IMG_UINT32); i++) |
| { |
| *(pui32MemoryVirtAddr + i) = 0xDEADBEEF; |
| } |
| |
| eError = DevmemServerGetImportHandle(psDevInfo->psRGXFaultAddressMemDesc,(void **)&psPMR); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Error getting PMR for fault address (%u)", |
| eError)); |
| |
| goto failFaultAddressDescGetPMR; |
| } |
| else |
| { |
| IMG_BOOL bValid; |
| IMG_UINT32 ui32Log2PageSize = OSGetPageShift(); |
| |
| eError = PMRLockSysPhysAddresses(psPMR); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Error locking physical address for fault address MemDesc (%u)", |
| eError)); |
| |
| goto failFaultAddressDescLockPhys; |
| } |
| |
| eError = PMR_DevPhysAddr(psPMR,ui32Log2PageSize,1,0,&(psRGXFWInit->sFaultPhysAddr),&bValid); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Error getting physical address for fault address MemDesc (%u)", |
| eError)); |
| |
| goto failFaultAddressDescGetPhys; |
| } |
| |
| if (!bValid) |
| { |
| psRGXFWInit->sFaultPhysAddr.uiAddr = 0; |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed getting physical address for fault address MemDesc - invalid page (0x%llX)", |
| psRGXFWInit->sFaultPhysAddr.uiAddr)); |
| |
| goto failFaultAddressDescGetPhys; |
| } |
| } |
| |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFaultAddressMemDesc); |
| |
| return PVRSRV_OK; |
| |
| failFaultAddressDescGetPhys: |
| PMRUnlockSysPhysAddresses(psPMR); |
| |
| failFaultAddressDescLockPhys: |
| |
| failFaultAddressDescGetPMR: |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFaultAddressMemDesc); |
| |
| failFaultAddressDescAqCpuVirt: |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFaultAddressMemDesc); |
| psDevInfo->psRGXFaultAddressMemDesc = NULL; |
| |
| failFaultAddressDescAlloc: |
| #endif |
| return eError; |
| } |
| |
| static PVRSRV_ERROR RGXHwBrn37200(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| IMG_UINT64 ui64ErnsBrns = psDevInfo->sDevFeatureCfg.ui64ErnsBrns; |
| IMG_UINT32 ui32CacheLineSize = GET_ROGUE_CACHE_LINE_SIZE(psDevInfo->sDevFeatureCfg.ui32CacheLineSize); |
| |
| if(ui64ErnsBrns & FIX_HW_BRN_37200_BIT_MASK) |
| { |
| struct _DEVMEM_HEAP_ *psBRNHeap; |
| DEVMEM_FLAGS_T uiFlags; |
| IMG_DEV_VIRTADDR sTmpDevVAddr; |
| size_t uiPageSize; |
| |
| uiPageSize = OSGetPageSize(); |
| |
| uiFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| eError = DevmemFindHeapByName(psDevInfo->psKernelDevmemCtx, |
| "HWBRN37200", /* FIXME: We need to create an IDENT macro for this string. |
| Make sure the IDENT macro is not accessible to userland */ |
| &psBRNHeap); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXHwBrn37200: HWBRN37200 Failed DevmemFindHeapByName (%u)", eError)); |
| goto failFWHWBRN37200FindHeapByName; |
| } |
| |
| psDevInfo->psRGXFWHWBRN37200MemDesc = NULL; |
| eError = DevmemAllocate(psBRNHeap, |
| uiPageSize, |
| ui32CacheLineSize, |
| uiFlags, |
| "HWBRN37200", |
| &psDevInfo->psRGXFWHWBRN37200MemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXHwBrn37200: Failed to allocate %u bytes for HWBRN37200 (%u)", |
| (IMG_UINT32)uiPageSize, |
| eError)); |
| goto failFWHWBRN37200MemDescAlloc; |
| } |
| |
| /* |
| We need to map it so the heap for this allocation |
| is set |
| */ |
| eError = DevmemMapToDevice(psDevInfo->psRGXFWHWBRN37200MemDesc, |
| psBRNHeap, |
| &sTmpDevVAddr); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXHwBrn37200: Failed to allocate %u bytes for HWBRN37200 (%u)", |
| (IMG_UINT32)uiPageSize, |
| eError)); |
| goto failFWHWBRN37200DevmemMapToDevice; |
| } |
| |
| |
| |
| return PVRSRV_OK; |
| |
| failFWHWBRN37200DevmemMapToDevice: |
| |
| failFWHWBRN37200MemDescAlloc: |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWHWBRN37200MemDesc); |
| psDevInfo->psRGXFWHWBRN37200MemDesc = NULL; |
| |
| failFWHWBRN37200FindHeapByName:; |
| } |
| #endif |
| return eError; |
| } |
| |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| /*************************************************************************/ /*! |
| @Function RGXTraceBufferIsInitRequired |
| |
| @Description Returns true if the firmware trace buffer is not allocated and |
| might be required by the firmware soon. Trace buffer allocated |
| on-demand to reduce RAM footprint on systems not needing |
| firmware trace. |
| |
| @Input psDevInfo RGX device info |
| |
| @Return IMG_BOOL Whether on-demand allocation(s) is/are needed |
| or not |
| */ /**************************************************************************/ |
| INLINE IMG_BOOL RGXTraceBufferIsInitRequired(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| |
| /* The firmware expects a trace buffer only when: |
| * - Logtype is "trace" AND |
| * - at least one LogGroup is configured |
| */ |
| if((psDevInfo->psRGXFWIfTraceBufferMemDesc[0] == NULL) |
| && (psTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_TRACE) |
| && (psTraceBufCtl->ui32LogType & RGXFWIF_LOG_TYPE_GROUP_MASK)) |
| { |
| return IMG_TRUE; |
| } |
| |
| return IMG_FALSE; |
| } |
| |
| /*************************************************************************/ /*! |
| @Function RGXTraceBufferInitOnDemandResources |
| |
| @Description Allocates the firmware trace buffer required for dumping trace |
| info from the firmware. |
| |
| @Input psDevInfo RGX device info |
| |
| @Return PVRSRV_OK If all went good, PVRSRV_ERROR otherwise. |
| */ /**************************************************************************/ |
| PVRSRV_ERROR RGXTraceBufferInitOnDemandResources(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| DEVMEM_FLAGS_T uiMemAllocFlags; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| IMG_UINT32 ui32FwThreadNum; |
| |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| for (ui32FwThreadNum = 0; ui32FwThreadNum < RGXFW_THREAD_NUM; ui32FwThreadNum++) |
| { |
| /* Ensure allocation API is only called when not already allocated */ |
| PVR_ASSERT(psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum] == NULL); |
| |
| PDUMPCOMMENT("Allocate rgxfw trace buffer(%u)", ui32FwThreadNum); |
| eError = DevmemFwAllocate(psDevInfo, |
| RGXFW_TRACE_BUFFER_SIZE * sizeof(*(psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32TraceBuffer)), |
| uiMemAllocFlags, |
| "FwTraceBuffer", |
| &psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum]); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to allocate %zu bytes for fw trace buffer %u (Error code:%u)", |
| __FUNCTION__, |
| RGXFW_TRACE_BUFFER_SIZE * sizeof(*(psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32TraceBuffer)), |
| ui32FwThreadNum, |
| eError)); |
| goto fail; |
| } |
| |
| /* Firmware address should not be already set */ |
| PVR_ASSERT(psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32RGXFWIfTraceBuffer.ui32Addr == 0x0); |
| |
| /* for the FW to use this address when dumping in log (trace) buffer */ |
| RGXSetFirmwareAddress(&psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32RGXFWIfTraceBuffer, |
| psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum], |
| 0, RFW_FWADDR_NOREF_FLAG); |
| /* Set an address for the host to be able to read fw trace buffer */ |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufferMemDesc[ui32FwThreadNum], |
| (void **)&psTraceBufCtl->sTraceBuf[ui32FwThreadNum].pui32TraceBuffer); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to acquire kernel tracebuf (%u) ctl (Error code: %u)", |
| __FUNCTION__, ui32FwThreadNum, eError)); |
| goto fail; |
| } |
| } |
| |
| /* Just return error in-case of failures, clean-up would be handled by DeInit function */ |
| fail: |
| return eError; |
| } |
| |
| /*************************************************************************/ /*! |
| @Function RGXTraceBufferDeinit |
| |
| @Description Deinitialises all the allocations and references that are made |
| for the FW trace buffer(s) |
| |
| @Input ppsDevInfo RGX device info |
| @Return void |
| */ /**************************************************************************/ |
| static void RGXTraceBufferDeinit(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| RGXFWIF_TRACEBUF* psTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| IMG_UINT32 i; |
| |
| for (i = 0; i < RGXFW_THREAD_NUM; i++) |
| { |
| if (psDevInfo->psRGXFWIfTraceBufferMemDesc[i]) |
| { |
| if (psTraceBufCtl->sTraceBuf[i].pui32TraceBuffer != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufferMemDesc[i]); |
| psTraceBufCtl->sTraceBuf[i].pui32TraceBuffer = NULL; |
| } |
| |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfTraceBufferMemDesc[i]); |
| psDevInfo->psRGXFWIfTraceBufferMemDesc[i] = NULL; |
| } |
| } |
| } |
| #endif |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function RGXSetupFirmware |
| |
| @Description |
| |
| Setups all the firmware related data |
| |
| @Input psDevInfo |
| |
| @Return PVRSRV_ERROR |
| |
| ******************************************************************************/ |
| PVRSRV_ERROR RGXSetupFirmware(PVRSRV_DEVICE_NODE *psDeviceNode, |
| IMG_BOOL bEnableSignatureChecks, |
| IMG_UINT32 ui32SignatureChecksBufSize, |
| IMG_UINT32 ui32HWPerfFWBufSizeKB, |
| IMG_UINT64 ui64HWPerfFilter, |
| IMG_UINT32 ui32RGXFWAlignChecksArrLength, |
| IMG_UINT32 *pui32RGXFWAlignChecks, |
| IMG_UINT32 ui32ConfigFlags, |
| IMG_UINT32 ui32LogType, |
| RGXFWIF_BIFTILINGMODE eBifTilingMode, |
| IMG_UINT32 ui32NumTilingCfgs, |
| IMG_UINT32 *pui32BIFTilingXStrides, |
| IMG_UINT32 ui32FilterFlags, |
| IMG_UINT32 ui32JonesDisableMask, |
| IMG_UINT32 ui32HWRDebugDumpLimit, |
| IMG_UINT32 ui32HWPerfCountersDataSize, |
| PMR **ppsHWPerfPMR, |
| RGXFWIF_DEV_VIRTADDR *psRGXFWInitFWAddr, |
| RGX_RD_POWER_ISLAND_CONF eRGXRDPowerIslandConf, |
| FW_PERF_CONF eFirmwarePerf) |
| |
| { |
| PVRSRV_ERROR eError; |
| DEVMEM_FLAGS_T uiMemAllocFlags; |
| RGXFWIF_INIT *psRGXFWInit = NULL; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| IMG_UINT32 dm, ui32Temp = 0; |
| IMG_UINT64 ui64ErnsBrns; |
| #if defined (SUPPORT_PDVFS) |
| RGXFWIF_PDVFS_OPP *psPDVFSOPPInfo; |
| IMG_DVFS_DEVICE_CFG *psDVFSDeviceCfg; |
| #endif |
| ui64ErnsBrns = psDevInfo->sDevFeatureCfg.ui64ErnsBrns; |
| |
| /* Fw init data */ |
| |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| /* FIXME: Change to Cached */ |
| |
| |
| PDUMPCOMMENT("Allocate RGXFWIF_INIT structure"); |
| |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_INIT), |
| uiMemAllocFlags, |
| "FwInitStructure", |
| &psDevInfo->psRGXFWIfInitMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %u bytes for fw if ctl (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_INIT), |
| eError)); |
| goto fail; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc, |
| (void **)&psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel fw if ctl (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psDevInfo->sFWInitFWAddr, |
| psDevInfo->psRGXFWIfInitMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| *psRGXFWInitFWAddr = psDevInfo->sFWInitFWAddr; |
| |
| #if defined(PVRSRV_GPUVIRT_GUESTDRV) |
| /* |
| * Guest drivers do not support the following functionality: |
| * - Perform actual on-chip fw loading & initialisation |
| * - Perform actual on-chip fw management (i.e. reset) |
| * - Perform actual on-chip fw HWPerf,Trace,Utils,ActivePM |
| */ |
| #else |
| /* FW trace control structure */ |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| PDUMPCOMMENT("Allocate rgxfw trace control structure"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_TRACEBUF), |
| uiMemAllocFlags, |
| "FwTraceCtlStruct", |
| &psDevInfo->psRGXFWIfTraceBufCtlMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %u bytes for fw trace (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_TRACEBUF), |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sTraceBufCtl, |
| psDevInfo->psRGXFWIfTraceBufCtlMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufCtlMemDesc, |
| (void **)&psDevInfo->psRGXFWIfTraceBuf); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel tracebuf ctl (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| /* Set initial firmware log type/group(s) */ |
| if (ui32LogType & ~RGXFWIF_LOG_TYPE_MASK) |
| { |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Invalid initial log type (0x%X)",ui32LogType)); |
| goto fail; |
| } |
| psDevInfo->psRGXFWIfTraceBuf->ui32LogType = ui32LogType; |
| |
| #if defined (PDUMP) |
| /* When PDUMP is enabled, ALWAYS allocate on-demand trace buffer resource |
| * (irrespective of loggroup(s) enabled), given that logtype/loggroups can |
| * be set during PDump playback in logconfig, at any point of time */ |
| eError = RGXTraceBufferInitOnDemandResources(psDevInfo); |
| #else |
| /* Otherwise, allocate only if required */ |
| if (RGXTraceBufferIsInitRequired(psDevInfo)) |
| { |
| eError = RGXTraceBufferInitOnDemandResources(psDevInfo); |
| } |
| else |
| { |
| eError = PVRSRV_OK; |
| } |
| #endif |
| PVR_LOGG_IF_ERROR(eError, "RGXTraceBufferInitOnDemandResources", fail); |
| |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| if ((0 != psDevInfo->sDevFeatureCfg.ui32MCMS) && \ |
| (0 == (ui64ErnsBrns & FIX_HW_BRN_50767_BIT_MASK))) |
| { |
| IMG_BOOL bMetaDMA = psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_META_DMA_BIT_MASK; |
| |
| #if defined(SUPPORT_TRUSTED_DEVICE) |
| if (bMetaDMA) |
| { |
| IMG_UINT64 ui64SecBufHandle; |
| |
| PDUMPCOMMENT("Import secure buffer to store FW coremem data"); |
| eError = DevmemImportTDSecureBuf(psDeviceNode, |
| RGX_META_COREMEM_BSS_SIZE, |
| OSGetPageShift(), |
| uiMemAllocFlags, |
| &psDevInfo->psRGXFWIfCorememDataStoreMemDesc, |
| &ui64SecBufHandle); |
| } |
| else |
| #endif |
| { |
| PDUMPCOMMENT("Allocate buffer to store FW coremem data"); |
| eError = DevmemFwAllocate(psDevInfo, |
| RGX_META_COREMEM_BSS_SIZE, |
| uiMemAllocFlags, |
| "FwCorememDataStore", |
| &psDevInfo->psRGXFWIfCorememDataStoreMemDesc); |
| } |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXSetupFirmware: Failed to allocate coremem data store (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sCorememDataStore.pbyFWAddr, |
| psDevInfo->psRGXFWIfCorememDataStoreMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| if (bMetaDMA) |
| { |
| RGXSetMetaDMAAddress(&psRGXFWInit->sCorememDataStore, |
| psDevInfo->psRGXFWIfCorememDataStoreMemDesc, |
| &psRGXFWInit->sCorememDataStore.pbyFWAddr, |
| 0); |
| } |
| } |
| |
| /* init HW frame info */ |
| PDUMPCOMMENT("Allocate rgxfw HW info buffer"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_HWRINFOBUF), |
| uiMemAllocFlags, |
| "FwHWInfoBuffer", |
| &psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %d bytes for HW info (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_HWRINFOBUF), |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sRGXFWIfHWRInfoBufCtl, |
| psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc, |
| (void **)&psDevInfo->psRGXFWIfHWRInfoBuf); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel tracebuf ctl (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| /* Might be uncached. Be conservative and use a DeviceMemSet */ |
| OSDeviceMemSet(psDevInfo->psRGXFWIfHWRInfoBuf, 0, sizeof(RGXFWIF_HWRINFOBUF)); |
| |
| /* Allocate shared buffer for GPU utilisation */ |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| PDUMPCOMMENT("Allocate shared buffer for GPU utilisation"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_GPU_UTIL_FWCB), |
| uiMemAllocFlags, |
| "FwGPUUtilisationBuffer", |
| &psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %u bytes for GPU utilisation buffer ctl (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_GPU_UTIL_FWCB), |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sGpuUtilFWCbCtl, |
| psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc, |
| (void **)&psDevInfo->psRGXFWIfGpuUtilFWCb); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel GPU utilisation buffer ctl (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| /* Initialise GPU utilisation buffer */ |
| psDevInfo->psRGXFWIfGpuUtilFWCb->ui64LastWord = |
| RGXFWIF_GPU_UTIL_MAKE_WORD(OSClockns64(),RGXFWIF_GPU_UTIL_STATE_IDLE); |
| |
| |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| PDUMPCOMMENT("Allocate rgxfw FW runtime configuration (FW)"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_RUNTIME_CFG), |
| uiMemAllocFlags, |
| "FwRuntimeCfg", |
| &psDevInfo->psRGXFWIfRuntimeCfgMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %u bytes for FW runtime configuration (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_RUNTIME_CFG), |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sRuntimeCfg, |
| psDevInfo->psRGXFWIfRuntimeCfgMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfRuntimeCfgMemDesc, |
| (void **)&psDevInfo->psRGXFWIfRuntimeCfg); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire kernel FW runtime configuration (%u)", |
| eError)); |
| goto fail; |
| } |
| |
| |
| /* HWPerf: Determine the size of the FW buffer */ |
| if (ui32HWPerfFWBufSizeKB == 0 || |
| ui32HWPerfFWBufSizeKB == RGXFW_HWPERF_L1_SIZE_DEFAULT) |
| { |
| /* Under pvrsrvctl 0 size implies AppHint not set or is set to zero, |
| * use default size from driver constant. Under SUPPORT_KERNEL_SRVINIT |
| * default is the above macro. In either case, set it to the default, |
| * size, no logging. |
| */ |
| psDevInfo->ui32RGXFWIfHWPerfBufSize = RGXFW_HWPERF_L1_SIZE_DEFAULT<<10; |
| } |
| else if (ui32HWPerfFWBufSizeKB > (RGXFW_HWPERF_L1_SIZE_MAX)) |
| { |
| /* Size specified as a AppHint but it is too big */ |
| PVR_DPF((PVR_DBG_WARNING,"RGXSetupFirmware: HWPerfFWBufSizeInKB value (%u) too big, using maximum (%u)", |
| ui32HWPerfFWBufSizeKB, RGXFW_HWPERF_L1_SIZE_MAX)); |
| psDevInfo->ui32RGXFWIfHWPerfBufSize = RGXFW_HWPERF_L1_SIZE_MAX<<10; |
| } |
| else if (ui32HWPerfFWBufSizeKB > (RGXFW_HWPERF_L1_SIZE_MIN)) |
| { |
| /* Size specified as in AppHint HWPerfFWBufSizeInKB */ |
| PVR_DPF((PVR_DBG_WARNING,"RGXSetupFirmware: Using HWPerf FW buffer size of %u KB", |
| ui32HWPerfFWBufSizeKB)); |
| psDevInfo->ui32RGXFWIfHWPerfBufSize = ui32HWPerfFWBufSizeKB<<10; |
| } |
| else |
| { |
| /* Size specified as a AppHint but it is too small */ |
| PVR_DPF((PVR_DBG_WARNING,"RGXSetupFirmware: HWPerfFWBufSizeInKB value (%u) too small, using minimum (%u)", |
| ui32HWPerfFWBufSizeKB, RGXFW_HWPERF_L1_SIZE_MIN)); |
| psDevInfo->ui32RGXFWIfHWPerfBufSize = RGXFW_HWPERF_L1_SIZE_MIN<<10; |
| } |
| |
| /* init HWPERF data */ |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfRIdx = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfWIdx = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfWrapCount = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfSize = psDevInfo->ui32RGXFWIfHWPerfBufSize; |
| psRGXFWInit->bDisableFilterHWPerfCustomCounter = (ui32ConfigFlags & RGXFWIF_INICFG_HWP_DISABLE_FILTER) ? IMG_TRUE : IMG_FALSE; |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfUt = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32HWPerfDropCount = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32FirstDropOrdinal = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32LastDropOrdinal = 0; |
| psDevInfo->psRGXFWIfTraceBuf->ui32PowMonEnergy = 0; |
| |
| /* Second stage initialisation or HWPerf, hHWPerfLock created in first |
| * stage. See RGXRegisterDevice() call to RGXHWPerfInit(). */ |
| if (psDevInfo->ui64HWPerfFilter == 0) |
| { |
| psDevInfo->ui64HWPerfFilter = ui64HWPerfFilter; |
| psRGXFWInit->ui64HWPerfFilter = ui64HWPerfFilter; |
| } |
| else |
| { |
| /* The filter has already been modified. This can happen if the driver |
| * was compiled with SUPPORT_KERNEL_SRVINIT enabled and e.g. |
| * pvr/gpu_tracing_on was enabled. */ |
| psRGXFWInit->ui64HWPerfFilter = psDevInfo->ui64HWPerfFilter; |
| } |
| |
| #if defined (PDUMP) |
| /* When PDUMP is enabled, ALWAYS allocate on-demand HWPerf resources |
| * (irrespective of HWPerf enabled or not), given that HWPerf can be |
| * enabled during PDump playback via RTCONF at any point of time. */ |
| eError = RGXHWPerfInitOnDemandResources(); |
| #else |
| /* Otherwise, only allocate if HWPerf is enabled via apphint */ |
| if (ui32ConfigFlags & RGXFWIF_INICFG_HWPERF_EN) |
| { |
| eError = RGXHWPerfInitOnDemandResources(); |
| } |
| #endif |
| PVR_LOGG_IF_ERROR(eError, "RGXHWPerfInitOnDemandResources", fail); |
| |
| RGXHWPerfInitAppHintCallbacks(psDeviceNode); |
| |
| #if defined(SUPPORT_USER_REGISTER_CONFIGURATION) |
| PDUMPCOMMENT("Allocate rgxfw register configuration structure"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(RGXFWIF_REG_CFG), |
| uiMemAllocFlags | PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE, |
| "FwRegisterConfigStructure", |
| &psDevInfo->psRGXFWIfRegCfgMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate %u bytes for fw register configurations (%u)", |
| (IMG_UINT32)sizeof(RGXFWIF_REG_CFG), |
| eError)); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sRegCfg, |
| psDevInfo->psRGXFWIfRegCfgMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| #endif |
| |
| uiMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| PDUMPCOMMENT("Allocate rgxfw hwperfctl structure"); |
| eError = DevmemFwAllocateExportable(psDeviceNode, |
| ui32HWPerfCountersDataSize, |
| OSGetPageSize(), |
| uiMemAllocFlags, |
| "FwExHWPerfControlStructure", |
| &psDevInfo->psRGXFWIfHWPerfCountersMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXInitHWPerfCounters: Failed to allocate %u bytes for fw hwperf control (%u)", |
| ui32HWPerfCountersDataSize, |
| eError)); |
| goto fail; |
| } |
| |
| eError = DevmemLocalGetImportHandle(psDevInfo->psRGXFWIfHWPerfCountersMemDesc, (void**) ppsHWPerfPMR); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"DevmemLocalGetImportHandle failed (%u)", eError)); |
| goto fail; |
| } |
| |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sHWPerfCtl, |
| psDevInfo->psRGXFWIfHWPerfCountersMemDesc, |
| 0, 0); |
| |
| /* Required info by FW to calculate the ActivePM idle timer latency */ |
| { |
| RGX_DATA *psRGXData = (RGX_DATA*) psDeviceNode->psDevConfig->hDevData; |
| RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg; |
| |
| psRGXFWInit->ui32InitialCoreClockSpeed = psRGXData->psRGXTimingInfo->ui32CoreClockSpeed; |
| psRGXFWInit->ui32ActivePMLatencyms = psRGXData->psRGXTimingInfo->ui32ActivePMLatencyms; |
| |
| /* Initialise variable runtime configuration to the system defaults */ |
| psRuntimeCfg->ui32CoreClockSpeed = psRGXFWInit->ui32InitialCoreClockSpeed; |
| psRuntimeCfg->ui32ActivePMLatencyms = psRGXFWInit->ui32ActivePMLatencyms; |
| psRuntimeCfg->bActivePMLatencyPersistant = IMG_TRUE; |
| |
| /* Initialize the DefaultDustsNumInit Field to Max Dusts */ |
| psRuntimeCfg->ui32DefaultDustsNumInit = MAX(1, (psDevInfo->sDevFeatureCfg.ui32NumClusters/2)); |
| } |
| #if defined(PDUMP) |
| PDUMPCOMMENT("Dump initial state of FW runtime configuration"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfRuntimeCfgMemDesc, |
| 0, |
| sizeof(RGXFWIF_RUNTIME_CFG), |
| PDUMP_FLAGS_CONTINUOUS); |
| #endif |
| #endif /* defined(PVRSRV_GPUVIRT_GUESTDRV) */ |
| |
| /* Allocate a sync for power management */ |
| eError = SyncPrimContextCreate(psDevInfo->psDeviceNode, |
| &psDevInfo->hSyncPrimContext); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate sync primitive context with error (%u)", eError)); |
| goto fail; |
| } |
| |
| eError = SyncPrimAlloc(psDevInfo->hSyncPrimContext, &psDevInfo->psPowSyncPrim, "fw power ack"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate sync primitive with error (%u)", eError)); |
| goto fail; |
| } |
| |
| eError = SyncPrimGetFirmwareAddr(psDevInfo->psPowSyncPrim, |
| &psRGXFWInit->sPowerSync.ui32Addr); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "%s: Failed to get Sync Prim FW address with error (%u)", |
| __FUNCTION__, eError)); |
| goto fail; |
| } |
| |
| /* Setup Fault read register */ |
| eError = RGXSetupFaultReadRegister(psDeviceNode, psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup fault read register")); |
| goto fail; |
| } |
| |
| /* Apply FIX_HW_BRN_37200 */ |
| eError = RGXHwBrn37200(psDevInfo); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to apply HWBRN37200")); |
| goto fail; |
| } |
| |
| #if defined(SUPPORT_PVRSRV_GPUVIRT) |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_GPU_VIRTUALISATION_BIT_MASK)) |
| { |
| ui32Temp = RGXFWIF_KCCB_NUMCMDS_LOG2_GPUVIRT_ONLY; |
| }else |
| #endif |
| { |
| ui32Temp = RGXFWIF_KCCB_NUMCMDS_LOG2_FEAT_GPU_VIRTUALISATION; |
| } |
| /* |
| * Set up kernel CCB. |
| */ |
| eError = RGXSetupKernelCCB(psDevInfo, |
| psRGXFWInit, |
| ui32Temp, |
| sizeof(RGXFWIF_KCCB_CMD)); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate Kernel CCB")); |
| goto fail; |
| } |
| |
| /* |
| * Set up firmware CCB. |
| */ |
| eError = RGXSetupFirmwareCCB(psDevInfo, |
| &psDevInfo->psFirmwareCCBCtl, |
| &psDevInfo->psFirmwareCCBCtlMemDesc, |
| &psDevInfo->psFirmwareCCB, |
| &psDevInfo->psFirmwareCCBMemDesc, |
| &psRGXFWInit->psFirmwareCCBCtl, |
| &psRGXFWInit->psFirmwareCCB, |
| RGXFWIF_FWCCB_NUMCMDS_LOG2, |
| sizeof(RGXFWIF_FWCCB_CMD), |
| "FwCCB"); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate Firmware CCB")); |
| goto fail; |
| } |
| /* RD Power Island */ |
| { |
| RGX_DATA *psRGXData = (RGX_DATA*) psDeviceNode->psDevConfig->hDevData; |
| IMG_BOOL bSysEnableRDPowIsland = psRGXData->psRGXTimingInfo->bEnableRDPowIsland; |
| IMG_BOOL bEnableRDPowIsland = ((eRGXRDPowerIslandConf == RGX_RD_POWER_ISLAND_DEFAULT) && bSysEnableRDPowIsland) || |
| (eRGXRDPowerIslandConf == RGX_RD_POWER_ISLAND_FORCE_ON); |
| |
| ui32ConfigFlags |= bEnableRDPowIsland? RGXFWIF_INICFG_POW_RASCALDUST : 0; |
| } |
| |
| #if defined(SUPPORT_WORKLOAD_ESTIMATION) |
| ui32ConfigFlags |= RGXFWIF_INICFG_WORKEST_V2; |
| |
| #if defined(SUPPORT_PDVFS) |
| /* Proactive DVFS depends on Workload Estimation */ |
| psPDVFSOPPInfo = &(psRGXFWInit->sPDVFSOPPInfo); |
| psDVFSDeviceCfg = &psDeviceNode->psDevConfig->sDVFS.sDVFSDeviceCfg; |
| |
| if(psDVFSDeviceCfg->pasOPPTable != NULL) |
| { |
| if(psDVFSDeviceCfg->ui32OPPTableSize > |
| sizeof(psPDVFSOPPInfo->asOPPValues)/sizeof(psPDVFSOPPInfo->asOPPValues[0])) |
| { |
| PVR_DPF((PVR_DBG_ERROR, |
| "RGXSetupFirmware: OPP Table too large :" |
| " Size = %u, Maximum size = %lu", |
| psDVFSDeviceCfg->ui32OPPTableSize, |
| (unsigned long)(sizeof(psPDVFSOPPInfo->asOPPValues)/sizeof(psPDVFSOPPInfo->asOPPValues[0])))); |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| goto fail; |
| } |
| |
| memcpy(psPDVFSOPPInfo->asOPPValues, |
| psDVFSDeviceCfg->pasOPPTable, |
| sizeof(psPDVFSOPPInfo->asOPPValues)); |
| psPDVFSOPPInfo->ui32MaxOPPPoint = |
| (psDVFSDeviceCfg->ui32OPPTableSize) - 1; |
| |
| ui32ConfigFlags |= RGXFWIF_INICFG_PDVFS_V2; |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Missing OPP Table")); |
| } |
| #endif |
| #endif |
| |
| psRGXFWInit->ui32ConfigFlags = ui32ConfigFlags & RGXFWIF_INICFG_ALL; |
| |
| #if defined(SUPPORT_WORKLOAD_ESTIMATION) |
| /* |
| * Set up Workload Estimation firmware CCB. |
| */ |
| eError = RGXSetupFirmwareCCB(psDevInfo, |
| &psDevInfo->psWorkEstFirmwareCCBCtl, |
| &psDevInfo->psWorkEstFirmwareCCBCtlMemDesc, |
| &psDevInfo->psWorkEstFirmwareCCB, |
| &psDevInfo->psWorkEstFirmwareCCBMemDesc, |
| &psRGXFWInit->psWorkEstFirmwareCCBCtl, |
| &psRGXFWInit->psWorkEstFirmwareCCB, |
| RGXFWIF_WORKEST_FWCCB_NUMCMDS_LOG2, |
| sizeof(RGXFWIF_WORKEST_FWCCB_CMD), |
| "FwWEstCCB"); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate Workload Estimation Firmware CCB")); |
| goto fail; |
| } |
| #endif |
| |
| /* Require a minimum amount of memory for the signature buffers */ |
| if (ui32SignatureChecksBufSize < RGXFW_SIG_BUFFER_SIZE_MIN) |
| { |
| ui32SignatureChecksBufSize = RGXFW_SIG_BUFFER_SIZE_MIN; |
| } |
| |
| /* Setup Signature and Checksum Buffers for TA and 3D */ |
| eError = RGXFWSetupSignatureChecks(psDevInfo, |
| &psDevInfo->psRGXFWSigTAChecksMemDesc, |
| ui32SignatureChecksBufSize, |
| &psRGXFWInit->asSigBufCtl[RGXFWIF_DM_TA], |
| "TA"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup TA signature checks")); |
| goto fail; |
| } |
| psDevInfo->ui32SigTAChecksSize = ui32SignatureChecksBufSize; |
| |
| eError = RGXFWSetupSignatureChecks(psDevInfo, |
| &psDevInfo->psRGXFWSig3DChecksMemDesc, |
| ui32SignatureChecksBufSize, |
| &psRGXFWInit->asSigBufCtl[RGXFWIF_DM_3D], |
| "3D"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup 3D signature checks")); |
| goto fail; |
| } |
| psDevInfo->ui32Sig3DChecksSize = ui32SignatureChecksBufSize; |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| eError = RGXFWSetupSignatureChecks(psDevInfo, |
| &psDevInfo->psRGXFWSigRTChecksMemDesc, |
| ui32SignatureChecksBufSize, |
| &psRGXFWInit->asSigBufCtl[RGXFWIF_DM_RTU], |
| "RTU"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup RTU signature checks")); |
| goto fail; |
| } |
| psDevInfo->ui32SigRTChecksSize = ui32SignatureChecksBufSize; |
| |
| eError = RGXFWSetupSignatureChecks(psDevInfo, |
| &psDevInfo->psRGXFWSigSHChecksMemDesc, |
| ui32SignatureChecksBufSize, |
| &psRGXFWInit->asSigBufCtl[RGXFWIF_DM_SHG], |
| "SHG"); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup SHG signature checks")); |
| goto fail; |
| } |
| psDevInfo->ui32SigSHChecksSize = ui32SignatureChecksBufSize; |
| } |
| |
| #if defined(RGXFW_ALIGNCHECKS) |
| eError = RGXFWSetupAlignChecks(psDevInfo, |
| &psRGXFWInit->sAlignChecks, |
| pui32RGXFWAlignChecks, |
| ui32RGXFWAlignChecksArrLength); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to setup alignment checks")); |
| goto fail; |
| } |
| #endif |
| |
| psRGXFWInit->ui32FilterFlags = ui32FilterFlags; |
| |
| #if defined(PVRSRV_GPUVIRT_GUESTDRV) |
| /* |
| * Guest drivers do not support the following functionality: |
| * - Perform actual on-chip fw RDPowIsland(ing) |
| * - Perform actual on-chip fw tracing |
| * - Configure FW perf counters |
| */ |
| PVR_UNREFERENCED_PARAMETER(dm); |
| PVR_UNREFERENCED_PARAMETER(eFirmwarePerf); |
| #else |
| |
| if(ui64ErnsBrns & FIX_HW_BRN_52402_BIT_MASK) |
| { |
| /* Fill the remaining bits of fw the init data */ |
| psRGXFWInit->sPDSExecBase.uiAddr = RGX_PDSCODEDATA_BRN_52402_HEAP_BASE; |
| psRGXFWInit->sUSCExecBase.uiAddr = RGX_USCCODE_BRN_52402_HEAP_BASE; |
| }else |
| { |
| /* Fill the remaining bits of fw the init data */ |
| psRGXFWInit->sPDSExecBase.uiAddr = RGX_PDSCODEDATA_HEAP_BASE; |
| psRGXFWInit->sUSCExecBase.uiAddr = RGX_USCCODE_HEAP_BASE; |
| } |
| |
| psRGXFWInit->sDPXControlStreamBase.uiAddr = RGX_DOPPLER_HEAP_BASE; |
| psRGXFWInit->sResultDumpBase.uiAddr = RGX_DOPPLER_OVERFLOW_HEAP_BASE; |
| psRGXFWInit->sRTUHeapBase.uiAddr = RGX_DOPPLER_HEAP_BASE; |
| psRGXFWInit->sTDMTPUYUVCeoffsHeapBase.uiAddr = RGX_TDM_TPU_YUV_COEFFS_HEAP_BASE; |
| |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_S7_TOP_INFRASTRUCTURE_BIT_MASK) |
| { |
| psRGXFWInit->ui32JonesDisableMask = ui32JonesDisableMask; |
| } |
| psDevInfo->bPDPEnabled = (ui32ConfigFlags & RGXFWIF_SRVCFG_DISABLE_PDP_EN) |
| ? IMG_FALSE : IMG_TRUE; |
| psRGXFWInit->ui32HWRDebugDumpLimit = ui32HWRDebugDumpLimit; |
| |
| psRGXFWInit->eFirmwarePerf = eFirmwarePerf; |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_SLC_VIVT_BIT_MASK) |
| { |
| eError = _AllocateSLC3Fence(psDevInfo, psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate memory for SLC3Fence")); |
| goto fail; |
| } |
| } |
| |
| |
| if ( (psDevInfo->sDevFeatureCfg.ui32META) && \ |
| ((ui32ConfigFlags & RGXFWIF_INICFG_METAT1_ENABLED) != 0)) |
| { |
| /* Allocate a page for T1 stack */ |
| eError = DevmemFwAllocate(psDevInfo, |
| RGX_META_STACK_SIZE, |
| RGX_FWCOMCTX_ALLOCFLAGS, |
| "FwMETAT1Stack", |
| & psDevInfo->psMETAT1StackMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate T1 Stack")); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sT1Stack, |
| psDevInfo->psMETAT1StackMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXSetupFirmware: T1 Stack Frame allocated at %x", |
| psRGXFWInit->sT1Stack.ui32Addr)); |
| } |
| |
| #if defined(SUPPORT_PDVFS) |
| /* Core clock rate */ |
| uiMemAllocFlags = |
| PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(IMG_UINT32), |
| uiMemAllocFlags, |
| "FwCoreClkRate", |
| &psDevInfo->psRGXFWIFCoreClkRateMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to allocate PDVFS core clock rate")); |
| goto fail; |
| } |
| |
| RGXSetFirmwareAddress(&psRGXFWInit->sCoreClockRate, |
| psDevInfo->psRGXFWIFCoreClkRateMemDesc, |
| 0, RFW_FWADDR_NOREF_FLAG); |
| |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXSetupFirmware: PDVFS core clock rate allocated at %x", |
| psRGXFWInit->sCoreClockRate.ui32Addr)); |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIFCoreClkRateMemDesc, |
| (void **)&psDevInfo->pui32RGXFWIFCoreClkRate); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to acquire core clk rate (%u)", |
| eError)); |
| goto fail; |
| } |
| #endif |
| |
| /* Timestamps */ |
| uiMemAllocFlags = |
| PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) | |
| PVRSRV_MEMALLOCFLAG_GPU_READABLE | /* XXX ?? */ |
| PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE | |
| PVRSRV_MEMALLOCFLAG_CPU_READABLE | |
| PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE | |
| PVRSRV_MEMALLOCFLAG_UNCACHED | |
| PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC; |
| |
| /* |
| the timer query arrays |
| */ |
| PDUMPCOMMENT("Allocate timer query arrays (FW)"); |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(IMG_UINT64) * RGX_MAX_TIMER_QUERIES, |
| uiMemAllocFlags, |
| "FwStartTimesArray", |
| & psDevInfo->psStartTimeMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to map start times array")); |
| goto fail; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psStartTimeMemDesc, |
| (void **)& psDevInfo->pui64StartTimeById); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to map start times array")); |
| goto fail; |
| } |
| |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(IMG_UINT64) * RGX_MAX_TIMER_QUERIES, |
| uiMemAllocFlags, |
| "FwEndTimesArray", |
| & psDevInfo->psEndTimeMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to map end times array")); |
| goto fail; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psEndTimeMemDesc, |
| (void **)& psDevInfo->pui64EndTimeById); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to map end times array")); |
| goto fail; |
| } |
| |
| eError = DevmemFwAllocate(psDevInfo, |
| sizeof(IMG_UINT32) * RGX_MAX_TIMER_QUERIES, |
| uiMemAllocFlags, |
| "FwCompletedOpsArray", |
| & psDevInfo->psCompletedMemDesc); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to completed ops array")); |
| goto fail; |
| } |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psCompletedMemDesc, |
| (void **)& psDevInfo->pui32CompletedById); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed to map completed ops array")); |
| goto fail; |
| } |
| |
| /* Initialize FW started flag */ |
| psRGXFWInit->bFirmwareStarted = IMG_FALSE; |
| psRGXFWInit->ui32MarkerVal = 1; |
| |
| /* Initialise the compatibility check data */ |
| RGXFWIF_COMPCHECKS_BVNC_INIT(psRGXFWInit->sRGXCompChecks.sFWBVNC); |
| RGXFWIF_COMPCHECKS_BVNC_INIT(psRGXFWInit->sRGXCompChecks.sHWBVNC); |
| |
| PDUMPCOMMENT("Dump RGXFW Init data"); |
| if (!bEnableSignatureChecks) |
| { |
| #if defined(PDUMP) |
| PDUMPCOMMENT("(to enable rgxfw signatures place the following line after the RTCONF line)"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfInitMemDesc, |
| offsetof(RGXFWIF_INIT, asSigBufCtl), |
| sizeof(RGXFWIF_SIGBUF_CTL)*(psDevInfo->sDevFeatureCfg.ui32MAXDMCount), |
| PDUMP_FLAGS_CONTINUOUS); |
| #endif |
| psRGXFWInit->asSigBufCtl[RGXFWIF_DM_3D].sBuffer.ui32Addr = 0x0; |
| psRGXFWInit->asSigBufCtl[RGXFWIF_DM_TA].sBuffer.ui32Addr = 0x0; |
| } |
| |
| for (dm = 0; dm < (psDevInfo->sDevFeatureCfg.ui32MAXDMCount); dm++) |
| { |
| psDevInfo->psRGXFWIfTraceBuf->aui32HwrDmLockedUpCount[dm] = 0; |
| psDevInfo->psRGXFWIfTraceBuf->aui32HwrDmOverranCount[dm] = 0; |
| psDevInfo->psRGXFWIfTraceBuf->aui32HwrDmRecoveredCount[dm] = 0; |
| psDevInfo->psRGXFWIfTraceBuf->aui32HwrDmFalseDetectCount[dm] = 0; |
| } |
| |
| /* |
| * BIF Tiling configuration |
| */ |
| |
| psRGXFWInit->eBifTilingMode = eBifTilingMode; |
| |
| psRGXFWInit->sBifTilingCfg[0].uiBase = RGX_BIF_TILING_HEAP_1_BASE; |
| psRGXFWInit->sBifTilingCfg[0].uiLen = RGX_BIF_TILING_HEAP_SIZE; |
| psRGXFWInit->sBifTilingCfg[0].uiXStride = pui32BIFTilingXStrides[0]; |
| psRGXFWInit->sBifTilingCfg[1].uiBase = RGX_BIF_TILING_HEAP_2_BASE; |
| psRGXFWInit->sBifTilingCfg[1].uiLen = RGX_BIF_TILING_HEAP_SIZE; |
| psRGXFWInit->sBifTilingCfg[1].uiXStride = pui32BIFTilingXStrides[1]; |
| psRGXFWInit->sBifTilingCfg[2].uiBase = RGX_BIF_TILING_HEAP_3_BASE; |
| psRGXFWInit->sBifTilingCfg[2].uiLen = RGX_BIF_TILING_HEAP_SIZE; |
| psRGXFWInit->sBifTilingCfg[2].uiXStride = pui32BIFTilingXStrides[2]; |
| psRGXFWInit->sBifTilingCfg[3].uiBase = RGX_BIF_TILING_HEAP_4_BASE; |
| psRGXFWInit->sBifTilingCfg[3].uiLen = RGX_BIF_TILING_HEAP_SIZE; |
| psRGXFWInit->sBifTilingCfg[3].uiXStride = pui32BIFTilingXStrides[3]; |
| |
| #if defined(PDUMP) |
| PDUMPCOMMENT("Dump rgxfw hwperfctl structure"); |
| DevmemPDumpLoadZeroMem (psDevInfo->psRGXFWIfHWPerfCountersMemDesc, |
| 0, |
| ui32HWPerfCountersDataSize, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| PDUMPCOMMENT("Dump rgxfw trace control structure"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfTraceBufCtlMemDesc, |
| 0, |
| sizeof(RGXFWIF_TRACEBUF), |
| PDUMP_FLAGS_CONTINUOUS); |
| #if defined(SUPPORT_USER_REGISTER_CONFIGURATION) |
| PDUMPCOMMENT("Dump rgxfw register configuration buffer"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfRegCfgMemDesc, |
| 0, |
| sizeof(RGXFWIF_REG_CFG), |
| PDUMP_FLAGS_CONTINUOUS); |
| #endif |
| PDUMPCOMMENT("Dump rgxfw init structure"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfInitMemDesc, |
| 0, |
| sizeof(RGXFWIF_INIT), |
| PDUMP_FLAGS_CONTINUOUS); |
| if ((0 != psDevInfo->sDevFeatureCfg.ui32MCMS) && \ |
| (0 == (psDevInfo->sDevFeatureCfg.ui64ErnsBrns & FIX_HW_BRN_50767_BIT_MASK))) |
| { |
| PDUMPCOMMENT("Dump rgxfw coremem data store"); |
| DevmemPDumpLoadMem( psDevInfo->psRGXFWIfCorememDataStoreMemDesc, |
| 0, |
| RGX_META_COREMEM_BSS_SIZE, |
| PDUMP_FLAGS_CONTINUOUS); |
| } |
| |
| PDUMPCOMMENT("RTCONF: run-time configuration"); |
| |
| |
| /* Dump the config options so they can be edited. |
| * |
| * FIXME: Need new DevmemPDumpWRW API which writes a WRW to load ui32ConfigFlags |
| */ |
| PDUMPCOMMENT("(Set the FW config options here)"); |
| PDUMPCOMMENT("( Ctx Switch TA Enable: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_TA_EN); |
| PDUMPCOMMENT("( Ctx Switch 3D Enable: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_3D_EN); |
| PDUMPCOMMENT("( Ctx Switch CDM Enable: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_CDM_EN); |
| PDUMPCOMMENT("( Ctx Switch Rand mode: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_MODE_RAND); |
| PDUMPCOMMENT("( Ctx Switch Soft Reset Enable: 0x%08x)", RGXFWIF_INICFG_CTXSWITCH_SRESET_EN); |
| PDUMPCOMMENT("( Reserved (do not set): 0x%08x)", RGXFWIF_INICFG_RSVD); |
| PDUMPCOMMENT("( Rascal+Dust Power Island: 0x%08x)", RGXFWIF_INICFG_POW_RASCALDUST); |
| PDUMPCOMMENT("( Enable HWPerf: 0x%08x)", RGXFWIF_INICFG_HWPERF_EN); |
| PDUMPCOMMENT("( Enable HWR: 0x%08x)", RGXFWIF_INICFG_HWR_EN); |
| PDUMPCOMMENT("( Check MList: 0x%08x)", RGXFWIF_INICFG_CHECK_MLIST_EN); |
| PDUMPCOMMENT("( Disable Auto Clock Gating: 0x%08x)", RGXFWIF_INICFG_DISABLE_CLKGATING_EN); |
| PDUMPCOMMENT("( Enable HWPerf Polling Perf Counter: 0x%08x)", RGXFWIF_INICFG_POLL_COUNTERS_EN); |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_VDM_OBJECT_LEVEL_LLS_BIT_MASK) |
| { |
| PDUMPCOMMENT("( Ctx Switch Object mode Index: 0x%08x)", RGXFWIF_INICFG_VDM_CTX_STORE_MODE_INDEX); |
| PDUMPCOMMENT("( Ctx Switch Object mode Instance: 0x%08x)", RGXFWIF_INICFG_VDM_CTX_STORE_MODE_INSTANCE); |
| PDUMPCOMMENT("( Ctx Switch Object mode List: 0x%08x)", RGXFWIF_INICFG_VDM_CTX_STORE_MODE_LIST); |
| } |
| |
| PDUMPCOMMENT("( Enable SHG Bypass mode: 0x%08x)", RGXFWIF_INICFG_SHG_BYPASS_EN); |
| PDUMPCOMMENT("( Enable RTU Bypass mode: 0x%08x)", RGXFWIF_INICFG_RTU_BYPASS_EN); |
| PDUMPCOMMENT("( Enable register configuration: 0x%08x)", RGXFWIF_INICFG_REGCONFIG_EN); |
| PDUMPCOMMENT("( Assert on TA Out-of-Memory: 0x%08x)", RGXFWIF_INICFG_ASSERT_ON_OUTOFMEMORY); |
| PDUMPCOMMENT("( Disable HWPerf custom counter filter: 0x%08x)", RGXFWIF_INICFG_HWP_DISABLE_FILTER); |
| PDUMPCOMMENT("( Enable HWPerf custom performance timer: 0x%08x)", RGXFWIF_INICFG_CUSTOM_PERF_TIMER_EN); |
| PDUMPCOMMENT("( Enable CDM Killing Rand mode: 0x%08x)", RGXFWIF_INICFG_CDM_KILL_MODE_RAND_EN); |
| PDUMPCOMMENT("( Enable Ctx Switch profile mode: 0x%08x (none=b'000, fast=b'001, medium=b'010, slow=b'011, nodelay=b'100))", RGXFWIF_INICFG_CTXSWITCH_PROFILE_MASK); |
| PDUMPCOMMENT("( Disable DM overlap (except TA during SPM): 0x%08x)", RGXFWIF_INICFG_DISABLE_DM_OVERLAP); |
| PDUMPCOMMENT("( Enable Meta T1 running main code: 0x%08x)", RGXFWIF_INICFG_METAT1_MAIN); |
| PDUMPCOMMENT("( Enable Meta T1 running dummy code: 0x%08x)", RGXFWIF_INICFG_METAT1_DUMMY); |
| PDUMPCOMMENT("( Assert on HWR trigger (page fault, lockup, overrun or poll failure): 0x%08x)", RGXFWIF_INICFG_ASSERT_ON_HWR_TRIGGER); |
| |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfInitMemDesc, |
| offsetof(RGXFWIF_INIT, ui32ConfigFlags), |
| psRGXFWInit->ui32ConfigFlags, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| /* default: no filter */ |
| psRGXFWInit->sPIDFilter.eMode = RGXFW_PID_FILTER_INCLUDE_ALL_EXCEPT; |
| psRGXFWInit->sPIDFilter.asItems[0].uiPID = 0; |
| |
| PDUMPCOMMENT("( PID filter type: %X=INCLUDE_ALL_EXCEPT, %X=EXCLUDE_ALL_EXCEPT)", |
| RGXFW_PID_FILTER_INCLUDE_ALL_EXCEPT, |
| RGXFW_PID_FILTER_EXCLUDE_ALL_EXCEPT); |
| |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfInitMemDesc, |
| offsetof(RGXFWIF_INIT, sPIDFilter.eMode), |
| psRGXFWInit->sPIDFilter.eMode, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| PDUMPCOMMENT("( PID filter PID/OSID list (Up to %u entries. Terminate with a zero PID))", |
| RGXFWIF_PID_FILTER_MAX_NUM_PIDS); |
| { |
| IMG_UINT32 i; |
| |
| /* generate a few WRWs in the pdump stream as an example */ |
| for(i = 0; i < MIN(RGXFWIF_PID_FILTER_MAX_NUM_PIDS, 8); i++) |
| { |
| /* |
| * Some compilers cannot cope with the uses of offsetof() below - the specific problem being the use of |
| * a non-const variable in the expression, which it needs to be const. Typical compiler output is |
| * "expression must have a constant value". |
| */ |
| const IMG_DEVMEM_OFFSET_T uiPIDOff |
| = (IMG_DEVMEM_OFFSET_T)(uintptr_t)&(((RGXFWIF_INIT *)0)->sPIDFilter.asItems[i].uiPID); |
| |
| const IMG_DEVMEM_OFFSET_T uiOSIDOff |
| = (IMG_DEVMEM_OFFSET_T)(uintptr_t)&(((RGXFWIF_INIT *)0)->sPIDFilter.asItems[i].ui32OSID); |
| |
| PDUMPCOMMENT("(PID and OSID pair %u)", i); |
| |
| PDUMPCOMMENT("(PID)"); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfInitMemDesc, |
| uiPIDOff, |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| PDUMPCOMMENT("(OSID)"); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfInitMemDesc, |
| uiOSIDOff, |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| } |
| } |
| |
| /* |
| * Dump the log config so it can be edited. |
| */ |
| PDUMPCOMMENT("(Set the log config here)"); |
| PDUMPCOMMENT("( Log Type: set bit 0 for TRACE, reset for TBI)"); |
| PDUMPCOMMENT("( MAIN Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_MAIN); |
| PDUMPCOMMENT("( MTS Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_MTS); |
| PDUMPCOMMENT("( CLEANUP Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_CLEANUP); |
| PDUMPCOMMENT("( CSW Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_CSW); |
| PDUMPCOMMENT("( BIF Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_BIF); |
| PDUMPCOMMENT("( PM Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_PM); |
| PDUMPCOMMENT("( RTD Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_RTD); |
| PDUMPCOMMENT("( SPM Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_SPM); |
| PDUMPCOMMENT("( POW Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_POW); |
| PDUMPCOMMENT("( HWR Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_HWR); |
| PDUMPCOMMENT("( HWP Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_HWP); |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| PDUMPCOMMENT("( RPM Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_RPM); |
| } |
| |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_META_DMA_BIT_MASK) |
| { |
| PDUMPCOMMENT("( DMA Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_DMA); |
| } |
| PDUMPCOMMENT("( DEBUG Group Enable: 0x%08x)", RGXFWIF_LOG_TYPE_GROUP_DEBUG); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfTraceBufCtlMemDesc, |
| offsetof(RGXFWIF_TRACEBUF, ui32LogType), |
| psDevInfo->psRGXFWIfTraceBuf->ui32LogType, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| PDUMPCOMMENT("Set the HWPerf Filter config here"); |
| DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfInitMemDesc, |
| offsetof(RGXFWIF_INIT, ui64HWPerfFilter), |
| psRGXFWInit->ui64HWPerfFilter, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| #if defined(SUPPORT_USER_REGISTER_CONFIGURATION) |
| PDUMPCOMMENT("(Number of registers configurations at pow on, dust change, ta, 3d, cdm and tla/tdm)"); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_PWR_ON]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_DUST_CHANGE]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_TA]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_3D]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_CDM]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_TLA_BIT_MASK) |
| { |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_TLA]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| } |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_FASTRENDER_DM_BIT_MASK) |
| { |
| DevmemPDumpLoadMemValue32(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, aui8NumRegsType[RGXFWIF_REG_CFG_TYPE_TDM]), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| } |
| |
| PDUMPCOMMENT("(Set registers here: address, mask, value)"); |
| DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Addr), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Mask), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| DevmemPDumpLoadMemValue64(psDevInfo->psRGXFWIfRegCfgMemDesc, |
| offsetof(RGXFWIF_REG_CFG, asRegConfigs[0].ui64Value), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| #endif /* SUPPORT_USER_REGISTER_CONFIGURATION */ |
| #endif /* PDUMP */ |
| #endif /* PVRSRV_GPUVIRT_GUESTDRV */ |
| |
| #if defined(SUPPORT_PVRSRV_GPUVIRT) |
| /* Perform additional virtualisation initialisation */ |
| eError = RGXVzSetupFirmware(psDeviceNode); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXSetupFirmware: Failed RGXVzSetupFirmware")); |
| goto fail; |
| } |
| #endif |
| |
| /* We don't need access to the fw init data structure anymore */ |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc); |
| psRGXFWInit = NULL; |
| |
| psDevInfo->bFirmwareInitialised = IMG_TRUE; |
| |
| return PVRSRV_OK; |
| |
| fail: |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| if (psDevInfo->psRGXFWIfInitMemDesc != NULL && psRGXFWInit != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc); |
| } |
| #endif |
| RGXFreeFirmware(psDevInfo); |
| |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function RGXFreeFirmware |
| |
| @Description |
| |
| Frees all the firmware-related allocations |
| |
| @Input psDevInfo |
| |
| @Return PVRSRV_ERROR |
| |
| ******************************************************************************/ |
| void RGXFreeFirmware(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| IMG_UINT64 ui64ErnsBrns = psDevInfo->sDevFeatureCfg.ui64ErnsBrns; |
| |
| psDevInfo->bFirmwareInitialised = IMG_FALSE; |
| |
| RGXFreeKernelCCB(psDevInfo); |
| |
| RGXFreeFirmwareCCB(psDevInfo, |
| &psDevInfo->psFirmwareCCBCtl, |
| &psDevInfo->psFirmwareCCBCtlMemDesc, |
| &psDevInfo->psFirmwareCCB, |
| &psDevInfo->psFirmwareCCBMemDesc); |
| |
| #if defined(SUPPORT_WORKLOAD_ESTIMATION) |
| RGXFreeFirmwareCCB(psDevInfo, |
| &psDevInfo->psWorkEstFirmwareCCBCtl, |
| &psDevInfo->psWorkEstFirmwareCCBCtlMemDesc, |
| &psDevInfo->psWorkEstFirmwareCCB, |
| &psDevInfo->psWorkEstFirmwareCCBMemDesc); |
| #endif |
| |
| #if defined(RGXFW_ALIGNCHECKS) |
| if (psDevInfo->psRGXFWAlignChecksMemDesc) |
| { |
| RGXFWFreeAlignChecks(psDevInfo); |
| } |
| #endif |
| |
| if (psDevInfo->psRGXFWSigTAChecksMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWSigTAChecksMemDesc); |
| psDevInfo->psRGXFWSigTAChecksMemDesc = NULL; |
| } |
| |
| if (psDevInfo->psRGXFWSig3DChecksMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWSig3DChecksMemDesc); |
| psDevInfo->psRGXFWSig3DChecksMemDesc = NULL; |
| } |
| |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (psDevInfo->psRGXFWSigRTChecksMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWSigRTChecksMemDesc); |
| psDevInfo->psRGXFWSigRTChecksMemDesc = NULL; |
| } |
| |
| if (psDevInfo->psRGXFWSigSHChecksMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWSigSHChecksMemDesc); |
| psDevInfo->psRGXFWSigSHChecksMemDesc = NULL; |
| } |
| } |
| |
| if(ui64ErnsBrns & FIX_HW_BRN_37200_BIT_MASK) |
| { |
| if (psDevInfo->psRGXFWHWBRN37200MemDesc) |
| { |
| DevmemReleaseDevVirtAddr(psDevInfo->psRGXFWHWBRN37200MemDesc); |
| DevmemFree(psDevInfo->psRGXFWHWBRN37200MemDesc); |
| psDevInfo->psRGXFWHWBRN37200MemDesc = NULL; |
| } |
| } |
| |
| RGXSetupFaultReadRegisterRollback(psDevInfo); |
| |
| if (psDevInfo->psPowSyncPrim != NULL) |
| { |
| SyncPrimFree(psDevInfo->psPowSyncPrim); |
| psDevInfo->psPowSyncPrim = NULL; |
| } |
| |
| if (psDevInfo->hSyncPrimContext != 0) |
| { |
| SyncPrimContextDestroy(psDevInfo->hSyncPrimContext); |
| psDevInfo->hSyncPrimContext = 0; |
| } |
| |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| if (psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc) |
| { |
| if (psDevInfo->psRGXFWIfGpuUtilFWCb != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc); |
| psDevInfo->psRGXFWIfGpuUtilFWCb = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc); |
| psDevInfo->psRGXFWIfGpuUtilFWCbCtlMemDesc = NULL; |
| } |
| |
| RGXHWPerfDeinit(); |
| |
| if (psDevInfo->psRGXFWIfRuntimeCfgMemDesc) |
| { |
| if (psDevInfo->psRGXFWIfRuntimeCfg != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfRuntimeCfgMemDesc); |
| psDevInfo->psRGXFWIfRuntimeCfg = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfRuntimeCfgMemDesc); |
| psDevInfo->psRGXFWIfRuntimeCfgMemDesc = NULL; |
| } |
| |
| if (psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc) |
| { |
| if (psDevInfo->psRGXFWIfHWRInfoBuf != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc); |
| psDevInfo->psRGXFWIfHWRInfoBuf = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc); |
| psDevInfo->psRGXFWIfHWRInfoBufCtlMemDesc = NULL; |
| } |
| |
| if ((0 != psDevInfo->sDevFeatureCfg.ui32MCMS) && \ |
| (0 == (ui64ErnsBrns & FIX_HW_BRN_50767_BIT_MASK))) |
| { |
| if (psDevInfo->psRGXFWIfCorememDataStoreMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfCorememDataStoreMemDesc); |
| psDevInfo->psRGXFWIfCorememDataStoreMemDesc = NULL; |
| } |
| } |
| |
| if (psDevInfo->psRGXFWIfTraceBufCtlMemDesc) |
| { |
| if (psDevInfo->psRGXFWIfTraceBuf != NULL) |
| { |
| /* first deinit/free the tracebuffer allocation */ |
| RGXTraceBufferDeinit(psDevInfo); |
| |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfTraceBufCtlMemDesc); |
| psDevInfo->psRGXFWIfTraceBuf = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfTraceBufCtlMemDesc); |
| psDevInfo->psRGXFWIfTraceBufCtlMemDesc = NULL; |
| } |
| #if defined(SUPPORT_USER_REGISTER_CONFIGURATION) |
| if (psDevInfo->psRGXFWIfRegCfgMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfRegCfgMemDesc); |
| psDevInfo->psRGXFWIfRegCfgMemDesc = NULL; |
| } |
| #endif |
| if (psDevInfo->psRGXFWIfHWPerfCountersMemDesc) |
| { |
| RGXUnsetFirmwareAddress(psDevInfo->psRGXFWIfHWPerfCountersMemDesc); |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfHWPerfCountersMemDesc); |
| psDevInfo->psRGXFWIfHWPerfCountersMemDesc = NULL; |
| } |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_SLC_VIVT_BIT_MASK) |
| { |
| _FreeSLC3Fence(psDevInfo); |
| } |
| |
| if( (psDevInfo->sDevFeatureCfg.ui32META) && (psDevInfo->psMETAT1StackMemDesc)) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psMETAT1StackMemDesc); |
| psDevInfo->psMETAT1StackMemDesc = NULL; |
| } |
| |
| #if defined(SUPPORT_PDVFS) |
| if (psDevInfo->psRGXFWIFCoreClkRateMemDesc) |
| { |
| if (psDevInfo->pui32RGXFWIFCoreClkRate != NULL) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIFCoreClkRateMemDesc); |
| psDevInfo->pui32RGXFWIFCoreClkRate = NULL; |
| } |
| |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIFCoreClkRateMemDesc); |
| psDevInfo->psRGXFWIFCoreClkRateMemDesc = NULL; |
| } |
| #endif |
| |
| if (psDevInfo->psRGXFWIfInitMemDesc) |
| { |
| DevmemFwFree(psDevInfo, psDevInfo->psRGXFWIfInitMemDesc); |
| psDevInfo->psRGXFWIfInitMemDesc = NULL; |
| } |
| #endif |
| |
| if (psDevInfo->psCompletedMemDesc) |
| { |
| if (psDevInfo->pui32CompletedById) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psCompletedMemDesc); |
| psDevInfo->pui32CompletedById = NULL; |
| } |
| DevmemFwFree(psDevInfo, psDevInfo->psCompletedMemDesc); |
| psDevInfo->psCompletedMemDesc = NULL; |
| } |
| if (psDevInfo->psEndTimeMemDesc) |
| { |
| if (psDevInfo->pui64EndTimeById) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psEndTimeMemDesc); |
| psDevInfo->pui64EndTimeById = NULL; |
| } |
| |
| DevmemFwFree(psDevInfo, psDevInfo->psEndTimeMemDesc); |
| psDevInfo->psEndTimeMemDesc = NULL; |
| } |
| if (psDevInfo->psStartTimeMemDesc) |
| { |
| if (psDevInfo->pui64StartTimeById) |
| { |
| DevmemReleaseCpuVirtAddr(psDevInfo->psStartTimeMemDesc); |
| psDevInfo->pui64StartTimeById = NULL; |
| } |
| |
| DevmemFwFree(psDevInfo, psDevInfo->psStartTimeMemDesc); |
| psDevInfo->psStartTimeMemDesc = NULL; |
| } |
| } |
| |
| |
| /****************************************************************************** |
| FUNCTION : RGXAcquireKernelCCBSlot |
| |
| PURPOSE : Attempts to obtain a slot in the Kernel CCB |
| |
| PARAMETERS : psCCB - the CCB |
| : Address of space if available, NULL otherwise |
| |
| RETURNS : PVRSRV_ERROR |
| ******************************************************************************/ |
| static PVRSRV_ERROR RGXAcquireKernelCCBSlot(DEVMEM_MEMDESC *psKCCBCtrlMemDesc, |
| RGXFWIF_CCB_CTL *psKCCBCtl, |
| IMG_UINT32 *pui32Offset) |
| { |
| IMG_UINT32 ui32OldWriteOffset, ui32NextWriteOffset; |
| |
| ui32OldWriteOffset = psKCCBCtl->ui32WriteOffset; |
| ui32NextWriteOffset = (ui32OldWriteOffset + 1) & psKCCBCtl->ui32WrapMask; |
| |
| /* Note: The MTS can queue up to 255 kicks (254 pending kicks and 1 executing kick) |
| * Hence the kernel CCB should not queue more 254 commands |
| */ |
| PVR_ASSERT(psKCCBCtl->ui32WrapMask < 255); |
| |
| #if defined(PDUMP) |
| /* Wait for sufficient CCB space to become available */ |
| PDUMPCOMMENTWITHFLAGS(0, "Wait for kCCB woff=%u", ui32NextWriteOffset); |
| DevmemPDumpCBP(psKCCBCtrlMemDesc, |
| offsetof(RGXFWIF_CCB_CTL, ui32ReadOffset), |
| ui32NextWriteOffset, |
| 1, |
| (psKCCBCtl->ui32WrapMask + 1)); |
| #endif |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| |
| if (ui32NextWriteOffset != psKCCBCtl->ui32ReadOffset) |
| { |
| *pui32Offset = ui32NextWriteOffset; |
| return PVRSRV_OK; |
| } |
| { |
| /* |
| * The following sanity check doesn't impact performance, |
| * since the CPU has to wait for the GPU anyway (full kernel CCB). |
| */ |
| if (PVRSRVGetPVRSRVData()->eServicesState != PVRSRV_SERVICES_STATE_OK) |
| { |
| return PVRSRV_ERROR_KERNEL_CCB_FULL; |
| } |
| } |
| |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| /* Time out on waiting for CCB space */ |
| return PVRSRV_ERROR_KERNEL_CCB_FULL; |
| } |
| |
| |
| PVRSRV_ERROR RGXSendCommandWithPowLock(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eKCCBType, |
| RGXFWIF_KCCB_CMD *psKCCBCmd, |
| IMG_UINT32 ui32CmdSize, |
| IMG_UINT32 ui32PDumpFlags) |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode; |
| |
| /* Ensure Rogue is powered up before kicking MTS */ |
| eError = PVRSRVPowerLock(psDeviceNode); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXSendCommandWithPowLock: failed to acquire powerlock (%s)", |
| PVRSRVGetErrorStringKM(eError))); |
| |
| goto _PVRSRVPowerLock_Exit; |
| } |
| |
| PDUMPPOWCMDSTART(); |
| eError = PVRSRVSetDevicePowerStateKM(psDeviceNode, |
| PVRSRV_DEV_POWER_STATE_ON, |
| IMG_FALSE); |
| PDUMPPOWCMDEND(); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXSendCommandWithPowLock: failed to transition Rogue to ON (%s)", |
| PVRSRVGetErrorStringKM(eError))); |
| |
| goto _PVRSRVSetDevicePowerStateKM_Exit; |
| } |
| |
| eError = RGXSendCommand(psDevInfo, eKCCBType, psKCCBCmd, ui32CmdSize, ui32PDumpFlags); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXSendCommandWithPowLock: failed to schedule command (%s)", |
| PVRSRVGetErrorStringKM(eError))); |
| #if defined(DEBUG) |
| /* PVRSRVDebugRequest must be called without powerlock */ |
| PVRSRVPowerUnlock(psDeviceNode); |
| PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL); |
| goto _PVRSRVPowerLock_Exit; |
| #endif |
| } |
| |
| _PVRSRVSetDevicePowerStateKM_Exit: |
| PVRSRVPowerUnlock(psDeviceNode); |
| |
| _PVRSRVPowerLock_Exit: |
| return eError; |
| } |
| |
| static PVRSRV_ERROR RGXSendCommandRaw(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eKCCBType, |
| RGXFWIF_KCCB_CMD *psKCCBCmd, |
| IMG_UINT32 ui32CmdSize, |
| IMG_UINT32 uiPdumpFlags) |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode; |
| RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| IMG_UINT8 *pui8KCCB = psDevInfo->psKernelCCB; |
| IMG_UINT32 ui32NewWriteOffset; |
| IMG_UINT32 ui32OldWriteOffset = psKCCBCtl->ui32WriteOffset; |
| |
| #if !defined(PDUMP) |
| PVR_UNREFERENCED_PARAMETER(uiPdumpFlags); |
| #else |
| IMG_BOOL bIsInCaptureRange; |
| IMG_BOOL bPdumpEnabled; |
| IMG_BOOL bPDumpPowTrans = PDUMPPOWCMDINTRANS(); |
| |
| PDumpIsCaptureFrameKM(&bIsInCaptureRange); |
| bPdumpEnabled = (bIsInCaptureRange || PDUMP_IS_CONTINUOUS(uiPdumpFlags)) && !bPDumpPowTrans; |
| |
| /* in capture range */ |
| if (bPdumpEnabled) |
| { |
| if (!psDevInfo->bDumpedKCCBCtlAlready) |
| { |
| /* entering capture range */ |
| psDevInfo->bDumpedKCCBCtlAlready = IMG_TRUE; |
| |
| /* wait for firmware to catch up */ |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXSendCommandRaw: waiting on fw to catch-up, roff: %d, woff: %d", |
| psKCCBCtl->ui32ReadOffset, ui32OldWriteOffset)); |
| PVRSRVPollForValueKM(&psKCCBCtl->ui32ReadOffset, ui32OldWriteOffset, 0xFFFFFFFF); |
| |
| /* Dump Init state of Kernel CCB control (read and write offset) */ |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Initial state of kernel CCB Control, roff: %d, woff: %d", |
| psKCCBCtl->ui32ReadOffset, psKCCBCtl->ui32WriteOffset); |
| |
| DevmemPDumpLoadMem(psDevInfo->psKernelCCBCtlMemDesc, |
| 0, |
| sizeof(RGXFWIF_CCB_CTL), |
| PDUMP_FLAGS_CONTINUOUS); |
| } |
| } |
| #endif |
| |
| psKCCBCmd->eDM = eKCCBType; |
| |
| PVR_ASSERT(ui32CmdSize == psKCCBCtl->ui32CmdSize); |
| if (!OSLockIsLocked(psDeviceNode->hPowerLock)) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXSendCommandRaw called without power lock held!")); |
| PVR_ASSERT(OSLockIsLocked(psDeviceNode->hPowerLock)); |
| } |
| |
| /* |
| * Acquire a slot in the CCB. |
| */ |
| eError = RGXAcquireKernelCCBSlot(psDevInfo->psKernelCCBCtlMemDesc, psKCCBCtl, &ui32NewWriteOffset); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXSendCommandRaw failed to acquire CCB slot. Type:%u Error:%u", |
| eKCCBType, eError)); |
| goto _RGXSendCommandRaw_Exit; |
| } |
| |
| /* |
| * Copy the command into the CCB. |
| */ |
| OSDeviceMemCopy(&pui8KCCB[ui32OldWriteOffset * psKCCBCtl->ui32CmdSize], |
| psKCCBCmd, psKCCBCtl->ui32CmdSize); |
| |
| /* ensure kCCB data is written before the offsets */ |
| OSWriteMemoryBarrier(); |
| |
| /* Move past the current command */ |
| psKCCBCtl->ui32WriteOffset = ui32NewWriteOffset; |
| |
| |
| #if defined(PDUMP) |
| /* in capture range */ |
| if (bPdumpEnabled) |
| { |
| /* Dump new Kernel CCB content */ |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Dump kCCB cmd for DM %d, woff = %d", |
| eKCCBType, |
| ui32OldWriteOffset); |
| DevmemPDumpLoadMem(psDevInfo->psKernelCCBMemDesc, |
| ui32OldWriteOffset * psKCCBCtl->ui32CmdSize, |
| psKCCBCtl->ui32CmdSize, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| /* Dump new kernel CCB write offset */ |
| PDUMPCOMMENTWITHFLAGS(uiPdumpFlags, "Dump kCCBCtl woff (added new cmd for DM %d): %d", |
| eKCCBType, |
| ui32NewWriteOffset); |
| DevmemPDumpLoadMem(psDevInfo->psKernelCCBCtlMemDesc, |
| offsetof(RGXFWIF_CCB_CTL, ui32WriteOffset), |
| sizeof(IMG_UINT32), |
| uiPdumpFlags); |
| } |
| |
| /* out of capture range */ |
| if (!bPdumpEnabled) |
| { |
| RGXPdumpDrainKCCB(psDevInfo, ui32OldWriteOffset); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXSendCommandRaw: problem draining kCCB (%d)", eError)); |
| goto _RGXSendCommandRaw_Exit; |
| } |
| } |
| #endif |
| |
| |
| PDUMPCOMMENTWITHFLAGS(uiPdumpFlags, "MTS kick for kernel CCB"); |
| /* |
| * Kick the MTS to schedule the firmware. |
| */ |
| { |
| IMG_UINT32 ui32MTSRegVal; |
| #if defined(SUPPORT_PVRSRV_GPUVIRT) |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_GPU_VIRTUALISATION_BIT_MASK)) |
| { |
| ui32MTSRegVal = ((RGXFWIF_DM_GP + PVRSRV_GPUVIRT_OSID) & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK) | RGX_CR_MTS_SCHEDULE_TASK_COUNTED; |
| }else |
| #endif |
| { |
| ui32MTSRegVal = (RGXFWIF_DM_GP & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK) | RGX_CR_MTS_SCHEDULE_TASK_COUNTED; |
| } |
| |
| |
| __MTSScheduleWrite(psDevInfo, ui32MTSRegVal); |
| |
| PDUMPREG32(RGX_PDUMPREG_NAME, RGX_CR_MTS_SCHEDULE, ui32MTSRegVal, uiPdumpFlags); |
| } |
| |
| #if defined (NO_HARDWARE) |
| /* keep the roff updated because fw isn't there to update it */ |
| psKCCBCtl->ui32ReadOffset = psKCCBCtl->ui32WriteOffset; |
| #endif |
| |
| _RGXSendCommandRaw_Exit: |
| return eError; |
| } |
| |
| |
| PVRSRV_ERROR RGXSendCommand(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eKCCBType, |
| RGXFWIF_KCCB_CMD *psKCCBCmd, |
| IMG_UINT32 ui32CmdSize, |
| IMG_UINT32 uiPdumpFlags) |
| { |
| |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| DLLIST_NODE *psNode, *psNext; |
| RGX_DEFERRED_KCCB_CMD *psTempDeferredKCCBCmd; |
| |
| /* Check if there is any deferred KCCB command before sending the command passed as argument */ |
| dllist_foreach_node(&psDevInfo->sKCCBDeferredCommandsListHead, psNode, psNext) |
| { |
| psTempDeferredKCCBCmd = IMG_CONTAINER_OF(psNode, RGX_DEFERRED_KCCB_CMD, sListNode); |
| /* For every deferred KCCB command, try to send it*/ |
| eError = RGXSendCommandRaw(psTempDeferredKCCBCmd->psDevInfo, |
| psTempDeferredKCCBCmd->eDM, |
| &(psTempDeferredKCCBCmd->sKCCBcmd), |
| sizeof(psTempDeferredKCCBCmd->sKCCBcmd), |
| psTempDeferredKCCBCmd->uiPdumpFlags); |
| if (eError != PVRSRV_OK) |
| { |
| goto _exit; |
| } |
| /* Remove from the deferred list the sent deferred KCCB command */ |
| dllist_remove_node(psNode); |
| OSFreeMem(psTempDeferredKCCBCmd); |
| } |
| |
| eError = RGXSendCommandRaw(psDevInfo, |
| eKCCBType, |
| psKCCBCmd, |
| ui32CmdSize, |
| uiPdumpFlags); |
| |
| |
| _exit: |
| /* |
| * If we don't manage to enqueue one of the deferred commands or the command |
| * passed as argument because the KCCB is full, insert the latter into the deferred commands list. |
| * The deferred commands will also be flushed eventually by: |
| * - one more KCCB command sent for any DM |
| * - the watchdog thread |
| * - the power off sequence |
| */ |
| if (eError == PVRSRV_ERROR_KERNEL_CCB_FULL) |
| { |
| RGX_DEFERRED_KCCB_CMD *psDeferredCommand; |
| |
| psDeferredCommand = OSAllocMem(sizeof(*psDeferredCommand)); |
| |
| if(!psDeferredCommand) |
| { |
| PVR_DPF((PVR_DBG_WARNING,"Deferring a KCCB command failed: allocation failure: requesting retry ")); |
| eError = PVRSRV_ERROR_RETRY; |
| } |
| else |
| { |
| psDeferredCommand->sKCCBcmd = *psKCCBCmd; |
| psDeferredCommand->eDM = eKCCBType; |
| psDeferredCommand->uiPdumpFlags = uiPdumpFlags; |
| psDeferredCommand->psDevInfo = psDevInfo; |
| |
| PVR_DPF((PVR_DBG_WARNING,"Deferring a KCCB command for DM %d" ,eKCCBType)); |
| dllist_add_to_tail(&(psDevInfo->sKCCBDeferredCommandsListHead), &(psDeferredCommand->sListNode)); |
| |
| eError = PVRSRV_OK; |
| } |
| } |
| |
| return eError; |
| |
| } |
| |
| |
| void RGXScheduleProcessQueuesKM(PVRSRV_CMDCOMP_HANDLE hCmdCompHandle) |
| { |
| PVRSRV_DEVICE_NODE *psDeviceNode = (PVRSRV_DEVICE_NODE*) hCmdCompHandle; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| |
| OSScheduleMISR(psDevInfo->hProcessQueuesMISR); |
| } |
| |
| /*! |
| ****************************************************************************** |
| |
| @Function _RGXScheduleProcessQueuesMISR |
| |
| @Description - Sends uncounted kick to all the DMs (the FW will process all |
| the queue for all the DMs) |
| ******************************************************************************/ |
| static void _RGXScheduleProcessQueuesMISR(void *pvData) |
| { |
| PVRSRV_DEVICE_NODE *psDeviceNode = pvData; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| PVRSRV_ERROR eError; |
| PVRSRV_DEV_POWER_STATE ePowerState; |
| |
| /* We don't need to acquire the BridgeLock as this power transition won't |
| send a command to the FW */ |
| eError = PVRSRVPowerLock(psDeviceNode); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXScheduleProcessQueuesKM: failed to acquire powerlock (%s)", |
| PVRSRVGetErrorStringKM(eError))); |
| |
| return; |
| } |
| |
| /* Check whether it's worth waking up the GPU */ |
| eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState); |
| |
| if ((eError == PVRSRV_OK) && (ePowerState == PVRSRV_DEV_POWER_STATE_OFF)) |
| { |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| /* For now, guest drivers will always wake-up the GPU */ |
| RGXFWIF_GPU_UTIL_FWCB *psUtilFWCb = psDevInfo->psRGXFWIfGpuUtilFWCb; |
| IMG_BOOL bGPUHasWorkWaiting; |
| |
| bGPUHasWorkWaiting = |
| (RGXFWIF_GPU_UTIL_GET_STATE(psUtilFWCb->ui64LastWord) == RGXFWIF_GPU_UTIL_STATE_BLOCKED); |
| |
| if (!bGPUHasWorkWaiting) |
| { |
| /* all queues are empty, don't wake up the GPU */ |
| PVRSRVPowerUnlock(psDeviceNode); |
| return; |
| } |
| #endif |
| } |
| |
| PDUMPPOWCMDSTART(); |
| /* wake up the GPU */ |
| eError = PVRSRVSetDevicePowerStateKM(psDeviceNode, |
| PVRSRV_DEV_POWER_STATE_ON, |
| IMG_FALSE); |
| PDUMPPOWCMDEND(); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXScheduleProcessQueuesKM: failed to transition Rogue to ON (%s)", |
| PVRSRVGetErrorStringKM(eError))); |
| |
| PVRSRVPowerUnlock(psDeviceNode); |
| return; |
| } |
| |
| /* uncounted kick to the FW */ |
| { |
| IMG_UINT32 ui32MTSRegVal; |
| #if defined(SUPPORT_PVRSRV_GPUVIRT) |
| if(!(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_GPU_VIRTUALISATION_BIT_MASK)) |
| { |
| ui32MTSRegVal = ((RGXFWIF_DM_GP + PVRSRV_GPUVIRT_OSID) & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK) | RGX_CR_MTS_SCHEDULE_TASK_NON_COUNTED; |
| }else |
| #endif |
| { |
| ui32MTSRegVal = (RGXFWIF_DM_GP & ~RGX_CR_MTS_SCHEDULE_DM_CLRMSK) | RGX_CR_MTS_SCHEDULE_TASK_NON_COUNTED; |
| } |
| |
| HTBLOGK(HTB_SF_MAIN_KICK_UNCOUNTED); |
| __MTSScheduleWrite(psDevInfo, ui32MTSRegVal); |
| } |
| |
| PVRSRVPowerUnlock(psDeviceNode); |
| } |
| |
| PVRSRV_ERROR RGXInstallProcessQueuesMISR(IMG_HANDLE *phMISR, PVRSRV_DEVICE_NODE *psDeviceNode) |
| { |
| return OSInstallMISR(phMISR, |
| _RGXScheduleProcessQueuesMISR, |
| psDeviceNode); |
| } |
| |
| /*! |
| ****************************************************************************** |
| |
| @Function RGXScheduleCommand |
| |
| @Description - Submits a CCB command and kicks the firmware but first schedules |
| any commands which have to happen before handle |
| |
| @Input psDevInfo - pointer to device info |
| @Input eKCCBType - see RGXFWIF_CMD_* |
| @Input psKCCBCmd - kernel CCB command |
| @Input ui32CmdSize - kernel CCB SIZE |
| @Input ui32CacheOpFence - CPU dcache operation fence |
| @Input ui32PDumpFlags - PDUMP_FLAGS_CONTINUOUS bit set if the pdump flags should be continuous |
| |
| |
| @Return PVRSRV_ERROR |
| |
| ******************************************************************************/ |
| PVRSRV_ERROR RGXScheduleCommand(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eKCCBType, |
| RGXFWIF_KCCB_CMD *psKCCBCmd, |
| IMG_UINT32 ui32CmdSize, |
| IMG_UINT32 ui32CacheOpFence, |
| IMG_UINT32 ui32PDumpFlags) |
| { |
| PVRSRV_ERROR eError; |
| IMG_UINT32 uiMMUSyncUpdate; |
| |
| eError = CacheOpFence(eKCCBType, ui32CacheOpFence); |
| if (eError != PVRSRV_OK) goto RGXScheduleCommand_exit; |
| |
| #if defined (SUPPORT_VALIDATION) |
| /* For validation, force the core to different dust count states with each kick */ |
| if ((eKCCBType == RGXFWIF_DM_TA) || (eKCCBType == RGXFWIF_DM_CDM)) |
| { |
| if (psDevInfo->ui32DeviceFlags & RGXKM_DEVICE_STATE_DUST_REQUEST_INJECT_EN) |
| { |
| IMG_UINT32 ui32NumDusts = RGXGetNextDustCount(&psDevInfo->sDustReqState, psDevInfo->sDevFeatureCfg.ui32MAXDustCount); |
| PVRSRVDeviceDustCountChange(psDevInfo->psDeviceNode, ui32NumDusts); |
| } |
| } |
| #endif |
| |
| eError = RGXPreKickCacheCommand(psDevInfo, eKCCBType, &uiMMUSyncUpdate, IMG_FALSE); |
| if (eError != PVRSRV_OK) goto RGXScheduleCommand_exit; |
| |
| eError = RGXSendCommandWithPowLock(psDevInfo, eKCCBType, psKCCBCmd, ui32CmdSize, ui32PDumpFlags); |
| if (eError != PVRSRV_OK) goto RGXScheduleCommand_exit; |
| |
| RGXScheduleCommand_exit: |
| return eError; |
| } |
| |
| /* |
| * RGXCheckFirmwareCCB |
| */ |
| void RGXCheckFirmwareCCB(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| RGXFWIF_FWCCB_CMD *psFwCCBCmd; |
| |
| RGXFWIF_CCB_CTL *psFWCCBCtl = psDevInfo->psFirmwareCCBCtl; |
| IMG_UINT8 *psFWCCB = psDevInfo->psFirmwareCCB; |
| |
| while (psFWCCBCtl->ui32ReadOffset != psFWCCBCtl->ui32WriteOffset) |
| { |
| /* Point to the next command */ |
| psFwCCBCmd = ((RGXFWIF_FWCCB_CMD *)psFWCCB) + psFWCCBCtl->ui32ReadOffset; |
| |
| HTBLOGK(HTB_SF_MAIN_FWCCB_CMD, psFwCCBCmd->eCmdType); |
| switch(psFwCCBCmd->eCmdType) |
| { |
| case RGXFWIF_FWCCB_CMD_ZSBUFFER_BACKING: |
| { |
| if (psDevInfo->bPDPEnabled) |
| { |
| PDUMP_PANIC(ZSBUFFER_BACKING, "Request to add backing to ZSBuffer"); |
| } |
| RGXProcessRequestZSBufferBacking(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdZSBufferBacking.ui32ZSBufferID); |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_ZSBUFFER_UNBACKING: |
| { |
| if (psDevInfo->bPDPEnabled) |
| { |
| PDUMP_PANIC(ZSBUFFER_UNBACKING, "Request to remove backing from ZSBuffer"); |
| } |
| RGXProcessRequestZSBufferUnbacking(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdZSBufferBacking.ui32ZSBufferID); |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_FREELIST_GROW: |
| { |
| if (psDevInfo->bPDPEnabled) |
| { |
| PDUMP_PANIC(FREELIST_GROW, "Request to grow the free list"); |
| } |
| RGXProcessRequestGrow(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdFreeListGS.ui32FreelistID); |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION: |
| { |
| if (psDevInfo->bPDPEnabled) |
| { |
| PDUMP_PANIC(FREELISTS_RECONSTRUCTION, "Request to reconstruct free lists"); |
| } |
| #if defined(PVRSRV_GPUVIRT_GUESTDRV) |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXCheckFirmwareCCBs: Freelist reconstruction request (%d) for %d freelists", |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32HwrCounter+1, |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount)); |
| #else |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXCheckFirmwareCCBs: Freelist reconstruction request (%d/%d) for %d freelists", |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32HwrCounter+1, |
| psDevInfo->psRGXFWIfTraceBuf->ui32HwrCounter+1, |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount)); |
| #endif |
| |
| RGXProcessRequestFreelistsReconstruction(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.ui32FreelistsCount, |
| psFwCCBCmd->uCmdData.sCmdFreeListsReconstruction.aui32FreelistIDs); |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_DOPPLER_MEMORY_GROW: |
| { |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| if (psDevInfo->bPDPEnabled) |
| { |
| PDUMP_PANIC(FREELIST_GROW, "Request to grow the RPM free list"); |
| } |
| RGXProcessRequestRPMGrow(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdFreeListGS.ui32FreelistID); |
| } |
| } |
| |
| case RGXFWIF_FWCCB_CMD_CONTEXT_RESET_NOTIFICATION: |
| { |
| DLLIST_NODE *psNode, *psNext; |
| RGXFWIF_FWCCB_CMD_CONTEXT_RESET_DATA *psCmdContextResetNotification = |
| &psFwCCBCmd->uCmdData.sCmdContextResetNotification; |
| IMG_UINT32 ui32ServerCommonContextID = |
| psCmdContextResetNotification->ui32ServerCommonContextID; |
| RGX_SERVER_COMMON_CONTEXT *psServerCommonContext = NULL; |
| |
| dllist_foreach_node(&psDevInfo->sCommonCtxtListHead, psNode, psNext) |
| { |
| RGX_SERVER_COMMON_CONTEXT *psThisContext = |
| IMG_CONTAINER_OF(psNode, RGX_SERVER_COMMON_CONTEXT, sListNode); |
| |
| if (psThisContext->ui32ContextID == ui32ServerCommonContextID) |
| { |
| psServerCommonContext = psThisContext; |
| break; |
| } |
| } |
| |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXCheckFirmwareCCBs: Context 0x%p reset (ID=0x%08x, Reason=%d, JobRef=0x%08x)", |
| psServerCommonContext, |
| psCmdContextResetNotification->ui32ServerCommonContextID, |
| (IMG_UINT32)(psCmdContextResetNotification->eResetReason), |
| psCmdContextResetNotification->ui32ResetJobRef)); |
| |
| if (psServerCommonContext != NULL) |
| { |
| psServerCommonContext->eLastResetReason = psCmdContextResetNotification->eResetReason; |
| psServerCommonContext->ui32LastResetJobRef = psCmdContextResetNotification->ui32ResetJobRef; |
| } |
| |
| if (psCmdContextResetNotification->bPageFault) |
| { |
| DevmemIntPFNotify(psDevInfo->psDeviceNode, |
| psCmdContextResetNotification->ui64PCAddress); |
| } |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_DEBUG_DUMP: |
| { |
| RGXDumpDebugInfo(NULL,NULL,psDevInfo); |
| break; |
| } |
| |
| case RGXFWIF_FWCCB_CMD_UPDATE_STATS: |
| { |
| #if defined(PVRSRV_ENABLE_PROCESS_STATS) |
| IMG_PID pidTmp = psFwCCBCmd->uCmdData.sCmdUpdateStatsData.pidOwner; |
| IMG_INT32 i32AdjustmentValue = psFwCCBCmd->uCmdData.sCmdUpdateStatsData.i32AdjustmentValue; |
| |
| switch (psFwCCBCmd->uCmdData.sCmdUpdateStatsData.eElementToUpdate) |
| { |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_PARTIAL_RENDERS: |
| { |
| PVRSRVStatsUpdateRenderContextStats(i32AdjustmentValue,0,0,0,0,0,pidTmp); |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_OUT_OF_MEMORY: |
| { |
| PVRSRVStatsUpdateRenderContextStats(0,i32AdjustmentValue,0,0,0,0,pidTmp); |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_TA_STORES: |
| { |
| PVRSRVStatsUpdateRenderContextStats(0,0,i32AdjustmentValue,0,0,0,pidTmp); |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_3D_STORES: |
| { |
| PVRSRVStatsUpdateRenderContextStats(0,0,0,i32AdjustmentValue,0,0,pidTmp); |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_SH_STORES: |
| { |
| PVRSRVStatsUpdateRenderContextStats(0,0,0,0,i32AdjustmentValue,0,pidTmp); |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_UPDATE_NUM_CDM_STORES: |
| { |
| PVRSRVStatsUpdateRenderContextStats(0,0,0,0,0,i32AdjustmentValue,pidTmp); |
| break; |
| } |
| } |
| #endif |
| break; |
| } |
| case RGXFWIF_FWCCB_CMD_CORE_CLK_RATE_CHANGE: |
| { |
| #if defined(SUPPORT_PDVFS) |
| PDVFSProcessCoreClkRateChange(psDevInfo, |
| psFwCCBCmd->uCmdData.sCmdCoreClkRateChange.ui32CoreClkRate); |
| #endif |
| break; |
| } |
| default: |
| { |
| PVR_ASSERT(IMG_FALSE); |
| } |
| } |
| |
| /* Update read offset */ |
| psFWCCBCtl->ui32ReadOffset = (psFWCCBCtl->ui32ReadOffset + 1) & psFWCCBCtl->ui32WrapMask; |
| } |
| } |
| |
| /* |
| * PVRSRVRGXFrameworkCopyCommand |
| */ |
| PVRSRV_ERROR PVRSRVRGXFrameworkCopyCommand(DEVMEM_MEMDESC *psFWFrameworkMemDesc, |
| IMG_PBYTE pbyGPUFRegisterList, |
| IMG_UINT32 ui32FrameworkRegisterSize) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_RF_REGISTERS *psRFReg; |
| |
| eError = DevmemAcquireCpuVirtAddr(psFWFrameworkMemDesc, |
| (void **)&psRFReg); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXFrameworkCopyCommand: Failed to map firmware render context state (%u)", |
| eError)); |
| return eError; |
| } |
| |
| OSDeviceMemCopy(psRFReg, pbyGPUFRegisterList, ui32FrameworkRegisterSize); |
| |
| /* Release the CPU mapping */ |
| DevmemReleaseCpuVirtAddr(psFWFrameworkMemDesc); |
| |
| /* |
| * Dump the FW framework buffer |
| */ |
| PDUMPCOMMENT("Dump FWFramework buffer"); |
| DevmemPDumpLoadMem(psFWFrameworkMemDesc, 0, ui32FrameworkRegisterSize, PDUMP_FLAGS_CONTINUOUS); |
| |
| return PVRSRV_OK; |
| } |
| |
| /* |
| * PVRSRVRGXFrameworkCreateKM |
| */ |
| PVRSRV_ERROR PVRSRVRGXFrameworkCreateKM(PVRSRV_DEVICE_NODE *psDeviceNode, |
| DEVMEM_MEMDESC **ppsFWFrameworkMemDesc, |
| IMG_UINT32 ui32FrameworkCommandSize) |
| { |
| PVRSRV_ERROR eError; |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| |
| /* |
| Allocate device memory for the firmware GPU framework state. |
| Sufficient info to kick one or more DMs should be contained in this buffer |
| */ |
| PDUMPCOMMENT("Allocate Rogue firmware framework state"); |
| |
| eError = DevmemFwAllocate(psDevInfo, |
| ui32FrameworkCommandSize, |
| RGX_FWCOMCTX_ALLOCFLAGS, |
| "FwGPUFrameworkState", |
| ppsFWFrameworkMemDesc); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXFrameworkContextKM: Failed to allocate firmware framework state (%u)", |
| eError)); |
| return eError; |
| } |
| |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR RGXWaitForFWOp(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eDM, |
| PVRSRV_CLIENT_SYNC_PRIM *psSyncPrim, |
| IMG_UINT32 ui32PDumpFlags) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode; |
| RGXFWIF_KCCB_CMD sCmdSyncPrim; |
| |
| /* Ensure Rogue is powered up before kicking MTS */ |
| eError = PVRSRVPowerLock(psDeviceNode); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: failed to acquire powerlock (%s)", |
| __FUNCTION__, |
| PVRSRVGetErrorStringKM(eError))); |
| |
| goto _PVRSRVPowerLock_Exit; |
| } |
| |
| PDUMPPOWCMDSTART(); |
| eError = PVRSRVSetDevicePowerStateKM(psDeviceNode, |
| PVRSRV_DEV_POWER_STATE_ON, |
| IMG_FALSE); |
| PDUMPPOWCMDEND(); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: failed to transition Rogue to ON (%s)", |
| __FUNCTION__, |
| PVRSRVGetErrorStringKM(eError))); |
| |
| goto _PVRSRVSetDevicePowerStateKM_Exit; |
| } |
| |
| /* Setup sync primitive */ |
| eError = SyncPrimSet(psSyncPrim, 0); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set SyncPrim (%u)", |
| __FUNCTION__, eError)); |
| goto _SyncPrimSet_Exit; |
| } |
| |
| /* prepare a sync command */ |
| eError = SyncPrimGetFirmwareAddr(psSyncPrim, |
| &sCmdSyncPrim.uCmdData.sSyncData.sSyncObjDevVAddr.ui32Addr); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to get SyncPrim FW address(%u)", |
| __FUNCTION__, eError)); |
| goto _SyncPrimGetFirmwareAddr_Exit; |
| } |
| sCmdSyncPrim.eCmdType = RGXFWIF_KCCB_CMD_SYNC; |
| sCmdSyncPrim.uCmdData.sSyncData.uiUpdateVal = 1; |
| |
| PDUMPCOMMENT("RGXWaitForFWOp: Submit Kernel SyncPrim [0x%08x] to DM %d ", |
| sCmdSyncPrim.uCmdData.sSyncData.sSyncObjDevVAddr.ui32Addr, eDM); |
| |
| /* submit the sync primitive to the kernel CCB */ |
| eError = RGXSendCommand(psDevInfo, |
| eDM, |
| &sCmdSyncPrim, |
| sizeof(RGXFWIF_KCCB_CMD), |
| ui32PDumpFlags); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to schedule Kernel SyncPrim with error (%u)", |
| __FUNCTION__, |
| eError)); |
| goto _RGXSendCommandRaw_Exit; |
| } |
| |
| /* Wait for sync primitive to be updated */ |
| #if defined(PDUMP) |
| PDUMPCOMMENT("RGXScheduleCommandAndWait: Poll for Kernel SyncPrim [0x%08x] on DM %d ", |
| sCmdSyncPrim.uCmdData.sSyncData.sSyncObjDevVAddr.ui32Addr, eDM); |
| |
| SyncPrimPDumpPol(psSyncPrim, |
| 1, |
| 0xffffffff, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| ui32PDumpFlags); |
| #endif |
| |
| { |
| RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| IMG_UINT32 ui32CurrentQueueLength = |
| (psKCCBCtl->ui32WrapMask+1 + |
| psKCCBCtl->ui32WriteOffset - |
| psKCCBCtl->ui32ReadOffset) & psKCCBCtl->ui32WrapMask; |
| IMG_UINT32 ui32MaxRetries; |
| |
| for (ui32MaxRetries = (ui32CurrentQueueLength + 1) * 3; |
| ui32MaxRetries > 0; |
| ui32MaxRetries--) |
| { |
| eError = PVRSRVWaitForValueKMAndHoldBridgeLockKM(psSyncPrim->pui32LinAddr, 1, 0xffffffff); |
| |
| if (eError != PVRSRV_ERROR_TIMEOUT) |
| { |
| break; |
| } |
| } |
| |
| if (eError == PVRSRV_ERROR_TIMEOUT) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: PVRSRVWaitForValueKMAndHoldBridgeLock timed out. Dump debug information.", |
| __FUNCTION__)); |
| PVRSRVPowerUnlock(psDeviceNode); |
| |
| PVRSRVDebugRequest(psDeviceNode, DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL); |
| PVR_ASSERT(eError != PVRSRV_ERROR_TIMEOUT); |
| goto _PVRSRVDebugRequest_Exit; |
| } |
| } |
| |
| _RGXSendCommandRaw_Exit: |
| _SyncPrimGetFirmwareAddr_Exit: |
| _SyncPrimSet_Exit: |
| _PVRSRVSetDevicePowerStateKM_Exit: |
| |
| PVRSRVPowerUnlock(psDeviceNode); |
| |
| _PVRSRVDebugRequest_Exit: |
| _PVRSRVPowerLock_Exit: |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXStateFlagCtrl(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32Config, |
| IMG_UINT32 *pui32ConfigState, |
| IMG_BOOL bSetNotClear) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_KCCB_CMD sStateFlagCmd; |
| PVRSRV_CLIENT_SYNC_PRIM *psResponseSync; |
| |
| if (!psDevInfo) |
| { |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| goto return_; |
| } |
| |
| if (psDevInfo->psDeviceNode->eDevState != PVRSRV_DEVICE_STATE_ACTIVE) |
| { |
| eError = PVRSRV_ERROR_NOT_INITIALISED; |
| goto return_; |
| } |
| |
| sStateFlagCmd.eCmdType = RGXFWIF_KCCB_CMD_STATEFLAGS_CTRL; |
| sStateFlagCmd.eDM = RGXFWIF_DM_GP; |
| sStateFlagCmd.uCmdData.sStateFlagCtrl.ui32Config = ui32Config; |
| sStateFlagCmd.uCmdData.sStateFlagCtrl.bSetNotClear = bSetNotClear; |
| |
| eError = SyncPrimAlloc(psDevInfo->hSyncPrimContext, &psResponseSync, "rgx config flags"); |
| if (PVRSRV_OK != eError) |
| { |
| goto return_; |
| } |
| eError = SyncPrimSet(psResponseSync, 0); |
| if (eError != PVRSRV_OK) |
| { |
| goto return_freesync_; |
| } |
| |
| eError = SyncPrimGetFirmwareAddr(psResponseSync, &sStateFlagCmd.uCmdData.sStateFlagCtrl.sSyncObjDevVAddr.ui32Addr); |
| if (PVRSRV_OK != eError) |
| { |
| goto return_freesync_; |
| } |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sStateFlagCmd, |
| sizeof(sStateFlagCmd), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| PVR_LOGG_IF_ERROR(eError, "RGXScheduleCommand", return_); |
| |
| /* Wait for FW to complete */ |
| eError = RGXWaitForFWOp(psDevInfo, |
| RGXFWIF_DM_GP, |
| psDevInfo->psDeviceNode->psSyncPrim, |
| PDUMP_FLAGS_CONTINUOUS); |
| PVR_LOGG_IF_ERROR(eError, "RGXWaitForFWOp", return_); |
| |
| if (pui32ConfigState) |
| { |
| *pui32ConfigState = *psResponseSync->pui32LinAddr; |
| } |
| |
| return_freesync_: |
| SyncPrimFree(psResponseSync); |
| return_: |
| return eError; |
| } |
| |
| static |
| PVRSRV_ERROR RGXScheduleCleanupCommand(PVRSRV_RGXDEV_INFO *psDevInfo, |
| RGXFWIF_DM eDM, |
| RGXFWIF_KCCB_CMD *psKCCBCmd, |
| IMG_UINT32 ui32CmdSize, |
| RGXFWIF_CLEANUP_TYPE eCleanupType, |
| PVRSRV_CLIENT_SYNC_PRIM *psSyncPrim, |
| IMG_UINT32 ui32PDumpFlags) |
| { |
| PVRSRV_ERROR eError; |
| |
| psKCCBCmd->eCmdType = RGXFWIF_KCCB_CMD_CLEANUP; |
| |
| psKCCBCmd->uCmdData.sCleanupData.eCleanupType = eCleanupType; |
| eError = SyncPrimGetFirmwareAddr(psSyncPrim, &psKCCBCmd->uCmdData.sCleanupData.sSyncObjDevVAddr.ui32Addr); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_command; |
| } |
| |
| eError = SyncPrimSet(psSyncPrim, 0); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_command; |
| } |
| |
| /* |
| Send the cleanup request to the firmware. If the resource is still busy |
| the firmware will tell us and we'll drop out with a retry. |
| */ |
| eError = RGXScheduleCommand(psDevInfo, |
| eDM, |
| psKCCBCmd, |
| ui32CmdSize, |
| 0, |
| ui32PDumpFlags); |
| if (eError != PVRSRV_OK) |
| { |
| goto fail_command; |
| } |
| |
| /* Wait for sync primitive to be updated */ |
| #if defined(PDUMP) |
| PDUMPCOMMENT("Wait for the firmware to reply to the cleanup command"); |
| SyncPrimPDumpPol(psSyncPrim, |
| RGXFWIF_CLEANUP_RUN, |
| RGXFWIF_CLEANUP_RUN, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| ui32PDumpFlags); |
| |
| /* |
| * The cleanup request to the firmware will tell us if a given resource is busy or not. |
| * If the RGXFWIF_CLEANUP_BUSY flag is set, this means that the resource is still in use. |
| * In this case we return a PVRSRV_ERROR_RETRY error to the client drivers and they will |
| * re-issue the cleanup request until it succeed. |
| * |
| * Since this retry mechanism doesn't work for pdumps, client drivers should ensure |
| * that cleanup requests are only submitted if the resource is unused. |
| * If this is not the case, the following poll will block infinitely, making sure |
| * the issue doesn't go unnoticed. |
| */ |
| PDUMPCOMMENT("Cleanup: If this poll fails, the following resource is still in use (DM=%u, type=%u, address=0x%08x), which is incorrect in pdumps", |
| eDM, |
| psKCCBCmd->uCmdData.sCleanupData.eCleanupType, |
| psKCCBCmd->uCmdData.sCleanupData.uCleanupData.psContext.ui32Addr); |
| SyncPrimPDumpPol(psSyncPrim, |
| 0, |
| RGXFWIF_CLEANUP_BUSY, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| ui32PDumpFlags); |
| #endif |
| |
| { |
| RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| IMG_UINT32 ui32CurrentQueueLength = (psKCCBCtl->ui32WrapMask+1 + |
| psKCCBCtl->ui32WriteOffset - |
| psKCCBCtl->ui32ReadOffset) & psKCCBCtl->ui32WrapMask; |
| IMG_UINT32 ui32MaxRetries; |
| |
| for (ui32MaxRetries = ui32CurrentQueueLength + 1; |
| ui32MaxRetries > 0; |
| ui32MaxRetries--) |
| { |
| eError = PVRSRVWaitForValueKMAndHoldBridgeLockKM(psSyncPrim->pui32LinAddr, RGXFWIF_CLEANUP_RUN, RGXFWIF_CLEANUP_RUN); |
| |
| if (eError != PVRSRV_ERROR_TIMEOUT) |
| { |
| break; |
| } |
| } |
| |
| /* |
| If the firmware hasn't got back to us in a timely manner |
| then bail and let the caller retry the command. |
| */ |
| if (eError == PVRSRV_ERROR_TIMEOUT) |
| { |
| PVR_DPF((PVR_DBG_WARNING,"RGXScheduleCleanupCommand: PVRSRVWaitForValueKMAndHoldBridgeLock timed out. Dump debug information.")); |
| |
| eError = PVRSRV_ERROR_RETRY; |
| #if defined(DEBUG) |
| PVRSRVDebugRequest(psDevInfo->psDeviceNode, |
| DEBUG_REQUEST_VERBOSITY_MAX, NULL, NULL); |
| #endif |
| goto fail_poll; |
| } |
| else if (eError != PVRSRV_OK) |
| { |
| goto fail_poll; |
| } |
| } |
| |
| /* |
| If the command has was run but a resource was busy, then the request |
| will need to be retried. |
| */ |
| if (*psSyncPrim->pui32LinAddr & RGXFWIF_CLEANUP_BUSY) |
| { |
| eError = PVRSRV_ERROR_RETRY; |
| goto fail_requestbusy; |
| } |
| |
| return PVRSRV_OK; |
| |
| fail_requestbusy: |
| fail_poll: |
| fail_command: |
| PVR_ASSERT(eError != PVRSRV_OK); |
| |
| return eError; |
| } |
| |
| /* |
| RGXRequestCommonContextCleanUp |
| */ |
| PVRSRV_ERROR RGXFWRequestCommonContextCleanUp(PVRSRV_DEVICE_NODE *psDeviceNode, |
| RGX_SERVER_COMMON_CONTEXT *psServerCommonContext, |
| PVRSRV_CLIENT_SYNC_PRIM *psSyncPrim, |
| RGXFWIF_DM eDM, |
| IMG_UINT32 ui32PDumpFlags) |
| { |
| RGXFWIF_KCCB_CMD sRCCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| PRGXFWIF_FWCOMMONCONTEXT psFWCommonContextFWAddr; |
| |
| psFWCommonContextFWAddr = FWCommonContextGetFWAddress(psServerCommonContext); |
| |
| PDUMPCOMMENT("Common ctx cleanup Request DM%d [context = 0x%08x]", |
| eDM, psFWCommonContextFWAddr.ui32Addr); |
| PDUMPCOMMENT("Wait for CCB to be empty before common ctx cleanup"); |
| |
| RGXCCBPDumpDrainCCB(FWCommonContextGetClientCCB(psServerCommonContext), ui32PDumpFlags); |
| |
| /* Setup our command data, the cleanup call will fill in the rest */ |
| sRCCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psContext = psFWCommonContextFWAddr; |
| |
| /* Request cleanup of the firmware resource */ |
| eError = RGXScheduleCleanupCommand(psDeviceNode->pvDevice, |
| eDM, |
| &sRCCleanUpCmd, |
| sizeof(RGXFWIF_KCCB_CMD), |
| RGXFWIF_CLEANUP_FWCOMMONCONTEXT, |
| psSyncPrim, |
| ui32PDumpFlags); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXRequestCommonContextCleanUp: Failed to schedule a memory context cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| /* |
| * RGXRequestHWRTDataCleanUp |
| */ |
| |
| PVRSRV_ERROR RGXFWRequestHWRTDataCleanUp(PVRSRV_DEVICE_NODE *psDeviceNode, |
| PRGXFWIF_HWRTDATA psHWRTData, |
| PVRSRV_CLIENT_SYNC_PRIM *psSync, |
| RGXFWIF_DM eDM) |
| { |
| RGXFWIF_KCCB_CMD sHWRTDataCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| |
| PDUMPCOMMENT("HW RTData cleanup Request DM%d [HWRTData = 0x%08x]", eDM, psHWRTData.ui32Addr); |
| |
| sHWRTDataCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psHWRTData = psHWRTData; |
| |
| eError = RGXScheduleCleanupCommand(psDeviceNode->pvDevice, |
| eDM, |
| &sHWRTDataCleanUpCmd, |
| sizeof(sHWRTDataCleanUpCmd), |
| RGXFWIF_CLEANUP_HWRTDATA, |
| psSync, |
| IMG_FALSE); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXRequestHWRTDataCleanUp: Failed to schedule a HWRTData cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| /* |
| RGXFWRequestFreeListCleanUp |
| */ |
| PVRSRV_ERROR RGXFWRequestFreeListCleanUp(PVRSRV_RGXDEV_INFO *psDevInfo, |
| PRGXFWIF_FREELIST psFWFreeList, |
| PVRSRV_CLIENT_SYNC_PRIM *psSync) |
| { |
| RGXFWIF_KCCB_CMD sFLCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| |
| PDUMPCOMMENT("Free list cleanup Request [FreeList = 0x%08x]", psFWFreeList.ui32Addr); |
| |
| /* Setup our command data, the cleanup call will fill in the rest */ |
| sFLCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psFreelist = psFWFreeList; |
| |
| /* Request cleanup of the firmware resource */ |
| eError = RGXScheduleCleanupCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sFLCleanUpCmd, |
| sizeof(RGXFWIF_KCCB_CMD), |
| RGXFWIF_CLEANUP_FREELIST, |
| psSync, |
| IMG_FALSE); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXFWRequestFreeListCleanUp: Failed to schedule a memory context cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| /* |
| RGXFWRequestZSBufferCleanUp |
| */ |
| PVRSRV_ERROR RGXFWRequestZSBufferCleanUp(PVRSRV_RGXDEV_INFO *psDevInfo, |
| PRGXFWIF_ZSBUFFER psFWZSBuffer, |
| PVRSRV_CLIENT_SYNC_PRIM *psSync) |
| { |
| RGXFWIF_KCCB_CMD sZSBufferCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| |
| PDUMPCOMMENT("ZS Buffer cleanup Request [ZS Buffer = 0x%08x]", psFWZSBuffer.ui32Addr); |
| |
| /* Setup our command data, the cleanup call will fill in the rest */ |
| sZSBufferCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psZSBuffer = psFWZSBuffer; |
| |
| /* Request cleanup of the firmware resource */ |
| eError = RGXScheduleCleanupCommand(psDevInfo, |
| RGXFWIF_DM_3D, |
| &sZSBufferCleanUpCmd, |
| sizeof(RGXFWIF_KCCB_CMD), |
| RGXFWIF_CLEANUP_ZSBUFFER, |
| psSync, |
| IMG_FALSE); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXFWRequestZSBufferCleanUp: Failed to schedule a memory context cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| |
| PVRSRV_ERROR RGXFWRequestRayFrameDataCleanUp(PVRSRV_DEVICE_NODE *psDeviceNode, |
| PRGXFWIF_RAY_FRAME_DATA psHWFrameData, |
| PVRSRV_CLIENT_SYNC_PRIM *psSync, |
| RGXFWIF_DM eDM) |
| { |
| RGXFWIF_KCCB_CMD sHWFrameDataCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| |
| PDUMPCOMMENT("HW FrameData cleanup Request DM%d [HWFrameData = 0x%08x]", eDM, psHWFrameData.ui32Addr); |
| |
| sHWFrameDataCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psHWFrameData = psHWFrameData; |
| |
| eError = RGXScheduleCleanupCommand(psDeviceNode->pvDevice, |
| eDM, |
| &sHWFrameDataCleanUpCmd, |
| sizeof(sHWFrameDataCleanUpCmd), |
| RGXFWIF_CLEANUP_HWFRAMEDATA, |
| psSync, |
| IMG_FALSE); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXFWRequestRayFrameDataCleanUp: Failed to schedule a HWFrameData cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| /* |
| RGXFWRequestRPMFreeListCleanUp |
| */ |
| PVRSRV_ERROR RGXFWRequestRPMFreeListCleanUp(PVRSRV_RGXDEV_INFO *psDevInfo, |
| PRGXFWIF_RPM_FREELIST psFWRPMFreeList, |
| PVRSRV_CLIENT_SYNC_PRIM *psSync) |
| { |
| RGXFWIF_KCCB_CMD sFLCleanUpCmd = {0}; |
| PVRSRV_ERROR eError; |
| |
| PDUMPCOMMENT("RPM Free list cleanup Request [RPM FreeList = 0x%08x]", psFWRPMFreeList.ui32Addr); |
| |
| /* Setup our command data, the cleanup call will fill in the rest */ |
| sFLCleanUpCmd.uCmdData.sCleanupData.uCleanupData.psRPMFreelist = psFWRPMFreeList; |
| |
| /* Request cleanup of the firmware resource */ |
| eError = RGXScheduleCleanupCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sFLCleanUpCmd, |
| sizeof(RGXFWIF_KCCB_CMD), |
| RGXFWIF_CLEANUP_RPM_FREELIST, |
| psSync, |
| IMG_FALSE); |
| |
| if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY)) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXFWRequestRPMFreeListCleanUp: Failed to schedule a memory context cleanup with error (%u)", eError)); |
| } |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXFWSetHCSDeadline(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32HCSDeadlineMs) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_KCCB_CMD sSetHCSDeadline; |
| |
| sSetHCSDeadline.eCmdType = RGXFWIF_KCCB_CMD_HCS_SET_DEADLINE; |
| sSetHCSDeadline.eDM = RGXFWIF_DM_GP; |
| sSetHCSDeadline.uCmdData.sHCSCtrl.ui32HCSDeadlineMS = ui32HCSDeadlineMs; |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sSetHCSDeadline, |
| sizeof(sSetHCSDeadline), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXFWOSConfig(PVRSRV_RGXDEV_INFO *psDevInfo) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_KCCB_CMD sOSConfigCmdData; |
| |
| sOSConfigCmdData.eCmdType = RGXFWIF_KCCB_CMD_OS_CFG_INIT; |
| sOSConfigCmdData.eDM = RGXFWIF_DM_GP; |
| sOSConfigCmdData.uCmdData.sCmdOSConfigData.sOSInit = psDevInfo->sFWInitFWAddr; |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sOSConfigCmdData, |
| sizeof(sOSConfigCmdData), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXFWSetOSIsolationThreshold(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32IsolationPriorityThreshold) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_KCCB_CMD sOSidIsoConfCmd; |
| |
| sOSidIsoConfCmd.eCmdType = RGXFWIF_KCCB_CMD_OS_ISOLATION_GROUP_CHANGE; |
| sOSidIsoConfCmd.uCmdData.sCmdOSidIsolationData.ui32IsolationPriorityThreshold = ui32IsolationPriorityThreshold; |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sOSidIsoConfCmd, |
| sizeof(sOSidIsoConfCmd), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXFWSetVMOnlineState(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32OSid, |
| RGXFWIF_OS_STATE_CHANGE eOSOnlineState) |
| { |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| RGXFWIF_KCCB_CMD sOSOnlineStateCmd; |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBuf = psDevInfo->psRGXFWIfTraceBuf; |
| volatile IMG_UINT32 *pui32OSStateFlags; |
| |
| sOSOnlineStateCmd.eCmdType = RGXFWIF_KCCB_CMD_OS_ONLINE_STATE_CONFIGURE; |
| sOSOnlineStateCmd.uCmdData.sCmdOSOnlineStateData.ui32OSid = ui32OSid; |
| sOSOnlineStateCmd.uCmdData.sCmdOSOnlineStateData.eNewOSState = eOSOnlineState; |
| |
| if (eOSOnlineState == RGXFWIF_OS_ONLINE) |
| { |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sOSOnlineStateCmd, |
| sizeof(sOSOnlineStateCmd), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return eError; |
| } |
| |
| if (psRGXFWIfTraceBuf == NULL) |
| { |
| return PVRSRV_ERROR_NOT_INITIALISED; |
| } |
| pui32OSStateFlags = (volatile IMG_UINT32*) &psRGXFWIfTraceBuf->ui32OSStateFlags[ui32OSid]; |
| |
| /* Attempt several times until the FW manages to offload the OS */ |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| IMG_UINT32 ui32OSStateFlags; |
| |
| /* Send request */ |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sOSOnlineStateCmd, |
| sizeof(sOSOnlineStateCmd), |
| 0, |
| IMG_TRUE); |
| if (unlikely(eError == PVRSRV_ERROR_RETRY)) |
| { |
| continue; |
| } |
| PVR_LOGG_IF_ERROR(eError, "RGXScheduleCommand", return_); |
| |
| /* Wait for FW to process the cmd */ |
| eError = RGXWaitForFWOp(psDevInfo, |
| RGXFWIF_DM_GP, |
| psDevInfo->psDeviceNode->psSyncPrim, |
| PDUMP_FLAGS_CONTINUOUS); |
| PVR_LOGG_IF_ERROR(eError, "RGXWaitForFWOp", return_); |
| |
| /* read the OS state */ |
| OSMemoryBarrier(); |
| ui32OSStateFlags = *pui32OSStateFlags; |
| |
| if ((ui32OSStateFlags & RGXFW_OS_STATE_ACTIVE_OS) == 0) |
| { |
| /* FW finished offloading the OSID */ |
| eError = PVRSRV_OK; |
| break; |
| } |
| else |
| { |
| eError = PVRSRV_ERROR_TIMEOUT; |
| } |
| |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return_ : |
| #endif |
| return eError; |
| } |
| |
| PVRSRV_ERROR RGXFWChangeOSidPriority(PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32OSid, |
| IMG_UINT32 ui32Priority) |
| { |
| PVRSRV_ERROR eError; |
| RGXFWIF_KCCB_CMD sOSidPriorityCmd; |
| |
| sOSidPriorityCmd.eCmdType = RGXFWIF_KCCB_CMD_OSID_PRIORITY_CHANGE; |
| sOSidPriorityCmd.uCmdData.sCmdOSidPriorityData.ui32OSidNum = ui32OSid; |
| sOSidPriorityCmd.uCmdData.sCmdOSidPriorityData.ui32Priority = ui32Priority; |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| RGXFWIF_DM_GP, |
| &sOSidPriorityCmd, |
| sizeof(sOSidPriorityCmd), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| return eError; |
| } |
| |
| PVRSRV_ERROR ContextSetPriority(RGX_SERVER_COMMON_CONTEXT *psContext, |
| CONNECTION_DATA *psConnection, |
| PVRSRV_RGXDEV_INFO *psDevInfo, |
| IMG_UINT32 ui32Priority, |
| RGXFWIF_DM eDM) |
| { |
| IMG_UINT32 ui32CmdSize; |
| IMG_UINT8 *pui8CmdPtr; |
| RGXFWIF_KCCB_CMD sPriorityCmd; |
| RGXFWIF_CCB_CMD_HEADER *psCmdHeader; |
| RGXFWIF_CMD_PRIORITY *psCmd; |
| PVRSRV_ERROR eError; |
| |
| /* |
| Get space for command |
| */ |
| ui32CmdSize = RGX_CCB_FWALLOC_ALIGN(sizeof(RGXFWIF_CCB_CMD_HEADER) + sizeof(RGXFWIF_CMD_PRIORITY)); |
| |
| eError = RGXAcquireCCB(FWCommonContextGetClientCCB(psContext), |
| ui32CmdSize, |
| (void **) &pui8CmdPtr, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_OK) |
| { |
| if(eError != PVRSRV_ERROR_RETRY) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed to acquire space for client CCB", __FUNCTION__)); |
| } |
| goto fail_ccbacquire; |
| } |
| |
| /* |
| Write the command header and command |
| */ |
| psCmdHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr; |
| psCmdHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_PRIORITY; |
| psCmdHeader->ui32CmdSize = RGX_CCB_FWALLOC_ALIGN(sizeof(RGXFWIF_CMD_PRIORITY)); |
| pui8CmdPtr += sizeof(*psCmdHeader); |
| |
| psCmd = (RGXFWIF_CMD_PRIORITY *) pui8CmdPtr; |
| psCmd->ui32Priority = ui32Priority; |
| pui8CmdPtr += sizeof(*psCmd); |
| |
| /* |
| We should reserved space in the kernel CCB here and fill in the command |
| directly. |
| This is so if there isn't space in the kernel CCB we can return with |
| retry back to services client before we take any operations |
| */ |
| |
| /* |
| Submit the command |
| */ |
| RGXReleaseCCB(FWCommonContextGetClientCCB(psContext), |
| ui32CmdSize, |
| PDUMP_FLAGS_CONTINUOUS); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "%s: Failed to release space in client CCB", __FUNCTION__)); |
| return eError; |
| } |
| |
| /* Construct the priority command. */ |
| sPriorityCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK; |
| sPriorityCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psContext); |
| sPriorityCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psContext)); |
| sPriorityCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0; |
| sPriorityCmd.uCmdData.sCmdKickData.sWorkloadDataFWAddress.ui32Addr = 0; |
| sPriorityCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset = 0; |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| eError = RGXScheduleCommand(psDevInfo, |
| eDM, |
| &sPriorityCmd, |
| sizeof(sPriorityCmd), |
| 0, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_ERROR_RETRY) |
| { |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"ContextSetPriority: Failed to submit set priority command with error (%u)", eError)); |
| } |
| |
| return PVRSRV_OK; |
| |
| fail_ccbacquire: |
| PVR_ASSERT(eError != PVRSRV_OK); |
| return eError; |
| } |
| |
| /* |
| RGXReadMETAAddr |
| */ |
| PVRSRV_ERROR RGXReadMETAAddr(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32METAAddr, IMG_UINT32 *pui32Value) |
| { |
| IMG_UINT8 *pui8RegBase = (IMG_UINT8*)psDevInfo->pvRegsBaseKM; |
| IMG_UINT32 ui32Value; |
| |
| /* Wait for Slave Port to be Ready */ |
| if (PVRSRVPollForValueKM( |
| (IMG_UINT32*) (pui8RegBase + RGX_CR_META_SP_MSLVCTRL1), |
| RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, |
| RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN) != PVRSRV_OK) |
| { |
| return PVRSRV_ERROR_TIMEOUT; |
| } |
| |
| /* Issue the Read */ |
| OSWriteHWReg32( |
| psDevInfo->pvRegsBaseKM, |
| RGX_CR_META_SP_MSLVCTRL0, |
| ui32METAAddr | RGX_CR_META_SP_MSLVCTRL0_RD_EN); |
| |
| /* Wait for Slave Port to be Ready: read complete */ |
| if (PVRSRVPollForValueKM( |
| (IMG_UINT32*) (pui8RegBase + RGX_CR_META_SP_MSLVCTRL1), |
| RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, |
| RGX_CR_META_SP_MSLVCTRL1_READY_EN|RGX_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN) != PVRSRV_OK) |
| { |
| return PVRSRV_ERROR_TIMEOUT; |
| } |
| |
| /* Read the value */ |
| ui32Value = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_META_SP_MSLVDATAX); |
| |
| *pui32Value = ui32Value; |
| |
| return PVRSRV_OK; |
| } |
| |
| |
| /* |
| RGXUpdateHealthStatus |
| */ |
| PVRSRV_ERROR RGXUpdateHealthStatus(PVRSRV_DEVICE_NODE* psDevNode, |
| IMG_BOOL bCheckAfterTimePassed) |
| { |
| #if !defined(PVRSRV_GPUVIRT_GUESTDRV) |
| PVRSRV_DATA* psPVRSRVData = PVRSRVGetPVRSRVData(); |
| PVRSRV_DEVICE_HEALTH_STATUS eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_OK; |
| PVRSRV_DEVICE_HEALTH_REASON eNewReason = PVRSRV_DEVICE_HEALTH_REASON_NONE; |
| PVRSRV_RGXDEV_INFO* psDevInfo; |
| RGXFWIF_TRACEBUF* psRGXFWIfTraceBufCtl; |
| RGXFWIF_CCB_CTL *psKCCBCtl; |
| IMG_UINT32 ui32ThreadCount; |
| IMG_BOOL bKCCBCmdsWaiting; |
| |
| PVR_ASSERT(psDevNode != NULL); |
| psDevInfo = psDevNode->pvDevice; |
| psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| |
| /* If the firmware is not initialised, there is not much point continuing! */ |
| if (!psDevInfo->bFirmwareInitialised || psDevInfo->pvRegsBaseKM == NULL || |
| psDevInfo->psDeviceNode == NULL) |
| { |
| return PVRSRV_OK; |
| } |
| |
| /* If Rogue is not powered on, don't continue |
| (there is a race condition where PVRSRVIsDevicePowered returns TRUE when the GPU is actually powering down. |
| That's not a problem as this function does not touch the HW except for the RGXScheduleCommand function, |
| which is already powerlock safe. The worst thing that could happen is that Rogue might power back up |
| but the chances of that are very low */ |
| if (!PVRSRVIsDevicePowered(psDevNode)) |
| { |
| return PVRSRV_OK; |
| } |
| |
| /* If this is a quick update, then include the last current value... */ |
| if (!bCheckAfterTimePassed) |
| { |
| eNewStatus = OSAtomicRead(&psDevNode->eHealthStatus); |
| eNewReason = OSAtomicRead(&psDevNode->eHealthReason); |
| } |
| |
| /* |
| Firmware thread checks... |
| */ |
| for (ui32ThreadCount = 0; ui32ThreadCount < RGXFW_THREAD_NUM; ui32ThreadCount++) |
| { |
| if (psRGXFWIfTraceBufCtl != NULL) |
| { |
| IMG_CHAR* pszTraceAssertInfo = psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.szInfo; |
| |
| /* |
| Check if the FW has hit an assert... |
| */ |
| if (*pszTraceAssertInfo != '\0') |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: Firmware thread %d has asserted: %s (%s:%d)", |
| ui32ThreadCount, pszTraceAssertInfo, |
| psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.szPath, |
| psRGXFWIfTraceBufCtl->sTraceBuf[ui32ThreadCount].sAssertBuf.ui32LineNum)); |
| eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_DEAD; |
| eNewReason = PVRSRV_DEVICE_HEALTH_REASON_ASSERTED; |
| goto _RGXUpdateHealthStatus_Exit; |
| } |
| |
| /* |
| Check the threads to see if they are in the same poll locations as last time... |
| */ |
| if (bCheckAfterTimePassed) |
| { |
| if (psRGXFWIfTraceBufCtl->aui32CrPollAddr[ui32ThreadCount] != 0 && |
| psRGXFWIfTraceBufCtl->aui32CrPollAddr[ui32ThreadCount] == psDevInfo->aui32CrLastPollAddr[ui32ThreadCount]) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: Firmware stuck on CR poll: T%u polling %s (reg:0x%08X mask:0x%08X)", |
| ui32ThreadCount, |
| ((psRGXFWIfTraceBufCtl->aui32CrPollAddr[ui32ThreadCount] & RGXFW_POLL_TYPE_SET)?("set"):("unset")), |
| psRGXFWIfTraceBufCtl->aui32CrPollAddr[ui32ThreadCount] & ~RGXFW_POLL_TYPE_SET, |
| psRGXFWIfTraceBufCtl->aui32CrPollMask[ui32ThreadCount])); |
| eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING; |
| eNewReason = PVRSRV_DEVICE_HEALTH_REASON_POLL_FAILING; |
| goto _RGXUpdateHealthStatus_Exit; |
| } |
| psDevInfo->aui32CrLastPollAddr[ui32ThreadCount] = psRGXFWIfTraceBufCtl->aui32CrPollAddr[ui32ThreadCount]; |
| } |
| } |
| } |
| |
| /* |
| Event Object Timeouts check... |
| */ |
| if (!bCheckAfterTimePassed) |
| { |
| if (psDevInfo->ui32GEOTimeoutsLastTime > 1 && psPVRSRVData->ui32GEOConsecutiveTimeouts > psDevInfo->ui32GEOTimeoutsLastTime) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: Global Event Object Timeouts have risen (from %d to %d)", |
| psDevInfo->ui32GEOTimeoutsLastTime, psPVRSRVData->ui32GEOConsecutiveTimeouts)); |
| eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING; |
| eNewReason = PVRSRV_DEVICE_HEALTH_REASON_TIMEOUTS; |
| } |
| psDevInfo->ui32GEOTimeoutsLastTime = psPVRSRVData->ui32GEOConsecutiveTimeouts; |
| } |
| |
| /* |
| Check the Kernel CCB pointer is valid. If any commands were waiting last time, then check |
| that some have executed since then. |
| */ |
| bKCCBCmdsWaiting = IMG_FALSE; |
| psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| |
| if (psKCCBCtl != NULL) |
| { |
| if (psKCCBCtl->ui32ReadOffset > psKCCBCtl->ui32WrapMask || |
| psKCCBCtl->ui32WriteOffset > psKCCBCtl->ui32WrapMask) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: KCCB has invalid offset (ROFF=%d WOFF=%d)", |
| psKCCBCtl->ui32ReadOffset, psKCCBCtl->ui32WriteOffset)); |
| eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_DEAD; |
| eNewReason = PVRSRV_DEVICE_HEALTH_REASON_QUEUE_CORRUPT; |
| } |
| |
| if (psKCCBCtl->ui32ReadOffset != psKCCBCtl->ui32WriteOffset) |
| { |
| bKCCBCmdsWaiting = IMG_TRUE; |
| } |
| } |
| |
| if (bCheckAfterTimePassed && psDevInfo->psRGXFWIfTraceBuf != NULL) |
| { |
| IMG_UINT32 ui32KCCBCmdsExecuted = psDevInfo->psRGXFWIfTraceBuf->ui32KCCBCmdsExecuted; |
| |
| if (psDevInfo->ui32KCCBCmdsExecutedLastTime == ui32KCCBCmdsExecuted) |
| { |
| /* |
| If something was waiting last time then the Firmware has stopped processing commands. |
| */ |
| if (psDevInfo->bKCCBCmdsWaitingLastTime) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: No KCCB commands executed since check!")); |
| eNewStatus = PVRSRV_DEVICE_HEALTH_STATUS_NOT_RESPONDING; |
| eNewReason = PVRSRV_DEVICE_HEALTH_REASON_QUEUE_STALLED; |
| } |
| |
| /* |
| If no commands are currently pending and nothing happened since the last poll, then |
| schedule a dummy command to ping the firmware so we know it is alive and processing. |
| */ |
| if (!bKCCBCmdsWaiting) |
| { |
| RGXFWIF_KCCB_CMD sCmpKCCBCmd; |
| PVRSRV_ERROR eError; |
| |
| sCmpKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_HEALTH_CHECK; |
| |
| eError = RGXScheduleCommand(psDevNode->pvDevice, |
| RGXFWIF_DM_GP, |
| &sCmpKCCBCmd, |
| sizeof(sCmpKCCBCmd), |
| 0, |
| IMG_TRUE); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "RGXGetDeviceHealthStatus: Cannot schedule Health Check command! (0x%x)", eError)); |
| } |
| else |
| { |
| bKCCBCmdsWaiting = IMG_TRUE; |
| } |
| } |
| } |
| |
| psDevInfo->bKCCBCmdsWaitingLastTime = bKCCBCmdsWaiting; |
| psDevInfo->ui32KCCBCmdsExecutedLastTime = ui32KCCBCmdsExecuted; |
| } |
| |
| if (bCheckAfterTimePassed && (PVRSRV_DEVICE_HEALTH_STATUS_OK==eNewStatus)) |
| { |
| /* Attempt to detect and deal with any stalled client contexts. |
| * Currently, ui32StalledClientMask is not a reliable method of detecting a stalled |
| * application as the app could just be busy with a long running task, |
| * or a lots of smaller workloads. Also the definition of stalled is |
| * effectively subject to the timer frequency calling this function |
| * (which is a platform config value with no guarantee it is correctly tuned). |
| */ |
| |
| IMG_UINT32 ui32StalledClientMask = 0; |
| |
| ui32StalledClientMask |= CheckForStalledClientTransferCtxt(psDevInfo); |
| |
| ui32StalledClientMask |= CheckForStalledClientRenderCtxt(psDevInfo); |
| |
| #if !defined(UNDER_WDDM) |
| if(psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_COMPUTE_BIT_MASK) |
| { |
| ui32StalledClientMask |= CheckForStalledClientComputeCtxt(psDevInfo); |
| } |
| #endif |
| |
| if (psDevInfo->sDevFeatureCfg.ui64Features & RGX_FEATURE_RAY_TRACING_BIT_MASK) |
| { |
| ui32StalledClientMask |= CheckForStalledClientRayCtxt(psDevInfo); |
| } |
| |
| /* If at least one DM stalled bit is different than before */ |
| if (psDevInfo->ui32StalledClientMask ^ ui32StalledClientMask) |
| { |
| /* Print all the stalled DMs */ |
| PVR_LOG(("RGXGetDeviceHealthStatus: Possible stalled client contexts detected: %s%s%s%s%s%s%s%s%s", |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_GP), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TDM_2D), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TA), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_3D), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_CDM), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_RTU), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_SHG), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TQ2D), |
| RGX_STRINGIFY_KICK_TYPE_DM_IF_SET(ui32StalledClientMask, RGX_KICK_TYPE_DM_TQ3D))); |
| } |
| psDevInfo->ui32StalledClientMask = ui32StalledClientMask; |
| } |
| |
| /* |
| Finished, save the new status... |
| */ |
| _RGXUpdateHealthStatus_Exit: |
| OSAtomicWrite(&psDevNode->eHealthStatus, eNewStatus); |
| OSAtomicWrite(&psDevNode->eHealthReason, eNewReason); |
| |
| /* |
| * Attempt to service the HWPerf buffer to regularly transport idle/periodic |
| * packets to host buffer. |
| */ |
| if (psDevNode->pfnServiceHWPerf != NULL) |
| { |
| PVRSRV_ERROR eError = psDevNode->pfnServiceHWPerf(psDevNode); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_WARNING, "DevicesWatchdogThread: " |
| "Error occurred when servicing HWPerf buffer (%d)", |
| eError)); |
| } |
| } |
| |
| #endif |
| return PVRSRV_OK; |
| } /* RGXUpdateHealthStatus */ |
| |
| PVRSRV_ERROR CheckStalledClientCommonContext(RGX_SERVER_COMMON_CONTEXT *psCurrentServerCommonContext, RGX_KICK_TYPE_DM eKickTypeDM) |
| { |
| RGX_CLIENT_CCB *psCurrentClientCCB = psCurrentServerCommonContext->psClientCCB; |
| |
| return CheckForStalledCCB(psCurrentClientCCB, eKickTypeDM); |
| } |
| |
| void DumpStalledFWCommonContext(RGX_SERVER_COMMON_CONTEXT *psCurrentServerCommonContext, |
| DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf, |
| void *pvDumpDebugFile) |
| { |
| RGX_CLIENT_CCB *psCurrentClientCCB = psCurrentServerCommonContext->psClientCCB; |
| PRGXFWIF_FWCOMMONCONTEXT sFWCommonContext = psCurrentServerCommonContext->sFWCommonContextFWAddr; |
| |
| #if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) || defined(PVRSRV_ENABLE_FULL_CCB_DUMP) |
| DumpCCB(psCurrentServerCommonContext->psDevInfo, sFWCommonContext, |
| psCurrentClientCCB, pfnDumpDebugPrintf, pvDumpDebugFile); |
| #else |
| DumpStalledCCBCommand(sFWCommonContext, psCurrentClientCCB, pfnDumpDebugPrintf, pvDumpDebugFile); |
| #endif |
| } |
| |
| void AttachKickResourcesCleanupCtls(PRGXFWIF_CLEANUP_CTL *apsCleanupCtl, |
| IMG_UINT32 *pui32NumCleanupCtl, |
| RGXFWIF_DM eDM, |
| IMG_BOOL bKick, |
| RGX_RTDATA_CLEANUP_DATA *psRTDataCleanup, |
| RGX_ZSBUFFER_DATA *psZBuffer, |
| RGX_ZSBUFFER_DATA *psSBuffer) |
| { |
| PRGXFWIF_CLEANUP_CTL *psCleanupCtlWrite = apsCleanupCtl; |
| |
| PVR_ASSERT((eDM == RGXFWIF_DM_TA) || (eDM == RGXFWIF_DM_3D)); |
| |
| if(bKick) |
| { |
| if(eDM == RGXFWIF_DM_TA) |
| { |
| if(psRTDataCleanup) |
| { |
| PRGXFWIF_CLEANUP_CTL psCleanupCtl; |
| |
| RGXSetFirmwareAddress(&psCleanupCtl, psRTDataCleanup->psFWHWRTDataMemDesc, |
| offsetof(RGXFWIF_HWRTDATA, sTACleanupState), |
| RFW_FWADDR_NOREF_FLAG); |
| |
| *(psCleanupCtlWrite++) = psCleanupCtl; |
| } |
| } |
| else |
| { |
| if(psRTDataCleanup) |
| { |
| PRGXFWIF_CLEANUP_CTL psCleanupCtl; |
| |
| RGXSetFirmwareAddress(&psCleanupCtl, psRTDataCleanup->psFWHWRTDataMemDesc, |
| offsetof(RGXFWIF_HWRTDATA, s3DCleanupState), |
| RFW_FWADDR_NOREF_FLAG); |
| |
| *(psCleanupCtlWrite++) = psCleanupCtl; |
| } |
| |
| if(psZBuffer) |
| { |
| (psCleanupCtlWrite++)->ui32Addr = psZBuffer->sZSBufferFWDevVAddr.ui32Addr + |
| offsetof(RGXFWIF_FWZSBUFFER, sCleanupState); |
| } |
| |
| if(psSBuffer) |
| { |
| (psCleanupCtlWrite++)->ui32Addr = psSBuffer->sZSBufferFWDevVAddr.ui32Addr + |
| offsetof(RGXFWIF_FWZSBUFFER, sCleanupState); |
| } |
| } |
| } |
| |
| *pui32NumCleanupCtl = psCleanupCtlWrite - apsCleanupCtl; |
| |
| PVR_ASSERT(*pui32NumCleanupCtl <= RGXFWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS); |
| } |
| |
| PVRSRV_ERROR RGXResetHWRLogs(PVRSRV_DEVICE_NODE *psDevNode) |
| { |
| #if defined(PVRSRV_GPUVIRT_GUESTDRV) |
| /* Guest drivers do not support HW reset */ |
| PVR_UNREFERENCED_PARAMETER(psDevNode); |
| #else |
| PVRSRV_RGXDEV_INFO *psDevInfo; |
| RGXFWIF_HWRINFOBUF *psHWRInfoBuf; |
| RGXFWIF_TRACEBUF *psRGXFWIfTraceBufCtl; |
| IMG_UINT32 i; |
| |
| if(psDevNode->pvDevice == NULL) |
| { |
| return PVRSRV_ERROR_INVALID_DEVINFO; |
| } |
| psDevInfo = psDevNode->pvDevice; |
| |
| psHWRInfoBuf = psDevInfo->psRGXFWIfHWRInfoBuf; |
| psRGXFWIfTraceBufCtl = psDevInfo->psRGXFWIfTraceBuf; |
| |
| for(i = 0 ; i < psDevInfo->sDevFeatureCfg.ui32MAXDMCount ; i++) |
| { |
| /* Reset the HWR numbers */ |
| psRGXFWIfTraceBufCtl->aui32HwrDmLockedUpCount[i] = 0; |
| psRGXFWIfTraceBufCtl->aui32HwrDmFalseDetectCount[i] = 0; |
| psRGXFWIfTraceBufCtl->aui32HwrDmRecoveredCount[i] = 0; |
| psRGXFWIfTraceBufCtl->aui32HwrDmOverranCount[i] = 0; |
| } |
| |
| for(i = 0 ; i < RGXFWIF_HWINFO_MAX ; i++) |
| { |
| psHWRInfoBuf->sHWRInfo[i].ui32HWRNumber = 0; |
| } |
| |
| for(i = 0 ; i < RGXFW_THREAD_NUM ; i++) |
| { |
| psHWRInfoBuf->ui32FirstCrPollAddr[i] = 0; |
| psHWRInfoBuf->ui32FirstCrPollMask[i] = 0; |
| } |
| |
| psHWRInfoBuf->ui32WriteIndex = 0; |
| psHWRInfoBuf->ui32DDReqCount = 0; |
| #endif |
| return PVRSRV_OK; |
| } |
| |
| PVRSRV_ERROR RGXGetPhyAddr(PMR *psPMR, |
| IMG_DEV_PHYADDR *psPhyAddr, |
| IMG_UINT32 ui32LogicalOffset, |
| IMG_UINT32 ui32Log2PageSize, |
| IMG_UINT32 ui32NumOfPages, |
| IMG_BOOL *bValid) |
| { |
| |
| PVRSRV_ERROR eError; |
| |
| eError = PMRLockSysPhysAddresses(psPMR); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXGetPhyAddr: PMRLockSysPhysAddresses failed (%u)", |
| eError)); |
| return eError; |
| } |
| |
| eError = PMR_DevPhysAddr(psPMR, |
| ui32Log2PageSize, |
| ui32NumOfPages, |
| ui32LogicalOffset, |
| psPhyAddr, |
| bValid); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXGetPhyAddr: PMR_DevPhysAddr failed (%u)", |
| eError)); |
| return eError; |
| } |
| |
| |
| eError = PMRUnlockSysPhysAddresses(psPMR); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"RGXGetPhyAddr: PMRUnLockSysPhysAddresses failed (%u)", |
| eError)); |
| return eError; |
| } |
| |
| return eError; |
| } |
| |
| #if defined(PDUMP) |
| PVRSRV_ERROR RGXPdumpDrainKCCB(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32WriteOffset) |
| { |
| RGXFWIF_CCB_CTL *psKCCBCtl = psDevInfo->psKernelCCBCtl; |
| PVRSRV_ERROR eError = PVRSRV_OK; |
| |
| if (psDevInfo->bDumpedKCCBCtlAlready) |
| { |
| /* exiting capture range */ |
| psDevInfo->bDumpedKCCBCtlAlready = IMG_FALSE; |
| |
| /* make sure previous cmd is drained in pdump in case we will 'jump' over some future cmds */ |
| PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_POWER, |
| "kCCB(%p): Draining rgxfw_roff (0x%x) == woff (0x%x)", |
| psKCCBCtl, |
| ui32WriteOffset, |
| ui32WriteOffset); |
| eError = DevmemPDumpDevmemPol32(psDevInfo->psKernelCCBCtlMemDesc, |
| offsetof(RGXFWIF_CCB_CTL, ui32ReadOffset), |
| ui32WriteOffset, |
| 0xffffffff, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_POWER); |
| |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXPdumpDrainKCCB: problem pdumping POL for kCCBCtl (%d)", eError)); |
| } |
| } |
| |
| return eError; |
| |
| } |
| #endif |
| |
| /*! |
| ******************************************************************************* |
| |
| @Function RGXClientConnectCompatCheck_ClientAgainstFW |
| |
| @Description |
| |
| Check compatibility of client and firmware (build options) |
| at the connection time. |
| |
| @Input psDeviceNode - device node |
| @Input ui32ClientBuildOptions - build options for the client |
| |
| @Return PVRSRV_ERROR - depending on mismatch found |
| |
| ******************************************************************************/ |
| PVRSRV_ERROR IMG_CALLCONV RGXClientConnectCompatCheck_ClientAgainstFW(PVRSRV_DEVICE_NODE * psDeviceNode, IMG_UINT32 ui32ClientBuildOptions) |
| { |
| PVRSRV_ERROR eError; |
| #if defined(PVRSRV_GPUVIRT_GUESTDRV) |
| eError = PVRSRV_OK; |
| #else |
| #if !defined(NO_HARDWARE) || defined(PDUMP) |
| PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice; |
| #endif |
| #if !defined(NO_HARDWARE) |
| RGXFWIF_INIT *psRGXFWInit = NULL; |
| IMG_UINT32 ui32BuildOptionsMismatch; |
| IMG_UINT32 ui32BuildOptionsFW; |
| |
| eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc, |
| (void **)&psRGXFWInit); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to acquire kernel fw compatibility check info (%u)", |
| __FUNCTION__, eError)); |
| return eError; |
| } |
| |
| LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) |
| { |
| if(*((volatile IMG_BOOL *)&psRGXFWInit->sRGXCompChecks.bUpdated)) |
| { |
| /* No need to wait if the FW has already updated the values */ |
| break; |
| } |
| OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT); |
| } END_LOOP_UNTIL_TIMEOUT(); |
| #endif |
| |
| #if defined(PDUMP) |
| PDUMPCOMMENT("Compatibility check: client and FW build options"); |
| eError = DevmemPDumpDevmemPol32(psDevInfo->psRGXFWIfInitMemDesc, |
| offsetof(RGXFWIF_INIT, sRGXCompChecks) + |
| offsetof(RGXFWIF_COMPCHECKS, ui32BuildOptions), |
| ui32ClientBuildOptions, |
| 0xffffffff, |
| PDUMP_POLL_OPERATOR_EQUAL, |
| PDUMP_FLAGS_CONTINUOUS); |
| if (eError != PVRSRV_OK) |
| { |
| PVR_DPF((PVR_DBG_ERROR, "RGXDevInitCompatCheck: problem pdumping POL for psRGXFWIfInitMemDesc (%d)", eError)); |
| return eError; |
| } |
| #endif |
| |
| #if !defined(NO_HARDWARE) |
| if (psRGXFWInit == NULL) |
| { |
| PVR_DPF((PVR_DBG_ERROR,"%s: Failed to acquire kernel fw compatibility check info, psRGXFWInit is NULL", __FUNCTION__)); |
| eError = PVRSRV_ERROR_INVALID_PARAMS; |
| goto chk_exit; |
| } |
| |
| ui32BuildOptionsFW = psRGXFWInit->sRGXCompChecks.ui32BuildOptions; |
| ui32BuildOptionsMismatch = ui32ClientBuildOptions ^ ui32BuildOptionsFW; |
| |
| if (ui32BuildOptionsMismatch != 0) |
| { |
| if ( (ui32ClientBuildOptions & ui32BuildOptionsMismatch) != 0) |
| { |
| PVR_LOG(("(FAIL) RGXDevInitCompatCheck: Mismatch in Firmware and client build options; " |
| "extra options present in client: (0x%x). Please check rgx_options.h", |
| ui32ClientBuildOptions & ui32BuildOptionsMismatch )); |
| } |
| |
| if ( (ui32BuildOptionsFW & ui32BuildOptionsMismatch) != 0) |
| { |
| PVR_LOG(("(FAIL) RGXDevInitCompatCheck: Mismatch in Firmware and client build options; " |
| "extra options present in Firmware: (0x%x). Please check rgx_options.h", |
| ui32BuildOptionsFW & ui32BuildOptionsMismatch )); |
| } |
| eError = PVRSRV_ERROR_BUILD_OPTIONS_MISMATCH; |
| goto chk_exit; |
| } |
| else |
| { |
| PVR_DPF((PVR_DBG_MESSAGE, "RGXDevInitCompatCheck: Firmware and client build options match. [ OK ]")); |
| } |
| #endif |
| |
| eError = PVRSRV_OK; |
| #if !defined(NO_HARDWARE) |
| chk_exit: |
| DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc); |
| #endif |
| #endif |
| return eError; |
| |
| } |
| |
| /****************************************************************************** |
| End of file (rgxfwutils.c) |
| ******************************************************************************/ |