blob: 6ff91928da746900405d8c8e50e2d285be9856d5 [file] [log] [blame]
/*************************************************************************/ /*!
@File
@Title RGX TA/3D routines
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@Description RGX TA/3D 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.
*/ /**************************************************************************/
/* for the offsetof macro */
#include <stddef.h>
#include "pdump_km.h"
#include "pvr_debug.h"
#include "rgxutils.h"
#include "rgxfwutils.h"
#include "rgxta3d.h"
#include "rgxmem.h"
#include "allocmem.h"
#include "devicemem.h"
#include "devicemem_pdump.h"
#include "ri_server.h"
#include "osfunc.h"
#include "pvrsrv.h"
#include "rgx_memallocflags.h"
#include "rgxccb.h"
#include "rgxhwperf.h"
#include "rgxtimerquery.h"
#include "htbuffer.h"
#include "rgxdefs_km.h"
#include "rgx_fwif_km.h"
#include "physmem.h"
#include "sync_server.h"
#include "sync_internal.h"
#include "sync.h"
#include "process_stats.h"
#if defined(SUPPORT_BUFFER_SYNC)
#include "pvr_buffer_sync.h"
#endif
#if defined(SUPPORT_NATIVE_FENCE_SYNC)
#include "pvr_sync.h"
#endif
#if defined(SUPPORT_PDVFS)
#include "rgxpdvfs.h"
#endif
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
#include "hash.h"
#include "rgxworkest.h"
#define HASH_CLEAN_LIMIT 6
#endif
typedef struct _DEVMEM_REF_LOOKUP_
{
IMG_UINT32 ui32ZSBufferID;
RGX_ZSBUFFER_DATA *psZSBuffer;
} DEVMEM_REF_LOOKUP;
typedef struct _DEVMEM_FREELIST_LOOKUP_
{
IMG_UINT32 ui32FreeListID;
RGX_FREELIST *psFreeList;
} DEVMEM_FREELIST_LOOKUP;
typedef struct {
DEVMEM_MEMDESC *psContextStateMemDesc;
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext;
IMG_UINT32 ui32Priority;
} RGX_SERVER_RC_TA_DATA;
typedef struct {
DEVMEM_MEMDESC *psContextStateMemDesc;
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext;
IMG_UINT32 ui32Priority;
} RGX_SERVER_RC_3D_DATA;
struct _RGX_SERVER_RENDER_CONTEXT_ {
PVRSRV_DEVICE_NODE *psDeviceNode;
DEVMEM_MEMDESC *psFWRenderContextMemDesc;
DEVMEM_MEMDESC *psFWFrameworkMemDesc;
RGX_SERVER_RC_TA_DATA sTAData;
RGX_SERVER_RC_3D_DATA s3DData;
IMG_UINT32 ui32CleanupStatus;
#define RC_CLEANUP_TA_COMPLETE (1 << 0)
#define RC_CLEANUP_3D_COMPLETE (1 << 1)
PVRSRV_CLIENT_SYNC_PRIM *psCleanupSync;
DLLIST_NODE sListNode;
SYNC_ADDR_LIST sSyncAddrListTAFence;
SYNC_ADDR_LIST sSyncAddrListTAUpdate;
SYNC_ADDR_LIST sSyncAddrList3DFence;
SYNC_ADDR_LIST sSyncAddrList3DUpdate;
ATOMIC_T hJobId;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
WORKEST_HOST_DATA sWorkEstData;
#endif
};
#if ! defined(NO_HARDWARE)
static
#ifdef __GNUC__
__attribute__((noreturn))
#endif
void sleep_for_ever(void)
{
#if defined(__KLOCWORK__) // klocworks would report an infinite loop because of while(1).
PVR_ASSERT(0);
#else
while(1)
{
OSSleepms(~0); // sleep the maximum amount of time possible
}
#endif
}
#endif
/*
Static functions used by render context code
*/
static
PVRSRV_ERROR _DestroyTAContext(RGX_SERVER_RC_TA_DATA *psTAData,
PVRSRV_DEVICE_NODE *psDeviceNode,
PVRSRV_CLIENT_SYNC_PRIM *psCleanupSync)
{
PVRSRV_ERROR eError;
/* Check if the FW has finished with this resource ... */
eError = RGXFWRequestCommonContextCleanUp(psDeviceNode,
psTAData->psServerCommonContext,
psCleanupSync,
RGXFWIF_DM_TA,
PDUMP_FLAGS_NONE);
if (eError == PVRSRV_ERROR_RETRY)
{
return eError;
}
else if (eError != PVRSRV_OK)
{
PVR_LOG(("%s: Unexpected error from RGXFWRequestCommonContextCleanUp (%s)",
__FUNCTION__,
PVRSRVGetErrorStringKM(eError)));
return eError;
}
/* ... it has so we can free it's resources */
#if defined(DEBUG)
/* Log the number of TA context stores which occurred */
{
RGXFWIF_TACTX_STATE *psFWTAState;
eError = DevmemAcquireCpuVirtAddr(psTAData->psContextStateMemDesc,
(void**)&psFWTAState);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"%s: Failed to map firmware render context state (%u)",
__FUNCTION__, eError));
}
else
{
/* Release the CPU virt addr */
DevmemReleaseCpuVirtAddr(psTAData->psContextStateMemDesc);
}
}
#endif
FWCommonContextFree(psTAData->psServerCommonContext);
DevmemFwFree(psDeviceNode->pvDevice, psTAData->psContextStateMemDesc);
psTAData->psServerCommonContext = NULL;
return PVRSRV_OK;
}
static
PVRSRV_ERROR _Destroy3DContext(RGX_SERVER_RC_3D_DATA *ps3DData,
PVRSRV_DEVICE_NODE *psDeviceNode,
PVRSRV_CLIENT_SYNC_PRIM *psCleanupSync)
{
PVRSRV_ERROR eError;
/* Check if the FW has finished with this resource ... */
eError = RGXFWRequestCommonContextCleanUp(psDeviceNode,
ps3DData->psServerCommonContext,
psCleanupSync,
RGXFWIF_DM_3D,
PDUMP_FLAGS_NONE);
if (eError == PVRSRV_ERROR_RETRY)
{
return eError;
}
else if (eError != PVRSRV_OK)
{
PVR_LOG(("%s: Unexpected error from RGXFWRequestCommonContextCleanUp (%s)",
__FUNCTION__,
PVRSRVGetErrorStringKM(eError)));
return eError;
}
/* ... it has so we can free it's resources */
#if defined(DEBUG)
/* Log the number of 3D context stores which occurred */
{
RGXFWIF_3DCTX_STATE *psFW3DState;
eError = DevmemAcquireCpuVirtAddr(ps3DData->psContextStateMemDesc,
(void**)&psFW3DState);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"%s: Failed to map firmware render context state (%u)",
__FUNCTION__, eError));
}
else
{
/* Release the CPU virt addr */
DevmemReleaseCpuVirtAddr(ps3DData->psContextStateMemDesc);
}
}
#endif
FWCommonContextFree(ps3DData->psServerCommonContext);
DevmemFwFree(psDeviceNode->pvDevice, ps3DData->psContextStateMemDesc);
ps3DData->psServerCommonContext = NULL;
return PVRSRV_OK;
}
static void _RGXDumpPMRPageList(DLLIST_NODE *psNode)
{
RGX_PMR_NODE *psPMRNode = IMG_CONTAINER_OF(psNode, RGX_PMR_NODE, sMemoryBlock);
PVRSRV_ERROR eError;
eError = PMRDumpPageList(psPMRNode->psPMR,
RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"Error (%u) printing pmr %p", eError, psPMRNode->psPMR));
}
}
IMG_BOOL RGXDumpFreeListPageList(RGX_FREELIST *psFreeList)
{
DLLIST_NODE *psNode, *psNext;
PVR_LOG(("Freelist FWAddr 0x%08x, ID = %d, CheckSum 0x%016llx",
psFreeList->sFreeListFWDevVAddr.ui32Addr,
psFreeList->ui32FreelistID,
psFreeList->ui64FreelistChecksum));
/* Dump Init FreeList page list */
PVR_LOG((" Initial Memory block"));
dllist_foreach_node(&psFreeList->sMemoryBlockInitHead, psNode, psNext)
{
_RGXDumpPMRPageList(psNode);
}
/* Dump Grow FreeList page list */
PVR_LOG((" Grow Memory blocks"));
dllist_foreach_node(&psFreeList->sMemoryBlockHead, psNode, psNext)
{
_RGXDumpPMRPageList(psNode);
}
return IMG_TRUE;
}
static PVRSRV_ERROR _UpdateFwFreelistSize(RGX_FREELIST *psFreeList,
IMG_BOOL bGrow,
IMG_UINT32 ui32DeltaSize)
{
PVRSRV_ERROR eError = PVRSRV_OK;
RGXFWIF_KCCB_CMD sGPCCBCmd;
sGPCCBCmd.eCmdType = (bGrow) ? RGXFWIF_KCCB_CMD_FREELIST_GROW_UPDATE : RGXFWIF_KCCB_CMD_FREELIST_SHRINK_UPDATE;
sGPCCBCmd.uCmdData.sFreeListGSData.sFreeListFWDevVAddr.ui32Addr = psFreeList->sFreeListFWDevVAddr.ui32Addr;
sGPCCBCmd.uCmdData.sFreeListGSData.ui32DeltaSize = ui32DeltaSize;
sGPCCBCmd.uCmdData.sFreeListGSData.ui32NewSize = psFreeList->ui32CurrentFLPages;
PVR_DPF((PVR_DBG_MESSAGE, "Send FW update: freelist [FWAddr=0x%08x] has 0x%08x pages",
psFreeList->sFreeListFWDevVAddr.ui32Addr,
psFreeList->ui32CurrentFLPages));
/* Submit command to the firmware. */
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError = RGXScheduleCommand(psFreeList->psDevInfo,
RGXFWIF_DM_GP,
&sGPCCBCmd,
sizeof(sGPCCBCmd),
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, "_UpdateFwFreelistSize: failed to update FW freelist size. (error = %u)", eError));
return eError;
}
return eError;
}
static void _CheckFreelist(RGX_FREELIST *psFreeList,
IMG_UINT32 ui32NumOfPagesToCheck,
IMG_UINT64 ui64ExpectedCheckSum,
IMG_UINT64 *pui64CalculatedCheckSum)
{
#if defined(NO_HARDWARE)
/* No checksum needed as we have all information in the pdumps */
PVR_UNREFERENCED_PARAMETER(psFreeList);
PVR_UNREFERENCED_PARAMETER(ui32NumOfPagesToCheck);
PVR_UNREFERENCED_PARAMETER(ui64ExpectedCheckSum);
*pui64CalculatedCheckSum = 0;
#else
PVRSRV_ERROR eError;
size_t uiNumBytes;
IMG_UINT8* pui8Buffer;
IMG_UINT32* pui32Buffer;
IMG_UINT32 ui32CheckSumAdd = 0;
IMG_UINT32 ui32CheckSumXor = 0;
IMG_UINT32 ui32Entry;
IMG_UINT32 ui32Entry2;
IMG_BOOL bFreelistBad = IMG_FALSE;
*pui64CalculatedCheckSum = 0;
/* Allocate Buffer of the size of the freelist */
pui8Buffer = OSAllocMem(psFreeList->ui32CurrentFLPages * sizeof(IMG_UINT32));
if (pui8Buffer == NULL)
{
PVR_LOG(("_CheckFreelist: Failed to allocate buffer to check freelist %p!", psFreeList));
sleep_for_ever();
//PVR_ASSERT(0);
return;
}
/* Copy freelist content into Buffer */
eError = PMR_ReadBytes(psFreeList->psFreeListPMR,
psFreeList->uiFreeListPMROffset + (psFreeList->ui32MaxFLPages - psFreeList->ui32CurrentFLPages) * sizeof(IMG_UINT32),
pui8Buffer,
psFreeList->ui32CurrentFLPages * sizeof(IMG_UINT32),
&uiNumBytes);
if (eError != PVRSRV_OK)
{
OSFreeMem(pui8Buffer);
PVR_LOG(("_CheckFreelist: Failed to get freelist data for freelist %p!", psFreeList));
sleep_for_ever();
//PVR_ASSERT(0);
return;
}
PVR_ASSERT(uiNumBytes == psFreeList->ui32CurrentFLPages * sizeof(IMG_UINT32));
PVR_ASSERT(ui32NumOfPagesToCheck <= psFreeList->ui32CurrentFLPages);
/* Generate checksum */
pui32Buffer = (IMG_UINT32 *)pui8Buffer;
for(ui32Entry = 0; ui32Entry < ui32NumOfPagesToCheck; ui32Entry++)
{
ui32CheckSumAdd += pui32Buffer[ui32Entry];
ui32CheckSumXor ^= pui32Buffer[ui32Entry];
/* Check for double entries */
for (ui32Entry2 = 0; ui32Entry2 < ui32NumOfPagesToCheck; ui32Entry2++)
{
if ((ui32Entry != ui32Entry2) &&
(pui32Buffer[ui32Entry] == pui32Buffer[ui32Entry2]))
{
PVR_LOG(("_CheckFreelist: Freelist consistency failure: FW addr: 0x%08X, Double entry found 0x%08x on idx: %d and %d of %d",
psFreeList->sFreeListFWDevVAddr.ui32Addr,
pui32Buffer[ui32Entry2],
ui32Entry,
ui32Entry2,
psFreeList->ui32CurrentFLPages));
bFreelistBad = IMG_TRUE;
}
}
}
OSFreeMem(pui8Buffer);
/* Check the calculated checksum against the expected checksum... */
*pui64CalculatedCheckSum = ((IMG_UINT64)ui32CheckSumXor << 32) | ui32CheckSumAdd;
if (ui64ExpectedCheckSum != 0 && ui64ExpectedCheckSum != *pui64CalculatedCheckSum)
{
PVR_LOG(("_CheckFreelist: Checksum mismatch for freelist %p! Expected 0x%016llx calculated 0x%016llx",
psFreeList, ui64ExpectedCheckSum, *pui64CalculatedCheckSum));
bFreelistBad = IMG_TRUE;
}
if (bFreelistBad)
{
PVR_LOG(("_CheckFreelist: Sleeping for ever!"));
sleep_for_ever();
// PVR_ASSERT(!bFreelistBad);
}
#endif
}
PVRSRV_ERROR RGXGrowFreeList(RGX_FREELIST *psFreeList,
IMG_UINT32 ui32NumPages,
PDLLIST_NODE pListHeader)
{
RGX_PMR_NODE *psPMRNode;
IMG_DEVMEM_SIZE_T uiSize;
IMG_UINT32 ui32MappingTable = 0;
IMG_DEVMEM_OFFSET_T uiOffset;
IMG_DEVMEM_SIZE_T uiLength;
IMG_DEVMEM_SIZE_T uistartPage;
PVRSRV_ERROR eError;
const IMG_CHAR * pszAllocName = "Free List";
/* Are we allowed to grow ? */
if ((psFreeList->ui32MaxFLPages - psFreeList->ui32CurrentFLPages) < ui32NumPages)
{
PVR_DPF((PVR_DBG_WARNING,"Freelist [0x%p]: grow by %u pages denied. Max PB size reached (current pages %u/%u)",
psFreeList,
ui32NumPages,
psFreeList->ui32CurrentFLPages,
psFreeList->ui32MaxFLPages));
return PVRSRV_ERROR_PBSIZE_ALREADY_MAX;
}
/* Allocate kernel memory block structure */
psPMRNode = OSAllocMem(sizeof(*psPMRNode));
if (psPMRNode == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "RGXGrowFreeList: failed to allocate host data structure"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorAllocHost;
}
/*
* Lock protects simultaneous manipulation of:
* - the memory block list
* - the freelist's ui32CurrentFLPages
*/
OSLockAcquire(psFreeList->psDevInfo->hLockFreeList);
psPMRNode->ui32NumPages = ui32NumPages;
psPMRNode->psFreeList = psFreeList;
/* Allocate Memory Block */
PDUMPCOMMENT("Allocate PB Block (Pages %08X)", ui32NumPages);
uiSize = (IMG_DEVMEM_SIZE_T)ui32NumPages * RGX_BIF_PM_PHYSICAL_PAGE_SIZE;
eError = PhysmemNewRamBackedPMR(NULL,
psFreeList->psDevInfo->psDeviceNode,
uiSize,
uiSize,
1,
1,
&ui32MappingTable,
RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT,
PVRSRV_MEMALLOCFLAG_GPU_READABLE,
OSStringLength(pszAllocName) + 1,
pszAllocName,
&psPMRNode->psPMR);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"RGXGrowFreeList: Failed to allocate PB block of size: 0x%016llX",
(IMG_UINT64)uiSize));
goto ErrorBlockAlloc;
}
/* Zeroing physical pages pointed by the PMR */
if (psFreeList->psDevInfo->ui32DeviceFlags & RGXKM_DEVICE_STATE_ZERO_FREELIST)
{
eError = PMRZeroingPMR(psPMRNode->psPMR, RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXGrowFreeList: Failed to zero PMR %p of freelist %p with Error %d",
psPMRNode->psPMR,
psFreeList,
eError));
PVR_ASSERT(0);
}
}
uiLength = psPMRNode->ui32NumPages * sizeof(IMG_UINT32);
uistartPage = (psFreeList->ui32MaxFLPages - psFreeList->ui32CurrentFLPages - psPMRNode->ui32NumPages);
uiOffset = psFreeList->uiFreeListPMROffset + (uistartPage * sizeof(IMG_UINT32));
#if defined(PVR_RI_DEBUG)
eError = RIWritePMREntryKM(psPMRNode->psPMR,
OSStringNLength(pszAllocName, RI_MAX_TEXT_LEN),
pszAllocName,
uiSize);
if( eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"%s: call to RIWritePMREntryKM failed (eError=%d)",
__func__,
eError));
}
/* Attach RI information */
eError = RIWriteMEMDESCEntryKM(psPMRNode->psPMR,
OSStringNLength(pszAllocName, RI_MAX_TEXT_LEN),
pszAllocName,
0,
uiSize,
uiSize,
IMG_FALSE,
IMG_FALSE,
&psPMRNode->hRIHandle);
if( eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"%s: call to RIWriteMEMDESCEntryKM failed (eError=%d)",
__func__,
eError));
}
#endif /* if defined(PVR_RI_DEBUG) */
/* write Freelist with Memory Block physical addresses */
eError = PMRWritePMPageList(
/* Target PMR, offset, and length */
psFreeList->psFreeListPMR,
uiOffset,
uiLength,
/* Referenced PMR, and "page" granularity */
psPMRNode->psPMR,
RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT,
&psPMRNode->psPageList);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"RGXGrowFreeList: Failed to write pages of Node %p",
psPMRNode));
goto ErrorPopulateFreelist;
}
/* We add It must be added to the tail, otherwise the freelist population won't work */
dllist_add_to_head(pListHeader, &psPMRNode->sMemoryBlock);
/* Update number of available pages */
psFreeList->ui32CurrentFLPages += ui32NumPages;
/* Update statistics */
if (psFreeList->ui32NumHighPages < psFreeList->ui32CurrentFLPages)
{
psFreeList->ui32NumHighPages = psFreeList->ui32CurrentFLPages;
}
if (psFreeList->bCheckFreelist)
{
/* We can only do a freelist check if the list is full (e.g. at initial creation time) */
if (psFreeList->ui32CurrentFLPages == ui32NumPages)
{
IMG_UINT64 ui64Dummy;
_CheckFreelist(psFreeList, ui32NumPages, psFreeList->ui64FreelistChecksum, &ui64Dummy);
}
}
OSLockRelease(psFreeList->psDevInfo->hLockFreeList);
PVR_DPF((PVR_DBG_MESSAGE,"Freelist [%p]: grow by %u pages (current pages %u/%u)",
psFreeList,
ui32NumPages,
psFreeList->ui32CurrentFLPages,
psFreeList->ui32MaxFLPages));
return PVRSRV_OK;
/* Error handling */
ErrorPopulateFreelist:
PMRUnrefPMR(psPMRNode->psPMR);
ErrorBlockAlloc:
OSFreeMem(psPMRNode);
OSLockRelease(psFreeList->psDevInfo->hLockFreeList);
ErrorAllocHost:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
static PVRSRV_ERROR RGXShrinkFreeList(PDLLIST_NODE pListHeader,
RGX_FREELIST *psFreeList)
{
DLLIST_NODE *psNode;
RGX_PMR_NODE *psPMRNode;
PVRSRV_ERROR eError = PVRSRV_OK;
IMG_UINT32 ui32OldValue;
/*
* Lock protects simultaneous manipulation of:
* - the memory block list
* - the freelist's ui32CurrentFLPages value
*/
PVR_ASSERT(pListHeader);
PVR_ASSERT(psFreeList);
PVR_ASSERT(psFreeList->psDevInfo);
PVR_ASSERT(psFreeList->psDevInfo->hLockFreeList);
OSLockAcquire(psFreeList->psDevInfo->hLockFreeList);
/* Get node from head of list and remove it */
psNode = dllist_get_next_node(pListHeader);
if (psNode)
{
dllist_remove_node(psNode);
psPMRNode = IMG_CONTAINER_OF(psNode, RGX_PMR_NODE, sMemoryBlock);
PVR_ASSERT(psPMRNode);
PVR_ASSERT(psPMRNode->psPMR);
PVR_ASSERT(psPMRNode->psFreeList);
/* remove block from freelist list */
/* Unwrite Freelist with Memory Block physical addresses */
eError = PMRUnwritePMPageList(psPMRNode->psPageList);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"RGXRemoveBlockFromFreeListKM: Failed to unwrite pages of Node %p",
psPMRNode));
PVR_ASSERT(IMG_FALSE);
}
#if defined(PVR_RI_DEBUG)
if (psPMRNode->hRIHandle)
{
PVRSRV_ERROR eError;
eError = RIDeleteMEMDESCEntryKM(psPMRNode->hRIHandle);
if( eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "%s: call to RIDeleteMEMDESCEntryKM failed (eError=%d)", __func__, eError));
}
}
#endif /* if defined(PVR_RI_DEBUG) */
/* Free PMR (We should be the only one that holds a ref on the PMR) */
eError = PMRUnrefPMR(psPMRNode->psPMR);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"RGXRemoveBlockFromFreeListKM: Failed to free PB block %p (error %u)",
psPMRNode->psPMR,
eError));
PVR_ASSERT(IMG_FALSE);
}
/* update available pages in freelist */
ui32OldValue = psFreeList->ui32CurrentFLPages;
psFreeList->ui32CurrentFLPages -= psPMRNode->ui32NumPages;
/* check underflow */
PVR_ASSERT(ui32OldValue > psFreeList->ui32CurrentFLPages);
PVR_DPF((PVR_DBG_MESSAGE, "Freelist [%p]: shrink by %u pages (current pages %u/%u)",
psFreeList,
psPMRNode->ui32NumPages,
psFreeList->ui32CurrentFLPages,
psFreeList->ui32MaxFLPages));
OSFreeMem(psPMRNode);
}
else
{
PVR_DPF((PVR_DBG_WARNING,"Freelist [0x%p]: shrink denied. PB already at initial PB size (%u pages)",
psFreeList,
psFreeList->ui32InitFLPages));
eError = PVRSRV_ERROR_PBSIZE_ALREADY_MIN;
}
OSLockRelease(psFreeList->psDevInfo->hLockFreeList);
return eError;
}
static RGX_FREELIST *FindFreeList(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32FreelistID)
{
DLLIST_NODE *psNode, *psNext;
RGX_FREELIST *psFreeList = NULL;
OSLockAcquire(psDevInfo->hLockFreeList);
dllist_foreach_node(&psDevInfo->sFreeListHead, psNode, psNext)
{
RGX_FREELIST *psThisFreeList = IMG_CONTAINER_OF(psNode, RGX_FREELIST, sNode);
if (psThisFreeList->ui32FreelistID == ui32FreelistID)
{
psFreeList = psThisFreeList;
break;
}
}
OSLockRelease(psDevInfo->hLockFreeList);
return psFreeList;
}
void RGXProcessRequestGrow(PVRSRV_RGXDEV_INFO *psDevInfo,
IMG_UINT32 ui32FreelistID)
{
RGX_FREELIST *psFreeList = NULL;
RGXFWIF_KCCB_CMD s3DCCBCmd;
IMG_UINT32 ui32GrowValue;
PVRSRV_ERROR eError;
PVR_ASSERT(psDevInfo);
psFreeList = FindFreeList(psDevInfo, ui32FreelistID);
if (psFreeList)
{
/* Try to grow the freelist */
eError = RGXGrowFreeList(psFreeList,
psFreeList->ui32GrowFLPages,
&psFreeList->sMemoryBlockHead);
if (eError == PVRSRV_OK)
{
/* Grow successful, return size of grow size */
ui32GrowValue = psFreeList->ui32GrowFLPages;
psFreeList->ui32NumGrowReqByFW++;
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
/* Update Stats */
PVRSRVStatsUpdateFreelistStats(0,
1, /* Add 1 to the appropriate counter (Requests by FW) */
psFreeList->ui32InitFLPages,
psFreeList->ui32NumHighPages,
psFreeList->ownerPid);
#endif
}
else
{
/* Grow failed */
ui32GrowValue = 0;
PVR_DPF((PVR_DBG_ERROR,"Grow for FreeList %p failed (error %u)",
psFreeList,
eError));
}
/* send feedback */
s3DCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_FREELIST_GROW_UPDATE;
s3DCCBCmd.uCmdData.sFreeListGSData.sFreeListFWDevVAddr.ui32Addr = psFreeList->sFreeListFWDevVAddr.ui32Addr;
s3DCCBCmd.uCmdData.sFreeListGSData.ui32DeltaSize = ui32GrowValue;
s3DCCBCmd.uCmdData.sFreeListGSData.ui32NewSize = psFreeList->ui32CurrentFLPages;
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError = RGXScheduleCommand(psDevInfo,
RGXFWIF_DM_3D,
&s3DCCBCmd,
sizeof(s3DCCBCmd),
0,
PDUMP_FLAGS_NONE);
if (eError != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
/* Kernel CCB should never fill up, as the FW is processing them right away */
PVR_ASSERT(eError == PVRSRV_OK);
}
else
{
/* Should never happen */
PVR_DPF((PVR_DBG_ERROR,"FreeList Lookup for FreeList ID 0x%08x failed (Populate)", ui32FreelistID));
PVR_ASSERT(IMG_FALSE);
}
}
static void _RGXCheckFreeListReconstruction(PDLLIST_NODE psNode)
{
PVRSRV_RGXDEV_INFO *psDevInfo;
RGX_FREELIST *psFreeList;
RGX_PMR_NODE *psPMRNode;
PVRSRV_ERROR eError;
IMG_DEVMEM_OFFSET_T uiOffset;
IMG_DEVMEM_SIZE_T uiLength;
IMG_UINT32 ui32StartPage;
psPMRNode = IMG_CONTAINER_OF(psNode, RGX_PMR_NODE, sMemoryBlock);
psFreeList = psPMRNode->psFreeList;
PVR_ASSERT(psFreeList);
psDevInfo = psFreeList->psDevInfo;
PVR_ASSERT(psDevInfo);
uiLength = psPMRNode->ui32NumPages * sizeof(IMG_UINT32);
ui32StartPage = (psFreeList->ui32MaxFLPages - psFreeList->ui32CurrentFLPages - psPMRNode->ui32NumPages);
uiOffset = psFreeList->uiFreeListPMROffset + (ui32StartPage * sizeof(IMG_UINT32));
PMRUnwritePMPageList(psPMRNode->psPageList);
psPMRNode->psPageList = NULL;
eError = PMRWritePMPageList(
/* Target PMR, offset, and length */
psFreeList->psFreeListPMR,
uiOffset,
uiLength,
/* Referenced PMR, and "page" granularity */
psPMRNode->psPMR,
RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT,
&psPMRNode->psPageList);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"Error (%u) writing FL 0x%08x", eError, (IMG_UINT32)psFreeList->ui32FreelistID));
}
/* Zeroing physical pages pointed by the reconstructed freelist */
if (psDevInfo->ui32DeviceFlags & RGXKM_DEVICE_STATE_ZERO_FREELIST)
{
eError = PMRZeroingPMR(psPMRNode->psPMR, RGX_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"_RGXCheckFreeListReconstruction: Failed to zero PMR %p of freelist %p with Error %d",
psPMRNode->psPMR,
psFreeList,
eError));
PVR_ASSERT(0);
}
}
psFreeList->ui32CurrentFLPages += psPMRNode->ui32NumPages;
}
static PVRSRV_ERROR RGXReconstructFreeList(RGX_FREELIST *psFreeList)
{
DLLIST_NODE *psNode, *psNext;
RGXFWIF_FREELIST *psFWFreeList;
PVRSRV_ERROR eError;
//PVR_DPF((PVR_DBG_ERROR, "FreeList RECONSTRUCTION: Reconstructing freelist %p (ID=%u)", psFreeList, psFreeList->ui32FreelistID));
/* Do the FreeList Reconstruction */
psFreeList->ui32CurrentFLPages = 0;
/* Reconstructing Init FreeList pages */
dllist_foreach_node(&psFreeList->sMemoryBlockInitHead, psNode, psNext)
{
_RGXCheckFreeListReconstruction(psNode);
}
/* Reconstructing Grow FreeList pages */
dllist_foreach_node(&psFreeList->sMemoryBlockHead, psNode, psNext)
{
_RGXCheckFreeListReconstruction(psNode);
}
/* Reset the firmware freelist structure */
eError = DevmemAcquireCpuVirtAddr(psFreeList->psFWFreelistMemDesc, (void **)&psFWFreeList);
if (eError != PVRSRV_OK)
{
return eError;
}
psFWFreeList->ui32CurrentStackTop = psFWFreeList->ui32CurrentPages - 1;
psFWFreeList->ui32AllocatedPageCount = 0;
psFWFreeList->ui32AllocatedMMUPageCount = 0;
psFWFreeList->ui32HWRCounter++;
DevmemReleaseCpuVirtAddr(psFreeList->psFWFreelistMemDesc);
/* Check the Freelist checksum if required (as the list is fully populated) */
if (psFreeList->bCheckFreelist)
{
IMG_UINT64 ui64CheckSum;
_CheckFreelist(psFreeList, psFreeList->ui32CurrentFLPages, psFreeList->ui64FreelistChecksum, &ui64CheckSum);
}
return eError;
}
void RGXProcessRequestFreelistsReconstruction(PVRSRV_RGXDEV_INFO *psDevInfo,
IMG_UINT32 ui32FreelistsCount,
IMG_UINT32 *paui32Freelists)
{
PVRSRV_ERROR eError = PVRSRV_OK;
DLLIST_NODE *psNode, *psNext;
IMG_UINT32 ui32Loop;
RGXFWIF_KCCB_CMD sTACCBCmd;
PVR_ASSERT(psDevInfo != NULL);
PVR_ASSERT(ui32FreelistsCount <= (MAX_HW_TA3DCONTEXTS * RGXFW_MAX_FREELISTS));
//PVR_DPF((PVR_DBG_ERROR, "FreeList RECONSTRUCTION: %u freelist(s) requested for reconstruction", ui32FreelistsCount));
/*
* Initialise the response command (in case we don't find a freelist ID)...
*/
sTACCBCmd.eCmdType = RGXFWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE;
sTACCBCmd.uCmdData.sFreeListsReconstructionData.ui32FreelistsCount = ui32FreelistsCount;
for (ui32Loop = 0; ui32Loop < ui32FreelistsCount; ui32Loop++)
{
sTACCBCmd.uCmdData.sFreeListsReconstructionData.aui32FreelistIDs[ui32Loop] = paui32Freelists[ui32Loop] |
RGXFWIF_FREELISTS_RECONSTRUCTION_FAILED_FLAG;
}
/*
* The list of freelists we have been given for reconstruction will
* consist of local and global freelists (maybe MMU as well). Any
* local freelists will have their global list specified as well.
* However there may be other local freelists not listed, which are
* going to have their global freelist reconstructed. Therefore we
* have to find those freelists as well meaning we will have to
* iterate the entire list of freelists to find which must be reconstructed.
*/
OSLockAcquire(psDevInfo->hLockFreeList);
dllist_foreach_node(&psDevInfo->sFreeListHead, psNode, psNext)
{
RGX_FREELIST *psFreeList = IMG_CONTAINER_OF(psNode, RGX_FREELIST, sNode);
IMG_BOOL bReconstruct = IMG_FALSE;
/*
* Check if this freelist needs to be reconstructed (was it requested
* or was its global freelist requested)...
*/
for (ui32Loop = 0; ui32Loop < ui32FreelistsCount; ui32Loop++)
{
if (paui32Freelists[ui32Loop] == psFreeList->ui32FreelistID ||
paui32Freelists[ui32Loop] == psFreeList->ui32FreelistGlobalID)
{
bReconstruct = IMG_TRUE;
break;
}
}
if (bReconstruct)
{
eError = RGXReconstructFreeList(psFreeList);
if (eError == PVRSRV_OK)
{
for (ui32Loop = 0; ui32Loop < ui32FreelistsCount; ui32Loop++)
{
if (paui32Freelists[ui32Loop] == psFreeList->ui32FreelistID)
{
/* Reconstruction of this requested freelist was successful... */
sTACCBCmd.uCmdData.sFreeListsReconstructionData.aui32FreelistIDs[ui32Loop] &= ~RGXFWIF_FREELISTS_RECONSTRUCTION_FAILED_FLAG;
break;
}
}
}
else
{
PVR_DPF((PVR_DBG_ERROR,"Reconstructing of FreeList %p failed (error %u)",
psFreeList,
eError));
}
}
}
OSLockRelease(psDevInfo->hLockFreeList);
/* Check that all freelists were found and reconstructed... */
for (ui32Loop = 0; ui32Loop < ui32FreelistsCount; ui32Loop++)
{
PVR_ASSERT((sTACCBCmd.uCmdData.sFreeListsReconstructionData.aui32FreelistIDs[ui32Loop] &
RGXFWIF_FREELISTS_RECONSTRUCTION_FAILED_FLAG) == 0);
}
/* send feedback */
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError = RGXScheduleCommand(psDevInfo,
RGXFWIF_DM_TA,
&sTACCBCmd,
sizeof(sTACCBCmd),
0,
PDUMP_FLAGS_NONE);
if (eError != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
/* Kernel CCB should never fill up, as the FW is processing them right away */
PVR_ASSERT(eError == PVRSRV_OK);
}
/* Create HWRTDataSet */
IMG_EXPORT
PVRSRV_ERROR RGXCreateHWRTData(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 psRenderTarget, /* FIXME this should not be IMG_UINT32 */
IMG_DEV_VIRTADDR psPMMListDevVAddr,
IMG_DEV_VIRTADDR psVFPPageTableAddr,
RGX_FREELIST *apsFreeLists[RGXFW_MAX_FREELISTS],
RGX_RTDATA_CLEANUP_DATA **ppsCleanupData,
DEVMEM_MEMDESC **ppsRTACtlMemDesc,
IMG_UINT32 ui32PPPScreen,
IMG_UINT32 ui32PPPGridOffset,
IMG_UINT64 ui64PPPMultiSampleCtl,
IMG_UINT32 ui32TPCStride,
IMG_DEV_VIRTADDR sTailPtrsDevVAddr,
IMG_UINT32 ui32TPCSize,
IMG_UINT32 ui32TEScreen,
IMG_UINT32 ui32TEAA,
IMG_UINT32 ui32TEMTILE1,
IMG_UINT32 ui32TEMTILE2,
IMG_UINT32 ui32MTileStride,
IMG_UINT32 ui32ISPMergeLowerX,
IMG_UINT32 ui32ISPMergeLowerY,
IMG_UINT32 ui32ISPMergeUpperX,
IMG_UINT32 ui32ISPMergeUpperY,
IMG_UINT32 ui32ISPMergeScaleX,
IMG_UINT32 ui32ISPMergeScaleY,
IMG_UINT16 ui16MaxRTs,
DEVMEM_MEMDESC **ppsMemDesc,
IMG_UINT32 *puiHWRTData)
{
PVRSRV_ERROR eError;
PVRSRV_RGXDEV_INFO *psDevInfo;
RGXFWIF_DEV_VIRTADDR pFirmwareAddr;
RGXFWIF_HWRTDATA *psHWRTData;
RGXFWIF_RTA_CTL *psRTACtl;
IMG_UINT32 ui32Loop;
RGX_RTDATA_CLEANUP_DATA *psTmpCleanup;
PVR_UNREFERENCED_PARAMETER(psConnection);
/* Prepare cleanup struct */
psTmpCleanup = OSAllocZMem(sizeof(*psTmpCleanup));
if (psTmpCleanup == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto AllocError;
}
*ppsCleanupData = psTmpCleanup;
/* Allocate cleanup sync */
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
&psTmpCleanup->psCleanupSync,
"HWRTData cleanup");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateHWRTData: Failed to allocate cleanup sync (0x%x)",
eError));
goto SyncAlloc;
}
psDevInfo = psDeviceNode->pvDevice;
/*
* This FW RT-Data is only mapped into kernel for initialisation.
* Otherwise this allocation is only used by the FW.
* Therefore the GPU cache doesn't need coherency,
* and write-combine is suffice on the CPU side (WC buffer will be flushed at the first TA-kick)
*/
eError = DevmemFwAllocate(psDevInfo,
sizeof(RGXFWIF_HWRTDATA),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) |
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT |
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE |
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE,
"FwHWRTData",
ppsMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "RGXCreateHWRTData: DevmemAllocate for RGX_FWIF_HWRTDATA failed"));
goto FWRTDataAllocateError;
}
psTmpCleanup->psDeviceNode = psDeviceNode;
psTmpCleanup->psFWHWRTDataMemDesc = *ppsMemDesc;
RGXSetFirmwareAddress(&pFirmwareAddr, *ppsMemDesc, 0, RFW_FWADDR_FLAG_NONE);
*puiHWRTData = pFirmwareAddr.ui32Addr;
eError = DevmemAcquireCpuVirtAddr(*ppsMemDesc, (void **)&psHWRTData);
PVR_LOGG_IF_ERROR(eError, "Devmem AcquireCpuVirtAddr", FWRTDataCpuMapError);
/* FIXME: MList is something that that PM writes physical addresses to,
* so ideally its best allocated in kernel */
psHWRTData->psPMMListDevVAddr = psPMMListDevVAddr;
psHWRTData->psParentRenderTarget.ui32Addr = psRenderTarget;
#if defined(SUPPORT_VFP)
psHWRTData->sVFPPageTableAddr = psVFPPageTableAddr;
#endif
psHWRTData->ui32PPPScreen = ui32PPPScreen;
psHWRTData->ui32PPPGridOffset = ui32PPPGridOffset;
psHWRTData->ui64PPPMultiSampleCtl = ui64PPPMultiSampleCtl;
psHWRTData->ui32TPCStride = ui32TPCStride;
psHWRTData->sTailPtrsDevVAddr = sTailPtrsDevVAddr;
psHWRTData->ui32TPCSize = ui32TPCSize;
psHWRTData->ui32TEScreen = ui32TEScreen;
psHWRTData->ui32TEAA = ui32TEAA;
psHWRTData->ui32TEMTILE1 = ui32TEMTILE1;
psHWRTData->ui32TEMTILE2 = ui32TEMTILE2;
psHWRTData->ui32MTileStride = ui32MTileStride;
psHWRTData->ui32ISPMergeLowerX = ui32ISPMergeLowerX;
psHWRTData->ui32ISPMergeLowerY = ui32ISPMergeLowerY;
psHWRTData->ui32ISPMergeUpperX = ui32ISPMergeUpperX;
psHWRTData->ui32ISPMergeUpperY = ui32ISPMergeUpperY;
psHWRTData->ui32ISPMergeScaleX = ui32ISPMergeScaleX;
psHWRTData->ui32ISPMergeScaleY = ui32ISPMergeScaleY;
OSLockAcquire(psDevInfo->hLockFreeList);
for (ui32Loop = 0; ui32Loop < RGXFW_MAX_FREELISTS; ui32Loop++)
{
psTmpCleanup->apsFreeLists[ui32Loop] = apsFreeLists[ui32Loop];
psTmpCleanup->apsFreeLists[ui32Loop]->ui32RefCount++;
psHWRTData->apsFreeLists[ui32Loop].ui32Addr = psTmpCleanup->apsFreeLists[ui32Loop]->sFreeListFWDevVAddr.ui32Addr;
/* invalid initial snapshot value, the snapshot is always taken during first kick
* and hence the value get replaced during the first kick anyway. So it's safe to set it 0.
*/
psHWRTData->aui32FreeListHWRSnapshot[ui32Loop] = 0;
}
OSLockRelease(psDevInfo->hLockFreeList);
PDUMPCOMMENT("Allocate RGXFW RTA control");
eError = DevmemFwAllocate(psDevInfo,
sizeof(RGXFWIF_RTA_CTL),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_UNCACHED |
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC,
"FwRTAControl",
ppsRTACtlMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateHWRTData: Failed to allocate RGX RTA control (%u)",
eError));
goto FWRTAAllocateError;
}
psTmpCleanup->psRTACtlMemDesc = *ppsRTACtlMemDesc;
RGXSetFirmwareAddress(&psHWRTData->psRTACtl,
*ppsRTACtlMemDesc,
0, RFW_FWADDR_FLAG_NONE);
eError = DevmemAcquireCpuVirtAddr(*ppsRTACtlMemDesc, (void **)&psRTACtl);
PVR_LOGG_IF_ERROR(eError, "Devmem AcquireCpuVirtAddr", FWRTACpuMapError);
psRTACtl->ui32RenderTargetIndex = 0;
psRTACtl->ui32ActiveRenderTargets = 0;
if (ui16MaxRTs > 1)
{
/* Allocate memory for the checks */
PDUMPCOMMENT("Allocate memory for shadow render target cache");
eError = DevmemFwAllocate(psDevInfo,
ui16MaxRTs * sizeof(IMG_UINT32),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_UNCACHED|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC,
"FwShadowRTCache",
&psTmpCleanup->psRTArrayMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateHWRTData: Failed to allocate %d bytes for render target array (%u)",
ui16MaxRTs, eError));
goto FWAllocateRTArryError;
}
RGXSetFirmwareAddress(&psRTACtl->sValidRenderTargets,
psTmpCleanup->psRTArrayMemDesc,
0, RFW_FWADDR_FLAG_NONE);
/* Allocate memory for the checks */
PDUMPCOMMENT("Allocate memory for tracking renders accumulation");
eError = DevmemFwAllocate(psDevInfo,
ui16MaxRTs * sizeof(IMG_UINT32),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_UNCACHED|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC,
"FwRendersAccumulation",
&psTmpCleanup->psRendersAccArrayMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateHWRTData: Failed to allocate %d bytes for render target array (%u) (renders accumulation)",
ui16MaxRTs, eError));
goto FWAllocateRTAccArryError;
}
RGXSetFirmwareAddress(&psRTACtl->sNumRenders,
psTmpCleanup->psRendersAccArrayMemDesc,
0, RFW_FWADDR_FLAG_NONE);
psRTACtl->ui16MaxRTs = ui16MaxRTs;
}
else
{
psRTACtl->sValidRenderTargets.ui32Addr = 0;
psRTACtl->sNumRenders.ui32Addr = 0;
psRTACtl->ui16MaxRTs = 1;
}
PDUMPCOMMENT("Dump HWRTData 0x%08X", *puiHWRTData);
DevmemPDumpLoadMem(*ppsMemDesc, 0, sizeof(*psHWRTData), PDUMP_FLAGS_CONTINUOUS);
PDUMPCOMMENT("Dump RTACtl");
DevmemPDumpLoadMem(*ppsRTACtlMemDesc, 0, sizeof(*psRTACtl), PDUMP_FLAGS_CONTINUOUS);
DevmemReleaseCpuVirtAddr(*ppsMemDesc);
DevmemReleaseCpuVirtAddr(*ppsRTACtlMemDesc);
return PVRSRV_OK;
FWAllocateRTAccArryError:
DevmemFwFree(psDevInfo, psTmpCleanup->psRTArrayMemDesc);
FWAllocateRTArryError:
DevmemReleaseCpuVirtAddr(*ppsRTACtlMemDesc);
FWRTACpuMapError:
RGXUnsetFirmwareAddress(*ppsRTACtlMemDesc);
DevmemFwFree(psDevInfo, *ppsRTACtlMemDesc);
FWRTAAllocateError:
OSLockAcquire(psDevInfo->hLockFreeList);
for (ui32Loop = 0; ui32Loop < RGXFW_MAX_FREELISTS; ui32Loop++)
{
PVR_ASSERT(psTmpCleanup->apsFreeLists[ui32Loop]->ui32RefCount > 0);
psTmpCleanup->apsFreeLists[ui32Loop]->ui32RefCount--;
}
OSLockRelease(psDevInfo->hLockFreeList);
DevmemReleaseCpuVirtAddr(*ppsMemDesc);
FWRTDataCpuMapError:
RGXUnsetFirmwareAddress(*ppsMemDesc);
DevmemFwFree(psDevInfo, *ppsMemDesc);
FWRTDataAllocateError:
SyncPrimFree(psTmpCleanup->psCleanupSync);
SyncAlloc:
*ppsCleanupData = NULL;
OSFreeMem(psTmpCleanup);
AllocError:
return eError;
}
/* Destroy HWRTDataSet */
IMG_EXPORT
PVRSRV_ERROR RGXDestroyHWRTData(RGX_RTDATA_CLEANUP_DATA *psCleanupData)
{
PVRSRV_RGXDEV_INFO *psDevInfo;
PVRSRV_ERROR eError;
PRGXFWIF_HWRTDATA psHWRTData;
IMG_UINT32 ui32Loop;
PVR_ASSERT(psCleanupData);
RGXSetFirmwareAddress(&psHWRTData, psCleanupData->psFWHWRTDataMemDesc, 0, RFW_FWADDR_NOREF_FLAG);
/* Cleanup HWRTData in TA */
eError = RGXFWRequestHWRTDataCleanUp(psCleanupData->psDeviceNode,
psHWRTData,
psCleanupData->psCleanupSync,
RGXFWIF_DM_TA);
if (eError == PVRSRV_ERROR_RETRY)
{
return eError;
}
psDevInfo = psCleanupData->psDeviceNode->pvDevice;
/* Cleanup HWRTData in 3D */
eError = RGXFWRequestHWRTDataCleanUp(psCleanupData->psDeviceNode,
psHWRTData,
psCleanupData->psCleanupSync,
RGXFWIF_DM_3D);
if (eError == PVRSRV_ERROR_RETRY)
{
return eError;
}
/* If we got here then TA and 3D operations on this RTData have finished */
if(psCleanupData->psRTACtlMemDesc)
{
RGXUnsetFirmwareAddress(psCleanupData->psRTACtlMemDesc);
DevmemFwFree(psDevInfo, psCleanupData->psRTACtlMemDesc);
}
RGXUnsetFirmwareAddress(psCleanupData->psFWHWRTDataMemDesc);
DevmemFwFree(psDevInfo, psCleanupData->psFWHWRTDataMemDesc);
if(psCleanupData->psRTArrayMemDesc)
{
RGXUnsetFirmwareAddress(psCleanupData->psRTArrayMemDesc);
DevmemFwFree(psDevInfo, psCleanupData->psRTArrayMemDesc);
}
if(psCleanupData->psRendersAccArrayMemDesc)
{
RGXUnsetFirmwareAddress(psCleanupData->psRendersAccArrayMemDesc);
DevmemFwFree(psDevInfo, psCleanupData->psRendersAccArrayMemDesc);
}
SyncPrimFree(psCleanupData->psCleanupSync);
/* decrease freelist refcount */
OSLockAcquire(psDevInfo->hLockFreeList);
for (ui32Loop = 0; ui32Loop < RGXFW_MAX_FREELISTS; ui32Loop++)
{
PVR_ASSERT(psCleanupData->apsFreeLists[ui32Loop]->ui32RefCount > 0);
psCleanupData->apsFreeLists[ui32Loop]->ui32RefCount--;
}
OSLockRelease(psDevInfo->hLockFreeList);
OSFreeMem(psCleanupData);
return PVRSRV_OK;
}
IMG_EXPORT
PVRSRV_ERROR RGXCreateFreeList(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 ui32MaxFLPages,
IMG_UINT32 ui32InitFLPages,
IMG_UINT32 ui32GrowFLPages,
RGX_FREELIST *psGlobalFreeList,
IMG_BOOL bCheckFreelist,
IMG_DEV_VIRTADDR sFreeListDevVAddr,
PMR *psFreeListPMR,
IMG_DEVMEM_OFFSET_T uiFreeListPMROffset,
RGX_FREELIST **ppsFreeList)
{
PVRSRV_ERROR eError;
RGXFWIF_FREELIST *psFWFreeList;
DEVMEM_MEMDESC *psFWFreelistMemDesc;
RGX_FREELIST *psFreeList;
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
/* Allocate kernel freelist struct */
psFreeList = OSAllocZMem(sizeof(*psFreeList));
if (psFreeList == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "RGXCreateFreeList: failed to allocate host data structure"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorAllocHost;
}
/* Allocate cleanup sync */
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
&psFreeList->psCleanupSync,
"ta3d free list cleanup");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateFreeList: Failed to allocate cleanup sync (0x%x)",
eError));
goto SyncAlloc;
}
/*
* This FW FreeList context is only mapped into kernel for initialisation
* and reconstruction (at other times it is not mapped and only used by
* the FW. Therefore the GPU cache doesn't need coherency, and write-combine
* is suffice on the CPU side (WC buffer will be flushed at the first TA-kick)
*/
eError = DevmemFwAllocate(psDevInfo,
sizeof(*psFWFreeList),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT |
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE |
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE,
"FwFreeList",
&psFWFreelistMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "RGXCreateFreeList: DevmemAllocate for RGXFWIF_FREELIST failed"));
goto FWFreeListAlloc;
}
/* Initialise host data structures */
psFreeList->psDevInfo = psDevInfo;
psFreeList->psFreeListPMR = psFreeListPMR;
psFreeList->uiFreeListPMROffset = uiFreeListPMROffset;
psFreeList->psFWFreelistMemDesc = psFWFreelistMemDesc;
RGXSetFirmwareAddress(&psFreeList->sFreeListFWDevVAddr, psFWFreelistMemDesc, 0, RFW_FWADDR_FLAG_NONE);
psFreeList->ui32FreelistID = psDevInfo->ui32FreelistCurrID++;
psFreeList->ui32FreelistGlobalID = (psGlobalFreeList ? psGlobalFreeList->ui32FreelistID : 0);
psFreeList->ui32MaxFLPages = ui32MaxFLPages;
psFreeList->ui32InitFLPages = ui32InitFLPages;
psFreeList->ui32GrowFLPages = ui32GrowFLPages;
psFreeList->ui32CurrentFLPages = 0;
psFreeList->ui64FreelistChecksum = 0;
psFreeList->ui32RefCount = 0;
psFreeList->bCheckFreelist = bCheckFreelist;
dllist_init(&psFreeList->sMemoryBlockHead);
dllist_init(&psFreeList->sMemoryBlockInitHead);
/* Add to list of freelists */
OSLockAcquire(psDevInfo->hLockFreeList);
dllist_add_to_tail(&psDevInfo->sFreeListHead, &psFreeList->sNode);
OSLockRelease(psDevInfo->hLockFreeList);
/* Initialise FW data structure */
eError = DevmemAcquireCpuVirtAddr(psFreeList->psFWFreelistMemDesc, (void **)&psFWFreeList);
PVR_LOGG_IF_ERROR(eError, "Devmem AcquireCpuVirtAddr", FWFreeListCpuMap);
psFWFreeList->ui32MaxPages = ui32MaxFLPages;
psFWFreeList->ui32CurrentPages = ui32InitFLPages;
psFWFreeList->ui32GrowPages = ui32GrowFLPages;
psFWFreeList->ui32CurrentStackTop = ui32InitFLPages - 1;
psFWFreeList->psFreeListDevVAddr = sFreeListDevVAddr;
psFWFreeList->ui64CurrentDevVAddr = sFreeListDevVAddr.uiAddr + ((ui32MaxFLPages - ui32InitFLPages) * sizeof(IMG_UINT32));
psFWFreeList->ui32FreeListID = psFreeList->ui32FreelistID;
psFWFreeList->bGrowPending = IMG_FALSE;
PVR_DPF((PVR_DBG_MESSAGE,"Freelist %p created: Max pages 0x%08x, Init pages 0x%08x, Max FL base address 0x%016llx, Init FL base address 0x%016llx",
psFreeList,
ui32MaxFLPages,
ui32InitFLPages,
sFreeListDevVAddr.uiAddr,
psFWFreeList->psFreeListDevVAddr.uiAddr));
PDUMPCOMMENT("Dump FW FreeList");
DevmemPDumpLoadMem(psFreeList->psFWFreelistMemDesc, 0, sizeof(*psFWFreeList), PDUMP_FLAGS_CONTINUOUS);
/*
* Separate dump of the Freelist's number of Pages and stack pointer.
* This allows to easily modify the PB size in the out2.txt files.
*/
PDUMPCOMMENT("FreeList TotalPages");
DevmemPDumpLoadMemValue32(psFreeList->psFWFreelistMemDesc,
offsetof(RGXFWIF_FREELIST, ui32CurrentPages),
psFWFreeList->ui32CurrentPages,
PDUMP_FLAGS_CONTINUOUS);
PDUMPCOMMENT("FreeList StackPointer");
DevmemPDumpLoadMemValue32(psFreeList->psFWFreelistMemDesc,
offsetof(RGXFWIF_FREELIST, ui32CurrentStackTop),
psFWFreeList->ui32CurrentStackTop,
PDUMP_FLAGS_CONTINUOUS);
DevmemReleaseCpuVirtAddr(psFreeList->psFWFreelistMemDesc);
/* Add initial PB block */
eError = RGXGrowFreeList(psFreeList,
ui32InitFLPages,
&psFreeList->sMemoryBlockInitHead);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,
"RGXCreateFreeList: failed to allocate initial memory block for free list 0x%016llx (error = %u)",
sFreeListDevVAddr.uiAddr,
eError));
goto FWFreeListCpuMap;
}
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
/* Update Stats */
PVRSRVStatsUpdateFreelistStats(1, /* Add 1 to the appropriate counter (Requests by App)*/
0,
psFreeList->ui32InitFLPages,
psFreeList->ui32NumHighPages,
psFreeList->ownerPid);
#endif
psFreeList->ownerPid = OSGetCurrentClientProcessIDKM();
/* return values */
*ppsFreeList = psFreeList;
return PVRSRV_OK;
/* Error handling */
FWFreeListCpuMap:
/* Remove freelists from list */
OSLockAcquire(psDevInfo->hLockFreeList);
dllist_remove_node(&psFreeList->sNode);
OSLockRelease(psDevInfo->hLockFreeList);
RGXUnsetFirmwareAddress(psFWFreelistMemDesc);
DevmemFwFree(psDevInfo, psFWFreelistMemDesc);
FWFreeListAlloc:
SyncPrimFree(psFreeList->psCleanupSync);
SyncAlloc:
OSFreeMem(psFreeList);
ErrorAllocHost:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
/*
RGXDestroyFreeList
*/
IMG_EXPORT
PVRSRV_ERROR RGXDestroyFreeList(RGX_FREELIST *psFreeList)
{
PVRSRV_ERROR eError;
PVR_ASSERT(psFreeList);
if (psFreeList->ui32RefCount != 0)
{
/* Freelist still busy */
return PVRSRV_ERROR_RETRY;
}
/* Freelist is not in use => start firmware cleanup */
eError = RGXFWRequestFreeListCleanUp(psFreeList->psDevInfo,
psFreeList->sFreeListFWDevVAddr,
psFreeList->psCleanupSync);
if(eError != PVRSRV_OK)
{
/* Can happen if the firmware took too long to handle the cleanup request,
* or if SLC-flushes didn't went through (due to some GPU lockup) */
return eError;
}
/* Remove FreeList from linked list before we destroy it... */
OSLockAcquire(psFreeList->psDevInfo->hLockFreeList);
dllist_remove_node(&psFreeList->sNode);
OSLockRelease(psFreeList->psDevInfo->hLockFreeList);
if (psFreeList->bCheckFreelist)
{
RGXFWIF_FREELIST *psFWFreeList;
IMG_UINT64 ui32CurrentStackTop;
IMG_UINT64 ui64CheckSum;
/* Get the current stack pointer for this free list */
DevmemAcquireCpuVirtAddr(psFreeList->psFWFreelistMemDesc, (void **)&psFWFreeList);
ui32CurrentStackTop = psFWFreeList->ui32CurrentStackTop;
DevmemReleaseCpuVirtAddr(psFreeList->psFWFreelistMemDesc);
if (ui32CurrentStackTop == psFreeList->ui32CurrentFLPages-1)
{
/* Do consistency tests (as the list is fully populated) */
_CheckFreelist(psFreeList, psFreeList->ui32CurrentFLPages, psFreeList->ui64FreelistChecksum, &ui64CheckSum);
}
else
{
/* Check for duplicate pages, but don't check the checksum as the list is not fully populated */
_CheckFreelist(psFreeList, ui32CurrentStackTop+1, 0, &ui64CheckSum);
}
}
/* Destroy FW structures */
RGXUnsetFirmwareAddress(psFreeList->psFWFreelistMemDesc);
DevmemFwFree(psFreeList->psDevInfo, psFreeList->psFWFreelistMemDesc);
/* Remove grow shrink blocks */
while (!dllist_is_empty(&psFreeList->sMemoryBlockHead))
{
eError = RGXShrinkFreeList(&psFreeList->sMemoryBlockHead, psFreeList);
PVR_ASSERT(eError == PVRSRV_OK);
}
/* Remove initial PB block */
eError = RGXShrinkFreeList(&psFreeList->sMemoryBlockInitHead, psFreeList);
PVR_ASSERT(eError == PVRSRV_OK);
/* consistency checks */
PVR_ASSERT(dllist_is_empty(&psFreeList->sMemoryBlockInitHead));
PVR_ASSERT(psFreeList->ui32CurrentFLPages == 0);
SyncPrimFree(psFreeList->psCleanupSync);
/* free Freelist */
OSFreeMem(psFreeList);
return eError;
}
/*
RGXAddBlockToFreeListKM
*/
IMG_EXPORT
PVRSRV_ERROR RGXAddBlockToFreeListKM(RGX_FREELIST *psFreeList,
IMG_UINT32 ui32NumPages)
{
PVRSRV_ERROR eError;
/* Check if we have reference to freelist's PMR */
if (psFreeList->psFreeListPMR == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "Freelist is not configured for grow"));
return PVRSRV_ERROR_INVALID_PARAMS;
}
/* grow freelist */
eError = RGXGrowFreeList(psFreeList,
ui32NumPages,
&psFreeList->sMemoryBlockHead);
if(eError == PVRSRV_OK)
{
/* update freelist data in firmware */
_UpdateFwFreelistSize(psFreeList, IMG_TRUE, ui32NumPages);
psFreeList->ui32NumGrowReqByApp++;
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
/* Update Stats */
PVRSRVStatsUpdateFreelistStats(1, /* Add 1 to the appropriate counter (Requests by App)*/
0,
psFreeList->ui32InitFLPages,
psFreeList->ui32NumHighPages,
psFreeList->ownerPid);
#endif
}
return eError;
}
/*
RGXRemoveBlockFromFreeListKM
*/
IMG_EXPORT
PVRSRV_ERROR RGXRemoveBlockFromFreeListKM(RGX_FREELIST *psFreeList)
{
PVRSRV_ERROR eError;
/*
* Make sure the pages part of the memory block are not in use anymore.
* Instruct the firmware to update the freelist pointers accordingly.
*/
eError = RGXShrinkFreeList(&psFreeList->sMemoryBlockHead,
psFreeList);
return eError;
}
/*
RGXCreateRenderTarget
*/
IMG_EXPORT
PVRSRV_ERROR RGXCreateRenderTarget(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_DEV_VIRTADDR psVHeapTableDevVAddr,
RGX_RT_CLEANUP_DATA **ppsCleanupData,
IMG_UINT32 *sRenderTargetFWDevVAddr)
{
PVRSRV_ERROR eError = PVRSRV_OK;
RGXFWIF_RENDER_TARGET *psRenderTarget;
RGXFWIF_DEV_VIRTADDR pFirmwareAddr;
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
RGX_RT_CLEANUP_DATA *psCleanupData;
PVR_UNREFERENCED_PARAMETER(psConnection);
psCleanupData = OSAllocZMem(sizeof(*psCleanupData));
if (psCleanupData == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto err_out;
}
psCleanupData->psDeviceNode = psDeviceNode;
/*
* This FW render target context is only mapped into kernel for initialisation.
* Otherwise this allocation is only used by the FW.
* Therefore the GPU cache doesn't need coherency,
* and write-combine is suffice on the CPU side (WC buffer will be flushed at the first TA-kick)
*/
eError = DevmemFwAllocate(psDevInfo,
sizeof(*psRenderTarget),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT |
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE |
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE,
"FwRenderTarget",
&psCleanupData->psRenderTargetMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "RGXCreateRenderTarget: DevmemAllocate for Render Target failed"));
goto err_free;
}
RGXSetFirmwareAddress(&pFirmwareAddr, psCleanupData->psRenderTargetMemDesc, 0, RFW_FWADDR_FLAG_NONE);
*sRenderTargetFWDevVAddr = pFirmwareAddr.ui32Addr;
eError = DevmemAcquireCpuVirtAddr(psCleanupData->psRenderTargetMemDesc, (void **)&psRenderTarget);
PVR_LOGG_IF_ERROR(eError, "Devmem AcquireCpuVirtAddr", err_fwalloc);
psRenderTarget->psVHeapTableDevVAddr = psVHeapTableDevVAddr;
psRenderTarget->bTACachesNeedZeroing = IMG_FALSE;
PDUMPCOMMENT("Dump RenderTarget");
DevmemPDumpLoadMem(psCleanupData->psRenderTargetMemDesc, 0, sizeof(*psRenderTarget), PDUMP_FLAGS_CONTINUOUS);
DevmemReleaseCpuVirtAddr(psCleanupData->psRenderTargetMemDesc);
*ppsCleanupData = psCleanupData;
err_out:
return eError;
err_free:
OSFreeMem(psCleanupData);
goto err_out;
err_fwalloc:
DevmemFwFree(psDevInfo, psCleanupData->psRenderTargetMemDesc);
goto err_free;
}
/*
RGXDestroyRenderTarget
*/
IMG_EXPORT
PVRSRV_ERROR RGXDestroyRenderTarget(RGX_RT_CLEANUP_DATA *psCleanupData)
{
PVRSRV_DEVICE_NODE *psDeviceNode = psCleanupData->psDeviceNode;
RGXUnsetFirmwareAddress(psCleanupData->psRenderTargetMemDesc);
/*
Note:
When we get RT cleanup in the FW call that instead
*/
/* Flush the the SLC before freeing */
{
RGXFWIF_KCCB_CMD sFlushInvalCmd;
PVRSRV_ERROR eError;
/* Schedule the SLC flush command ... */
#if defined(PDUMP)
PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Submit SLC flush and invalidate");
#endif
sFlushInvalCmd.eCmdType = RGXFWIF_KCCB_CMD_SLCFLUSHINVAL;
sFlushInvalCmd.uCmdData.sSLCFlushInvalData.bInval = IMG_TRUE;
sFlushInvalCmd.uCmdData.sSLCFlushInvalData.bDMContext = IMG_FALSE;
sFlushInvalCmd.uCmdData.sSLCFlushInvalData.eDM = 0;
sFlushInvalCmd.uCmdData.sSLCFlushInvalData.psContext.ui32Addr = 0;
eError = RGXSendCommandWithPowLock(psDeviceNode->pvDevice,
RGXFWIF_DM_GP,
&sFlushInvalCmd,
sizeof(sFlushInvalCmd),
PDUMP_FLAGS_CONTINUOUS);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXDestroyRenderTarget: Failed to schedule SLC flush command with error (%u)", eError));
}
else
{
/* Wait for the SLC flush to complete */
eError = RGXWaitForFWOp(psDeviceNode->pvDevice, RGXFWIF_DM_GP, psDeviceNode->psSyncPrim, PDUMP_FLAGS_CONTINUOUS);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXDestroyRenderTarget: SLC flush and invalidate aborted with error (%u)", eError));
}
}
}
DevmemFwFree(psDeviceNode->pvDevice, psCleanupData->psRenderTargetMemDesc);
OSFreeMem(psCleanupData);
return PVRSRV_OK;
}
/*
RGXCreateZSBuffer
*/
IMG_EXPORT
PVRSRV_ERROR RGXCreateZSBufferKM(CONNECTION_DATA * psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
DEVMEMINT_RESERVATION *psReservation,
PMR *psPMR,
PVRSRV_MEMALLOCFLAGS_T uiMapFlags,
RGX_ZSBUFFER_DATA **ppsZSBuffer,
IMG_UINT32 *pui32ZSBufferFWDevVAddr)
{
PVRSRV_ERROR eError;
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
RGXFWIF_FWZSBUFFER *psFWZSBuffer;
RGX_ZSBUFFER_DATA *psZSBuffer;
DEVMEM_MEMDESC *psFWZSBufferMemDesc;
IMG_BOOL bOnDemand = PVRSRV_CHECK_ON_DEMAND(uiMapFlags) ? IMG_TRUE : IMG_FALSE;
/* Allocate host data structure */
psZSBuffer = OSAllocZMem(sizeof(*psZSBuffer));
if (psZSBuffer == NULL)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateZSBufferKM: Failed to allocate cleanup data structure for ZS-Buffer"));
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto ErrorAllocCleanup;
}
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
&psZSBuffer->psCleanupSync,
"ta3d zs buffer cleanup");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateZSBufferKM: Failed to allocate cleanup sync (0x%x)",
eError));
goto ErrorSyncAlloc;
}
/* Populate Host data */
psZSBuffer->psDevInfo = psDevInfo;
psZSBuffer->psReservation = psReservation;
psZSBuffer->psPMR = psPMR;
psZSBuffer->uiMapFlags = uiMapFlags;
psZSBuffer->ui32RefCount = 0;
psZSBuffer->bOnDemand = bOnDemand;
if (bOnDemand)
{
psZSBuffer->ui32ZSBufferID = psDevInfo->ui32ZSBufferCurrID++;
psZSBuffer->psMapping = NULL;
OSLockAcquire(psDevInfo->hLockZSBuffer);
dllist_add_to_tail(&psDevInfo->sZSBufferHead, &psZSBuffer->sNode);
OSLockRelease(psDevInfo->hLockZSBuffer);
}
/* Allocate firmware memory for ZS-Buffer. */
PDUMPCOMMENT("Allocate firmware ZS-Buffer data structure");
eError = DevmemFwAllocate(psDevInfo,
sizeof(*psFWZSBuffer),
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_GPU_CACHE_INCOHERENT |
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE |
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE |
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE,
"FwZSBuffer",
&psFWZSBufferMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateZSBufferKM: Failed to allocate firmware ZS-Buffer (%u)", eError));
goto ErrorAllocFWZSBuffer;
}
psZSBuffer->psZSBufferMemDesc = psFWZSBufferMemDesc;
/* Temporarily map the firmware render context to the kernel. */
eError = DevmemAcquireCpuVirtAddr(psFWZSBufferMemDesc,
(void **)&psFWZSBuffer);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"RGXCreateZSBufferKM: Failed to map firmware ZS-Buffer (%u)", eError));
goto ErrorAcquireFWZSBuffer;
}
/* Populate FW ZS-Buffer data structure */
psFWZSBuffer->bOnDemand = bOnDemand;
psFWZSBuffer->eState = (bOnDemand) ? RGXFWIF_ZSBUFFER_UNBACKED : RGXFWIF_ZSBUFFER_BACKED;
psFWZSBuffer->ui32ZSBufferID = psZSBuffer->ui32ZSBufferID;
/* Get firmware address of ZS-Buffer. */
RGXSetFirmwareAddress(&psZSBuffer->sZSBufferFWDevVAddr, psFWZSBufferMemDesc, 0, RFW_FWADDR_FLAG_NONE);
/* Dump the ZS-Buffer and the memory content */
PDUMPCOMMENT("Dump firmware ZS-Buffer");
DevmemPDumpLoadMem(psFWZSBufferMemDesc, 0, sizeof(*psFWZSBuffer), PDUMP_FLAGS_CONTINUOUS);
/* Release address acquired above. */
DevmemReleaseCpuVirtAddr(psFWZSBufferMemDesc);
/* define return value */
*ppsZSBuffer = psZSBuffer;
*pui32ZSBufferFWDevVAddr = psZSBuffer->sZSBufferFWDevVAddr.ui32Addr;
PVR_DPF((PVR_DBG_MESSAGE, "ZS-Buffer [%p] created (%s)",
psZSBuffer,
(bOnDemand) ? "On-Demand": "Up-front"));
psZSBuffer->owner=OSGetCurrentClientProcessIDKM();
return PVRSRV_OK;
/* error handling */
ErrorAcquireFWZSBuffer:
DevmemFwFree(psDevInfo, psFWZSBufferMemDesc);
ErrorAllocFWZSBuffer:
SyncPrimFree(psZSBuffer->psCleanupSync);
ErrorSyncAlloc:
OSFreeMem(psZSBuffer);
ErrorAllocCleanup:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
/*
RGXDestroyZSBuffer
*/
IMG_EXPORT
PVRSRV_ERROR RGXDestroyZSBufferKM(RGX_ZSBUFFER_DATA *psZSBuffer)
{
POS_LOCK hLockZSBuffer;
PVRSRV_ERROR eError;
PVR_ASSERT(psZSBuffer);
hLockZSBuffer = psZSBuffer->psDevInfo->hLockZSBuffer;
/* Request ZS Buffer cleanup */
eError = RGXFWRequestZSBufferCleanUp(psZSBuffer->psDevInfo,
psZSBuffer->sZSBufferFWDevVAddr,
psZSBuffer->psCleanupSync);
if (eError != PVRSRV_ERROR_RETRY)
{
/* Free the firmware render context. */
RGXUnsetFirmwareAddress(psZSBuffer->psZSBufferMemDesc);
DevmemFwFree(psZSBuffer->psDevInfo, psZSBuffer->psZSBufferMemDesc);
/* Remove Deferred Allocation from list */
if (psZSBuffer->bOnDemand)
{
OSLockAcquire(hLockZSBuffer);
PVR_ASSERT(dllist_node_is_in_list(&psZSBuffer->sNode));
dllist_remove_node(&psZSBuffer->sNode);
OSLockRelease(hLockZSBuffer);
}
SyncPrimFree(psZSBuffer->psCleanupSync);
PVR_ASSERT(psZSBuffer->ui32RefCount == 0);
PVR_DPF((PVR_DBG_MESSAGE,"ZS-Buffer [%p] destroyed",psZSBuffer));
/* Free ZS-Buffer host data structure */
OSFreeMem(psZSBuffer);
}
return eError;
}
PVRSRV_ERROR
RGXBackingZSBuffer(RGX_ZSBUFFER_DATA *psZSBuffer)
{
POS_LOCK hLockZSBuffer;
PVRSRV_ERROR eError;
if (!psZSBuffer)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (!psZSBuffer->bOnDemand)
{
/* Only deferred allocations can be populated */
return PVRSRV_ERROR_INVALID_PARAMS;
}
PVR_DPF((PVR_DBG_MESSAGE,"ZS Buffer [%p, ID=0x%08x]: Physical backing requested",
psZSBuffer,
psZSBuffer->ui32ZSBufferID));
hLockZSBuffer = psZSBuffer->psDevInfo->hLockZSBuffer;
OSLockAcquire(hLockZSBuffer);
if (psZSBuffer->ui32RefCount == 0)
{
if (psZSBuffer->bOnDemand)
{
IMG_HANDLE hDevmemHeap;
PVR_ASSERT(psZSBuffer->psMapping == NULL);
/* Get Heap */
eError = DevmemServerGetHeapHandle(psZSBuffer->psReservation, &hDevmemHeap);
PVR_ASSERT(psZSBuffer->psMapping == NULL);
eError = DevmemIntMapPMR(hDevmemHeap,
psZSBuffer->psReservation,
psZSBuffer->psPMR,
psZSBuffer->uiMapFlags,
&psZSBuffer->psMapping);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"Unable populate ZS Buffer [%p, ID=0x%08x] with error %u",
psZSBuffer,
psZSBuffer->ui32ZSBufferID,
eError));
OSLockRelease(hLockZSBuffer);
return eError;
}
PVR_DPF((PVR_DBG_MESSAGE, "ZS Buffer [%p, ID=0x%08x]: Physical backing acquired",
psZSBuffer,
psZSBuffer->ui32ZSBufferID));
}
}
/* Increase refcount*/
psZSBuffer->ui32RefCount++;
OSLockRelease(hLockZSBuffer);
return PVRSRV_OK;
}
PVRSRV_ERROR
RGXPopulateZSBufferKM(RGX_ZSBUFFER_DATA *psZSBuffer,
RGX_POPULATION **ppsPopulation)
{
RGX_POPULATION *psPopulation;
PVRSRV_ERROR eError;
psZSBuffer->ui32NumReqByApp++;
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
PVRSRVStatsUpdateZSBufferStats(1,0,psZSBuffer->owner);
#endif
/* Do the backing */
eError = RGXBackingZSBuffer(psZSBuffer);
if (eError != PVRSRV_OK)
{
goto OnErrorBacking;
}
/* Create the handle to the backing */
psPopulation = OSAllocMem(sizeof(*psPopulation));
if (psPopulation == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto OnErrorAlloc;
}
psPopulation->psZSBuffer = psZSBuffer;
/* return value */
*ppsPopulation = psPopulation;
return PVRSRV_OK;
OnErrorAlloc:
RGXUnbackingZSBuffer(psZSBuffer);
OnErrorBacking:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
PVRSRV_ERROR
RGXUnbackingZSBuffer(RGX_ZSBUFFER_DATA *psZSBuffer)
{
POS_LOCK hLockZSBuffer;
PVRSRV_ERROR eError;
if (!psZSBuffer)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
PVR_ASSERT(psZSBuffer->ui32RefCount);
PVR_DPF((PVR_DBG_MESSAGE,"ZS Buffer [%p, ID=0x%08x]: Physical backing removal requested",
psZSBuffer,
psZSBuffer->ui32ZSBufferID));
hLockZSBuffer = psZSBuffer->psDevInfo->hLockZSBuffer;
OSLockAcquire(hLockZSBuffer);
if (psZSBuffer->bOnDemand)
{
if (psZSBuffer->ui32RefCount == 1)
{
PVR_ASSERT(psZSBuffer->psMapping);
eError = DevmemIntUnmapPMR(psZSBuffer->psMapping);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"Unable to unpopulate ZS Buffer [%p, ID=0x%08x] with error %u",
psZSBuffer,
psZSBuffer->ui32ZSBufferID,
eError));
OSLockRelease(hLockZSBuffer);
return eError;
}
PVR_DPF((PVR_DBG_MESSAGE, "ZS Buffer [%p, ID=0x%08x]: Physical backing removed",
psZSBuffer,
psZSBuffer->ui32ZSBufferID));
}
}
/* Decrease refcount*/
psZSBuffer->ui32RefCount--;
OSLockRelease(hLockZSBuffer);
return PVRSRV_OK;
}
PVRSRV_ERROR
RGXUnpopulateZSBufferKM(RGX_POPULATION *psPopulation)
{
PVRSRV_ERROR eError;
if (!psPopulation)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
eError = RGXUnbackingZSBuffer(psPopulation->psZSBuffer);
if (eError != PVRSRV_OK)
{
return eError;
}
OSFreeMem(psPopulation);
return PVRSRV_OK;
}
static RGX_ZSBUFFER_DATA *FindZSBuffer(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_UINT32 ui32ZSBufferID)
{
DLLIST_NODE *psNode, *psNext;
RGX_ZSBUFFER_DATA *psZSBuffer = NULL;
OSLockAcquire(psDevInfo->hLockZSBuffer);
dllist_foreach_node(&psDevInfo->sZSBufferHead, psNode, psNext)
{
RGX_ZSBUFFER_DATA *psThisZSBuffer = IMG_CONTAINER_OF(psNode, RGX_ZSBUFFER_DATA, sNode);
if (psThisZSBuffer->ui32ZSBufferID == ui32ZSBufferID)
{
psZSBuffer = psThisZSBuffer;
break;
}
}
OSLockRelease(psDevInfo->hLockZSBuffer);
return psZSBuffer;
}
void RGXProcessRequestZSBufferBacking(PVRSRV_RGXDEV_INFO *psDevInfo,
IMG_UINT32 ui32ZSBufferID)
{
RGX_ZSBUFFER_DATA *psZSBuffer;
RGXFWIF_KCCB_CMD sTACCBCmd;
PVRSRV_ERROR eError;
PVR_ASSERT(psDevInfo);
/* scan all deferred allocations */
psZSBuffer = FindZSBuffer(psDevInfo, ui32ZSBufferID);
if (psZSBuffer)
{
IMG_BOOL bBackingDone = IMG_TRUE;
/* Populate ZLS */
eError = RGXBackingZSBuffer(psZSBuffer);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"Populating ZS-Buffer failed with error %u (ID = 0x%08x)", eError, ui32ZSBufferID));
bBackingDone = IMG_FALSE;
}
/* send confirmation */
sTACCBCmd.eCmdType = RGXFWIF_KCCB_CMD_ZSBUFFER_BACKING_UPDATE;
sTACCBCmd.uCmdData.sZSBufferBackingData.sZSBufferFWDevVAddr.ui32Addr = psZSBuffer->sZSBufferFWDevVAddr.ui32Addr;
sTACCBCmd.uCmdData.sZSBufferBackingData.bDone = bBackingDone;
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError = RGXScheduleCommand(psDevInfo,
RGXFWIF_DM_TA,
&sTACCBCmd,
sizeof(sTACCBCmd),
0,
PDUMP_FLAGS_NONE);
if (eError != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
/* Kernel CCB should never fill up, as the FW is processing them right away */
PVR_ASSERT(eError == PVRSRV_OK);
psZSBuffer->ui32NumReqByFW++;
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
PVRSRVStatsUpdateZSBufferStats(0,1,psZSBuffer->owner);
#endif
}
else
{
PVR_DPF((PVR_DBG_ERROR,"ZS Buffer Lookup for ZS Buffer ID 0x%08x failed (Populate)", ui32ZSBufferID));
}
}
void RGXProcessRequestZSBufferUnbacking(PVRSRV_RGXDEV_INFO *psDevInfo,
IMG_UINT32 ui32ZSBufferID)
{
RGX_ZSBUFFER_DATA *psZSBuffer;
RGXFWIF_KCCB_CMD sTACCBCmd;
PVRSRV_ERROR eError;
PVR_ASSERT(psDevInfo);
/* scan all deferred allocations */
psZSBuffer = FindZSBuffer(psDevInfo, ui32ZSBufferID);
if (psZSBuffer)
{
/* Unpopulate ZLS */
eError = RGXUnbackingZSBuffer(psZSBuffer);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"UnPopulating ZS-Buffer failed failed with error %u (ID = 0x%08x)", eError, ui32ZSBufferID));
PVR_ASSERT(IMG_FALSE);
}
/* send confirmation */
sTACCBCmd.eCmdType = RGXFWIF_KCCB_CMD_ZSBUFFER_UNBACKING_UPDATE;
sTACCBCmd.uCmdData.sZSBufferBackingData.sZSBufferFWDevVAddr.ui32Addr = psZSBuffer->sZSBufferFWDevVAddr.ui32Addr;
sTACCBCmd.uCmdData.sZSBufferBackingData.bDone = IMG_TRUE;
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError = RGXScheduleCommand(psDevInfo,
RGXFWIF_DM_TA,
&sTACCBCmd,
sizeof(sTACCBCmd),
0,
PDUMP_FLAGS_NONE);
if (eError != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
/* Kernel CCB should never fill up, as the FW is processing them right away */
PVR_ASSERT(eError == PVRSRV_OK);
}
else
{
PVR_DPF((PVR_DBG_ERROR,"ZS Buffer Lookup for ZS Buffer ID 0x%08x failed (UnPopulate)", ui32ZSBufferID));
}
}
static
PVRSRV_ERROR _CreateTAContext(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
DEVMEM_MEMDESC *psAllocatedMemDesc,
IMG_UINT32 ui32AllocatedOffset,
DEVMEM_MEMDESC *psFWMemContextMemDesc,
IMG_DEV_VIRTADDR sVDMCallStackAddr,
IMG_UINT32 ui32Priority,
RGX_COMMON_CONTEXT_INFO *psInfo,
RGX_SERVER_RC_TA_DATA *psTAData)
{
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
RGXFWIF_TACTX_STATE *psContextState;
PVRSRV_ERROR eError;
/*
Allocate device memory for the firmware GPU context suspend state.
Note: the FW reads/writes the state to memory by accessing the GPU register interface.
*/
PDUMPCOMMENT("Allocate RGX firmware TA context suspend state");
eError = DevmemFwAllocate(psDevInfo,
sizeof(RGXFWIF_TACTX_STATE),
RGX_FWCOMCTX_ALLOCFLAGS,
"FwTAContextState",
&psTAData->psContextStateMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to allocate firmware GPU context suspend state (%u)",
eError));
goto fail_tacontextsuspendalloc;
}
eError = DevmemAcquireCpuVirtAddr(psTAData->psContextStateMemDesc,
(void **)&psContextState);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to map firmware render context state (%u)",
eError));
goto fail_suspendcpuvirtacquire;
}
psContextState->uTAReg_VDM_CALL_STACK_POINTER_Init = sVDMCallStackAddr.uiAddr;
DevmemReleaseCpuVirtAddr(psTAData->psContextStateMemDesc);
eError = FWCommonContextAllocate(psConnection,
psDeviceNode,
REQ_TYPE_TA,
RGXFWIF_DM_TA,
psAllocatedMemDesc,
ui32AllocatedOffset,
psFWMemContextMemDesc,
psTAData->psContextStateMemDesc,
RGX_TA_CCB_SIZE_LOG2,
ui32Priority,
psInfo,
&psTAData->psServerCommonContext);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to init TA fw common context (%u)",
eError));
goto fail_tacommoncontext;
}
/*
* Dump the FW 3D context suspend state buffer
*/
PDUMPCOMMENT("Dump the TA context suspend state buffer");
DevmemPDumpLoadMem(psTAData->psContextStateMemDesc,
0,
sizeof(RGXFWIF_TACTX_STATE),
PDUMP_FLAGS_CONTINUOUS);
psTAData->ui32Priority = ui32Priority;
return PVRSRV_OK;
fail_tacommoncontext:
fail_suspendcpuvirtacquire:
DevmemFwFree(psDevInfo, psTAData->psContextStateMemDesc);
fail_tacontextsuspendalloc:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
static
PVRSRV_ERROR _Create3DContext(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
DEVMEM_MEMDESC *psAllocatedMemDesc,
IMG_UINT32 ui32AllocatedOffset,
DEVMEM_MEMDESC *psFWMemContextMemDesc,
IMG_UINT32 ui32Priority,
RGX_COMMON_CONTEXT_INFO *psInfo,
RGX_SERVER_RC_3D_DATA *ps3DData)
{
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
PVRSRV_ERROR eError;
/*
Allocate device memory for the firmware GPU context suspend state.
Note: the FW reads/writes the state to memory by accessing the GPU register interface.
*/
PDUMPCOMMENT("Allocate RGX firmware 3D context suspend state");
eError = DevmemFwAllocate(psDevInfo,
sizeof(RGXFWIF_3DCTX_STATE),
RGX_FWCOMCTX_ALLOCFLAGS,
"Fw3DContextState",
&ps3DData->psContextStateMemDesc);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to allocate firmware GPU context suspend state (%u)",
eError));
goto fail_3dcontextsuspendalloc;
}
eError = FWCommonContextAllocate(psConnection,
psDeviceNode,
REQ_TYPE_3D,
RGXFWIF_DM_3D,
psAllocatedMemDesc,
ui32AllocatedOffset,
psFWMemContextMemDesc,
ps3DData->psContextStateMemDesc,
RGX_3D_CCB_SIZE_LOG2,
ui32Priority,
psInfo,
&ps3DData->psServerCommonContext);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to init 3D fw common context (%u)",
eError));
goto fail_3dcommoncontext;
}
/*
* Dump the FW 3D context suspend state buffer
*/
PDUMPCOMMENT("Dump the 3D context suspend state buffer");
DevmemPDumpLoadMem(ps3DData->psContextStateMemDesc,
0,
sizeof(RGXFWIF_3DCTX_STATE),
PDUMP_FLAGS_CONTINUOUS);
ps3DData->ui32Priority = ui32Priority;
return PVRSRV_OK;
fail_3dcommoncontext:
DevmemFwFree(psDevInfo, ps3DData->psContextStateMemDesc);
fail_3dcontextsuspendalloc:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
/*
* PVRSRVRGXCreateRenderContextKM
*/
IMG_EXPORT
PVRSRV_ERROR PVRSRVRGXCreateRenderContextKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_UINT32 ui32Priority,
IMG_DEV_VIRTADDR sMCUFenceAddr,
IMG_DEV_VIRTADDR sVDMCallStackAddr,
IMG_UINT32 ui32FrameworkRegisterSize,
IMG_PBYTE pabyFrameworkRegisters,
IMG_HANDLE hMemCtxPrivData,
RGX_SERVER_RENDER_CONTEXT **ppsRenderContext)
{
PVRSRV_ERROR eError;
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
RGX_SERVER_RENDER_CONTEXT *psRenderContext;
DEVMEM_MEMDESC *psFWMemContextMemDesc = RGXGetFWMemDescFromMemoryContextHandle(hMemCtxPrivData);
RGX_COMMON_CONTEXT_INFO sInfo;
/* Prepare cleanup structure */
*ppsRenderContext = NULL;
psRenderContext = OSAllocZMem(sizeof(*psRenderContext));
if (psRenderContext == NULL)
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
psRenderContext->psDeviceNode = psDeviceNode;
/*
Create the FW render context, this has the TA and 3D FW common
contexts embedded within it
*/
eError = DevmemFwAllocate(psDevInfo,
sizeof(RGXFWIF_FWRENDERCONTEXT),
RGX_FWCOMCTX_ALLOCFLAGS,
"FwRenderContext",
&psRenderContext->psFWRenderContextMemDesc);
if (eError != PVRSRV_OK)
{
goto fail_fwrendercontext;
}
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
WorkEstRCInit(&(psRenderContext->sWorkEstData));
#endif
/* Allocate cleanup sync */
eError = SyncPrimAlloc(psDeviceNode->hSyncPrimContext,
&psRenderContext->psCleanupSync,
"ta3d render context cleanup");
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to allocate cleanup sync (0x%x)",
eError));
goto fail_syncalloc;
}
/*
* Create the FW framework buffer
*/
eError = PVRSRVRGXFrameworkCreateKM(psDeviceNode,
&psRenderContext->psFWFrameworkMemDesc,
ui32FrameworkRegisterSize);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to allocate firmware GPU framework state (%u)",
eError));
goto fail_frameworkcreate;
}
/* Copy the Framework client data into the framework buffer */
eError = PVRSRVRGXFrameworkCopyCommand(psRenderContext->psFWFrameworkMemDesc,
pabyFrameworkRegisters,
ui32FrameworkRegisterSize);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateRenderContextKM: Failed to populate the framework buffer (%u)",
eError));
goto fail_frameworkcopy;
}
sInfo.psFWFrameworkMemDesc = psRenderContext->psFWFrameworkMemDesc;
sInfo.psMCUFenceAddr = &sMCUFenceAddr;
eError = _CreateTAContext(psConnection,
psDeviceNode,
psRenderContext->psFWRenderContextMemDesc,
offsetof(RGXFWIF_FWRENDERCONTEXT, sTAContext),
psFWMemContextMemDesc,
sVDMCallStackAddr,
ui32Priority,
&sInfo,
&psRenderContext->sTAData);
if (eError != PVRSRV_OK)
{
goto fail_tacontext;
}
eError = _Create3DContext(psConnection,
psDeviceNode,
psRenderContext->psFWRenderContextMemDesc,
offsetof(RGXFWIF_FWRENDERCONTEXT, s3DContext),
psFWMemContextMemDesc,
ui32Priority,
&sInfo,
&psRenderContext->s3DData);
if (eError != PVRSRV_OK)
{
goto fail_3dcontext;
}
SyncAddrListInit(&psRenderContext->sSyncAddrListTAFence);
SyncAddrListInit(&psRenderContext->sSyncAddrListTAUpdate);
SyncAddrListInit(&psRenderContext->sSyncAddrList3DFence);
SyncAddrListInit(&psRenderContext->sSyncAddrList3DUpdate);
{
PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
OSWRLockAcquireWrite(psDevInfo->hRenderCtxListLock);
dllist_add_to_tail(&(psDevInfo->sRenderCtxtListHead), &(psRenderContext->sListNode));
OSWRLockReleaseWrite(psDevInfo->hRenderCtxListLock);
}
*ppsRenderContext= psRenderContext;
return PVRSRV_OK;
fail_3dcontext:
_DestroyTAContext(&psRenderContext->sTAData,
psDeviceNode,
psRenderContext->psCleanupSync);
fail_tacontext:
fail_frameworkcopy:
DevmemFwFree(psDevInfo, psRenderContext->psFWFrameworkMemDesc);
fail_frameworkcreate:
SyncPrimFree(psRenderContext->psCleanupSync);
fail_syncalloc:
DevmemFwFree(psDevInfo, psRenderContext->psFWRenderContextMemDesc);
fail_fwrendercontext:
OSFreeMem(psRenderContext);
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
/*
* PVRSRVRGXDestroyRenderContextKM
*/
IMG_EXPORT
PVRSRV_ERROR PVRSRVRGXDestroyRenderContextKM(RGX_SERVER_RENDER_CONTEXT *psRenderContext)
{
PVRSRV_ERROR eError;
PVRSRV_RGXDEV_INFO *psDevInfo = psRenderContext->psDeviceNode->pvDevice;
RGXFWIF_FWRENDERCONTEXT *psFWRenderContext;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
IMG_UINT32 ui32WorkEstCCBSubmitted;
#endif
/* remove node from list before calling destroy - as destroy, if successful
* will invalidate the node
* must be re-added if destroy fails
*/
OSWRLockAcquireWrite(psDevInfo->hRenderCtxListLock);
dllist_remove_node(&(psRenderContext->sListNode));
OSWRLockReleaseWrite(psDevInfo->hRenderCtxListLock);
/* Cleanup the TA if we haven't already */
if ((psRenderContext->ui32CleanupStatus & RC_CLEANUP_TA_COMPLETE) == 0)
{
eError = _DestroyTAContext(&psRenderContext->sTAData,
psRenderContext->psDeviceNode,
psRenderContext->psCleanupSync);
if (eError == PVRSRV_OK)
{
psRenderContext->ui32CleanupStatus |= RC_CLEANUP_TA_COMPLETE;
}
else
{
goto e0;
}
}
/* Cleanup the 3D if we haven't already */
if ((psRenderContext->ui32CleanupStatus & RC_CLEANUP_3D_COMPLETE) == 0)
{
eError = _Destroy3DContext(&psRenderContext->s3DData,
psRenderContext->psDeviceNode,
psRenderContext->psCleanupSync);
if (eError == PVRSRV_OK)
{
psRenderContext->ui32CleanupStatus |= RC_CLEANUP_3D_COMPLETE;
}
else
{
goto e0;
}
}
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
eError = DevmemAcquireCpuVirtAddr(psRenderContext->psFWRenderContextMemDesc,
(void **)&psFWRenderContext);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXDestroyRenderContextKM: Failed to map firmware render context (%u)",
eError));
goto e0;
}
ui32WorkEstCCBSubmitted = psFWRenderContext->ui32WorkEstCCBSubmitted;
DevmemReleaseCpuVirtAddr(psRenderContext->psFWRenderContextMemDesc);
/* Check if all of the workload estimation CCB commands for this workload
* are read
*/
if(ui32WorkEstCCBSubmitted != psRenderContext->sWorkEstData.ui32WorkEstCCBReceived)
{
eError = PVRSRV_ERROR_RETRY;
goto e0;
}
#endif
/*
Only if both TA and 3D contexts have been cleaned up can we
free the shared resources
*/
if (psRenderContext->ui32CleanupStatus == (RC_CLEANUP_3D_COMPLETE | RC_CLEANUP_TA_COMPLETE))
{
/* Update SPM statistics */
eError = DevmemAcquireCpuVirtAddr(psRenderContext->psFWRenderContextMemDesc,
(void **)&psFWRenderContext);
if (eError == PVRSRV_OK)
{
DevmemReleaseCpuVirtAddr(psRenderContext->psFWRenderContextMemDesc);
}
else
{
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXDestroyRenderContextKM: Failed to map firmware render context (%u)",
eError));
}
/* Free the framework buffer */
DevmemFwFree(psDevInfo, psRenderContext->psFWFrameworkMemDesc);
/* Free the firmware render context */
DevmemFwFree(psDevInfo, psRenderContext->psFWRenderContextMemDesc);
/* Free the cleanup sync */
SyncPrimFree(psRenderContext->psCleanupSync);
SyncAddrListDeinit(&psRenderContext->sSyncAddrListTAFence);
SyncAddrListDeinit(&psRenderContext->sSyncAddrListTAUpdate);
SyncAddrListDeinit(&psRenderContext->sSyncAddrList3DFence);
SyncAddrListDeinit(&psRenderContext->sSyncAddrList3DUpdate);
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
WorkEstRCDeInit(&(psRenderContext->sWorkEstData),
psDevInfo);
#endif
OSFreeMem(psRenderContext);
}
return PVRSRV_OK;
e0:
OSWRLockAcquireWrite(psDevInfo->hRenderCtxListLock);
dllist_add_to_tail(&(psDevInfo->sRenderCtxtListHead), &(psRenderContext->sListNode));
OSWRLockReleaseWrite(psDevInfo->hRenderCtxListLock);
return eError;
}
/* TODO !!! this was local on the stack, and we managed to blow the stack for the kernel.
* THIS - 46 argument function needs to be sorted out.
*/
/* 1 command for the TA */
static RGX_CCB_CMD_HELPER_DATA asTACmdHelperData[1];
/* Up to 3 commands for the 3D (partial render fence, partial reader, and render) */
static RGX_CCB_CMD_HELPER_DATA as3DCmdHelperData[3];
/*
* PVRSRVRGXKickTA3DKM
*/
IMG_EXPORT
PVRSRV_ERROR PVRSRVRGXKickTA3DKM(RGX_SERVER_RENDER_CONTEXT *psRenderContext,
IMG_UINT32 ui32ClientCacheOpSeqNum,
IMG_UINT32 ui32ClientTAFenceCount,
SYNC_PRIMITIVE_BLOCK **apsClientTAFenceSyncPrimBlock,
IMG_UINT32 *paui32ClientTAFenceSyncOffset,
IMG_UINT32 *paui32ClientTAFenceValue,
IMG_UINT32 ui32ClientTAUpdateCount,
SYNC_PRIMITIVE_BLOCK **apsClientTAUpdateSyncPrimBlock,
IMG_UINT32 *paui32ClientTAUpdateSyncOffset,
IMG_UINT32 *paui32ClientTAUpdateValue,
IMG_UINT32 ui32ServerTASyncPrims,
IMG_UINT32 *paui32ServerTASyncFlags,
SERVER_SYNC_PRIMITIVE **pasServerTASyncs,
IMG_UINT32 ui32Client3DFenceCount,
SYNC_PRIMITIVE_BLOCK **apsClient3DFenceSyncPrimBlock,
IMG_UINT32 *paui32Client3DFenceSyncOffset,
IMG_UINT32 *paui32Client3DFenceValue,
IMG_UINT32 ui32Client3DUpdateCount,
SYNC_PRIMITIVE_BLOCK **apsClient3DUpdateSyncPrimBlock,
IMG_UINT32 *paui32Client3DUpdateSyncOffset,
IMG_UINT32 *paui32Client3DUpdateValue,
IMG_UINT32 ui32Server3DSyncPrims,
IMG_UINT32 *paui32Server3DSyncFlags,
SERVER_SYNC_PRIMITIVE **pasServer3DSyncs,
SYNC_PRIMITIVE_BLOCK *psPRFenceSyncPrimBlock,
IMG_UINT32 ui32PRFenceSyncOffset,
IMG_UINT32 ui32PRFenceValue,
IMG_INT32 i32CheckFenceFD,
IMG_INT32 i32UpdateTimelineFD,
IMG_INT32 *pi32UpdateFenceFD,
IMG_CHAR szFenceName[32],
IMG_UINT32 ui32TACmdSize,
IMG_PBYTE pui8TADMCmd,
IMG_UINT32 ui323DPRCmdSize,
IMG_PBYTE pui83DPRDMCmd,
IMG_UINT32 ui323DCmdSize,
IMG_PBYTE pui83DDMCmd,
IMG_UINT32 ui32ExtJobRef,
IMG_BOOL bLastTAInScene,
IMG_BOOL bKickTA,
IMG_BOOL bKickPR,
IMG_BOOL bKick3D,
IMG_BOOL bAbort,
IMG_UINT32 ui32PDumpFlags,
RGX_RTDATA_CLEANUP_DATA *psRTDataCleanup,
RGX_ZSBUFFER_DATA *psZBuffer,
RGX_ZSBUFFER_DATA *psSBuffer,
IMG_BOOL bCommitRefCountsTA,
IMG_BOOL bCommitRefCounts3D,
IMG_BOOL *pbCommittedRefCountsTA,
IMG_BOOL *pbCommittedRefCounts3D,
IMG_UINT32 ui32SyncPMRCount,
IMG_UINT32 *paui32SyncPMRFlags,
PMR **ppsSyncPMRs,
IMG_UINT32 ui32RenderTargetSize,
IMG_UINT32 ui32NumberOfDrawCalls,
IMG_UINT32 ui32NumberOfIndices,
IMG_UINT32 ui32NumberOfMRTs,
IMG_UINT64 ui64DeadlineInus)
{
IMG_UINT32 ui32TACmdCount=0;
IMG_UINT32 ui323DCmdCount=0;
IMG_UINT32 ui32TACmdOffset=0;
IMG_UINT32 ui323DCmdOffset=0;
RGXFWIF_UFO sPRUFO;
IMG_UINT32 i;
PVRSRV_ERROR eError = PVRSRV_OK;
PVRSRV_ERROR eError2;
IMG_INT32 i32UpdateFenceFD = -1;
IMG_UINT32 ui32JobId;
IMG_UINT32 ui32ClientPRUpdateCount = 0;
PRGXFWIF_UFO_ADDR *pauiClientPRUpdateUFOAddress = NULL;
IMG_UINT32 *paui32ClientPRUpdateValue = NULL;
PRGXFWIF_TIMESTAMP_ADDR pPreAddr;
PRGXFWIF_TIMESTAMP_ADDR pPostAddr;
PRGXFWIF_UFO_ADDR pRMWUFOAddr;
PRGXFWIF_UFO_ADDR *pauiClientTAFenceUFOAddress;
PRGXFWIF_UFO_ADDR *pauiClientTAUpdateUFOAddress;
PRGXFWIF_UFO_ADDR *pauiClient3DFenceUFOAddress;
PRGXFWIF_UFO_ADDR *pauiClient3DUpdateUFOAddress;
PRGXFWIF_UFO_ADDR uiPRFenceUFOAddress;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
RGXFWIF_WORKEST_KICK_DATA sWorkloadKickDataTA;
RGXFWIF_WORKEST_KICK_DATA sWorkloadKickData3D;
IMG_UINT32 ui32TACommandOffset = 0;
IMG_UINT32 ui323DCommandOffset = 0;
IMG_UINT32 ui32TACmdHeaderOffset = 0;
IMG_UINT32 ui323DCmdHeaderOffset = 0;
IMG_UINT32 ui323DFullRenderCommandOffset = 0;
IMG_UINT32 ui32TACmdOffsetWrapCheck = 0;
IMG_UINT32 ui323DCmdOffsetWrapCheck = 0;
#endif
#if defined(SUPPORT_BUFFER_SYNC)
struct pvr_buffer_sync_append_data *psAppendData = NULL;
#endif
#if defined(SUPPORT_NATIVE_FENCE_SYNC)
/* Android fd sync update info */
struct pvr_sync_append_data *psFDData = NULL;
if (i32UpdateTimelineFD >= 0 && !pi32UpdateFenceFD)
{
return PVRSRV_ERROR_INVALID_PARAMS;
}
#else
if (i32UpdateTimelineFD >= 0)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Providing native sync timeline (%d) in non native sync enabled driver",
__func__, i32UpdateTimelineFD));
}
if (i32CheckFenceFD >= 0)
{
PVR_DPF((PVR_DBG_WARNING, "%s: Providing native check sync (%d) in non native sync enabled driver",
__func__, i32CheckFenceFD));
}
#endif
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
sWorkloadKickDataTA.ui64ReturnDataIndex = 0;
sWorkloadKickData3D.ui64ReturnDataIndex = 0;
#endif
ui32JobId = OSAtomicIncrement(&psRenderContext->hJobId);
/* Ensure the string is null-terminated (Required for safety) */
szFenceName[31] = '\0';
*pbCommittedRefCountsTA = IMG_FALSE;
*pbCommittedRefCounts3D = IMG_FALSE;
eError = SyncAddrListPopulate(&psRenderContext->sSyncAddrListTAFence,
ui32ClientTAFenceCount,
apsClientTAFenceSyncPrimBlock,
paui32ClientTAFenceSyncOffset);
if(eError != PVRSRV_OK)
{
goto err_populate_sync_addr_list;
}
pauiClientTAFenceUFOAddress = psRenderContext->sSyncAddrListTAFence.pasFWAddrs;
eError = SyncAddrListPopulate(&psRenderContext->sSyncAddrListTAUpdate,
ui32ClientTAUpdateCount,
apsClientTAUpdateSyncPrimBlock,
paui32ClientTAUpdateSyncOffset);
if(eError != PVRSRV_OK)
{
goto err_populate_sync_addr_list;
}
pauiClientTAUpdateUFOAddress = psRenderContext->sSyncAddrListTAUpdate.pasFWAddrs;
eError = SyncAddrListPopulate(&psRenderContext->sSyncAddrList3DFence,
ui32Client3DFenceCount,
apsClient3DFenceSyncPrimBlock,
paui32Client3DFenceSyncOffset);
if(eError != PVRSRV_OK)
{
goto err_populate_sync_addr_list;
}
pauiClient3DFenceUFOAddress = psRenderContext->sSyncAddrList3DFence.pasFWAddrs;
eError = SyncAddrListPopulate(&psRenderContext->sSyncAddrList3DUpdate,
ui32Client3DUpdateCount,
apsClient3DUpdateSyncPrimBlock,
paui32Client3DUpdateSyncOffset);
if(eError != PVRSRV_OK)
{
goto err_populate_sync_addr_list;
}
pauiClient3DUpdateUFOAddress = psRenderContext->sSyncAddrList3DUpdate.pasFWAddrs;
eError = SyncPrimitiveBlockToFWAddr(psPRFenceSyncPrimBlock,
ui32PRFenceSyncOffset,
&uiPRFenceUFOAddress);
if(eError != PVRSRV_OK)
{
goto err_pr_fence_address;
}
/* Sanity check the server fences */
for (i=0;i<ui32ServerTASyncPrims;i++)
{
if (!(paui32ServerTASyncFlags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK))
{
PVR_DPF((PVR_DBG_ERROR, "%s: Server fence (on TA) must fence", __FUNCTION__));
return PVRSRV_ERROR_INVALID_SYNC_PRIM_OP;
}
}
for (i=0;i<ui32Server3DSyncPrims;i++)
{
if (!(paui32Server3DSyncFlags[i] & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK))
{
PVR_DPF((PVR_DBG_ERROR, "%s: Server fence (on 3D) must fence", __FUNCTION__));
return PVRSRV_ERROR_INVALID_SYNC_PRIM_OP;
}
}
RGX_GetTimestampCmdHelper((PVRSRV_RGXDEV_INFO*) psRenderContext->psDeviceNode->pvDevice,
& pPreAddr,
& pPostAddr,
& pRMWUFOAddr);
/*
Sanity check we have a PR kick if there are client or server fences
*/
if (!bKickPR && ((ui32Client3DFenceCount != 0) || (ui32Server3DSyncPrims != 0)))
{
PVR_DPF((PVR_DBG_ERROR, "%s: 3D fence (client or server) passed without a PR kick", __FUNCTION__));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (ui32SyncPMRCount)
{
#if defined(SUPPORT_BUFFER_SYNC)
PVRSRV_DEVICE_NODE *psDeviceNode = psRenderContext->psDeviceNode;
IMG_UINT32 ui32ClientIntUpdateCount = 0;
PRGXFWIF_UFO_ADDR *pauiClientIntUpdateUFOAddress = NULL;
IMG_UINT32 *paui32ClientIntUpdateValue = NULL;
int err;
if (!bKickTA)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Buffer sync only supported for kicks including a TA",
__FUNCTION__));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (!bKickPR)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Buffer sync only supported for kicks including a PR",
__FUNCTION__));
return PVRSRV_ERROR_INVALID_PARAMS;
}
if (bKick3D)
{
ui32ClientIntUpdateCount = ui32Client3DUpdateCount;
pauiClientIntUpdateUFOAddress = pauiClient3DUpdateUFOAddress;
paui32ClientIntUpdateValue = paui32Client3DUpdateValue;
}
else
{
ui32ClientIntUpdateCount = ui32ClientPRUpdateCount;
pauiClientIntUpdateUFOAddress = pauiClientPRUpdateUFOAddress;
paui32ClientIntUpdateValue = paui32ClientPRUpdateValue;
}
err = pvr_buffer_sync_append_start(psDeviceNode->psBufferSyncContext,
ui32SyncPMRCount,
ppsSyncPMRs,
paui32SyncPMRFlags,
ui32ClientTAFenceCount,
pauiClientTAFenceUFOAddress,
paui32ClientTAFenceValue,
ui32ClientIntUpdateCount,
pauiClientIntUpdateUFOAddress,
paui32ClientIntUpdateValue,
&psAppendData);
if (err)
{
eError = (err == -ENOMEM) ? PVRSRV_ERROR_OUT_OF_MEMORY : PVRSRV_ERROR_INVALID_PARAMS;
goto fail_sync_append;
}
pvr_buffer_sync_append_checks_get(psAppendData,
&ui32ClientTAFenceCount,
&pauiClientTAFenceUFOAddress,
&paui32ClientTAFenceValue);
if (bKick3D)
{
pvr_buffer_sync_append_updates_get(psAppendData,
&ui32Client3DUpdateCount,
&pauiClient3DUpdateUFOAddress,
&paui32Client3DUpdateValue);
}
else
{
pvr_buffer_sync_append_updates_get(psAppendData,
&ui32ClientPRUpdateCount,
&pauiClientPRUpdateUFOAddress,
&paui32ClientPRUpdateValue);
}
#else
PVR_DPF((PVR_DBG_ERROR, "%s: Buffer sync not supported but got %u buffers", __FUNCTION__, ui32SyncPMRCount));
return PVRSRV_ERROR_INVALID_PARAMS;
#endif /* defined(SUPPORT_BUFFER_SYNC) */
}
#if defined(SUPPORT_NATIVE_FENCE_SYNC)
/*
* The hardware requires a PR to be submitted if there is a TA (otherwise
* it can wedge if we run out of PB space with no PR to run)
*
* If we only have a TA, attach native checks to the TA and updates to the PR
* If we have a TA and 3D, attach checks to TA, updates to 3D
* If we only have a 3D, attach checks and updates to the 3D
*
* Note that 'updates' includes the cleanup syncs for 'check' fence FDs, in
* addition to the update fence FD (if supplied)
*
* Currently, the client driver never kicks only the 3D, so we only support
* that for the time being.
*/
if (i32CheckFenceFD >= 0 || i32UpdateTimelineFD >= 0)
{
IMG_UINT32 ui32ClientIntUpdateCount = 0;
PRGXFWIF_UFO_ADDR *pauiClientIntUpdateUFOAddress = NULL;
IMG_UINT32 *paui32ClientIntUpdateValue = NULL;
if (!bKickTA)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Native syncs only supported for kicks including a TA",
__FUNCTION__));
eError = PVRSRV_ERROR_INVALID_PARAMS;
goto fail_fdsync;
}
if (!bKickPR)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Native syncs require a PR for all kicks",
__FUNCTION__));
eError = PVRSRV_ERROR_INVALID_PARAMS;
goto fail_fdsync;
}
/* If we have a 3D, attach updates to that. Otherwise, we attach it to a PR */
if (bKick3D)
{
ui32ClientIntUpdateCount = ui32Client3DUpdateCount;
pauiClientIntUpdateUFOAddress = pauiClient3DUpdateUFOAddress;
paui32ClientIntUpdateValue = paui32Client3DUpdateValue;
}
else
{
ui32ClientIntUpdateCount = ui32ClientPRUpdateCount;
pauiClientIntUpdateUFOAddress = pauiClientPRUpdateUFOAddress;
paui32ClientIntUpdateValue = paui32ClientPRUpdateValue;
}
eError =
pvr_sync_append_fences(szFenceName,
i32CheckFenceFD,
i32UpdateTimelineFD,
ui32ClientIntUpdateCount,
pauiClientIntUpdateUFOAddress,
paui32ClientIntUpdateValue,
ui32ClientTAFenceCount,
pauiClientTAFenceUFOAddress,
paui32ClientTAFenceValue,
&psFDData);
if (eError != PVRSRV_OK)
{
goto fail_fdsync;
}
/* If we have a 3D, attach updates to that. Otherwise, we attach it to a PR */
if (bKick3D)
{
pvr_sync_get_updates(psFDData, &ui32Client3DUpdateCount,
&pauiClient3DUpdateUFOAddress, &paui32Client3DUpdateValue);
}
else
{
pvr_sync_get_updates(psFDData, &ui32ClientPRUpdateCount,
&pauiClientPRUpdateUFOAddress, &paui32ClientPRUpdateValue);
}
pvr_sync_get_checks(psFDData, &ui32ClientTAFenceCount,
&pauiClientTAFenceUFOAddress, &paui32ClientTAFenceValue);
if (ui32ClientPRUpdateCount)
{
PVR_ASSERT(pauiClientPRUpdateUFOAddress);
PVR_ASSERT(paui32ClientPRUpdateValue);
}
if (ui32Client3DUpdateCount)
{
PVR_ASSERT(pauiClient3DUpdateUFOAddress);
PVR_ASSERT(paui32Client3DUpdateValue);
}
}
#endif /* SUPPORT_NATIVE_FENCE_SYNC */
/* Init and acquire to TA command if required */
if(bKickTA)
{
RGX_SERVER_RC_TA_DATA *psTAData = &psRenderContext->sTAData;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* Prepare workload estimation */
WorkEstPrepare(psRenderContext->psDeviceNode->pvDevice,
&(psRenderContext->sWorkEstData),
&(psRenderContext->sWorkEstData.sWorkloadMatchingDataTA),
ui32RenderTargetSize,
ui32NumberOfDrawCalls,
ui32NumberOfIndices,
ui32NumberOfMRTs,
ui64DeadlineInus,
&sWorkloadKickDataTA);
#endif
/* Init the TA command helper */
eError = RGXCmdHelperInitCmdCCB(FWCommonContextGetClientCCB(psTAData->psServerCommonContext),
ui32ClientTAFenceCount,
pauiClientTAFenceUFOAddress,
paui32ClientTAFenceValue,
ui32ClientTAUpdateCount,
pauiClientTAUpdateUFOAddress,
paui32ClientTAUpdateValue,
ui32ServerTASyncPrims,
paui32ServerTASyncFlags,
SYNC_FLAG_MASK_ALL,
pasServerTASyncs,
ui32TACmdSize,
pui8TADMCmd,
& pPreAddr,
(bKick3D ? NULL : & pPostAddr),
(bKick3D ? NULL : & pRMWUFOAddr),
RGXFWIF_CCB_CMD_TYPE_TA,
ui32ExtJobRef,
ui32JobId,
ui32PDumpFlags,
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
&sWorkloadKickDataTA,
#else
NULL,
#endif
"TA",
asTACmdHelperData);
if (eError != PVRSRV_OK)
{
goto fail_tacmdinit;
}
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* The following is used to determine the offset of the command header
* containing the workload estimation data so that can be accessed when
* the KCCB is read.
*/
ui32TACmdHeaderOffset = RGXCmdHelperGetDMCommandHeaderOffset(asTACmdHelperData);
#endif
eError = RGXCmdHelperAcquireCmdCCB(IMG_ARR_NUM_ELEMS(asTACmdHelperData),
asTACmdHelperData);
if (eError != PVRSRV_OK)
{
goto fail_taacquirecmd;
}
else
{
ui32TACmdCount++;
}
}
/* Only kick the 3D if required */
if (bKickPR)
{
RGX_SERVER_RC_3D_DATA *ps3DData = &psRenderContext->s3DData;
/*
The command helper doesn't know about the PR fence so create
the command with all the fences against it and later create
the PR command itself which _must_ come after the PR fence.
*/
sPRUFO.puiAddrUFO = uiPRFenceUFOAddress;
sPRUFO.ui32Value = ui32PRFenceValue;
/* Init the PR fence command helper */
eError = RGXCmdHelperInitCmdCCB(FWCommonContextGetClientCCB(ps3DData->psServerCommonContext),
ui32Client3DFenceCount,
pauiClient3DFenceUFOAddress,
paui32Client3DFenceValue,
0,
NULL,
NULL,
(bKick3D ? ui32Server3DSyncPrims : 0),
paui32Server3DSyncFlags,
PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK,
pasServer3DSyncs,
sizeof(sPRUFO),
(IMG_UINT8*) &sPRUFO,
NULL,
NULL,
NULL,
RGXFWIF_CCB_CMD_TYPE_FENCE_PR,
ui32ExtJobRef,
ui32JobId,
ui32PDumpFlags,
NULL,
"3D-PR-Fence",
&as3DCmdHelperData[ui323DCmdCount++]);
if (eError != PVRSRV_OK)
{
goto fail_prfencecmdinit;
}
/* Init the 3D PR command helper */
/*
See note above PVRFDSyncQueryFencesKM as to why updates for android
syncs are passed in with the PR
*/
eError = RGXCmdHelperInitCmdCCB(FWCommonContextGetClientCCB(ps3DData->psServerCommonContext),
0,
NULL,
NULL,
ui32ClientPRUpdateCount,
pauiClientPRUpdateUFOAddress,
paui32ClientPRUpdateValue,
0,
NULL,
SYNC_FLAG_MASK_ALL,
NULL,
ui323DPRCmdSize,
pui83DPRDMCmd,
NULL,
NULL,
NULL,
RGXFWIF_CCB_CMD_TYPE_3D_PR,
ui32ExtJobRef,
ui32JobId,
ui32PDumpFlags,
NULL,
"3D-PR",
&as3DCmdHelperData[ui323DCmdCount++]);
if (eError != PVRSRV_OK)
{
goto fail_prcmdinit;
}
}
if (bKick3D || bAbort)
{
RGX_SERVER_RC_3D_DATA *ps3DData = &psRenderContext->s3DData;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* Prepare workload estimation */
WorkEstPrepare(psRenderContext->psDeviceNode->pvDevice,
&(psRenderContext->sWorkEstData),
&(psRenderContext->sWorkEstData.sWorkloadMatchingData3D),
ui32RenderTargetSize,
ui32NumberOfDrawCalls,
ui32NumberOfIndices,
ui32NumberOfMRTs,
ui64DeadlineInus,
&sWorkloadKickData3D);
#endif
/* Init the 3D command helper */
eError = RGXCmdHelperInitCmdCCB(FWCommonContextGetClientCCB(ps3DData->psServerCommonContext),
0,
NULL,
NULL,
ui32Client3DUpdateCount,
pauiClient3DUpdateUFOAddress,
paui32Client3DUpdateValue,
ui32Server3DSyncPrims,
paui32Server3DSyncFlags,
PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE,
pasServer3DSyncs,
ui323DCmdSize,
pui83DDMCmd,
(bKickTA ? NULL : & pPreAddr),
& pPostAddr,
& pRMWUFOAddr,
RGXFWIF_CCB_CMD_TYPE_3D,
ui32ExtJobRef,
ui32JobId,
ui32PDumpFlags,
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
&sWorkloadKickData3D,
#else
NULL,
#endif
"3D",
&as3DCmdHelperData[ui323DCmdCount++]);
if (eError != PVRSRV_OK)
{
goto fail_3dcmdinit;
}
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* The following are used to determine the offset of the command header
* containing the workload estimation data so that can be accessed when
* the KCCB is read.
*/
ui323DCmdHeaderOffset =
RGXCmdHelperGetDMCommandHeaderOffset(&as3DCmdHelperData[ui323DCmdCount - 1]);
ui323DFullRenderCommandOffset =
RGXCmdHelperGetCommandOffset(as3DCmdHelperData,
ui323DCmdCount - 1);
#endif
}
/* Protect against array overflow in RGXCmdHelperAcquireCmdCCB() */
if (ui323DCmdCount > IMG_ARR_NUM_ELEMS(as3DCmdHelperData))
{
goto fail_3dcmdinit;
}
if (ui323DCmdCount)
{
PVR_ASSERT(bKickPR || bKick3D);
/* Acquire space for all the 3D command(s) */
eError = RGXCmdHelperAcquireCmdCCB(ui323DCmdCount,
as3DCmdHelperData);
if (eError != PVRSRV_OK)
{
/* If RGXCmdHelperAcquireCmdCCB fails we skip the scheduling
* of a new TA command with the same Write offset in Kernel CCB.
*/
goto fail_3dacquirecmd;
}
}
/*
We should acquire the space in the kernel CCB here as after this point
we release the commands which will take operations on server syncs
which can't be undone
*/
/*
Everything is ready to go now, release the commands
*/
if (ui32TACmdCount)
{
ui32TACmdOffset = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->sTAData.psServerCommonContext));
RGXCmdHelperReleaseCmdCCB(ui32TACmdCount,
asTACmdHelperData,
"TA",
FWCommonContextGetFWAddress(psRenderContext->sTAData.psServerCommonContext).ui32Addr);
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
ui32TACmdOffsetWrapCheck =
RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->sTAData.psServerCommonContext));
/* This checks if the command would wrap around at the end of the CCB
* and therefore would start at an offset of 0 rather than the current
* command offset.
*/
if(ui32TACmdOffset < ui32TACmdOffsetWrapCheck)
{
ui32TACommandOffset = ui32TACmdOffset;
}
else
{
ui32TACommandOffset = 0;
}
#endif
}
if (ui323DCmdCount)
{
ui323DCmdOffset = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->s3DData.psServerCommonContext));
RGXCmdHelperReleaseCmdCCB(ui323DCmdCount,
as3DCmdHelperData,
"3D",
FWCommonContextGetFWAddress(psRenderContext->s3DData.psServerCommonContext).ui32Addr);
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
ui323DCmdOffsetWrapCheck = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->s3DData.psServerCommonContext));
if(ui323DCmdOffset < ui323DCmdOffsetWrapCheck)
{
ui323DCommandOffset = ui323DCmdOffset;
}
else
{
ui323DCommandOffset = 0;
}
#endif
}
if (ui32TACmdCount)
{
RGXFWIF_KCCB_CMD sTAKCCBCmd;
IMG_UINT32 ui32FWCtx = FWCommonContextGetFWAddress(psRenderContext->sTAData.psServerCommonContext).ui32Addr;
/* Construct the kernel TA CCB command. */
sTAKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
sTAKCCBCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psRenderContext->sTAData.psServerCommonContext);
sTAKCCBCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->sTAData.psServerCommonContext));
/* Add the Workload data into the KCCB kick */
sTAKCCBCmd.uCmdData.sCmdKickData.sWorkloadDataFWAddress.ui32Addr = 0;
sTAKCCBCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset = 0;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* Store the offset to the CCCB command header so that it can be
* referenced when the KCCB command reaches the FW
*/
sTAKCCBCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset =
ui32TACommandOffset + ui32TACmdHeaderOffset;
#endif
if(bCommitRefCountsTA)
{
AttachKickResourcesCleanupCtls((PRGXFWIF_CLEANUP_CTL *) &sTAKCCBCmd.uCmdData.sCmdKickData.apsCleanupCtl,
&sTAKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl,
RGXFWIF_DM_TA,
bKickTA,
psRTDataCleanup,
psZBuffer,
psSBuffer);
*pbCommittedRefCountsTA = IMG_TRUE;
}
else
{
sTAKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;
}
HTBLOGK(HTB_SF_MAIN_KICK_TA,
sTAKCCBCmd.uCmdData.sCmdKickData.psContext,
ui32TACmdOffset
);
RGX_HWPERF_HOST_ENQ(psRenderContext, OSGetCurrentClientProcessIDKM(),
ui32FWCtx, ui32ExtJobRef, ui32JobId,
RGX_HWPERF_KICK_TYPE_TA3D);
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError2 = RGXScheduleCommand(psRenderContext->psDeviceNode->pvDevice,
RGXFWIF_DM_TA,
&sTAKCCBCmd,
sizeof(sTAKCCBCmd),
ui32ClientCacheOpSeqNum,
ui32PDumpFlags);
if (eError2 != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
#if defined(SUPPORT_GPUTRACE_EVENTS)
RGXHWPerfFTraceGPUEnqueueEvent(psRenderContext->psDeviceNode->pvDevice,
ui32FWCtx, ui32JobId, RGX_HWPERF_KICK_TYPE_TA3D);
#endif
}
if (ui323DCmdCount)
{
RGXFWIF_KCCB_CMD s3DKCCBCmd;
/* Construct the kernel 3D CCB command. */
s3DKCCBCmd.eCmdType = RGXFWIF_KCCB_CMD_KICK;
s3DKCCBCmd.uCmdData.sCmdKickData.psContext = FWCommonContextGetFWAddress(psRenderContext->s3DData.psServerCommonContext);
s3DKCCBCmd.uCmdData.sCmdKickData.ui32CWoffUpdate = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(psRenderContext->s3DData.psServerCommonContext));
/* Add the Workload data into the KCCB kick */
s3DKCCBCmd.uCmdData.sCmdKickData.sWorkloadDataFWAddress.ui32Addr = 0;
s3DKCCBCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset = 0;
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
/* Store the offset to the CCCB command header so that it can be
* referenced when the KCCB command reaches the FW
*/
s3DKCCBCmd.uCmdData.sCmdKickData.ui32WorkEstCmdHeaderOffset = ui323DCommandOffset + ui323DCmdHeaderOffset + ui323DFullRenderCommandOffset;
#endif
if(bCommitRefCounts3D)
{
AttachKickResourcesCleanupCtls((PRGXFWIF_CLEANUP_CTL *) &s3DKCCBCmd.uCmdData.sCmdKickData.apsCleanupCtl,
&s3DKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl,
RGXFWIF_DM_3D,
bKick3D,
psRTDataCleanup,
psZBuffer,
psSBuffer);
*pbCommittedRefCounts3D = IMG_TRUE;
}
else
{
s3DKCCBCmd.uCmdData.sCmdKickData.ui32NumCleanupCtl = 0;
}
HTBLOGK(HTB_SF_MAIN_KICK_3D,
s3DKCCBCmd.uCmdData.sCmdKickData.psContext,
ui323DCmdOffset);
LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US)
{
eError2 = RGXScheduleCommand(psRenderContext->psDeviceNode->pvDevice,
RGXFWIF_DM_3D,
&s3DKCCBCmd,
sizeof(s3DKCCBCmd),
ui32ClientCacheOpSeqNum,
ui32PDumpFlags);
if (eError2 != PVRSRV_ERROR_RETRY)
{
break;
}
OSWaitus(MAX_HW_TIME_US/WAIT_TRY_COUNT);
} END_LOOP_UNTIL_TIMEOUT();
}
/*
* Now check eError (which may have returned an error from our earlier calls
* to RGXCmdHelperAcquireCmdCCB) - we needed to process any flush command first
* so we check it now...
*/
if (eError != PVRSRV_OK )
{
goto fail_3dacquirecmd;
}
#if defined(SUPPORT_NATIVE_FENCE_SYNC)
if (i32UpdateTimelineFD >= 0)
{
/* If we get here, this should never fail. Hitting that likely implies
* a code error above */
i32UpdateFenceFD = pvr_sync_get_update_fd(psFDData);
if (i32UpdateFenceFD < 0)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to get install update sync fd",
__FUNCTION__));
/* If we fail here, we cannot rollback the syncs as the hw already
* has references to resources they may be protecting in the kick
* so fallthrough */
eError = PVRSRV_ERROR_INVALID_PARAMS;
goto fail_3dacquirecmd;
}
}
#if defined(NO_HARDWARE)
pvr_sync_nohw_complete_fences(psFDData);
#endif
pvr_sync_free_append_fences_data(psFDData);
#endif
#if defined(SUPPORT_BUFFER_SYNC)
if (psAppendData)
{
pvr_buffer_sync_append_finish(psAppendData);
}
#endif
*pi32UpdateFenceFD = i32UpdateFenceFD;
return PVRSRV_OK;
fail_3dacquirecmd:
fail_3dcmdinit:
fail_prcmdinit:
fail_prfencecmdinit:
fail_taacquirecmd:
fail_tacmdinit:
#if defined(SUPPORT_NATIVE_FENCE_SYNC)
pvr_sync_rollback_append_fences(psFDData);
pvr_sync_free_append_fences_data(psFDData);
fail_fdsync:
#endif
#if defined(SUPPORT_BUFFER_SYNC)
pvr_buffer_sync_append_abort(psAppendData);
fail_sync_append:
#endif
err_pr_fence_address:
err_populate_sync_addr_list:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
PVRSRV_ERROR PVRSRVRGXSetRenderContextPriorityKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE * psDeviceNode,
RGX_SERVER_RENDER_CONTEXT *psRenderContext,
IMG_UINT32 ui32Priority)
{
PVRSRV_ERROR eError;
PVR_UNREFERENCED_PARAMETER(psDeviceNode);
if (psRenderContext->sTAData.ui32Priority != ui32Priority)
{
eError = ContextSetPriority(psRenderContext->sTAData.psServerCommonContext,
psConnection,
psRenderContext->psDeviceNode->pvDevice,
ui32Priority,
RGXFWIF_DM_TA);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to set the priority of the TA part of the rendercontext (%s)", __FUNCTION__, PVRSRVGetErrorStringKM(eError)));
goto fail_tacontext;
}
psRenderContext->sTAData.ui32Priority = ui32Priority;
}
if (psRenderContext->s3DData.ui32Priority != ui32Priority)
{
eError = ContextSetPriority(psRenderContext->s3DData.psServerCommonContext,
psConnection,
psRenderContext->psDeviceNode->pvDevice,
ui32Priority,
RGXFWIF_DM_3D);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to set the priority of the 3D part of the rendercontext (%s)", __FUNCTION__, PVRSRVGetErrorStringKM(eError)));
goto fail_3dcontext;
}
psRenderContext->s3DData.ui32Priority = ui32Priority;
}
return PVRSRV_OK;
fail_3dcontext:
fail_tacontext:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
/*
* PVRSRVRGXGetLastRenderContextResetReasonKM
*/
PVRSRV_ERROR PVRSRVRGXGetLastRenderContextResetReasonKM(RGX_SERVER_RENDER_CONTEXT *psRenderContext,
IMG_UINT32 *peLastResetReason,
IMG_UINT32 *pui32LastResetJobRef)
{
RGX_SERVER_RC_TA_DATA *psRenderCtxTAData;
RGX_SERVER_RC_3D_DATA *psRenderCtx3DData;
RGX_SERVER_COMMON_CONTEXT *psCurrentServerTACommonCtx, *psCurrentServer3DCommonCtx;
RGXFWIF_CONTEXT_RESET_REASON eLastTAResetReason, eLast3DResetReason;
IMG_UINT32 ui32LastTAResetJobRef, ui32Last3DResetJobRef;
PVR_ASSERT(psRenderContext != NULL);
PVR_ASSERT(peLastResetReason != NULL);
PVR_ASSERT(pui32LastResetJobRef != NULL);
psRenderCtxTAData = &(psRenderContext->sTAData);
psCurrentServerTACommonCtx = psRenderCtxTAData->psServerCommonContext;
psRenderCtx3DData = &(psRenderContext->s3DData);
psCurrentServer3DCommonCtx = psRenderCtx3DData->psServerCommonContext;
/* Get the last reset reasons from both the TA and 3D so they are reset... */
eLastTAResetReason = FWCommonContextGetLastResetReason(psCurrentServerTACommonCtx, &ui32LastTAResetJobRef);
eLast3DResetReason = FWCommonContextGetLastResetReason(psCurrentServer3DCommonCtx, &ui32Last3DResetJobRef);
/* Combine the reset reason from TA and 3D into one... */
*peLastResetReason = (IMG_UINT32) eLast3DResetReason;
*pui32LastResetJobRef = ui32Last3DResetJobRef;
if (eLast3DResetReason == RGXFWIF_CONTEXT_RESET_REASON_NONE ||
((eLast3DResetReason == RGXFWIF_CONTEXT_RESET_REASON_INNOCENT_LOCKUP ||
eLast3DResetReason == RGXFWIF_CONTEXT_RESET_REASON_INNOCENT_OVERRUNING) &&
(eLastTAResetReason == RGXFWIF_CONTEXT_RESET_REASON_GUILTY_LOCKUP ||
eLastTAResetReason == RGXFWIF_CONTEXT_RESET_REASON_GUILTY_OVERRUNING)))
{
*peLastResetReason = eLastTAResetReason;
*pui32LastResetJobRef = ui32LastTAResetJobRef;
}
return PVRSRV_OK;
}
/*
* PVRSRVRGXGetPartialRenderCountKM
*/
PVRSRV_ERROR PVRSRVRGXGetPartialRenderCountKM(DEVMEM_MEMDESC *psHWRTDataMemDesc,
IMG_UINT32 *pui32NumPartialRenders)
{
RGXFWIF_HWRTDATA *psHWRTData;
PVRSRV_ERROR eError;
eError = DevmemAcquireCpuVirtAddr(psHWRTDataMemDesc, (void **)&psHWRTData);
if (eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "PVRSRVRGXGetPartialRenderCountKM: Failed to map Firmware Render Target Data (%u)", eError));
return eError;
}
*pui32NumPartialRenders = psHWRTData->ui32NumPartialRenders;
DevmemReleaseCpuVirtAddr(psHWRTDataMemDesc);
return PVRSRV_OK;
}
void CheckForStalledRenderCtxt(PVRSRV_RGXDEV_INFO *psDevInfo,
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
void *pvDumpDebugFile)
{
DLLIST_NODE *psNode, *psNext;
OSWRLockAcquireRead(psDevInfo->hRenderCtxListLock);
dllist_foreach_node(&psDevInfo->sRenderCtxtListHead, psNode, psNext)
{
RGX_SERVER_RENDER_CONTEXT *psCurrentServerRenderCtx =
IMG_CONTAINER_OF(psNode, RGX_SERVER_RENDER_CONTEXT, sListNode);
DumpStalledFWCommonContext(psCurrentServerRenderCtx->sTAData.psServerCommonContext,
pfnDumpDebugPrintf, pvDumpDebugFile);
DumpStalledFWCommonContext(psCurrentServerRenderCtx->s3DData.psServerCommonContext,
pfnDumpDebugPrintf, pvDumpDebugFile);
}
OSWRLockReleaseRead(psDevInfo->hRenderCtxListLock);
}
IMG_UINT32 CheckForStalledClientRenderCtxt(PVRSRV_RGXDEV_INFO *psDevInfo)
{
DLLIST_NODE *psNode, *psNext;
IMG_UINT32 ui32ContextBitMask = 0;
OSWRLockAcquireRead(psDevInfo->hRenderCtxListLock);
dllist_foreach_node(&psDevInfo->sRenderCtxtListHead, psNode, psNext)
{
RGX_SERVER_RENDER_CONTEXT *psCurrentServerRenderCtx =
IMG_CONTAINER_OF(psNode, RGX_SERVER_RENDER_CONTEXT, sListNode);
if(NULL != psCurrentServerRenderCtx->sTAData.psServerCommonContext)
{
if (CheckStalledClientCommonContext(psCurrentServerRenderCtx->sTAData.psServerCommonContext, RGX_KICK_TYPE_DM_TA) == PVRSRV_ERROR_CCCB_STALLED)
{
ui32ContextBitMask |= RGX_KICK_TYPE_DM_TA;
}
}
if(NULL != psCurrentServerRenderCtx->s3DData.psServerCommonContext)
{
if (CheckStalledClientCommonContext(psCurrentServerRenderCtx->s3DData.psServerCommonContext, RGX_KICK_TYPE_DM_3D) == PVRSRV_ERROR_CCCB_STALLED)
{
ui32ContextBitMask |= RGX_KICK_TYPE_DM_3D;
}
}
}
OSWRLockReleaseRead(psDevInfo->hRenderCtxListLock);
return ui32ContextBitMask;
}
/******************************************************************************
End of file (rgxta3d.c)
******************************************************************************/