/*************************************************************************/ /*!
|
@File
|
@Title RGX CCB routines
|
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
|
@Description RGX CCB routines
|
@License Dual MIT/GPLv2
|
|
The contents of this file are subject to the MIT license as set out below.
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
of this software and associated documentation files (the "Software"), to deal
|
in the Software without restriction, including without limitation the rights
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
copies of the Software, and to permit persons to whom the Software is
|
furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in
|
all copies or substantial portions of the Software.
|
|
Alternatively, the contents of this file may be used under the terms of
|
the GNU General Public License Version 2 ("GPL") in which case the provisions
|
of GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms of
|
GPL, and not to allow others to use your version of this file under the terms
|
of the MIT license, indicate your decision by deleting the provisions above
|
and replace them with the notice and other provisions required by GPL as set
|
out in the file called "GPL-COPYING" included in this distribution. If you do
|
not delete the provisions above, a recipient may use your version of this file
|
under the terms of either the MIT license or GPL.
|
|
This License is also included in this distribution in the file called
|
"MIT-COPYING".
|
|
EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
|
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
*/ /**************************************************************************/
|
|
#include "pvr_debug.h"
|
#include "rgxdevice.h"
|
#include "pdump_km.h"
|
#include "allocmem.h"
|
#include "devicemem.h"
|
#include "rgxfwutils.h"
|
#include "osfunc.h"
|
#include "rgxccb.h"
|
#include "rgx_memallocflags.h"
|
#include "devicemem_pdump.h"
|
#include "dllist.h"
|
#include "rgx_fwif_shared.h"
|
#include "rgxtimerquery.h"
|
#if defined(LINUX)
|
#include "trace_events.h"
|
#endif
|
#include "rgxutils.h"
|
|
/*
|
* Defines the number of fence updates to record so that future fences in the CCB
|
* can be checked to see if they are already known to be satisfied.
|
*/
|
#define RGX_CCCB_FENCE_UPDATE_LIST_SIZE (32)
|
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
|
#define PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_THRESHOLD 0x1
|
#define PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_ACQUIRE_FAILED 0x2
|
|
typedef struct _RGX_CLIENT_CCB_UTILISATION_
|
{
|
/* the threshold in bytes.
|
* when the CCB utilisation hits the threshold then we will print
|
* a warning message.
|
*/
|
IMG_UINT32 ui32ThresholdBytes;
|
/* Maximum cCCB usage at some point in time */
|
IMG_UINT32 ui32HighWaterMark;
|
/* keep track of the warnings already printed.
|
* bit mask of PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_xyz
|
*/
|
IMG_UINT32 ui32Warnings;
|
} RGX_CLIENT_CCB_UTILISATION;
|
|
#endif /* PVRSRV_ENABLE_CCCB_UTILISATION_INFO */
|
|
struct _RGX_CLIENT_CCB_ {
|
volatile RGXFWIF_CCCB_CTL *psClientCCBCtrl; /*!< CPU mapping of the CCB control structure used by the fw */
|
IMG_UINT8 *pui8ClientCCB; /*!< CPU mapping of the CCB */
|
DEVMEM_MEMDESC *psClientCCBMemDesc; /*!< MemDesc for the CCB */
|
DEVMEM_MEMDESC *psClientCCBCtrlMemDesc; /*!< MemDesc for the CCB control */
|
IMG_UINT32 ui32HostWriteOffset; /*!< CCB write offset from the driver side */
|
IMG_UINT32 ui32LastPDumpWriteOffset; /*!< CCB write offset from the last time we submitted a command in capture range */
|
IMG_UINT32 ui32LastROff; /*!< Last CCB Read offset to help detect any CCB wedge */
|
IMG_UINT32 ui32LastWOff; /*!< Last CCB Write offset to help detect any CCB wedge */
|
IMG_UINT32 ui32ByteCount; /*!< Count of the number of bytes written to CCCB */
|
IMG_UINT32 ui32LastByteCount; /*!< Last value of ui32ByteCount to help detect any CCB wedge */
|
IMG_UINT32 ui32Size; /*!< Size of the CCB */
|
DLLIST_NODE sNode; /*!< Node used to store this CCB on the per connection list */
|
PDUMP_CONNECTION_DATA *psPDumpConnectionData; /*!< Pointer to the per connection data in which we reside */
|
void *hTransition; /*!< Handle for Transition callback */
|
IMG_CHAR szName[MAX_CLIENT_CCB_NAME]; /*!< Name of this client CCB */
|
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext; /*!< Parent server common context that this CCB belongs to */
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
RGX_CCB_REQUESTOR_TYPE eRGXCCBRequestor;
|
RGX_CLIENT_CCB_UTILISATION sUtilisation; /*!< CCB utilisation data */
|
#endif
|
#if defined(DEBUG)
|
IMG_UINT32 ui32UpdateEntries; /*!< Number of Fence Updates in asFenceUpdateList */
|
RGXFWIF_UFO asFenceUpdateList[RGX_CCCB_FENCE_UPDATE_LIST_SIZE]; /*!< List of recent updates written in this CCB */
|
#endif
|
};
|
|
|
/* Forms a table, with array of strings for each requestor type (listed in RGX_CCB_REQUESTORS X macro), to be used for
|
DevMemAllocation comments and PDump comments. Each tuple in the table consists of 3 strings:
|
{ "FwClientCCB:" <requestor_name>, "FwClientCCBControl:" <requestor_name>, <requestor_name> },
|
The first string being used as comment when allocating ClientCCB for the given requestor, the second for CCBControl
|
structure, and the 3rd one for use in PDUMP comments. The number of tuples in the table must adhere to the following
|
build assert. */
|
IMG_CHAR *const aszCCBRequestors[][3] =
|
{
|
#define REQUESTOR_STRING(prefix,req) #prefix ":" #req
|
#define FORM_REQUESTOR_TUPLE(req) { REQUESTOR_STRING(FwClientCCB,req), REQUESTOR_STRING(FwClientCCBControl,req), #req },
|
RGX_CCB_REQUESTORS(FORM_REQUESTOR_TUPLE)
|
#undef FORM_REQUESTOR_TUPLE
|
};
|
/* The number of tuples in the above table is always equal to those provided in the RGX_CCB_REQUESTORS X macro list.
|
In an event of change in value of DPX_MAX_RAY_CONTEXTS to say 'n', appropriate entry/entries up to FC[n-1] must be added to
|
the RGX_CCB_REQUESTORS list. */
|
static_assert((sizeof(aszCCBRequestors)/(3*sizeof(aszCCBRequestors[0][0]))) == (REQ_TYPE_FIXED_COUNT + DPX_MAX_RAY_CONTEXTS + 1),
|
"Mismatch between aszCCBRequestors table and DPX_MAX_RAY_CONTEXTS");
|
|
IMG_EXPORT PVRSRV_ERROR RGXCCBPDumpDrainCCB(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32PDumpFlags)
|
{
|
|
PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags,
|
"cCCB(%s@%p): Draining CCB rgxfw_roff == woff (%d)",
|
psClientCCB->szName,
|
psClientCCB,
|
psClientCCB->ui32LastPDumpWriteOffset);
|
|
return DevmemPDumpDevmemPol32(psClientCCB->psClientCCBCtrlMemDesc,
|
offsetof(RGXFWIF_CCCB_CTL, ui32ReadOffset),
|
psClientCCB->ui32LastPDumpWriteOffset,
|
0xffffffff,
|
PDUMP_POLL_OPERATOR_EQUAL,
|
ui32PDumpFlags);
|
}
|
|
static PVRSRV_ERROR _RGXCCBPDumpTransition(void **pvData, IMG_BOOL bInto, IMG_UINT32 ui32PDumpFlags)
|
{
|
RGX_CLIENT_CCB *psClientCCB = (RGX_CLIENT_CCB *) pvData;
|
|
/*
|
We're about to Transition into capture range and we've submitted
|
new commands since the last time we entered capture range so drain
|
the CCB as required
|
*/
|
if (bInto)
|
{
|
volatile RGXFWIF_CCCB_CTL *psCCBCtl = psClientCCB->psClientCCBCtrl;
|
PVRSRV_ERROR eError;
|
|
/*
|
Wait for the FW to catch up (retry will get pushed back out services
|
client where we wait on the event object and try again later)
|
*/
|
if (psClientCCB->psClientCCBCtrl->ui32ReadOffset != psClientCCB->ui32HostWriteOffset)
|
{
|
return PVRSRV_ERROR_RETRY;
|
}
|
|
/*
|
We drain whenever capture range is entered. Even if no commands
|
have been issued while where out of capture range we have to wait for
|
operations that we might have issued in the last capture range
|
to finish so the sync prim update that will happen after all the
|
PDumpTransition callbacks have been called doesn't clobber syncs
|
which the FW is currently working on.
|
Although this is suboptimal, while out of capture range for every
|
persistent operation we serialise the PDump script processing and
|
the FW, there is no easy solution.
|
Not all modules that work on syncs register a PDumpTransition and
|
thus we have no way of knowing if we can skip drain and the sync
|
prim dump or not.
|
*/
|
|
eError = RGXCCBPDumpDrainCCB(psClientCCB, ui32PDumpFlags);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_WARNING, "_RGXCCBPDumpTransition: problem pdumping POL for cCCBCtl (%d)", eError));
|
}
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
/*
|
If new command(s) have been written out of capture range then we
|
need to fast forward past uncaptured operations.
|
*/
|
if (psClientCCB->ui32LastPDumpWriteOffset != psClientCCB->ui32HostWriteOffset)
|
{
|
/*
|
There are commands that where not captured so after the
|
simulation drain (above) we also need to fast-forward pass
|
those commands so the FW can start with the 1st command
|
which is in the new capture range
|
*/
|
psCCBCtl->ui32ReadOffset = psClientCCB->ui32HostWriteOffset;
|
psCCBCtl->ui32DepOffset = psClientCCB->ui32HostWriteOffset;
|
psCCBCtl->ui32WriteOffset = psClientCCB->ui32HostWriteOffset;
|
|
PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags,
|
"cCCB(%s@%p): Fast-forward from %d to %d",
|
psClientCCB->szName,
|
psClientCCB,
|
psClientCCB->ui32LastPDumpWriteOffset,
|
psClientCCB->ui32HostWriteOffset);
|
|
DevmemPDumpLoadMem(psClientCCB->psClientCCBCtrlMemDesc,
|
0,
|
sizeof(RGXFWIF_CCCB_CTL),
|
ui32PDumpFlags);
|
|
/*
|
Although we've entered capture range we might not do any work
|
on this CCB so update the ui32LastPDumpWriteOffset to reflect
|
where we got to for next so we start the drain from where we
|
got to last time
|
*/
|
psClientCCB->ui32LastPDumpWriteOffset = psClientCCB->ui32HostWriteOffset;
|
}
|
}
|
return PVRSRV_OK;
|
}
|
|
#if defined (PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
|
static INLINE void _RGXInitCCBUtilisation(RGX_CLIENT_CCB *psClientCCB)
|
{
|
psClientCCB->sUtilisation.ui32HighWaterMark = 0; /* initialize ui32HighWaterMark level to zero */
|
psClientCCB->sUtilisation.ui32ThresholdBytes = (psClientCCB->ui32Size *
|
PVRSRV_ENABLE_CCCB_UTILISATION_INFO_THRESHOLD) / 100;
|
psClientCCB->sUtilisation.ui32Warnings = 0;
|
}
|
|
static INLINE void _RGXPrintCCBUtilisationWarning(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32WarningType,
|
IMG_UINT32 ui32CmdSize)
|
{
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO_VERBOSE)
|
if(ui32WarningType == PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_ACQUIRE_FAILED)
|
{
|
PVR_LOG(("Failed to acquire CCB space for %u byte command:", ui32CmdSize));
|
}
|
|
PVR_LOG(("%s: Client CCB (%s) watermark (%u) hit %d%% of its allocation size (%u)",
|
__FUNCTION__,
|
psClientCCB->szName,
|
psClientCCB->sUtilisation.ui32HighWaterMark,
|
psClientCCB->sUtilisation.ui32HighWaterMark * 100 / psClientCCB->ui32Size,
|
psClientCCB->ui32Size));
|
#else
|
PVR_UNREFERENCED_PARAMETER(ui32WarningType);
|
PVR_UNREFERENCED_PARAMETER(ui32CmdSize);
|
|
PVR_LOG(("GPU %s command buffer usage high (%u). This is not an error but the application may not run optimally.",
|
aszCCBRequestors[psClientCCB->eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
psClientCCB->sUtilisation.ui32HighWaterMark * 100 / psClientCCB->ui32Size));
|
#endif
|
}
|
|
static INLINE void _RGXCCBUtilisationEvent(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32WarningType,
|
IMG_UINT32 ui32CmdSize)
|
{
|
/* in VERBOSE mode we will print a message for each different
|
* event type as they happen.
|
* but by default we will only issue one message
|
*/
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO_VERBOSE)
|
if(!(psClientCCB->sUtilisation.ui32Warnings & ui32WarningType))
|
#else
|
if(!psClientCCB->sUtilisation.ui32Warnings)
|
#endif
|
{
|
_RGXPrintCCBUtilisationWarning(psClientCCB,
|
ui32WarningType,
|
ui32CmdSize);
|
/* record that we have issued a warning of this type */
|
psClientCCB->sUtilisation.ui32Warnings |= ui32WarningType;
|
}
|
}
|
|
/* Check the current CCB utilisation. Print a one-time warning message if it is above the
|
* specified threshold
|
*/
|
static INLINE void _RGXCheckCCBUtilisation(RGX_CLIENT_CCB *psClientCCB)
|
{
|
/* Print a warning message if the cCCB watermark is above the threshold value */
|
if(psClientCCB->sUtilisation.ui32HighWaterMark >= psClientCCB->sUtilisation.ui32ThresholdBytes)
|
{
|
_RGXCCBUtilisationEvent(psClientCCB,
|
PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_THRESHOLD,
|
0);
|
}
|
}
|
|
/* Update the cCCB high watermark level if necessary */
|
static void _RGXUpdateCCBUtilisation(RGX_CLIENT_CCB *psClientCCB)
|
{
|
IMG_UINT32 ui32FreeSpace, ui32MemCurrentUsage;
|
|
ui32FreeSpace = GET_CCB_SPACE(psClientCCB->ui32HostWriteOffset,
|
psClientCCB->psClientCCBCtrl->ui32ReadOffset,
|
psClientCCB->ui32Size);
|
ui32MemCurrentUsage = psClientCCB->ui32Size - ui32FreeSpace;
|
|
if (ui32MemCurrentUsage > psClientCCB->sUtilisation.ui32HighWaterMark)
|
{
|
psClientCCB->sUtilisation.ui32HighWaterMark = ui32MemCurrentUsage;
|
|
/* The high water mark has increased. Check if it is above the
|
* threshold so we can print a warning if necessary.
|
*/
|
_RGXCheckCCBUtilisation(psClientCCB);
|
}
|
}
|
|
#endif /* PVRSRV_ENABLE_CCCB_UTILISATION_INFO */
|
|
PVRSRV_ERROR RGXCreateCCB(PVRSRV_RGXDEV_INFO *psDevInfo,
|
IMG_UINT32 ui32CCBSizeLog2,
|
CONNECTION_DATA *psConnectionData,
|
RGX_CCB_REQUESTOR_TYPE eRGXCCBRequestor,
|
RGX_SERVER_COMMON_CONTEXT *psServerCommonContext,
|
RGX_CLIENT_CCB **ppsClientCCB,
|
DEVMEM_MEMDESC **ppsClientCCBMemDesc,
|
DEVMEM_MEMDESC **ppsClientCCBCtrlMemDesc)
|
{
|
PVRSRV_ERROR eError;
|
DEVMEM_FLAGS_T uiClientCCBMemAllocFlags, uiClientCCBCtlMemAllocFlags;
|
IMG_UINT32 ui32AllocSize = (1U << ui32CCBSizeLog2);
|
RGX_CLIENT_CCB *psClientCCB;
|
|
/* All client CCBs should be at-least of the "minimum" size declared by the API */
|
PVR_ASSERT (ui32CCBSizeLog2 >= MIN_SAFE_CCB_SIZE_LOG2);
|
|
psClientCCB = OSAllocMem(sizeof(*psClientCCB));
|
if (psClientCCB == NULL)
|
{
|
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
|
goto fail_alloc;
|
}
|
psClientCCB->psServerCommonContext = psServerCommonContext;
|
|
uiClientCCBMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(FIRMWARE_CACHED) |
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE |
|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
|
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE;
|
|
uiClientCCBCtlMemAllocFlags = PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
PVRSRV_MEMALLOCFLAG_UNCACHED |
|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
|
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE;
|
|
PDUMPCOMMENT("Allocate RGXFW cCCB");
|
eError = DevmemFwAllocate(psDevInfo,
|
ui32AllocSize,
|
uiClientCCBMemAllocFlags,
|
aszCCBRequestors[eRGXCCBRequestor][REQ_RGX_FW_CLIENT_CCB_STRING],
|
&psClientCCB->psClientCCBMemDesc);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateCCBKM: Failed to allocate RGX client CCB (%s)",
|
PVRSRVGetErrorStringKM(eError)));
|
goto fail_alloc_ccb;
|
}
|
|
|
eError = DevmemAcquireCpuVirtAddr(psClientCCB->psClientCCBMemDesc,
|
(void **) &psClientCCB->pui8ClientCCB);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateCCBKM: Failed to map RGX client CCB (%s)",
|
PVRSRVGetErrorStringKM(eError)));
|
goto fail_map_ccb;
|
}
|
|
PDUMPCOMMENT("Allocate RGXFW cCCB control");
|
eError = DevmemFwAllocate(psDevInfo,
|
sizeof(RGXFWIF_CCCB_CTL),
|
uiClientCCBCtlMemAllocFlags,
|
aszCCBRequestors[eRGXCCBRequestor][REQ_RGX_FW_CLIENT_CCB_CONTROL_STRING],
|
&psClientCCB->psClientCCBCtrlMemDesc);
|
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateCCBKM: Failed to allocate RGX client CCB control (%s)",
|
PVRSRVGetErrorStringKM(eError)));
|
goto fail_alloc_ccbctrl;
|
}
|
|
|
eError = DevmemAcquireCpuVirtAddr(psClientCCB->psClientCCBCtrlMemDesc,
|
(void **) &psClientCCB->psClientCCBCtrl);
|
if (eError != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR,"PVRSRVRGXCreateCCBKM: Failed to map RGX client CCB (%s)",
|
PVRSRVGetErrorStringKM(eError)));
|
goto fail_map_ccbctrl;
|
}
|
|
psClientCCB->psClientCCBCtrl->ui32WriteOffset = 0;
|
psClientCCB->psClientCCBCtrl->ui32ReadOffset = 0;
|
psClientCCB->psClientCCBCtrl->ui32DepOffset = 0;
|
psClientCCB->psClientCCBCtrl->ui32WrapMask = ui32AllocSize - 1;
|
OSSNPrintf(psClientCCB->szName, MAX_CLIENT_CCB_NAME, "%s-P%lu-T%lu-%s",
|
aszCCBRequestors[eRGXCCBRequestor][REQ_PDUMP_COMMENT],
|
(unsigned long) OSGetCurrentClientProcessIDKM(),
|
(unsigned long) OSGetCurrentClientThreadIDKM(),
|
OSGetCurrentClientProcessNameKM());
|
|
PDUMPCOMMENT("cCCB control");
|
DevmemPDumpLoadMem(psClientCCB->psClientCCBCtrlMemDesc,
|
0,
|
sizeof(RGXFWIF_CCCB_CTL),
|
PDUMP_FLAGS_CONTINUOUS);
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
psClientCCB->ui32HostWriteOffset = 0;
|
psClientCCB->ui32LastPDumpWriteOffset = 0;
|
psClientCCB->ui32Size = ui32AllocSize;
|
psClientCCB->ui32LastROff = ui32AllocSize - 1;
|
psClientCCB->ui32ByteCount = 0;
|
psClientCCB->ui32LastByteCount = 0;
|
|
#if defined(DEBUG)
|
psClientCCB->ui32UpdateEntries = 0;
|
#endif
|
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
_RGXInitCCBUtilisation(psClientCCB);
|
psClientCCB->eRGXCCBRequestor = eRGXCCBRequestor;
|
#endif
|
eError = PDumpRegisterTransitionCallback(psConnectionData->psPDumpConnectionData,
|
_RGXCCBPDumpTransition,
|
psClientCCB,
|
&psClientCCB->hTransition);
|
if (eError != PVRSRV_OK)
|
{
|
goto fail_pdumpreg;
|
}
|
|
/*
|
* Note:
|
* Save the PDump specific structure, which is ref counted unlike
|
* the connection data, to ensure it's not freed too early
|
*/
|
psClientCCB->psPDumpConnectionData = psConnectionData->psPDumpConnectionData;
|
PDUMPCOMMENT("New RGXFW cCCB(%s@%p) created",
|
psClientCCB->szName,
|
psClientCCB);
|
|
*ppsClientCCB = psClientCCB;
|
*ppsClientCCBMemDesc = psClientCCB->psClientCCBMemDesc;
|
*ppsClientCCBCtrlMemDesc = psClientCCB->psClientCCBCtrlMemDesc;
|
return PVRSRV_OK;
|
|
fail_pdumpreg:
|
DevmemReleaseCpuVirtAddr(psClientCCB->psClientCCBCtrlMemDesc);
|
fail_map_ccbctrl:
|
DevmemFwFree(psDevInfo, psClientCCB->psClientCCBCtrlMemDesc);
|
fail_alloc_ccbctrl:
|
DevmemReleaseCpuVirtAddr(psClientCCB->psClientCCBMemDesc);
|
fail_map_ccb:
|
DevmemFwFree(psDevInfo, psClientCCB->psClientCCBMemDesc);
|
fail_alloc_ccb:
|
OSFreeMem(psClientCCB);
|
fail_alloc:
|
PVR_ASSERT(eError != PVRSRV_OK);
|
return eError;
|
}
|
|
void RGXDestroyCCB(PVRSRV_RGXDEV_INFO *psDevInfo, RGX_CLIENT_CCB *psClientCCB)
|
{
|
PDumpUnregisterTransitionCallback(psClientCCB->hTransition);
|
DevmemReleaseCpuVirtAddr(psClientCCB->psClientCCBCtrlMemDesc);
|
DevmemFwFree(psDevInfo, psClientCCB->psClientCCBCtrlMemDesc);
|
DevmemReleaseCpuVirtAddr(psClientCCB->psClientCCBMemDesc);
|
DevmemFwFree(psDevInfo, psClientCCB->psClientCCBMemDesc);
|
OSFreeMem(psClientCCB);
|
}
|
|
|
/******************************************************************************
|
FUNCTION : RGXAcquireCCB
|
|
PURPOSE : Obtains access to write some commands to a CCB
|
|
PARAMETERS : psClientCCB - The client CCB
|
ui32CmdSize - How much space is required
|
ppvBufferSpace - Pointer to space in the buffer
|
ui32PDumpFlags - Should this be PDump continuous?
|
|
RETURNS : PVRSRV_ERROR
|
******************************************************************************/
|
IMG_INTERNAL PVRSRV_ERROR RGXAcquireCCB(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32CmdSize,
|
void **ppvBufferSpace,
|
IMG_UINT32 ui32PDumpFlags)
|
{
|
PVRSRV_ERROR eError;
|
IMG_BOOL bInCaptureRange;
|
IMG_BOOL bPdumpEnabled;
|
|
PDumpIsCaptureFrameKM(&bInCaptureRange);
|
bPdumpEnabled = (bInCaptureRange || PDUMP_IS_CONTINUOUS(ui32PDumpFlags));
|
|
/*
|
PDumpSetFrame will detect as we Transition into capture range for
|
frame based data but if we are PDumping continuous data then we
|
need to inform the PDump layer ourselves
|
*/
|
if (PDUMP_IS_CONTINUOUS(ui32PDumpFlags) && !bInCaptureRange)
|
{
|
eError = PDumpTransition(psClientCCB->psPDumpConnectionData, IMG_TRUE, PDUMP_FLAGS_CONTINUOUS);
|
if (eError != PVRSRV_OK)
|
{
|
return eError;
|
}
|
}
|
|
/* Check that the CCB can hold this command + padding */
|
if ((ui32CmdSize + PADDING_COMMAND_SIZE + 1) > psClientCCB->ui32Size)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "Command size (%d bytes) too big for CCB (%d bytes)",
|
ui32CmdSize, psClientCCB->ui32Size));
|
return PVRSRV_ERROR_CMD_TOO_BIG;
|
}
|
|
/*
|
Check we don't overflow the end of the buffer and make sure we have
|
enough space for the padding command. We don't have enough space (including the
|
minimum amount for the padding command) we will need to make sure we insert a
|
padding command now and wrap before adding the main command.
|
*/
|
if ((psClientCCB->ui32HostWriteOffset + ui32CmdSize + PADDING_COMMAND_SIZE) <= psClientCCB->ui32Size)
|
{
|
/*
|
The command can fit without wrapping...
|
*/
|
IMG_UINT32 ui32FreeSpace;
|
|
#if defined(PDUMP)
|
/* Wait for sufficient CCB space to become available */
|
PDUMPCOMMENTWITHFLAGS(0, "Wait for %u bytes to become available according cCCB Ctl (woff=%x) for %s",
|
ui32CmdSize, psClientCCB->ui32HostWriteOffset,
|
psClientCCB->szName);
|
DevmemPDumpCBP(psClientCCB->psClientCCBCtrlMemDesc,
|
offsetof(RGXFWIF_CCCB_CTL, ui32ReadOffset),
|
psClientCCB->ui32HostWriteOffset,
|
ui32CmdSize,
|
psClientCCB->ui32Size);
|
#endif
|
|
ui32FreeSpace = GET_CCB_SPACE(psClientCCB->ui32HostWriteOffset,
|
psClientCCB->psClientCCBCtrl->ui32ReadOffset,
|
psClientCCB->ui32Size);
|
|
/* Don't allow all the space to be used */
|
if (ui32FreeSpace > ui32CmdSize)
|
{
|
*ppvBufferSpace = (void *) (psClientCCB->pui8ClientCCB +
|
psClientCCB->ui32HostWriteOffset);
|
return PVRSRV_OK;
|
}
|
|
goto e_retry;
|
}
|
else
|
{
|
/*
|
We're at the end of the buffer without enough contiguous space.
|
The command cannot fit without wrapping, we need to insert a
|
padding command and wrap. We need to do this in one go otherwise
|
we would be leaving unflushed commands and forcing the client to
|
deal with flushing the padding command but not the command they
|
wanted to write. Therefore we either do all or nothing.
|
*/
|
RGXFWIF_CCB_CMD_HEADER *psHeader;
|
IMG_UINT32 ui32FreeSpace;
|
IMG_UINT32 ui32Remain = psClientCCB->ui32Size - psClientCCB->ui32HostWriteOffset;
|
|
#if defined(PDUMP)
|
/* Wait for sufficient CCB space to become available */
|
PDUMPCOMMENTWITHFLAGS(0, "Wait for %u bytes to become available according cCCB Ctl (woff=%x) for %s",
|
ui32Remain, psClientCCB->ui32HostWriteOffset,
|
psClientCCB->szName);
|
DevmemPDumpCBP(psClientCCB->psClientCCBCtrlMemDesc,
|
offsetof(RGXFWIF_CCCB_CTL, ui32ReadOffset),
|
psClientCCB->ui32HostWriteOffset,
|
ui32Remain,
|
psClientCCB->ui32Size);
|
PDUMPCOMMENTWITHFLAGS(0, "Wait for %u bytes to become available according cCCB Ctl (woff=%x) for %s",
|
ui32CmdSize, 0 /*ui32HostWriteOffset after wrap */,
|
psClientCCB->szName);
|
DevmemPDumpCBP(psClientCCB->psClientCCBCtrlMemDesc,
|
offsetof(RGXFWIF_CCCB_CTL, ui32ReadOffset),
|
0 /*ui32HostWriteOffset after wrap */,
|
ui32CmdSize,
|
psClientCCB->ui32Size);
|
#endif
|
|
ui32FreeSpace = GET_CCB_SPACE(psClientCCB->ui32HostWriteOffset,
|
psClientCCB->psClientCCBCtrl->ui32ReadOffset,
|
psClientCCB->ui32Size);
|
|
/* Don't allow all the space to be used */
|
if (ui32FreeSpace > ui32Remain + ui32CmdSize)
|
{
|
psHeader = (void *) (psClientCCB->pui8ClientCCB + psClientCCB->ui32HostWriteOffset);
|
psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_PADDING;
|
psHeader->ui32CmdSize = ui32Remain - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
|
PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags, "cCCB(%p): Padding cmd %d", psClientCCB, psHeader->ui32CmdSize);
|
if (bPdumpEnabled)
|
{
|
DevmemPDumpLoadMem(psClientCCB->psClientCCBMemDesc,
|
psClientCCB->ui32HostWriteOffset,
|
ui32Remain,
|
ui32PDumpFlags);
|
}
|
|
*ppvBufferSpace = (void *) (psClientCCB->pui8ClientCCB +
|
0 /*ui32HostWriteOffset after wrap */);
|
return PVRSRV_OK;
|
}
|
|
goto e_retry;
|
}
|
e_retry:
|
#if defined(PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
_RGXCCBUtilisationEvent(psClientCCB,
|
PVRSRV_CLIENT_CCCB_UTILISATION_WARNING_ACQUIRE_FAILED,
|
ui32CmdSize);
|
#endif /* PVRSRV_ENABLE_CCCB_UTILISATION_INFO */
|
return PVRSRV_ERROR_RETRY;
|
}
|
|
/******************************************************************************
|
FUNCTION : RGXReleaseCCB
|
|
PURPOSE : Release a CCB that we have been writing to.
|
|
PARAMETERS : psDevData - device data
|
psCCB - the CCB
|
|
RETURNS : None
|
******************************************************************************/
|
IMG_INTERNAL void RGXReleaseCCB(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32CmdSize,
|
IMG_UINT32 ui32PDumpFlags)
|
{
|
IMG_BOOL bInCaptureRange;
|
IMG_BOOL bPdumpEnabled;
|
|
PDumpIsCaptureFrameKM(&bInCaptureRange);
|
bPdumpEnabled = (bInCaptureRange || PDUMP_IS_CONTINUOUS(ui32PDumpFlags));
|
|
/*
|
* If a padding command was needed then we should now move ui32HostWriteOffset
|
* forward. The command has already be dumped (if bPdumpEnabled).
|
*/
|
if ((psClientCCB->ui32HostWriteOffset + ui32CmdSize + PADDING_COMMAND_SIZE) > psClientCCB->ui32Size)
|
{
|
IMG_UINT32 ui32Remain = psClientCCB->ui32Size - psClientCCB->ui32HostWriteOffset;
|
|
UPDATE_CCB_OFFSET(psClientCCB->ui32HostWriteOffset,
|
ui32Remain,
|
psClientCCB->ui32Size);
|
psClientCCB->ui32ByteCount += ui32Remain;
|
}
|
|
/* Dump the CCB data */
|
if (bPdumpEnabled)
|
{
|
DevmemPDumpLoadMem(psClientCCB->psClientCCBMemDesc,
|
psClientCCB->ui32HostWriteOffset,
|
ui32CmdSize,
|
ui32PDumpFlags);
|
}
|
|
/*
|
* Check if there any fences being written that will already be
|
* satisfied by the last written update command in this CCB. At the
|
* same time we can ASSERT that all sync addresses are not NULL.
|
*/
|
#if defined(DEBUG)
|
{
|
IMG_UINT8 *pui8BufferStart = (void *)((uintptr_t)psClientCCB->pui8ClientCCB + psClientCCB->ui32HostWriteOffset);
|
IMG_UINT8 *pui8BufferEnd = (void *)((uintptr_t)psClientCCB->pui8ClientCCB + psClientCCB->ui32HostWriteOffset + ui32CmdSize);
|
IMG_BOOL bMessagePrinted = IMG_FALSE;
|
|
/* Walk through the commands in this section of CCB being released... */
|
while (pui8BufferStart < pui8BufferEnd)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psCmdHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8BufferStart;
|
|
if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_UPDATE)
|
{
|
/* If an UPDATE then record the values incase an adjacent fence uses it. */
|
IMG_UINT32 ui32NumUFOs = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO);
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER));
|
|
psClientCCB->ui32UpdateEntries = 0;
|
while (ui32NumUFOs-- > 0)
|
{
|
PVR_ASSERT(psUFOPtr->puiAddrUFO.ui32Addr != 0);
|
if (psClientCCB->ui32UpdateEntries < RGX_CCCB_FENCE_UPDATE_LIST_SIZE)
|
{
|
psClientCCB->asFenceUpdateList[psClientCCB->ui32UpdateEntries++] = *psUFOPtr++;
|
}
|
}
|
}
|
else if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_FENCE)
|
{
|
/* If a FENCE then check the values against the last UPDATE issued. */
|
IMG_UINT32 ui32NumUFOs = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO);
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER));
|
|
while (ui32NumUFOs-- > 0)
|
{
|
PVR_ASSERT(psUFOPtr->puiAddrUFO.ui32Addr != 0);
|
|
if (bMessagePrinted == IMG_FALSE)
|
{
|
RGXFWIF_UFO *psUpdatePtr = psClientCCB->asFenceUpdateList;
|
IMG_UINT32 ui32UpdateIndex;
|
|
for (ui32UpdateIndex = 0; ui32UpdateIndex < psClientCCB->ui32UpdateEntries; ui32UpdateIndex++)
|
{
|
if (psUFOPtr->puiAddrUFO.ui32Addr == psUpdatePtr->puiAddrUFO.ui32Addr &&
|
psUFOPtr->ui32Value == psUpdatePtr->ui32Value)
|
{
|
PVR_DPF((PVR_DBG_MESSAGE, "Redundant fence check found in cCCB(%p) - 0x%x -> 0x%x",
|
psClientCCB, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value));
|
bMessagePrinted = IMG_TRUE;
|
break;
|
}
|
|
psUpdatePtr++;
|
}
|
}
|
|
psUFOPtr++;
|
}
|
}
|
else if (psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_FENCE_PR ||
|
psCmdHeader->eCmdType == RGXFWIF_CCB_CMD_TYPE_UNFENCED_UPDATE)
|
{
|
/* For all other UFO ops check the UFO address is not NULL. */
|
IMG_UINT32 ui32NumUFOs = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO);
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO*)(pui8BufferStart + sizeof(RGXFWIF_CCB_CMD_HEADER));
|
|
while (ui32NumUFOs-- > 0)
|
{
|
PVR_ASSERT(psUFOPtr->puiAddrUFO.ui32Addr != 0);
|
psUFOPtr++;
|
}
|
}
|
|
/* Move to the next command in this section of CCB being released... */
|
pui8BufferStart += sizeof(RGXFWIF_CCB_CMD_HEADER) + psCmdHeader->ui32CmdSize;
|
}
|
}
|
#endif /* REDUNDANT_SYNCS_DEBUG */
|
|
/*
|
* Update the CCB write offset.
|
*/
|
UPDATE_CCB_OFFSET(psClientCCB->ui32HostWriteOffset,
|
ui32CmdSize,
|
psClientCCB->ui32Size);
|
psClientCCB->ui32ByteCount += ui32CmdSize;
|
|
#if defined (PVRSRV_ENABLE_CCCB_UTILISATION_INFO)
|
_RGXUpdateCCBUtilisation(psClientCCB);
|
#endif
|
/*
|
PDumpSetFrame will detect as we Transition out of capture range for
|
frame based data but if we are PDumping continuous data then we
|
need to inform the PDump layer ourselves
|
*/
|
if (PDUMP_IS_CONTINUOUS(ui32PDumpFlags)&& !bInCaptureRange)
|
{
|
PVRSRV_ERROR eError;
|
|
/* Only Transitioning into capture range can cause an error */
|
eError = PDumpTransition(psClientCCB->psPDumpConnectionData, IMG_FALSE, PDUMP_FLAGS_CONTINUOUS);
|
PVR_ASSERT(eError == PVRSRV_OK);
|
}
|
|
if (bPdumpEnabled)
|
{
|
/* Update the PDump write offset to show we PDumped this command */
|
psClientCCB->ui32LastPDumpWriteOffset = psClientCCB->ui32HostWriteOffset;
|
}
|
|
#if defined(NO_HARDWARE)
|
/*
|
The firmware is not running, it cannot update these; we do here instead.
|
*/
|
psClientCCB->psClientCCBCtrl->ui32ReadOffset = psClientCCB->ui32HostWriteOffset;
|
psClientCCB->psClientCCBCtrl->ui32DepOffset = psClientCCB->ui32HostWriteOffset;
|
#endif
|
}
|
|
IMG_UINT32 RGXGetHostWriteOffsetCCB(RGX_CLIENT_CCB *psClientCCB)
|
{
|
return psClientCCB->ui32HostWriteOffset;
|
}
|
|
#define SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL PVR_DBG_ERROR
|
#define CHECK_COMMAND(cmd, fenceupdate) \
|
case RGXFWIF_CCB_CMD_TYPE_##cmd: \
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, #cmd " command (%d bytes)", psHeader->ui32CmdSize)); \
|
bFenceUpdate = fenceupdate; \
|
break
|
|
static void _RGXClientCCBDumpCommands(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32Offset,
|
IMG_UINT32 ui32ByteCount)
|
{
|
#if defined(SUPPORT_DUMP_CLIENT_CCB_COMMANDS)
|
IMG_UINT8 *pui8Ptr = psClientCCB->pui8ClientCCB + ui32Offset;
|
IMG_UINT32 ui32ConsumeSize = ui32ByteCount;
|
|
while (ui32ConsumeSize)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8Ptr;
|
IMG_BOOL bFenceUpdate = IMG_FALSE;
|
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "@offset 0x%08x", pui8Ptr - psClientCCB->pui8ClientCCB));
|
switch(psHeader->eCmdType)
|
{
|
CHECK_COMMAND(TA, IMG_FALSE);
|
CHECK_COMMAND(3D, IMG_FALSE);
|
CHECK_COMMAND(CDM, IMG_FALSE);
|
CHECK_COMMAND(TQ_3D, IMG_FALSE);
|
CHECK_COMMAND(TQ_2D, IMG_FALSE);
|
CHECK_COMMAND(3D_PR, IMG_FALSE);
|
CHECK_COMMAND(NULL, IMG_FALSE);
|
CHECK_COMMAND(SHG, IMG_FALSE);
|
CHECK_COMMAND(RTU, IMG_FALSE);
|
CHECK_COMMAND(RTU_FC, IMG_FALSE);
|
CHECK_COMMAND(PRE_TIMESTAMP, IMG_FALSE);
|
CHECK_COMMAND(POST_TIMESTAMP, IMG_FALSE);
|
CHECK_COMMAND(FENCE, IMG_TRUE);
|
CHECK_COMMAND(UPDATE, IMG_TRUE);
|
CHECK_COMMAND(UNFENCED_UPDATE, IMG_FALSE);
|
CHECK_COMMAND(RMW_UPDATE, IMG_TRUE);
|
CHECK_COMMAND(FENCE_PR, IMG_TRUE);
|
CHECK_COMMAND(UNFENCED_RMW_UPDATE, IMG_FALSE);
|
CHECK_COMMAND(PADDING, IMG_FALSE);
|
default:
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "Unknown command!"));
|
break;
|
}
|
pui8Ptr += sizeof(*psHeader);
|
if (bFenceUpdate)
|
{
|
IMG_UINT32 j;
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *) pui8Ptr;
|
for (j=0;j<psHeader->ui32CmdSize/sizeof(RGXFWIF_UFO);j++)
|
{
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "Addr = 0x%08x, value = 0x%08x",
|
psUFOPtr[j].puiAddrUFO.ui32Addr, psUFOPtr[j].ui32Value));
|
}
|
}
|
else
|
{
|
IMG_UINT32 *pui32Ptr = (IMG_UINT32 *) pui8Ptr;
|
IMG_UINT32 ui32Remain = psHeader->ui32CmdSize/sizeof(IMG_UINT32);
|
while(ui32Remain)
|
{
|
if (ui32Remain >= 4)
|
{
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "0x%08x 0x%08x 0x%08x 0x%08x",
|
pui32Ptr[0], pui32Ptr[1], pui32Ptr[2], pui32Ptr[3]));
|
pui32Ptr += 4;
|
ui32Remain -= 4;
|
}
|
if (ui32Remain == 3)
|
{
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "0x%08x 0x%08x 0x%08x",
|
pui32Ptr[0], pui32Ptr[1], pui32Ptr[2]));
|
pui32Ptr += 3;
|
ui32Remain -= 3;
|
}
|
if (ui32Remain == 2)
|
{
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "0x%08x 0x%08x",
|
pui32Ptr[0], pui32Ptr[1]));
|
pui32Ptr += 2;
|
ui32Remain -= 2;
|
}
|
if (ui32Remain == 1)
|
{
|
PVR_DPF((SUPPORT_DUMP_CLIENT_CCB_COMMANDS_DBG_LEVEL, "0x%08x",
|
pui32Ptr[0]));
|
pui32Ptr += 1;
|
ui32Remain -= 1;
|
}
|
}
|
}
|
pui8Ptr += psHeader->ui32CmdSize;
|
ui32ConsumeSize -= sizeof(*psHeader) + psHeader->ui32CmdSize;
|
}
|
#else
|
PVR_UNREFERENCED_PARAMETER(psClientCCB);
|
PVR_UNREFERENCED_PARAMETER(ui32Offset);
|
PVR_UNREFERENCED_PARAMETER(ui32ByteCount);
|
#endif
|
}
|
|
/*
|
Workout how much space this command will require
|
*/
|
PVRSRV_ERROR RGXCmdHelperInitCmdCCB(RGX_CLIENT_CCB *psClientCCB,
|
IMG_UINT32 ui32ClientFenceCount,
|
PRGXFWIF_UFO_ADDR *pauiFenceUFOAddress,
|
IMG_UINT32 *paui32FenceValue,
|
IMG_UINT32 ui32ClientUpdateCount,
|
PRGXFWIF_UFO_ADDR *pauiUpdateUFOAddress,
|
IMG_UINT32 *paui32UpdateValue,
|
IMG_UINT32 ui32ServerSyncCount,
|
IMG_UINT32 *paui32ServerSyncFlags,
|
IMG_UINT32 ui32ServerSyncFlagMask,
|
SERVER_SYNC_PRIMITIVE **papsServerSyncs,
|
IMG_UINT32 ui32CmdSize,
|
IMG_PBYTE pui8DMCmd,
|
PRGXFWIF_TIMESTAMP_ADDR *ppPreAddr,
|
PRGXFWIF_TIMESTAMP_ADDR *ppPostAddr,
|
PRGXFWIF_UFO_ADDR *ppRMWUFOAddr,
|
RGXFWIF_CCB_CMD_TYPE eType,
|
IMG_UINT32 ui32ExtJobRef,
|
IMG_UINT32 ui32IntJobRef,
|
IMG_UINT32 ui32PDumpFlags,
|
RGXFWIF_WORKEST_KICK_DATA *psWorkEstKickData,
|
IMG_CHAR *pszCommandName,
|
RGX_CCB_CMD_HELPER_DATA *psCmdHelperData)
|
{
|
IMG_UINT32 ui32FenceCount;
|
IMG_UINT32 ui32UpdateCount;
|
IMG_UINT32 i;
|
|
/* Job reference values */
|
psCmdHelperData->ui32ExtJobRef = ui32ExtJobRef;
|
psCmdHelperData->ui32IntJobRef = ui32IntJobRef;
|
|
/* Save the data we require in the submit call */
|
psCmdHelperData->psClientCCB = psClientCCB;
|
psCmdHelperData->ui32PDumpFlags = ui32PDumpFlags;
|
psCmdHelperData->pszCommandName = pszCommandName;
|
|
/* Client sync data */
|
psCmdHelperData->ui32ClientFenceCount = ui32ClientFenceCount;
|
psCmdHelperData->pauiFenceUFOAddress = pauiFenceUFOAddress;
|
psCmdHelperData->paui32FenceValue = paui32FenceValue;
|
psCmdHelperData->ui32ClientUpdateCount = ui32ClientUpdateCount;
|
psCmdHelperData->pauiUpdateUFOAddress = pauiUpdateUFOAddress;
|
psCmdHelperData->paui32UpdateValue = paui32UpdateValue;
|
|
/* Server sync data */
|
psCmdHelperData->ui32ServerSyncCount = ui32ServerSyncCount;
|
psCmdHelperData->paui32ServerSyncFlags = paui32ServerSyncFlags;
|
psCmdHelperData->ui32ServerSyncFlagMask = ui32ServerSyncFlagMask;
|
psCmdHelperData->papsServerSyncs = papsServerSyncs;
|
|
/* Command data */
|
psCmdHelperData->ui32CmdSize = ui32CmdSize;
|
psCmdHelperData->pui8DMCmd = pui8DMCmd;
|
psCmdHelperData->eType = eType;
|
|
PDUMPCOMMENTWITHFLAGS(ui32PDumpFlags,
|
"%s Command Server Init on FWCtx %08x", pszCommandName,
|
FWCommonContextGetFWAddress(psClientCCB->psServerCommonContext).ui32Addr);
|
|
/* Init the generated data members */
|
psCmdHelperData->ui32ServerFenceCount = 0;
|
psCmdHelperData->ui32ServerUpdateCount = 0;
|
psCmdHelperData->ui32ServerUnfencedUpdateCount = 0;
|
psCmdHelperData->ui32PreTimeStampCmdSize = 0;
|
psCmdHelperData->ui32PostTimeStampCmdSize = 0;
|
psCmdHelperData->ui32RMWUFOCmdSize = 0;
|
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
/* Workload Data added */
|
psCmdHelperData->psWorkEstKickData = psWorkEstKickData;
|
#endif
|
|
if (ppPreAddr && (ppPreAddr->ui32Addr != 0))
|
{
|
|
psCmdHelperData->pPreTimestampAddr = *ppPreAddr;
|
psCmdHelperData->ui32PreTimeStampCmdSize = sizeof(RGXFWIF_CCB_CMD_HEADER)
|
+ ((sizeof(RGXFWIF_DEV_VIRTADDR) + RGXFWIF_FWALLOC_ALIGN - 1) & ~(RGXFWIF_FWALLOC_ALIGN - 1));
|
}
|
|
if (ppPostAddr && (ppPostAddr->ui32Addr != 0))
|
{
|
psCmdHelperData->pPostTimestampAddr = *ppPostAddr;
|
psCmdHelperData->ui32PostTimeStampCmdSize = sizeof(RGXFWIF_CCB_CMD_HEADER)
|
+ ((sizeof(RGXFWIF_DEV_VIRTADDR) + RGXFWIF_FWALLOC_ALIGN - 1) & ~(RGXFWIF_FWALLOC_ALIGN - 1));
|
}
|
|
if (ppRMWUFOAddr && (ppRMWUFOAddr->ui32Addr != 0))
|
{
|
psCmdHelperData->pRMWUFOAddr = * ppRMWUFOAddr;
|
psCmdHelperData->ui32RMWUFOCmdSize = sizeof(RGXFWIF_CCB_CMD_HEADER) + sizeof(RGXFWIF_UFO);
|
}
|
|
|
/* Workout how many fences and updates this command will have */
|
for (i = 0; i < ui32ServerSyncCount; i++)
|
{
|
IMG_UINT32 ui32Flag = paui32ServerSyncFlags[i] & ui32ServerSyncFlagMask;
|
|
if (ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK)
|
{
|
/* Server syncs must fence */
|
psCmdHelperData->ui32ServerFenceCount++;
|
}
|
|
/* If it is an update */
|
if (ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE)
|
{
|
/* is it a fenced update or a progress update (a.k.a unfenced update) ?*/
|
if ((ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_UNFENCED_UPDATE) == PVRSRV_CLIENT_SYNC_PRIM_OP_UNFENCED_UPDATE)
|
{
|
/* it is a progress update */
|
psCmdHelperData->ui32ServerUnfencedUpdateCount++;
|
}
|
else
|
{
|
/* it is a fenced update */
|
psCmdHelperData->ui32ServerUpdateCount++;
|
}
|
}
|
}
|
|
|
/* Total fence command size (header plus command data) */
|
ui32FenceCount = ui32ClientFenceCount + psCmdHelperData->ui32ServerFenceCount;
|
if (ui32FenceCount)
|
{
|
psCmdHelperData->ui32FenceCmdSize = RGX_CCB_FWALLOC_ALIGN((ui32FenceCount * sizeof(RGXFWIF_UFO)) +
|
sizeof(RGXFWIF_CCB_CMD_HEADER));
|
}
|
else
|
{
|
psCmdHelperData->ui32FenceCmdSize = 0;
|
}
|
|
/* Total DM command size (header plus command data) */
|
psCmdHelperData->ui32DMCmdSize = RGX_CCB_FWALLOC_ALIGN(ui32CmdSize +
|
sizeof(RGXFWIF_CCB_CMD_HEADER));
|
|
/* Total update command size (header plus command data) */
|
ui32UpdateCount = ui32ClientUpdateCount + psCmdHelperData->ui32ServerUpdateCount;
|
if (ui32UpdateCount)
|
{
|
psCmdHelperData->ui32UpdateCmdSize = RGX_CCB_FWALLOC_ALIGN((ui32UpdateCount * sizeof(RGXFWIF_UFO)) +
|
sizeof(RGXFWIF_CCB_CMD_HEADER));
|
}
|
else
|
{
|
psCmdHelperData->ui32UpdateCmdSize = 0;
|
}
|
|
/* Total unfenced update command size (header plus command data) */
|
if (psCmdHelperData->ui32ServerUnfencedUpdateCount != 0)
|
{
|
psCmdHelperData->ui32UnfencedUpdateCmdSize = RGX_CCB_FWALLOC_ALIGN((psCmdHelperData->ui32ServerUnfencedUpdateCount * sizeof(RGXFWIF_UFO)) +
|
sizeof(RGXFWIF_CCB_CMD_HEADER));
|
}
|
else
|
{
|
psCmdHelperData->ui32UnfencedUpdateCmdSize = 0;
|
}
|
|
return PVRSRV_OK;
|
}
|
|
|
/*
|
Reserve space in the CCB and fill in the command and client sync data
|
*/
|
PVRSRV_ERROR RGXCmdHelperAcquireCmdCCB(IMG_UINT32 ui32CmdCount,
|
RGX_CCB_CMD_HELPER_DATA *asCmdHelperData)
|
{
|
IMG_UINT32 ui32AllocSize = 0;
|
IMG_UINT32 i;
|
IMG_UINT8 *pui8StartPtr;
|
PVRSRV_ERROR eError;
|
|
/*
|
Workout how much space we need for all the command(s)
|
*/
|
ui32AllocSize = RGXCmdHelperGetCommandSize(ui32CmdCount, asCmdHelperData);
|
|
|
for (i = 0; i < ui32CmdCount; i++)
|
{
|
if ((asCmdHelperData[0].ui32PDumpFlags ^ asCmdHelperData[i].ui32PDumpFlags) & PDUMP_FLAGS_CONTINUOUS)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "%s: PDump continuous is not consistent (%s != %s) for command %d",
|
__FUNCTION__,
|
PDUMP_IS_CONTINUOUS(asCmdHelperData[0].ui32PDumpFlags)?"IMG_TRUE":"IMG_FALSE",
|
PDUMP_IS_CONTINUOUS(asCmdHelperData[i].ui32PDumpFlags)?"IMG_TRUE":"IMG_FALSE",
|
ui32CmdCount));
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
}
|
|
/*
|
Acquire space in the CCB for all the command(s).
|
*/
|
eError = RGXAcquireCCB(asCmdHelperData[0].psClientCCB,
|
ui32AllocSize,
|
(void **)&pui8StartPtr,
|
asCmdHelperData[0].ui32PDumpFlags);
|
if (eError != PVRSRV_OK)
|
{
|
return eError;
|
}
|
|
/*
|
For each command fill in the fence, DM, and update command
|
|
Note:
|
We only fill in the client fences here, the server fences (and updates)
|
will be filled in together at the end. This is because we might fail the
|
kernel CCB alloc and would then have to rollback the server syncs if
|
we took the operation here
|
*/
|
for (i = 0; i < ui32CmdCount; i++)
|
{
|
RGX_CCB_CMD_HELPER_DATA *psCmdHelperData = & asCmdHelperData[i];
|
IMG_UINT8 *pui8CmdPtr;
|
IMG_UINT8 *pui8ServerFenceStart = 0;
|
IMG_UINT8 *pui8ServerUpdateStart = 0;
|
#if defined(PDUMP)
|
IMG_UINT32 ui32CtxAddr = FWCommonContextGetFWAddress(asCmdHelperData->psClientCCB->psServerCommonContext).ui32Addr;
|
IMG_UINT32 ui32CcbWoff = RGXGetHostWriteOffsetCCB(FWCommonContextGetClientCCB(asCmdHelperData->psClientCCB->psServerCommonContext));
|
#endif
|
|
if (psCmdHelperData->ui32ClientFenceCount+psCmdHelperData->ui32ClientUpdateCount != 0)
|
{
|
PDUMPCOMMENT("Start of %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
|
psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
|
}
|
|
|
|
/*
|
Create the fence command.
|
*/
|
if (psCmdHelperData->ui32FenceCmdSize)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psHeader;
|
IMG_UINT k;
|
|
/* Fences are at the start of the command */
|
pui8CmdPtr = pui8StartPtr;
|
|
psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
|
psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_FENCE;
|
psHeader->ui32CmdSize = psCmdHelperData->ui32FenceCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
psHeader->ui32ExtJobRef = psCmdHelperData->ui32ExtJobRef;
|
psHeader->ui32IntJobRef = psCmdHelperData->ui32IntJobRef;
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
psHeader->sWorkloadDataFWAddr.ui32Addr = 0;
|
psHeader->sWorkEstKickData.ui64ReturnDataIndex = 0;
|
psHeader->sWorkEstKickData.ui64DeadlineInus = 0;
|
psHeader->sWorkEstKickData.ui64CyclesPrediction = 0;
|
#endif
|
|
pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);
|
|
/* Fill in the client fences */
|
for (k = 0; k < psCmdHelperData->ui32ClientFenceCount; k++)
|
{
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *) pui8CmdPtr;
|
|
psUFOPtr->puiAddrUFO = psCmdHelperData->pauiFenceUFOAddress[k];
|
psUFOPtr->ui32Value = psCmdHelperData->paui32FenceValue[k];
|
pui8CmdPtr += sizeof(RGXFWIF_UFO);
|
|
#if defined SYNC_COMMAND_DEBUG
|
PVR_DPF((PVR_DBG_ERROR, "%s client sync fence - 0x%x -> 0x%x",
|
psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value));
|
#endif
|
PDUMPCOMMENT(".. %s client sync fence - 0x%x -> 0x%x",
|
psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value);
|
|
|
}
|
pui8ServerFenceStart = pui8CmdPtr;
|
}
|
|
/* jump over the Server fences */
|
pui8CmdPtr = pui8StartPtr + psCmdHelperData->ui32FenceCmdSize;
|
|
|
/*
|
Create the pre DM timestamp commands. Pre and Post timestamp commands are supposed to
|
sandwich the DM cmd. The padding code with the CCB wrap upsets the FW if we don't have
|
the task type bit cleared for POST_TIMESTAMPs. That's why we have 2 different cmd types.
|
*/
|
if (psCmdHelperData->ui32PreTimeStampCmdSize != 0)
|
{
|
RGXWriteTimestampCommand(& pui8CmdPtr,
|
RGXFWIF_CCB_CMD_TYPE_PRE_TIMESTAMP,
|
psCmdHelperData->pPreTimestampAddr);
|
}
|
|
/*
|
Create the DM command
|
*/
|
if (psCmdHelperData->ui32DMCmdSize)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psHeader;
|
|
psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
|
psHeader->eCmdType = psCmdHelperData->eType;
|
psHeader->ui32CmdSize = psCmdHelperData->ui32DMCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
psHeader->ui32ExtJobRef = psCmdHelperData->ui32ExtJobRef;
|
psHeader->ui32IntJobRef = psCmdHelperData->ui32IntJobRef;
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
psHeader->sWorkloadDataFWAddr.ui32Addr = 0;
|
|
if(psCmdHelperData->psWorkEstKickData != NULL)
|
{
|
PVR_ASSERT(psCmdHelperData->eType == RGXFWIF_CCB_CMD_TYPE_TA ||
|
psCmdHelperData->eType == RGXFWIF_CCB_CMD_TYPE_3D);
|
psHeader->sWorkEstKickData = *psCmdHelperData->psWorkEstKickData;
|
}
|
else
|
{
|
psHeader->sWorkEstKickData.ui64ReturnDataIndex = 0;
|
psHeader->sWorkEstKickData.ui64DeadlineInus = 0;
|
psHeader->sWorkEstKickData.ui64CyclesPrediction = 0;
|
}
|
#endif
|
pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);
|
|
/* The buffer is write-combine, so no special device memory treatment required. */
|
OSCachedMemCopy(pui8CmdPtr, psCmdHelperData->pui8DMCmd, psCmdHelperData->ui32CmdSize);
|
pui8CmdPtr += psCmdHelperData->ui32CmdSize;
|
}
|
|
if (psCmdHelperData->ui32PostTimeStampCmdSize != 0)
|
{
|
RGXWriteTimestampCommand(& pui8CmdPtr,
|
RGXFWIF_CCB_CMD_TYPE_POST_TIMESTAMP,
|
psCmdHelperData->pPostTimestampAddr);
|
}
|
|
|
if (psCmdHelperData->ui32RMWUFOCmdSize != 0)
|
{
|
RGXFWIF_CCB_CMD_HEADER * psHeader;
|
RGXFWIF_UFO * psUFO;
|
|
psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
|
psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_RMW_UPDATE;
|
psHeader->ui32CmdSize = psCmdHelperData->ui32RMWUFOCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
psHeader->ui32ExtJobRef = psCmdHelperData->ui32ExtJobRef;
|
psHeader->ui32IntJobRef = psCmdHelperData->ui32IntJobRef;
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
|
psHeader->sWorkloadDataFWAddr.ui32Addr = 0;
|
psHeader->sWorkEstKickData.ui64ReturnDataIndex = 0;
|
psHeader->sWorkEstKickData.ui64DeadlineInus = 0;
|
psHeader->sWorkEstKickData.ui64CyclesPrediction = 0;
|
#endif
|
pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);
|
|
psUFO = (RGXFWIF_UFO *) pui8CmdPtr;
|
psUFO->puiAddrUFO = psCmdHelperData->pRMWUFOAddr;
|
|
pui8CmdPtr += sizeof(RGXFWIF_UFO);
|
}
|
|
|
/*
|
Create the update command.
|
|
Note:
|
We only fill in the client updates here, the server updates (and fences)
|
will be filled in together at the end
|
*/
|
if (psCmdHelperData->ui32UpdateCmdSize)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psHeader;
|
IMG_UINT k;
|
|
psHeader = (RGXFWIF_CCB_CMD_HEADER *) pui8CmdPtr;
|
psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_UPDATE;
|
psHeader->ui32CmdSize = psCmdHelperData->ui32UpdateCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
psHeader->ui32ExtJobRef = psCmdHelperData->ui32ExtJobRef;
|
psHeader->ui32IntJobRef = psCmdHelperData->ui32IntJobRef;
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
psHeader->sWorkloadDataFWAddr.ui32Addr = 0;
|
psHeader->sWorkEstKickData.ui64ReturnDataIndex = 0;
|
psHeader->sWorkEstKickData.ui64DeadlineInus = 0;
|
psHeader->sWorkEstKickData.ui64CyclesPrediction = 0;
|
#endif
|
pui8CmdPtr += sizeof(RGXFWIF_CCB_CMD_HEADER);
|
|
/* Fill in the client updates */
|
for (k = 0; k < psCmdHelperData->ui32ClientUpdateCount; k++)
|
{
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *) pui8CmdPtr;
|
|
psUFOPtr->puiAddrUFO = psCmdHelperData->pauiUpdateUFOAddress[k];
|
psUFOPtr->ui32Value = psCmdHelperData->paui32UpdateValue[k];
|
pui8CmdPtr += sizeof(RGXFWIF_UFO);
|
|
#if defined SYNC_COMMAND_DEBUG
|
PVR_DPF((PVR_DBG_ERROR, "%s client sync update - 0x%x -> 0x%x",
|
psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value));
|
#endif
|
PDUMPCOMMENT(".. %s client sync update - 0x%x -> 0x%x",
|
psCmdHelperData->psClientCCB->szName, psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value);
|
|
}
|
pui8ServerUpdateStart = pui8CmdPtr;
|
}
|
|
/* Save the server sync fence & update offsets for submit time */
|
psCmdHelperData->pui8ServerFenceStart = pui8ServerFenceStart;
|
psCmdHelperData->pui8ServerUpdateStart = pui8ServerUpdateStart;
|
|
/* jump over the fenced update */
|
if (psCmdHelperData->ui32UnfencedUpdateCmdSize != 0)
|
{
|
RGXFWIF_CCB_CMD_HEADER * const psHeader = (RGXFWIF_CCB_CMD_HEADER * ) psCmdHelperData->pui8ServerUpdateStart + psCmdHelperData->ui32UpdateCmdSize;
|
/* set up the header for unfenced updates, */
|
PVR_ASSERT(psHeader); /* Could be zero if ui32UpdateCmdSize is 0 which is never expected */
|
psHeader->eCmdType = RGXFWIF_CCB_CMD_TYPE_UNFENCED_UPDATE;
|
psHeader->ui32CmdSize = psCmdHelperData->ui32UnfencedUpdateCmdSize - sizeof(RGXFWIF_CCB_CMD_HEADER);
|
psHeader->ui32ExtJobRef = psCmdHelperData->ui32ExtJobRef;
|
psHeader->ui32IntJobRef = psCmdHelperData->ui32IntJobRef;
|
#if defined(SUPPORT_WORKLOAD_ESTIMATION)
|
psHeader->sWorkloadDataFWAddr.ui32Addr = 0;
|
psHeader->sWorkEstKickData.ui64ReturnDataIndex = 0;
|
psHeader->sWorkEstKickData.ui64DeadlineInus = 0;
|
psHeader->sWorkEstKickData.ui64CyclesPrediction = 0;
|
#endif
|
|
/* jump over the header */
|
psCmdHelperData->pui8ServerUnfencedUpdateStart = ((IMG_UINT8*) psHeader) + sizeof(RGXFWIF_CCB_CMD_HEADER);
|
}
|
else
|
{
|
psCmdHelperData->pui8ServerUnfencedUpdateStart = NULL;
|
}
|
|
/* Save start for sanity checking at submit time */
|
psCmdHelperData->pui8StartPtr = pui8StartPtr;
|
|
/* Set the start pointer for the next iteration around the loop */
|
pui8StartPtr +=
|
psCmdHelperData->ui32FenceCmdSize +
|
psCmdHelperData->ui32PreTimeStampCmdSize +
|
psCmdHelperData->ui32DMCmdSize +
|
psCmdHelperData->ui32PostTimeStampCmdSize +
|
psCmdHelperData->ui32RMWUFOCmdSize +
|
psCmdHelperData->ui32UpdateCmdSize +
|
psCmdHelperData->ui32UnfencedUpdateCmdSize;
|
|
if (psCmdHelperData->ui32ClientFenceCount+psCmdHelperData->ui32ClientUpdateCount != 0)
|
{
|
PDUMPCOMMENT("End of %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
|
psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
|
}
|
else
|
{
|
PDUMPCOMMENT("No %s client syncs for cmd[%d] on FWCtx %08x Woff 0x%x bytes",
|
psCmdHelperData->psClientCCB->szName, i, ui32CtxAddr, ui32CcbWoff);
|
}
|
}
|
|
return PVRSRV_OK;
|
}
|
|
/*
|
Fill in the server syncs data and release the CCB space
|
*/
|
void RGXCmdHelperReleaseCmdCCB(IMG_UINT32 ui32CmdCount,
|
RGX_CCB_CMD_HELPER_DATA *asCmdHelperData,
|
const IMG_CHAR *pcszDMName,
|
IMG_UINT32 ui32CtxAddr)
|
{
|
IMG_UINT32 ui32AllocSize = 0;
|
IMG_UINT32 i;
|
#if defined(LINUX)
|
IMG_BOOL bTraceChecks = trace_rogue_are_fence_checks_traced();
|
IMG_BOOL bTraceUpdates = trace_rogue_are_fence_updates_traced();
|
#endif
|
|
/*
|
Workout how much space we need for all the command(s)
|
*/
|
ui32AllocSize = RGXCmdHelperGetCommandSize(ui32CmdCount, asCmdHelperData);
|
|
/*
|
For each command fill in the server sync info
|
*/
|
for (i=0;i<ui32CmdCount;i++)
|
{
|
RGX_CCB_CMD_HELPER_DATA *psCmdHelperData = &asCmdHelperData[i];
|
IMG_UINT8 *pui8ServerFenceStart = psCmdHelperData->pui8ServerFenceStart;
|
IMG_UINT8 *pui8ServerUpdateStart = psCmdHelperData->pui8ServerUpdateStart;
|
IMG_UINT8 *pui8ServerUnfencedUpdateStart = psCmdHelperData->pui8ServerUnfencedUpdateStart;
|
IMG_UINT32 j;
|
|
/* Now fill in the server fence and updates together */
|
for (j = 0; j < psCmdHelperData->ui32ServerSyncCount; j++)
|
{
|
RGXFWIF_UFO *psUFOPtr;
|
IMG_UINT32 ui32UpdateValue;
|
IMG_UINT32 ui32FenceValue;
|
IMG_UINT32 ui32SyncAddr;
|
PVRSRV_ERROR eError;
|
IMG_UINT32 ui32Flag = psCmdHelperData->paui32ServerSyncFlags[j] & psCmdHelperData->ui32ServerSyncFlagMask;
|
IMG_BOOL bFence = ((ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_CHECK)!=0)?IMG_TRUE:IMG_FALSE;
|
IMG_BOOL bUpdate = ((ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_UPDATE)!=0)?IMG_TRUE:IMG_FALSE;
|
const IMG_BOOL bUnfencedUpdate = ((ui32Flag & PVRSRV_CLIENT_SYNC_PRIM_OP_UNFENCED_UPDATE) == PVRSRV_CLIENT_SYNC_PRIM_OP_UNFENCED_UPDATE)
|
? IMG_TRUE
|
: IMG_FALSE;
|
|
eError = PVRSRVServerSyncQueueHWOpKM(psCmdHelperData->papsServerSyncs[j],
|
bUpdate,
|
&ui32FenceValue,
|
&ui32UpdateValue);
|
/* This function can't fail */
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
/*
|
As server syncs always fence (we have a check in RGXCmcdHelperInitCmdCCB
|
which ensures the client is playing ball) the filling in of the fence
|
is unconditional.
|
*/
|
eError = ServerSyncGetFWAddr(psCmdHelperData->papsServerSyncs[j], &ui32SyncAddr);
|
if (PVRSRV_OK != eError)
|
{
|
PVR_DPF((PVR_DBG_ERROR,
|
"%s: Failed to read Server Sync FW address (%d)",
|
__FUNCTION__, eError));
|
PVR_ASSERT(eError == PVRSRV_OK);
|
}
|
if (bFence)
|
{
|
PVR_ASSERT(pui8ServerFenceStart != 0);
|
|
psUFOPtr = (RGXFWIF_UFO *) pui8ServerFenceStart;
|
psUFOPtr->puiAddrUFO.ui32Addr = ui32SyncAddr;
|
psUFOPtr->ui32Value = ui32FenceValue;
|
pui8ServerFenceStart += sizeof(RGXFWIF_UFO);
|
|
#if defined(LINUX)
|
if (bTraceChecks)
|
{
|
trace_rogue_fence_checks(psCmdHelperData->pszCommandName,
|
pcszDMName,
|
ui32CtxAddr,
|
psCmdHelperData->psClientCCB->ui32HostWriteOffset + ui32AllocSize,
|
1,
|
&psUFOPtr->puiAddrUFO,
|
&psUFOPtr->ui32Value);
|
}
|
#endif
|
}
|
|
/* If there is an update then fill that in as well */
|
if (bUpdate)
|
{
|
if (bUnfencedUpdate)
|
{
|
PVR_ASSERT(pui8ServerUnfencedUpdateStart != 0);
|
|
psUFOPtr = (RGXFWIF_UFO *) pui8ServerUnfencedUpdateStart;
|
psUFOPtr->puiAddrUFO.ui32Addr = ui32SyncAddr;
|
psUFOPtr->ui32Value = ui32UpdateValue;
|
pui8ServerUnfencedUpdateStart += sizeof(RGXFWIF_UFO);
|
}
|
else
|
{
|
/* fenced update */
|
PVR_ASSERT(pui8ServerUpdateStart != 0);
|
|
psUFOPtr = (RGXFWIF_UFO *) pui8ServerUpdateStart;
|
psUFOPtr->puiAddrUFO.ui32Addr = ui32SyncAddr;
|
psUFOPtr->ui32Value = ui32UpdateValue;
|
pui8ServerUpdateStart += sizeof(RGXFWIF_UFO);
|
}
|
#if defined(LINUX)
|
if (bTraceUpdates)
|
{
|
trace_rogue_fence_updates(psCmdHelperData->pszCommandName,
|
pcszDMName,
|
ui32CtxAddr,
|
psCmdHelperData->psClientCCB->ui32HostWriteOffset + ui32AllocSize,
|
1,
|
&psUFOPtr->puiAddrUFO,
|
&psUFOPtr->ui32Value);
|
}
|
#endif
|
|
#if defined(NO_HARDWARE)
|
/*
|
There is no FW so the host has to do any Sync updates
|
(client sync updates are done in the client
|
*/
|
PVRSRVServerSyncPrimSetKM(psCmdHelperData->papsServerSyncs[j], ui32UpdateValue);
|
#endif
|
}
|
}
|
|
#if defined(LINUX)
|
if (bTraceChecks)
|
{
|
trace_rogue_fence_checks(psCmdHelperData->pszCommandName,
|
pcszDMName,
|
ui32CtxAddr,
|
psCmdHelperData->psClientCCB->ui32HostWriteOffset + ui32AllocSize,
|
psCmdHelperData->ui32ClientFenceCount,
|
psCmdHelperData->pauiFenceUFOAddress,
|
psCmdHelperData->paui32FenceValue);
|
}
|
if (bTraceUpdates)
|
{
|
trace_rogue_fence_updates(psCmdHelperData->pszCommandName,
|
pcszDMName,
|
ui32CtxAddr,
|
psCmdHelperData->psClientCCB->ui32HostWriteOffset + ui32AllocSize,
|
psCmdHelperData->ui32ClientUpdateCount,
|
psCmdHelperData->pauiUpdateUFOAddress,
|
psCmdHelperData->paui32UpdateValue);
|
}
|
#endif
|
|
if (psCmdHelperData->ui32ServerSyncCount)
|
{
|
/*
|
Do some sanity checks to ensure we did the point math right
|
*/
|
if (pui8ServerFenceStart != 0)
|
{
|
PVR_ASSERT(pui8ServerFenceStart ==
|
(psCmdHelperData->pui8StartPtr +
|
psCmdHelperData->ui32FenceCmdSize));
|
}
|
|
if (pui8ServerUpdateStart != 0)
|
{
|
PVR_ASSERT(pui8ServerUpdateStart ==
|
psCmdHelperData->pui8StartPtr +
|
psCmdHelperData->ui32FenceCmdSize +
|
psCmdHelperData->ui32PreTimeStampCmdSize +
|
psCmdHelperData->ui32DMCmdSize +
|
psCmdHelperData->ui32RMWUFOCmdSize +
|
psCmdHelperData->ui32PostTimeStampCmdSize +
|
psCmdHelperData->ui32UpdateCmdSize);
|
}
|
|
if (pui8ServerUnfencedUpdateStart != 0)
|
{
|
PVR_ASSERT(pui8ServerUnfencedUpdateStart ==
|
psCmdHelperData->pui8StartPtr +
|
psCmdHelperData->ui32FenceCmdSize +
|
psCmdHelperData->ui32PreTimeStampCmdSize +
|
psCmdHelperData->ui32DMCmdSize +
|
psCmdHelperData->ui32RMWUFOCmdSize +
|
psCmdHelperData->ui32PostTimeStampCmdSize +
|
psCmdHelperData->ui32UpdateCmdSize +
|
psCmdHelperData->ui32UnfencedUpdateCmdSize);
|
}
|
}
|
|
/*
|
All the commands have been filled in so release the CCB space.
|
The FW still won't run this command until we kick it
|
*/
|
PDUMPCOMMENTWITHFLAGS(psCmdHelperData->ui32PDumpFlags,
|
"%s Command Server Release on FWCtx %08x",
|
psCmdHelperData->pszCommandName, ui32CtxAddr);
|
}
|
|
_RGXClientCCBDumpCommands(asCmdHelperData[0].psClientCCB,
|
asCmdHelperData[0].psClientCCB->ui32HostWriteOffset,
|
ui32AllocSize);
|
|
RGXReleaseCCB(asCmdHelperData[0].psClientCCB,
|
ui32AllocSize,
|
asCmdHelperData[0].ui32PDumpFlags);
|
}
|
|
|
IMG_UINT32 RGXCmdHelperGetCommandSize(IMG_UINT32 ui32CmdCount,
|
RGX_CCB_CMD_HELPER_DATA *asCmdHelperData)
|
{
|
IMG_UINT32 ui32AllocSize = 0;
|
IMG_UINT32 i;
|
|
/*
|
Workout how much space we need for all the command(s)
|
*/
|
for (i = 0; i < ui32CmdCount; i++)
|
{
|
ui32AllocSize +=
|
asCmdHelperData[i].ui32FenceCmdSize +
|
asCmdHelperData[i].ui32DMCmdSize +
|
asCmdHelperData[i].ui32UpdateCmdSize +
|
asCmdHelperData[i].ui32UnfencedUpdateCmdSize +
|
asCmdHelperData[i].ui32PreTimeStampCmdSize +
|
asCmdHelperData[i].ui32PostTimeStampCmdSize +
|
asCmdHelperData[i].ui32RMWUFOCmdSize;
|
}
|
|
return ui32AllocSize;
|
}
|
|
/* Work out how much of an offset there is to a specific command. */
|
IMG_UINT32 RGXCmdHelperGetCommandOffset(RGX_CCB_CMD_HELPER_DATA *asCmdHelperData,
|
IMG_UINT32 ui32Cmdindex)
|
{
|
IMG_UINT32 ui32Offset = 0;
|
IMG_UINT32 i;
|
|
for (i = 0; i < ui32Cmdindex; i++)
|
{
|
ui32Offset +=
|
asCmdHelperData[i].ui32FenceCmdSize +
|
asCmdHelperData[i].ui32DMCmdSize +
|
asCmdHelperData[i].ui32UpdateCmdSize +
|
asCmdHelperData[i].ui32UnfencedUpdateCmdSize +
|
asCmdHelperData[i].ui32PreTimeStampCmdSize +
|
asCmdHelperData[i].ui32PostTimeStampCmdSize +
|
asCmdHelperData[i].ui32RMWUFOCmdSize;
|
}
|
|
return ui32Offset;
|
}
|
|
/* Returns the offset of the data master command from a write offset */
|
IMG_UINT32 RGXCmdHelperGetDMCommandHeaderOffset(RGX_CCB_CMD_HELPER_DATA *psCmdHelperData)
|
{
|
return psCmdHelperData->ui32FenceCmdSize + psCmdHelperData->ui32PreTimeStampCmdSize;
|
}
|
|
|
static const char *_CCBCmdTypename(RGXFWIF_CCB_CMD_TYPE cmdType)
|
{
|
switch (cmdType)
|
{
|
case RGXFWIF_CCB_CMD_TYPE_TA: return "TA";
|
case RGXFWIF_CCB_CMD_TYPE_3D: return "3D";
|
case RGXFWIF_CCB_CMD_TYPE_CDM: return "CDM";
|
case RGXFWIF_CCB_CMD_TYPE_TQ_3D: return "TQ_3D";
|
case RGXFWIF_CCB_CMD_TYPE_TQ_2D: return "TQ_2D";
|
case RGXFWIF_CCB_CMD_TYPE_3D_PR: return "3D_PR";
|
case RGXFWIF_CCB_CMD_TYPE_NULL: return "NULL";
|
case RGXFWIF_CCB_CMD_TYPE_SHG: return "SHG";
|
case RGXFWIF_CCB_CMD_TYPE_RTU: return "RTU";
|
case RGXFWIF_CCB_CMD_TYPE_RTU_FC: return "RTU_FC";
|
case RGXFWIF_CCB_CMD_TYPE_PRE_TIMESTAMP: return "PRE_TIMESTAMP";
|
case RGXFWIF_CCB_CMD_TYPE_TQ_TDM: return "TQ_TDM";
|
|
case RGXFWIF_CCB_CMD_TYPE_FENCE: return "FENCE";
|
case RGXFWIF_CCB_CMD_TYPE_UPDATE: return "UPDATE";
|
case RGXFWIF_CCB_CMD_TYPE_RMW_UPDATE: return "RMW_UPDATE";
|
case RGXFWIF_CCB_CMD_TYPE_FENCE_PR: return "FENCE_PR";
|
case RGXFWIF_CCB_CMD_TYPE_PRIORITY: return "PRIORITY";
|
|
case RGXFWIF_CCB_CMD_TYPE_POST_TIMESTAMP: return "POST_TIMESTAMP";
|
case RGXFWIF_CCB_CMD_TYPE_UNFENCED_UPDATE: return "UNFENCED_UPDATE";
|
case RGXFWIF_CCB_CMD_TYPE_UNFENCED_RMW_UPDATE: return "UNFENCED_RMW_UPDATE";
|
|
case RGXFWIF_CCB_CMD_TYPE_PADDING: return "PADDING";
|
|
default:
|
PVR_ASSERT(IMG_FALSE);
|
break;
|
}
|
|
return "INVALID";
|
}
|
|
PVRSRV_ERROR CheckForStalledCCB(RGX_CLIENT_CCB *psCurrentClientCCB, RGX_KICK_TYPE_DM eKickTypeDM)
|
{
|
volatile RGXFWIF_CCCB_CTL *psClientCCBCtrl;
|
IMG_UINT32 ui32SampledRdOff, ui32SampledWrOff;
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
if (psCurrentClientCCB == NULL)
|
{
|
PVR_DPF((PVR_DBG_WARNING, "CheckForStalledCCB: CCCB is NULL"));
|
return PVRSRV_ERROR_INVALID_PARAMS;
|
}
|
|
psClientCCBCtrl = psCurrentClientCCB->psClientCCBCtrl;
|
ui32SampledRdOff = psClientCCBCtrl->ui32ReadOffset;
|
ui32SampledWrOff = psCurrentClientCCB->ui32HostWriteOffset;
|
|
if (ui32SampledRdOff > psClientCCBCtrl->ui32WrapMask ||
|
ui32SampledWrOff > psClientCCBCtrl->ui32WrapMask)
|
{
|
PVR_DPF((PVR_DBG_WARNING, "CheckForStalledCCB: CCCB has invalid offset (ROFF=%d WOFF=%d)",
|
ui32SampledRdOff, ui32SampledWrOff));
|
return PVRSRV_ERROR_INVALID_OFFSET;
|
}
|
|
if (ui32SampledRdOff != ui32SampledWrOff &&
|
psCurrentClientCCB->ui32LastROff != psCurrentClientCCB->ui32LastWOff &&
|
ui32SampledRdOff == psCurrentClientCCB->ui32LastROff &&
|
(psCurrentClientCCB->ui32ByteCount - psCurrentClientCCB->ui32LastByteCount) < psCurrentClientCCB->ui32Size)
|
{
|
//RGXFWIF_DEV_VIRTADDR v = {0};
|
//DumpStalledCCBCommand(v,psCurrentClientCCB,NULL);
|
|
/* Don't log this by default unless debugging since a higher up
|
* function will log the stalled condition. Helps avoid double
|
* messages in the log.
|
*/
|
PVR_DPF((PVR_DBG_WARNING, "CheckForStalledCCB: CCCB has not progressed (ROFF=%d WOFF=%d) for DM: %s",
|
ui32SampledRdOff, ui32SampledWrOff, RGXStringifyKickTypeDM(eKickTypeDM)));
|
eError = PVRSRV_ERROR_CCCB_STALLED;
|
}
|
|
psCurrentClientCCB->ui32LastROff = ui32SampledRdOff;
|
psCurrentClientCCB->ui32LastWOff = ui32SampledWrOff;
|
psCurrentClientCCB->ui32LastByteCount = psCurrentClientCCB->ui32ByteCount;
|
|
return eError;
|
}
|
|
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) || defined(PVRSRV_ENABLE_FULL_CCB_DUMP)
|
void DumpCCB(PVRSRV_RGXDEV_INFO *psDevInfo,
|
PRGXFWIF_FWCOMMONCONTEXT sFWCommonContext,
|
RGX_CLIENT_CCB *psCurrentClientCCB,
|
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
void *pvDumpDebugFile)
|
{
|
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
|
PVRSRV_DEVICE_NODE *psDeviceNode = psDevInfo->psDeviceNode;
|
#endif
|
volatile RGXFWIF_CCCB_CTL *psClientCCBCtrl = psCurrentClientCCB->psClientCCBCtrl;
|
IMG_UINT8 *pui8ClientCCBBuff = psCurrentClientCCB->pui8ClientCCB;
|
IMG_UINT32 ui32Offset = psClientCCBCtrl->ui32ReadOffset;
|
IMG_UINT32 ui32DepOffset = psClientCCBCtrl->ui32DepOffset;
|
IMG_UINT32 ui32EndOffset = psCurrentClientCCB->ui32HostWriteOffset;
|
IMG_UINT32 ui32WrapMask = psClientCCBCtrl->ui32WrapMask;
|
IMG_CHAR * pszState = "Ready";
|
|
PVR_DUMPDEBUG_LOG("FWCtx 0x%08X (%s)", sFWCommonContext.ui32Addr,
|
(IMG_PCHAR)&psCurrentClientCCB->szName);
|
if (ui32Offset == ui32EndOffset)
|
{
|
PVR_DUMPDEBUG_LOG(" `--<Empty>");
|
}
|
|
while (ui32Offset != ui32EndOffset)
|
{
|
RGXFWIF_CCB_CMD_HEADER *psCmdHeader = (RGXFWIF_CCB_CMD_HEADER*)(pui8ClientCCBBuff + ui32Offset);
|
IMG_UINT32 ui32NextOffset = (ui32Offset + psCmdHeader->ui32CmdSize + sizeof(RGXFWIF_CCB_CMD_HEADER)) & ui32WrapMask;
|
IMG_BOOL bLastCommand = (ui32NextOffset == ui32EndOffset)? IMG_TRUE: IMG_FALSE;
|
IMG_BOOL bLastUFO;
|
#define CCB_SYNC_INFO_LEN 80
|
IMG_CHAR pszSyncInfo[CCB_SYNC_INFO_LEN];
|
IMG_UINT32 ui32NoOfUpdates, i;
|
RGXFWIF_UFO *psUFOPtr;
|
|
ui32NoOfUpdates = psCmdHeader->ui32CmdSize / sizeof(RGXFWIF_UFO);
|
psUFOPtr = (RGXFWIF_UFO*)(pui8ClientCCBBuff + ui32Offset + sizeof(RGXFWIF_CCB_CMD_HEADER));
|
pszSyncInfo[0] = '\0';
|
|
if (ui32Offset == ui32DepOffset)
|
{
|
pszState = "Waiting";
|
}
|
|
PVR_DUMPDEBUG_LOG(" %s--%s %s @ %u Int=%u Ext=%u",
|
bLastCommand? "`": "|",
|
pszState, _CCBCmdTypename(psCmdHeader->eCmdType),
|
ui32Offset, psCmdHeader->ui32IntJobRef, psCmdHeader->ui32ExtJobRef
|
);
|
|
/* switch on type and write checks and updates */
|
switch (psCmdHeader->eCmdType)
|
{
|
case RGXFWIF_CCB_CMD_TYPE_UPDATE:
|
case RGXFWIF_CCB_CMD_TYPE_UNFENCED_UPDATE:
|
case RGXFWIF_CCB_CMD_TYPE_FENCE:
|
case RGXFWIF_CCB_CMD_TYPE_FENCE_PR:
|
{
|
for (i = 0; i < ui32NoOfUpdates; i++, psUFOPtr++)
|
{
|
bLastUFO = (ui32NoOfUpdates-1 == i)? IMG_TRUE: IMG_FALSE;
|
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
|
SyncRecordLookup(psDeviceNode, psUFOPtr->puiAddrUFO.ui32Addr,
|
pszSyncInfo, CCB_SYNC_INFO_LEN);
|
#endif
|
PVR_DUMPDEBUG_LOG(" %s %s--Addr:0x%08x Val=0x%08x %s",
|
bLastCommand? " ": "|",
|
bLastUFO? "`": "|",
|
psUFOPtr->puiAddrUFO.ui32Addr, psUFOPtr->ui32Value,
|
pszSyncInfo
|
);
|
}
|
break;
|
}
|
|
case RGXFWIF_CCB_CMD_TYPE_RMW_UPDATE:
|
case RGXFWIF_CCB_CMD_TYPE_UNFENCED_RMW_UPDATE:
|
{
|
for (i = 0; i < ui32NoOfUpdates; i++, psUFOPtr++)
|
{
|
bLastUFO = (ui32NoOfUpdates-1 == i)? IMG_TRUE: IMG_FALSE;
|
#if defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING)
|
SyncRecordLookup(psDeviceNode, psUFOPtr->puiAddrUFO.ui32Addr,
|
pszSyncInfo, CCB_SYNC_INFO_LEN);
|
#endif
|
PVR_DUMPDEBUG_LOG(" %s %s--Addr:0x%08x Val++ %s",
|
bLastCommand? " ": "|",
|
bLastUFO? "`": "|",
|
psUFOPtr->puiAddrUFO.ui32Addr,
|
pszSyncInfo
|
);
|
}
|
break;
|
}
|
|
default:
|
break;
|
}
|
ui32Offset = ui32NextOffset;
|
}
|
|
}
|
#endif /* defined(PVRSRV_ENABLE_FULL_SYNC_TRACKING) || defined(PVRSRV_ENABLE_FULL_CCB_DUMP) */
|
|
void DumpStalledCCBCommand(PRGXFWIF_FWCOMMONCONTEXT sFWCommonContext,
|
RGX_CLIENT_CCB *psCurrentClientCCB,
|
DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
|
void *pvDumpDebugFile)
|
{
|
volatile RGXFWIF_CCCB_CTL *psClientCCBCtrl = psCurrentClientCCB->psClientCCBCtrl;
|
IMG_UINT8 *pui8ClientCCBBuff = psCurrentClientCCB->pui8ClientCCB;
|
volatile IMG_UINT8 *pui8Ptr;
|
IMG_UINT32 ui32SampledRdOff = psClientCCBCtrl->ui32ReadOffset;
|
IMG_UINT32 ui32SampledDepOff = psClientCCBCtrl->ui32DepOffset;
|
IMG_UINT32 ui32SampledWrOff = psCurrentClientCCB->ui32HostWriteOffset;
|
|
pui8Ptr = pui8ClientCCBBuff + ui32SampledRdOff;
|
|
if ((ui32SampledRdOff == ui32SampledDepOff) &&
|
(ui32SampledRdOff != ui32SampledWrOff))
|
{
|
volatile RGXFWIF_CCB_CMD_HEADER *psCommandHeader = (RGXFWIF_CCB_CMD_HEADER *)(pui8ClientCCBBuff + ui32SampledRdOff);
|
RGXFWIF_CCB_CMD_TYPE eCommandType = psCommandHeader->eCmdType;
|
volatile IMG_UINT8 *pui8Ptr = (IMG_UINT8 *)psCommandHeader;
|
|
/* CCB is stalled on a fence... */
|
if ((eCommandType == RGXFWIF_CCB_CMD_TYPE_FENCE) || (eCommandType == RGXFWIF_CCB_CMD_TYPE_FENCE_PR))
|
{
|
RGXFWIF_UFO *psUFOPtr = (RGXFWIF_UFO *)(pui8Ptr + sizeof(*psCommandHeader));
|
IMG_UINT32 jj;
|
|
/* Display details of the fence object on which the context is pending */
|
PVR_DUMPDEBUG_LOG("FWCtx 0x%08X @ %d (%s) pending on %s:",
|
sFWCommonContext.ui32Addr,
|
ui32SampledRdOff,
|
(IMG_PCHAR)&psCurrentClientCCB->szName,
|
_CCBCmdTypename(eCommandType));
|
for (jj=0; jj<psCommandHeader->ui32CmdSize/sizeof(RGXFWIF_UFO); jj++)
|
{
|
#if !defined(SUPPORT_EXTRA_METASP_DEBUG)
|
PVR_DUMPDEBUG_LOG(" Addr:0x%08x Value=0x%08x",psUFOPtr[jj].puiAddrUFO.ui32Addr, psUFOPtr[jj].ui32Value);
|
#else
|
PVR_DUMPDEBUG_LOG(" Addr:0x%08x Value(Host)=0x%08x Value(FW)=0x%08x",
|
psUFOPtr[jj].puiAddrUFO.ui32Addr,
|
psUFOPtr[jj].ui32Value,
|
RGXReadWithSP(psUFOPtr[jj].puiAddrUFO.ui32Addr));
|
#endif
|
}
|
|
/* Advance psCommandHeader past the FENCE to the next command header (this will be the TA/3D command that is fenced) */
|
pui8Ptr = (IMG_UINT8 *)psUFOPtr + psCommandHeader->ui32CmdSize;
|
psCommandHeader = (RGXFWIF_CCB_CMD_HEADER *)pui8Ptr;
|
if( (uintptr_t)psCommandHeader != ((uintptr_t)pui8ClientCCBBuff + ui32SampledWrOff))
|
{
|
PVR_DUMPDEBUG_LOG(" FWCtx 0x%08X fenced command is of type %s",sFWCommonContext.ui32Addr, _CCBCmdTypename(psCommandHeader->eCmdType));
|
/* Advance psCommandHeader past the TA/3D to the next command header (this will possibly be an UPDATE) */
|
pui8Ptr += sizeof(*psCommandHeader) + psCommandHeader->ui32CmdSize;
|
psCommandHeader = (RGXFWIF_CCB_CMD_HEADER *)pui8Ptr;
|
/* If the next command is an update, display details of that so we can see what would then become unblocked */
|
if( (uintptr_t)psCommandHeader != ((uintptr_t)pui8ClientCCBBuff + ui32SampledWrOff))
|
{
|
eCommandType = psCommandHeader->eCmdType;
|
|
if (eCommandType == RGXFWIF_CCB_CMD_TYPE_UPDATE)
|
{
|
psUFOPtr = (RGXFWIF_UFO *)((IMG_UINT8 *)psCommandHeader + sizeof(*psCommandHeader));
|
PVR_DUMPDEBUG_LOG(" preventing %s:",_CCBCmdTypename(eCommandType));
|
for (jj=0; jj<psCommandHeader->ui32CmdSize/sizeof(RGXFWIF_UFO); jj++)
|
{
|
#if !defined(SUPPORT_EXTRA_METASP_DEBUG)
|
PVR_DUMPDEBUG_LOG(" Addr:0x%08x Value=0x%08x",psUFOPtr[jj].puiAddrUFO.ui32Addr, psUFOPtr[jj].ui32Value);
|
#else
|
PVR_DUMPDEBUG_LOG(" Addr:0x%08x Value(Host)=0x%08x Value(FW)=0x%08x",
|
psUFOPtr[jj].puiAddrUFO.ui32Addr,
|
psUFOPtr[jj].ui32Value,
|
RGXReadWithSP(psUFOPtr[jj].puiAddrUFO.ui32Addr));
|
#endif
|
}
|
}
|
}
|
else
|
{
|
PVR_DUMPDEBUG_LOG(" FWCtx 0x%08X has no further commands",sFWCommonContext.ui32Addr);
|
}
|
}
|
else
|
{
|
PVR_DUMPDEBUG_LOG(" FWCtx 0x%08X has no further commands",sFWCommonContext.ui32Addr);
|
}
|
}
|
}
|
}
|
|
/******************************************************************************
|
End of file (rgxccb.c)
|
******************************************************************************/
|