blob: 63884a50c2a18156228015073a2d2f271278f78c [file] [log] [blame]
/*************************************************************************/ /*!
@File
@Title Common Server PDump functions layer
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@License Dual MIT/GPLv2
The contents of this file are subject to the MIT license as set out below.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 2 ("GPL") in which case the provisions
of GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms of
GPL, and not to allow others to use your version of this file under the terms
of the MIT license, indicate your decision by deleting the provisions above
and replace them with the notice and other provisions required by GPL as set
out in the file called "GPL-COPYING" included in this distribution. If you do
not delete the provisions above, a recipient may use your version of this file
under the terms of either the MIT license or GPL.
This License is also included in this distribution in the file called
"MIT-COPYING".
EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ /**************************************************************************/
#if defined(PDUMP)
#include <stdarg.h>
#include "pvrversion.h"
#include "allocmem.h"
#include "osfunc.h"
#include "pvrsrv.h"
#include "pvr_debug.h"
#include "srvkm.h"
#include "pdump_physmem.h"
#include "hash.h"
#include "connection_server.h"
#include "sync_server.h"
#include "services_km.h"
/* pdump headers */
#include "dbgdrvif_srv5.h"
#include "pdump_osfunc.h"
#include "pdump_km.h"
/* Allow temporary buffer size override */
#if !defined(PDUMP_TEMP_BUFFER_SIZE)
#define PDUMP_TEMP_BUFFER_SIZE (64 * 1024U)
#endif
/* DEBUG */
#if 0
#define PDUMP_DBG(a) PDumpOSDebugPrintf (a)
#else
#define PDUMP_DBG(a)
#endif
#define PTR_PLUS(t, p, x) ((t)(((IMG_CHAR *)(p)) + (x)))
#define VPTR_PLUS(p, x) PTR_PLUS(void *, p, x)
#define VPTR_INC(p, x) ((p) = VPTR_PLUS(p, x))
#define MAX_PDUMP_MMU_CONTEXTS (32)
static void *gpvTempBuffer = NULL;
#define PRM_FILE_SIZE_MAX 0x7FDFFFFFU /*!< Default maximum file size to split output files, 2GB-2MB as fwrite limits it to 2GB-1 on 32bit systems */
#define FRAME_UNSET 0xFFFFFFFFU /*|< Used to signify no or invalid frame number */
static IMG_BOOL g_PDumpInitialised = IMG_FALSE;
static IMG_UINT32 g_ConnectionCount = 0;
typedef struct
{
PDUMP_CHANNEL sCh; /*!< Channel handles */
} PDUMP_SCRIPT;
typedef struct
{
IMG_UINT32 ui32Init; /*|< Count of bytes written to the init phase stream */
IMG_UINT32 ui32Main; /*!< Count of bytes written to the main stream */
IMG_UINT32 ui32Deinit; /*!< Count of bytes written to the deinit stream */
} PDUMP_CHANNEL_WOFFSETS;
typedef struct
{
PDUMP_CHANNEL sCh; /*!< Channel handles */
PDUMP_CHANNEL_WOFFSETS sWOff; /*!< Channel file write offsets */
IMG_UINT32 ui32FileIdx; /*!< File index used when file size limit reached and a new file is started, parameter channel only */
IMG_UINT32 ui32MaxFileSize; /*!< Maximum file size for parameter files */
PDUMP_FILEOFFSET_T uiZeroPageOffset; /*!< Offset of the zero page in the parameter file */
size_t uiZeroPageSize; /*!< Size of the zero page in the parameter file */
IMG_CHAR szZeroPageFilename[PDUMP_PARAM_MAX_FILE_NAME]; /*< PRM file name where the zero page was pdumped */
} PDUMP_PARAMETERS;
static PDUMP_SCRIPT g_PDumpScript = { { 0, 0, 0} };
static PDUMP_PARAMETERS g_PDumpParameters = { { 0, 0, 0}, {0, 0, 0}, 0, PRM_FILE_SIZE_MAX};
#if defined(PDUMP_DEBUG_OUTFILES)
/* counter increments each time debug write is called */
IMG_UINT32 g_ui32EveryLineCounter = 1U;
#endif
#if defined(PDUMP_DEBUG) || defined(REFCOUNT_DEBUG)
#define PDUMP_REFCOUNT_PRINT(fmt, ...) PVRSRVDebugPrintf(PVR_DBG_WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__)
#else
#define PDUMP_REFCOUNT_PRINT(fmt, ...)
#endif
/* Prototype for the test/debug state dump routine used in debugging */
void PDumpCommonDumpState(IMG_BOOL bDumpOSLayerState);
#undef PDUMP_TRACE_STATE
/*****************************************************************************/
/* PDump Control Module Definitions */
/*****************************************************************************/
typedef struct _PDUMP_CAPTURE_RANGE_
{
IMG_UINT32 ui32Start; /*!< Start frame number of range */
IMG_UINT32 ui32End; /*!< Send frame number of range */
IMG_UINT32 ui32Interval; /*!< Frame sample rate interval */
} PDUMP_CAPTURE_RANGE;
/* No direct access to members from outside the control module - please */
typedef struct _PDUMP_CTRL_STATE_
{
IMG_BOOL bInitPhaseActive; /*!< State of driver initialisation phase */
IMG_UINT32 ui32Flags; /*!< Unused */
IMG_UINT32 ui32DefaultCapMode; /*!< Capture mode of the dump */
PDUMP_CAPTURE_RANGE sCaptureRange; /*|< The capture range for capture mode 'framed' */
IMG_UINT32 ui32CurrentFrame; /*!< Current frame number */
IMG_BOOL bCaptureOn; /*!< Current capture status, is current frame in range */
IMG_BOOL bSuspended; /*!< Suspend flag set on unrecoverable error */
IMG_BOOL bInPowerTransition; /*!< Device power transition state */
POS_LOCK hLock; /*!< Exclusive lock to this structure */
} PDUMP_CTRL_STATE;
static PDUMP_CTRL_STATE g_PDumpCtrl =
{
IMG_TRUE,
0,
0, /*!< Value obtained from OS PDump layer during initialisation */
{
FRAME_UNSET,
FRAME_UNSET,
1
},
0,
IMG_FALSE,
IMG_FALSE,
IMG_FALSE,
NULL
};
static PVRSRV_ERROR PDumpCtrlInit(IMG_UINT32 ui32InitCapMode)
{
g_PDumpCtrl.ui32DefaultCapMode = ui32InitCapMode;
PVR_ASSERT(g_PDumpCtrl.ui32DefaultCapMode != 0);
/* Create lock for PDUMP_CTRL_STATE struct, which is shared between pdump client
and PDumping app. This lock will help us serialize calls from pdump client
and PDumping app */
PVR_LOGR_IF_ERROR(OSLockCreate(&g_PDumpCtrl.hLock, LOCK_TYPE_PASSIVE), "OSLockCreate");
return PVRSRV_OK;
}
static void PDumpCtrlDeInit(void)
{
if (g_PDumpCtrl.hLock)
{
OSLockDestroy(g_PDumpCtrl.hLock);
g_PDumpCtrl.hLock = NULL;
}
}
static INLINE void PDumpCtrlLockAcquire(void)
{
OSLockAcquire(g_PDumpCtrl.hLock);
}
static INLINE void PDumpCtrlLockRelease(void)
{
OSLockRelease(g_PDumpCtrl.hLock);
}
/**********************************************************************************************************
NOTE:
The following PDumpCtrl*** functions require the PDUMP_CTRL_STATE lock be acquired BEFORE they are
called. This is because the PDUMP_CTRL_STATE data is shared between the PDumping App and the PDump
client, hence an exclusive access is required. The lock can be acquired and released by using the
PDumpCtrlLockAcquire & PDumpCtrlLockRelease functions respectively.
**********************************************************************************************************/
static void PDumpCtrlUpdateCaptureStatus(void)
{
if (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED)
{
if ((g_PDumpCtrl.ui32CurrentFrame >= g_PDumpCtrl.sCaptureRange.ui32Start) &&
(g_PDumpCtrl.ui32CurrentFrame <= g_PDumpCtrl.sCaptureRange.ui32End) &&
(((g_PDumpCtrl.ui32CurrentFrame - g_PDumpCtrl.sCaptureRange.ui32Start) % g_PDumpCtrl.sCaptureRange.ui32Interval) == 0))
{
g_PDumpCtrl.bCaptureOn = IMG_TRUE;
}
else
{
g_PDumpCtrl.bCaptureOn = IMG_FALSE;
}
}
else if (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_CONTINUOUS)
{
g_PDumpCtrl.bCaptureOn = IMG_TRUE;
}
else
{
g_PDumpCtrl.bCaptureOn = IMG_FALSE;
PVR_DPF((PVR_DBG_ERROR, "PDumpCtrlSetCurrentFrame: Unexpected capture mode (%x)", g_PDumpCtrl.ui32DefaultCapMode));
}
}
static void PDumpCtrlSetCurrentFrame(IMG_UINT32 ui32Frame)
{
g_PDumpCtrl.ui32CurrentFrame = ui32Frame;
/* Mirror the value into the debug driver */
PDumpOSSetFrame(ui32Frame);
PDumpCtrlUpdateCaptureStatus();
#if defined(PDUMP_TRACE_STATE)
PDumpCommonDumpState(IMG_FALSE);
#endif
}
static void PDumpCtrlSetDefaultCaptureParams(IMG_UINT32 ui32Mode, IMG_UINT32 ui32Start, IMG_UINT32 ui32End, IMG_UINT32 ui32Interval)
{
PVR_ASSERT(ui32Interval > 0);
PVR_ASSERT(ui32End >= ui32Start);
PVR_ASSERT((ui32Mode == DEBUG_CAPMODE_FRAMED) || (ui32Mode == DEBUG_CAPMODE_CONTINUOUS));
/* Set the capture range to that supplied by the PDump client tool
*/
g_PDumpCtrl.ui32DefaultCapMode = ui32Mode;
g_PDumpCtrl.sCaptureRange.ui32Start = ui32Start;
g_PDumpCtrl.sCaptureRange.ui32End = ui32End;
g_PDumpCtrl.sCaptureRange.ui32Interval = ui32Interval;
/* Reset the current frame on reset of the capture range, the helps to
* avoid inter-pdump start frame issues when the driver is not reloaded.
* No need to call PDumpCtrlUpdateCaptureStatus() direct as the set
* current frame call will.
*/
PDumpCtrlSetCurrentFrame(0);
}
static INLINE IMG_BOOL PDumpCtrlCapModIsFramed(void)
{
return g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED;
}
static INLINE IMG_BOOL PDumpCtrlCapModIsContinuous(void)
{
return g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_CONTINUOUS;
}
static IMG_UINT32 PDumpCtrlGetCurrentFrame(void)
{
return g_PDumpCtrl.ui32CurrentFrame;
}
static INLINE IMG_BOOL PDumpCtrlCaptureOn(void)
{
return !g_PDumpCtrl.bSuspended && g_PDumpCtrl.bCaptureOn;
}
static INLINE IMG_BOOL PDumpCtrlCaptureRangePast(void)
{
return (g_PDumpCtrl.ui32CurrentFrame > g_PDumpCtrl.sCaptureRange.ui32End);
}
/* Used to imply if the PDump client is connected or not. */
static INLINE IMG_BOOL PDumpCtrlCaptureRangeUnset(void)
{
return ((g_PDumpCtrl.sCaptureRange.ui32Start == FRAME_UNSET) &&
(g_PDumpCtrl.sCaptureRange.ui32End == FRAME_UNSET));
}
static IMG_BOOL PDumpCtrlIsLastCaptureFrame(void)
{
if (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED)
{
/* Is the next capture frame within the range end limit? */
if ((g_PDumpCtrl.ui32CurrentFrame + g_PDumpCtrl.sCaptureRange.ui32Interval) > g_PDumpCtrl.sCaptureRange.ui32End)
{
return IMG_TRUE;
}
}
else
{
PVR_DPF((PVR_DBG_ERROR, "PDumpCtrIsLastCaptureFrame: Unexpected capture mode (%x)", g_PDumpCtrl.ui32DefaultCapMode));
}
/* Return false for continuous capture mode or when in framed mode */
return IMG_FALSE;
}
static INLINE IMG_BOOL PDumpCtrlInitPhaseComplete(void)
{
return !g_PDumpCtrl.bInitPhaseActive;
}
static INLINE void PDumpCtrlSetInitPhaseComplete(IMG_BOOL bIsComplete)
{
if (bIsComplete)
{
g_PDumpCtrl.bInitPhaseActive = IMG_FALSE;
PDUMP_HEREA(102);
}
else
{
g_PDumpCtrl.bInitPhaseActive = IMG_TRUE;
PDUMP_HEREA(103);
}
}
static INLINE void PDumpCtrlSuspend(void)
{
PDUMP_HEREA(104);
g_PDumpCtrl.bSuspended = IMG_TRUE;
}
static INLINE void PDumpCtrlResume(void)
{
PDUMP_HEREA(105);
g_PDumpCtrl.bSuspended = IMG_FALSE;
}
static INLINE IMG_BOOL PDumpCtrlIsDumpSuspended(void)
{
return g_PDumpCtrl.bSuspended;
}
static INLINE void PDumpCtrlPowerTransitionStart(void)
{
g_PDumpCtrl.bInPowerTransition = IMG_TRUE;
}
static INLINE void PDumpCtrlPowerTransitionEnd(void)
{
g_PDumpCtrl.bInPowerTransition = IMG_FALSE;
}
static INLINE IMG_BOOL PDumpCtrlInPowerTransition(void)
{
return g_PDumpCtrl.bInPowerTransition;
}
static PVRSRV_ERROR PDumpCtrlIsCaptureFrame(IMG_BOOL *bIsCapturing)
{
*bIsCapturing = PDumpCtrlCaptureOn();
return PVRSRV_OK;
}
/********************************************************************************
End of PDumpCtrl*** functions
*********************************************************************************/
/*
Wrapper functions which need to be exposed in pdump_km.h for use in other
pdump_*** modules safely. These functions call the specific PDumpCtrl layer
function after acquiring the PDUMP_CTRL_STATE lock, hence making the calls
from other modules hassle free by avoiding the acquire/release CtrlLock
calls.
*/
void PDumpPowerTransitionStart(void)
{
PDumpCtrlLockAcquire();
PDumpCtrlPowerTransitionStart();
PDumpCtrlLockRelease();
}
void PDumpPowerTransitionEnd(void)
{
PDumpCtrlLockAcquire();
PDumpCtrlPowerTransitionEnd();
PDumpCtrlLockRelease();
}
IMG_BOOL PDumpInPowerTransition(void)
{
IMG_BOOL bPDumpInPowerTransition = IMG_FALSE;
PDumpCtrlLockAcquire();
bPDumpInPowerTransition = PDumpCtrlInPowerTransition();
PDumpCtrlLockRelease();
return bPDumpInPowerTransition;
}
IMG_BOOL PDumpIsDumpSuspended(void)
{
IMG_BOOL bPDumpIsDumpSuspended;
PDumpCtrlLockAcquire();
bPDumpIsDumpSuspended = PDumpCtrlIsDumpSuspended();
PDumpCtrlLockRelease();
return bPDumpIsDumpSuspended;
}
/*****************************************************************************/
/* PDump Common Write Layer just above PDump OS Layer */
/*****************************************************************************/
/*
Checks in this method were seeded from the original PDumpWriteILock()
and DBGDrivWriteCM() and have grown since to ensure PDump output
matches legacy output.
Note: the order of the checks in this method is important as some
writes have multiple pdump flags set!
*/
static IMG_BOOL PDumpWriteAllowed(IMG_UINT32 ui32Flags)
{
/* Lock down the PDUMP_CTRL_STATE struct before calling the following
PDumpCtrl*** functions. This is to avoid updates to the Control data
while we are reading from it */
PDumpCtrlLockAcquire();
/* No writes if in framed mode and range pasted */
if (PDumpCtrlCaptureRangePast())
{
PDUMP_HERE(10);
goto unlockAndReturnFalse;
}
/* No writes while writing is suspended */
if (PDumpCtrlIsDumpSuspended())
{
PDUMP_HERE(11);
goto unlockAndReturnFalse;
}
/* Prevent PDumping during a power transition */
if (PDumpCtrlInPowerTransition())
{ /* except when it's flagged */
if (ui32Flags & PDUMP_FLAGS_POWER)
{
PDUMP_HERE(20);
goto unlockAndReturnTrue;
}
PDUMP_HERE(16);
goto unlockAndReturnFalse;
}
/* Always allow dumping in init phase and when persistent flagged */
if (ui32Flags & PDUMP_FLAGS_PERSISTENT)
{
PDUMP_HERE(12);
goto unlockAndReturnTrue;
}
if (!PDumpCtrlInitPhaseComplete())
{
PDUMP_HERE(15);
goto unlockAndReturnTrue;
}
/* The following checks are made when the driver has completed initialisation */
/* If PDump client connected allow continuous flagged writes */
if (PDUMP_IS_CONTINUOUS(ui32Flags))
{
if (PDumpCtrlCaptureRangeUnset()) /* Is client connected? */
{
PDUMP_HERE(13);
goto unlockAndReturnFalse;
}
PDUMP_HERE(14);
goto unlockAndReturnTrue;
}
/* No last/deinit statements allowed when not in initialisation phase */
if (PDUMP_IS_CONTINUOUS(ui32Flags))
{
if (PDumpCtrlInitPhaseComplete())
{
PDUMP_HERE(17);
PVR_DPF((PVR_DBG_ERROR, "PDumpWriteAllowed: DEINIT flag used at the wrong time outside of initialisation!"));
goto unlockAndReturnFalse;
}
}
/*
If no flags are provided then it is FRAMED output and the frame
range must be checked matching expected behaviour.
*/
if (PDumpCtrlCapModIsFramed() && !PDumpCtrlCaptureOn())
{
PDUMP_HERE(18);
goto unlockAndReturnFalse;
}
PDUMP_HERE(19);
unlockAndReturnTrue:
/* Allow the write to take place */
PDumpCtrlLockRelease();
return IMG_TRUE;
unlockAndReturnFalse:
PDumpCtrlLockRelease();
return IMG_FALSE;
}
#undef PDUMP_DEBUG_SCRIPT_LINES
#if defined(PDUMP_DEBUG_SCRIPT_LINES)
#define PDUMPOSDEBUGDRIVERWRITE(a,b,c,d) _PDumpOSDebugDriverWrite(a,b,c,d)
static IMG_UINT32 _PDumpOSDebugDriverWrite( IMG_HANDLE psStream,
IMG_UINT8 *pui8Data,
IMG_UINT32 ui32BCount,
IMG_UINT32 ui32Flags)
{
IMG_CHAR tmp1[80];
IMG_CHAR* streamName = "unkn";
if (g_PDumpScript.sCh.hDeinit == psStream)
streamName = "dein";
else if (g_PDumpScript.sCh.hInit == psStream)
streamName = "init";
else if (g_PDumpScript.sCh.hMain == psStream)
streamName = "main";
(void) PDumpOSSprintf(tmp1, 80, "-- %s, %x\n", streamName, ui32Flags);
(void) PDumpOSDebugDriverWrite(psStream, tmp1, OSStringLength(tmp1));
return PDumpOSDebugDriverWrite(psStream, pui8Data, ui32BCount);
}
#else
#define PDUMPOSDEBUGDRIVERWRITE(a,b,c,d) PDumpOSDebugDriverWrite(a,b,c)
#endif
/**************************************************************************/ /*!
@Function PDumpWriteToBuffer
@Description Write the supplied data to the PDump stream buffer and attempt
to handle any buffer full conditions to ensure all the data
requested to be written, is.
@Input psStream The address of the PDump stream buffer to write to
@Input pui8Data Pointer to the data to be written
@Input ui32BCount Number of bytes to write
@Input ui32Flags PDump statement flags.
@Return IMG_UINT32 Actual number of bytes written, may be less than
ui32BCount when buffer full condition could not
be avoided.
*/ /***************************************************************************/
static IMG_UINT32 PDumpWriteToBuffer(IMG_HANDLE psStream, IMG_UINT8 *pui8Data,
IMG_UINT32 ui32BCount, IMG_UINT32 ui32Flags)
{
IMG_UINT32 ui32BytesWritten = 0;
IMG_UINT32 ui32Off = 0;
while (ui32BCount > 0)
{
ui32BytesWritten = PDUMPOSDEBUGDRIVERWRITE(psStream, &pui8Data[ui32Off], ui32BCount, ui32Flags);
if (ui32BytesWritten == 0)
{
PVR_DPF((PVR_DBG_MESSAGE, "PDumpWriteToBuffer: Zero bytes written - release execution"));
PDumpOSReleaseExecution();
}
if (ui32BytesWritten != 0xFFFFFFFFU)
{
if (ui32BCount != ui32BytesWritten)
{
PVR_DPF((PVR_DBG_MESSAGE, "PDumpWriteToBuffer: partial write of %d bytes of %d bytes", ui32BytesWritten, ui32BCount));
}
ui32Off += ui32BytesWritten;
ui32BCount -= ui32BytesWritten;
}
else
{
PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToBuffer: Unrecoverable error received from the debug driver"));
if( PDumpOSGetCtrlState(psStream, DBG_GET_STATE_FLAG_IS_READONLY) )
{
/* Fatal -suspend PDump to prevent flooding kernel log buffer */
PVR_LOG(("PDump suspended, debug driver out of memory"));
/*
Acquire the control lock before updating "suspended" state. This may not be required
because "this" is the context which checks the "suspended" state in PDumpWriteAllowed
before calling this function. So, this update is mainly for other contexts.
Also, all the other contexts which will/wish-to read the "suspended" state ought to be
waiting on the bridge lock first and then the PDUMP_OSLOCK (to pdump into script or
parameter buffer). However, this acquire may be useful incase the PDump call is being
made from a direct bridge
*/
PDumpCtrlLockAcquire();
PDumpCtrlSuspend();
PDumpCtrlLockRelease();
}
return 0;
}
}
/* reset buffer counters */
ui32BCount = ui32Off; ui32Off = 0; ui32BytesWritten = 0;
return ui32BCount;
}
/**************************************************************************/ /*!
@Function PDumpWriteToChannel
@Description Write the supplied data to the PDump channel specified obeying
flags to write to the necessary channel buffers.
@Input psChannel The address of the script or parameter channel object
@Input/Output psWOff The address of the channel write offsets object to
update on successful writing
@Input pui8Data Pointer to the data to be written
@Input ui32Size Number of bytes to write
@Input ui32Flags PDump statement flags, they may be clear (no flags)
which implies framed data, continuous flagged,
persistent flagged, or continuous AND persistent
flagged and they determine how the data is output.
On the first test app run after driver load, the
Display Controller dumps a resource that is both
continuous and persistent and this needs writing to
both the init (persistent) and main (continuous)
channel buffers to ensure the data is dumped in
subsequent test runs without reloading the driver.
In subsequent runs the PDump client 'freezes' the
init buffer so that only one dump of persistent data
for the "extended init phase" is captured to the
init buffer.
@Return IMG_BOOL True when the data has been consumed, false otherwise
*/ /***************************************************************************/
static IMG_BOOL PDumpWriteToChannel(PDUMP_CHANNEL* psChannel, PDUMP_CHANNEL_WOFFSETS* psWOff,
IMG_UINT8* pui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags)
{
IMG_UINT32 ui32BytesWritten = 0;
PDUMP_HERE(210);
/* Dump data to deinit buffer when flagged as deinit */
if (ui32Flags & PDUMP_FLAGS_DEINIT)
{
PDUMP_HERE(211);
ui32BytesWritten = PDumpWriteToBuffer(psChannel->hDeinit, pui8Data, ui32Size, ui32Flags);
if (ui32BytesWritten != ui32Size)
{
PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: DEINIT Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
PDUMP_HERE(212);
return IMG_FALSE;
}
if (psWOff)
{
psWOff->ui32Deinit += ui32Size;
}
}
else
{
IMG_BOOL bDumpedToInitAlready = IMG_FALSE;
IMG_HANDLE* phStream = NULL;
IMG_UINT32* pui32Offset = NULL;
/* Always append persistent data to init phase so it's available on
* subsequent app runs, but also to the main stream if client connected */
if (ui32Flags & PDUMP_FLAGS_PERSISTENT)
{
PDUMP_HERE(213);
ui32BytesWritten = PDumpWriteToBuffer( psChannel->hInit, pui8Data, ui32Size, ui32Flags);
if (ui32BytesWritten != ui32Size)
{
PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: PERSIST Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
PDUMP_HERE(214);
return IMG_FALSE;
}
bDumpedToInitAlready = IMG_TRUE;
if (psWOff)
{
psWOff->ui32Init += ui32Size;
}
/* Don't write continuous data if client not connected */
PDumpCtrlLockAcquire();
if (PDUMP_IS_CONTINUOUS(ui32Flags) && PDumpCtrlCaptureRangeUnset())
{
PDumpCtrlLockRelease();
return IMG_TRUE;
}
PDumpCtrlLockRelease();
}
/* Prepare to write the data to the main stream for
* persistent, continuous or framed data. Override and use init
* stream if driver still in init phase and we have not written
* to it yet.*/
PDumpCtrlLockAcquire();
if (!PDumpCtrlInitPhaseComplete() && !bDumpedToInitAlready)
{
PDUMP_HERE(215);
phStream = &psChannel->hInit;
if (psWOff)
{
pui32Offset = &psWOff->ui32Init;
}
}
else
{
PDUMP_HERE(216);
phStream = &psChannel->hMain;
if (psWOff)
{
pui32Offset = &psWOff->ui32Main;
}
}
PDumpCtrlLockRelease();
/* Write the data to the stream */
ui32BytesWritten = PDumpWriteToBuffer(*phStream, pui8Data, ui32Size, ui32Flags);
if (ui32BytesWritten != ui32Size)
{
PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: MAIN Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
PDUMP_HERE(217);
return IMG_FALSE;
}
if (pui32Offset)
{
*pui32Offset += ui32BytesWritten;
}
}
return IMG_TRUE;
}
#if defined(PDUMP_DEBUG_OUTFILES)
static IMG_UINT32 _GenerateChecksum(void *pvData, size_t uiSize)
{
IMG_UINT32 ui32Sum = 0;
IMG_UINT32 *pui32Data = pvData;
IMG_UINT8 *pui8Data = pvData;
IMG_UINT32 i;
IMG_UINT32 ui32LeftOver;
for(i = 0; i < uiSize / sizeof(IMG_UINT32); i++)
{
ui32Sum += pui32Data[i];
}
ui32LeftOver = uiSize % sizeof(IMG_UINT32);
while(ui32LeftOver)
{
ui32Sum += pui8Data[uiSize - ui32LeftOver];
ui32LeftOver--;
}
return ui32Sum;
}
#endif
PVRSRV_ERROR PDumpWriteParameter(IMG_UINT8 *pui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags,
IMG_UINT32* pui32FileOffset, IMG_CHAR* aszFilenameStr)
{
PVRSRV_ERROR eError = PVRSRV_OK;
IMG_BOOL bPDumpCtrlInitPhaseComplete = IMG_FALSE;
PVR_ASSERT(pui8Data && (ui32Size!=0));
PVR_ASSERT(pui32FileOffset && aszFilenameStr);
PDUMP_HERE(1);
if (!PDumpWriteAllowed(ui32Flags))
{
/* Abort write for the above reason but indicate what happened to
* caller to avoid disrupting the driver, caller should treat it as OK
* but skip any related PDump writes to the script file. */
return PVRSRV_ERROR_PDUMP_NOT_ALLOWED;
}
PDUMP_HERE(2);
PDumpCtrlLockAcquire();
bPDumpCtrlInitPhaseComplete = PDumpCtrlInitPhaseComplete();
PDumpCtrlLockRelease();
if (!bPDumpCtrlInitPhaseComplete || (ui32Flags & PDUMP_FLAGS_PERSISTENT))
{
PDUMP_HERE(3);
/* Init phase stream not expected to get above the file size max */
PVR_ASSERT(g_PDumpParameters.sWOff.ui32Init < g_PDumpParameters.ui32MaxFileSize);
/* Return the file write offset at which the parameter data was dumped */
*pui32FileOffset = g_PDumpParameters.sWOff.ui32Init;
}
else
{
PDUMP_HERE(4);
/* Do we need to signal the PDump client that a split is required? */
if (g_PDumpParameters.sWOff.ui32Main + ui32Size > g_PDumpParameters.ui32MaxFileSize)
{
PDUMP_HERE(5);
PDumpOSSetSplitMarker(g_PDumpParameters.sCh.hMain, g_PDumpParameters.sWOff.ui32Main);
g_PDumpParameters.ui32FileIdx++;
g_PDumpParameters.sWOff.ui32Main = 0;
}
/* Return the file write offset at which the parameter data was dumped */
*pui32FileOffset = g_PDumpParameters.sWOff.ui32Main;
}
/* Create the parameter file name, based on index, to be used in the script */
if (g_PDumpParameters.ui32FileIdx == 0)
{
eError = PDumpOSSprintf(aszFilenameStr, PDUMP_PARAM_MAX_FILE_NAME, PDUMP_PARAM_0_FILE_NAME);
}
else
{
PDUMP_HERE(6);
eError = PDumpOSSprintf(aszFilenameStr, PDUMP_PARAM_MAX_FILE_NAME, PDUMP_PARAM_N_FILE_NAME, g_PDumpParameters.ui32FileIdx);
}
PVR_LOGG_IF_ERROR(eError, "PDumpOSSprintf", errExit);
/* Write the parameter data to the parameter channel */
eError = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
if (!PDumpWriteToChannel(&g_PDumpParameters.sCh, &g_PDumpParameters.sWOff, pui8Data, ui32Size, ui32Flags))
{
PDUMP_HERE(7);
PVR_LOGG_IF_ERROR(eError, "PDumpWrite", errExit);
}
#if defined(PDUMP_DEBUG_OUTFILES)
else
{
IMG_UINT32 ui32Checksum;
PDUMP_GET_SCRIPT_STRING();
ui32Checksum = _GenerateChecksum(pui8Data, ui32Size);
/* CHK CHKSUM SIZE PRMOFFSET PRMFILE */
eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- CHK 0x%08X 0x%08X 0x%08X %s",
ui32Checksum,
ui32Size,
*pui32FileOffset,
aszFilenameStr);
if(eError != PVRSRV_OK)
{
goto errExit;
}
PDumpWriteScript(hScript, ui32Flags);
}
#endif
return PVRSRV_OK;
errExit:
return eError;
}
IMG_BOOL PDumpWriteScript(IMG_HANDLE hString, IMG_UINT32 ui32Flags)
{
PVR_ASSERT(hString);
PDUMP_HERE(201);
if (!PDumpWriteAllowed(ui32Flags))
{
/* Abort write for the above reasons but indicated it was OK to
* caller to avoid disrupting the driver */
return IMG_TRUE;
}
return PDumpWriteToChannel(&g_PDumpScript.sCh, NULL, (IMG_UINT8*) hString, (IMG_UINT32) OSStringLength((IMG_CHAR*) hString), ui32Flags);
}
/*****************************************************************************/
struct _PDUMP_CONNECTION_DATA_ {
IMG_UINT32 ui32RefCount;
POS_LOCK hLock;
DLLIST_NODE sListHead;
IMG_BOOL bLastInto;
IMG_UINT32 ui32LastSetFrameNumber;
IMG_BOOL bWasInCaptureRange;
IMG_BOOL bIsInCaptureRange;
IMG_BOOL bLastTransitionFailed;
SYNC_CONNECTION_DATA *psSyncConnectionData;
};
static PDUMP_CONNECTION_DATA * _PDumpConnectionAcquire(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
IMG_UINT32 ui32RefCount;
OSLockAcquire(psPDumpConnectionData->hLock);
ui32RefCount = ++psPDumpConnectionData->ui32RefCount;
OSLockRelease(psPDumpConnectionData->hLock);
PDUMP_REFCOUNT_PRINT("%s: PDump connection %p, refcount = %d",
__FUNCTION__, psPDumpConnectionData, ui32RefCount);
return psPDumpConnectionData;
}
static void _PDumpConnectionRelease(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
IMG_UINT32 ui32RefCount;
OSLockAcquire(psPDumpConnectionData->hLock);
ui32RefCount = --psPDumpConnectionData->ui32RefCount;
OSLockRelease(psPDumpConnectionData->hLock);
if (ui32RefCount == 0)
{
OSLockDestroy(psPDumpConnectionData->hLock);
PVR_ASSERT(dllist_is_empty(&psPDumpConnectionData->sListHead));
OSFreeMem(psPDumpConnectionData);
}
PDUMP_REFCOUNT_PRINT("%s: PDump connection %p, refcount = %d",
__FUNCTION__, psPDumpConnectionData, ui32RefCount);
}
/**************************************************************************
* Function Name : GetTempBuffer
* Inputs : None
* Outputs : None
* Returns : Temporary buffer address, or NULL
* Description : Get temporary buffer address.
**************************************************************************/
static void *GetTempBuffer(void)
{
/*
* Allocate the temporary buffer, if it hasn't been allocated already.
* Return the address of the temporary buffer, or NULL if it
* couldn't be allocated.
* It is expected that the buffer will be allocated once, at driver
* load time, and left in place until the driver unloads.
*/
if (gpvTempBuffer == NULL)
{
gpvTempBuffer = OSAllocMem(PDUMP_TEMP_BUFFER_SIZE);
if (gpvTempBuffer == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "GetTempBuffer: OSAllocMem failed"));
}
}
return gpvTempBuffer;
}
static void FreeTempBuffer(void)
{
if (gpvTempBuffer != NULL)
{
OSFreeMem(gpvTempBuffer);
gpvTempBuffer = NULL;
}
}
/**************************************************************************
* Function Name : PDumpParameterChannelZeroedPageBlock
* Inputs : None
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Set up the zero page block in the parameter stream
**************************************************************************/
static PVRSRV_ERROR PDumpParameterChannelZeroedPageBlock(void)
{
IMG_UINT8 aui8Zero[32] = { 0 };
size_t uiBytesToWrite;
PVRSRV_ERROR eError;
g_PDumpParameters.uiZeroPageSize = OSGetPageSize();
/* ensure the zero page size of a multiple of the zero source on the stack */
PVR_ASSERT(g_PDumpParameters.uiZeroPageSize % sizeof(aui8Zero) == 0);
/* the first write gets the parameter file name and stream offset,
* then subsequent writes do not need to know this as the data is
* contiguous in the stream
*/
PDUMP_LOCK();
eError = PDumpWriteParameter(aui8Zero,
sizeof(aui8Zero),
0,
&g_PDumpParameters.uiZeroPageOffset,
g_PDumpParameters.szZeroPageFilename);
if(eError != PVRSRV_OK)
{
/* Also treat PVRSRV_ERROR_PDUMP_NOT_ALLOWED as an error in this case
* as it should never happen since all writes during driver Init are allowed.
*/
goto err_write;
}
uiBytesToWrite = g_PDumpParameters.uiZeroPageSize - sizeof(aui8Zero);
while(uiBytesToWrite)
{
IMG_BOOL bOK;
bOK = PDumpWriteToChannel(&g_PDumpParameters.sCh, &g_PDumpParameters.sWOff,
aui8Zero,
sizeof(aui8Zero), 0);
if(!bOK)
{
eError = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
goto err_write;
}
uiBytesToWrite -= sizeof(aui8Zero);
}
err_write:
PDUMP_UNLOCK();
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "Failed to initialise parameter stream zero block"));
}
return eError;
}
/**************************************************************************
* Function Name : PDumpGetParameterZeroPageInfo
* Inputs : None
* Outputs : puiZeroPageOffset: will be set to the offset of the zero page
* : puiZeroPageSize: will be set to the size of the zero page
* : ppszZeroPageFilename: will be set to a pointer to the PRM file name
* : containing the zero page
* Returns : None
* Description : Get information about the zero page
**************************************************************************/
void PDumpGetParameterZeroPageInfo(PDUMP_FILEOFFSET_T *puiZeroPageOffset,
size_t *puiZeroPageSize,
const IMG_CHAR **ppszZeroPageFilename)
{
*puiZeroPageOffset = g_PDumpParameters.uiZeroPageOffset;
*puiZeroPageSize = g_PDumpParameters.uiZeroPageSize;
*ppszZeroPageFilename = g_PDumpParameters.szZeroPageFilename;
}
PVRSRV_ERROR PDumpInitCommon(void)
{
PVRSRV_ERROR eError;
IMG_UINT32 ui32InitCapMode = 0;
IMG_CHAR* pszEnvComment = NULL;
PDUMP_HEREA(2010);
/* Allocate temporary buffer for copying from user space */
(void) GetTempBuffer();
/* create the global PDump lock */
eError = PDumpCreateLockKM();
PVR_LOGG_IF_ERROR(eError, "PDumpCreateLockKM", errExit);
/* Call environment specific PDump initialisation */
eError = PDumpOSInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh, &ui32InitCapMode, &pszEnvComment);
PVR_LOGG_IF_ERROR(eError, "PDumpOSInit", errExitLock);
/* Initialise PDump control module in common layer */
eError = PDumpCtrlInit(ui32InitCapMode);
PVR_LOGG_IF_ERROR(eError, "PDumpCtrlInit", errExitOSDeInit);
/* Test PDump initialised and ready by logging driver details */
eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Driver Product Version: %s - %s (%s)", PVRVERSION_STRING, PVR_BUILD_DIR, PVR_BUILD_TYPE);
PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);
if (pszEnvComment != NULL)
{
eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "%s", pszEnvComment);
PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);
}
eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Start of Init Phase");
PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);
eError = PDumpParameterChannelZeroedPageBlock();
PVR_LOGG_IF_ERROR(eError, "PDumpParameterChannelZeroedPageBlock", errExitCtrl);
g_PDumpInitialised = IMG_TRUE;
PDUMP_HEREA(2011);
return PVRSRV_OK;
errExitCtrl:
PDumpCtrlDeInit();
errExitOSDeInit:
PDUMP_HEREA(2018);
PDumpOSDeInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh);
errExitLock:
PDUMP_HEREA(2019);
PDumpDestroyLockKM();
errExit:
return eError;
}
void PDumpDeInitCommon(void)
{
PDUMP_HEREA(2020);
g_PDumpInitialised = IMG_FALSE;
/* Free temporary buffer */
FreeTempBuffer();
/* DeInit the PDUMP_CTRL_STATE data */
PDumpCtrlDeInit();
/* Call environment specific PDump Deinitialisation */
PDumpOSDeInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh);
/* take down the global PDump lock */
PDumpDestroyLockKM();
}
IMG_BOOL PDumpReady(void)
{
return g_PDumpInitialised;
}
void PDumpStopInitPhase(IMG_BOOL bPDumpClient, IMG_BOOL bInitClient)
{
/* Check with the OS we a running on */
if (PDumpOSAllowInitPhaseToComplete(bPDumpClient, bInitClient))
{
if (bInitClient)
{
/* We only ouptut this once for bInitClient init phase ending OSs */
PDUMPCOMMENT("Stop Init Phase");
}
PDumpCtrlLockAcquire();
PDumpCtrlSetInitPhaseComplete(IMG_TRUE);
PDumpCtrlLockRelease();
}
}
PVRSRV_ERROR PDumpIsLastCaptureFrameKM(IMG_BOOL *pbIsLastCaptureFrame)
{
PDumpCtrlLockAcquire();
*pbIsLastCaptureFrame = PDumpCtrlIsLastCaptureFrame();
PDumpCtrlLockRelease();
return PVRSRV_OK;
}
typedef struct _PDUMP_Transition_DATA_ {
PFN_PDUMP_TRANSITION pfnCallback;
void *hPrivData;
PDUMP_CONNECTION_DATA *psPDumpConnectionData;
DLLIST_NODE sNode;
} PDUMP_Transition_DATA;
PVRSRV_ERROR PDumpRegisterTransitionCallback(PDUMP_CONNECTION_DATA *psPDumpConnectionData,
PFN_PDUMP_TRANSITION pfnCallback,
void *hPrivData,
void **ppvHandle)
{
PDUMP_Transition_DATA *psData;
PVRSRV_ERROR eError;
psData = OSAllocMem(sizeof(*psData));
if (psData == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_alloc;
}
/* Setup the callback and add it to the list for this process */
psData->pfnCallback = pfnCallback;
psData->hPrivData = hPrivData;
dllist_add_to_head(&psPDumpConnectionData->sListHead, &psData->sNode);
/* Take a reference on the connection so it doesn't get freed too early */
psData->psPDumpConnectionData =_PDumpConnectionAcquire(psPDumpConnectionData);
*ppvHandle = psData;
return PVRSRV_OK;
fail_alloc:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
void PDumpUnregisterTransitionCallback(void *pvHandle)
{
PDUMP_Transition_DATA *psData = pvHandle;
dllist_remove_node(&psData->sNode);
_PDumpConnectionRelease(psData->psPDumpConnectionData);
OSFreeMem(psData);
}
PVRSRV_ERROR PDumpTransition(PDUMP_CONNECTION_DATA *psPDumpConnectionData, IMG_BOOL bInto, IMG_UINT32 ui32PDumpFlags)
{
DLLIST_NODE *psNode, *psNext;
PVRSRV_ERROR eError;
/* Only call the callbacks if we've really done a Transition */
if (bInto != psPDumpConnectionData->bLastInto)
{
/* We're Transitioning either into or out of capture range */
dllist_foreach_node(&psPDumpConnectionData->sListHead, psNode, psNext)
{
PDUMP_Transition_DATA *psData =
IMG_CONTAINER_OF(psNode, PDUMP_Transition_DATA, sNode);
eError = psData->pfnCallback(psData->hPrivData, bInto, ui32PDumpFlags);
if (eError != PVRSRV_OK)
{
return eError;
}
}
if (bInto)
{
SyncConnectionPDumpSyncBlocks(psPDumpConnectionData->psSyncConnectionData);
}
psPDumpConnectionData->bLastInto = bInto;
}
return PVRSRV_OK;
}
PVRSRV_ERROR PDumpIsCaptureFrameKM(IMG_BOOL *bIsCapturing)
{
PDumpCtrlLockAcquire();
PDumpCtrlIsCaptureFrame(bIsCapturing);
PDumpCtrlLockRelease();
return PVRSRV_OK;
}
static PVRSRV_ERROR _PDumpSetFrameKM(CONNECTION_DATA *psConnection,
IMG_UINT32 ui32Frame)
{
PDUMP_CONNECTION_DATA *psPDumpConnectionData = psConnection->psPDumpConnectionData;
IMG_BOOL bWasInCaptureRange = IMG_FALSE;
IMG_BOOL bIsInCaptureRange = IMG_FALSE;
PVRSRV_ERROR eError;
/*
Note:
As we can't test to see if the new frame will be in capture range
before we set the frame number and we don't want to roll back the
frame number if we fail then we have to save the "transient" data
which decides if we're entering or exiting capture range along
with a failure boolean so we know what's required on a retry
*/
if (psPDumpConnectionData->ui32LastSetFrameNumber != ui32Frame)
{
(void) PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Set pdump frame %u", ui32Frame);
/*
The boolean values below decide if the PDump transition
should trigger because of the current context setting the
frame number, hence the functions below should execute
atomically and do not give a chance to some other context
to transition
*/
PDumpCtrlLockAcquire();
PDumpCtrlIsCaptureFrame(&bWasInCaptureRange);
PDumpCtrlSetCurrentFrame(ui32Frame);
PDumpCtrlIsCaptureFrame(&bIsInCaptureRange);
PDumpCtrlLockRelease();
psPDumpConnectionData->ui32LastSetFrameNumber = ui32Frame;
/* Save the Transition data incase we fail the Transition */
psPDumpConnectionData->bWasInCaptureRange = bWasInCaptureRange;
psPDumpConnectionData->bIsInCaptureRange = bIsInCaptureRange;
}
else if (psPDumpConnectionData->bLastTransitionFailed)
{
/* Load the Transition data so we can try again */
bWasInCaptureRange = psPDumpConnectionData->bWasInCaptureRange;
bIsInCaptureRange = psPDumpConnectionData->bIsInCaptureRange;
}
else
{
/* New frame is the same as the last frame set and the last
* transition succeeded, no need to perform another transition.
*/
return PVRSRV_OK;
}
if (!bWasInCaptureRange && bIsInCaptureRange)
{
eError = PDumpTransition(psPDumpConnectionData, IMG_TRUE, PDUMP_FLAGS_NONE);
if (eError != PVRSRV_OK)
{
goto fail_Transition;
}
}
else if (bWasInCaptureRange && !bIsInCaptureRange)
{
eError = PDumpTransition(psPDumpConnectionData, IMG_FALSE, PDUMP_FLAGS_NONE);
if (eError != PVRSRV_OK)
{
goto fail_Transition;
}
}
else
{
/* Here both previous and current frames are in or out of range.
* There is no transition in this case.
*/
}
psPDumpConnectionData->bLastTransitionFailed = IMG_FALSE;
return PVRSRV_OK;
fail_Transition:
psPDumpConnectionData->bLastTransitionFailed = IMG_TRUE;
return eError;
}
PVRSRV_ERROR PDumpSetFrameKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE * psDeviceNode,
IMG_UINT32 ui32Frame)
{
PVRSRV_ERROR eError = PVRSRV_OK;
PVR_UNREFERENCED_PARAMETER(psDeviceNode);
#if defined(PDUMP_TRACE_STATE)
PVR_DPF((PVR_DBG_WARNING, "PDumpSetFrameKM: ui32Frame( %d )", ui32Frame));
#endif
#if defined(PDUMP_DEBUG_OUTFILES)
(void) PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Set pdump frame %u (pre)", ui32Frame);
#endif
eError = _PDumpSetFrameKM(psConnection, ui32Frame);
if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY))
{
PVR_LOG_ERROR(eError, "_PDumpSetFrameKM");
}
#if defined(PDUMP_DEBUG_OUTFILES)
(void) PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Set pdump frame %u (post)", ui32Frame);
#endif
return eError;
}
PVRSRV_ERROR PDumpGetFrameKM(CONNECTION_DATA *psConnection,
PVRSRV_DEVICE_NODE * psDeviceNode,
IMG_UINT32* pui32Frame)
{
PVRSRV_ERROR eError = PVRSRV_OK;
PVR_UNREFERENCED_PARAMETER(psConnection);
/*
It may be safe to avoid acquiring this lock here as all the other calls
which read/modify current frame will wait on the PDump Control bridge
lock first. Also, in no way as of now, does the PDumping app modify the
current frame through a call which acquires the global bridge lock.
Still, as a legacy we acquire and then read.
*/
PDumpCtrlLockAcquire();
*pui32Frame = PDumpCtrlGetCurrentFrame();
PDumpCtrlLockRelease();
return eError;
}
PVRSRV_ERROR PDumpSetDefaultCaptureParamsKM(IMG_UINT32 ui32Mode,
IMG_UINT32 ui32Start,
IMG_UINT32 ui32End,
IMG_UINT32 ui32Interval,
IMG_UINT32 ui32MaxParamFileSize)
{
/*
Acquire PDUMP_CTRL_STATE struct lock before modifications as a
PDumping app may be reading the state data for some checks
*/
PDumpCtrlLockAcquire();
PDumpCtrlSetDefaultCaptureParams(ui32Mode, ui32Start, ui32End, ui32Interval);
PDumpCtrlLockRelease();
if (ui32MaxParamFileSize == 0)
{
g_PDumpParameters.ui32MaxFileSize = PRM_FILE_SIZE_MAX;
}
else
{
g_PDumpParameters.ui32MaxFileSize = ui32MaxParamFileSize;
}
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpReg32
* Inputs : pszPDumpDevName, Register offset, and value to write
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a register write
**************************************************************************/
PVRSRV_ERROR PDumpReg32(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
IMG_UINT32 ui32Data,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpReg32"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:0x%08X 0x%08X", pszPDumpRegName, ui32Reg, ui32Data);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpReg64
* Inputs : pszPDumpDevName, Register offset, and value to write
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a register write
**************************************************************************/
PVRSRV_ERROR PDumpReg64(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
IMG_UINT64 ui64Data,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpRegKM"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X 0x%010llX", pszPDumpRegName, ui32Reg, ui64Data);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpRegLabelToReg64
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a register write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToReg64(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32RegDst,
IMG_UINT32 ui32RegSrc,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpRegLabelToReg64"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X :%s:0x%08X", pszPDumpRegName, ui32RegDst, pszPDumpRegName, ui32RegSrc);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpRegLabelToMem32
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a memory write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToMem32(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
PMR *psPMR,
IMG_DEVMEM_OFFSET_T uiLogicalOffset,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
IMG_DEVMEM_OFFSET_T uiNextSymName;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpRegLabelToMem32"));
eErr = PMR_PDumpSymbolicAddr(psPMR,
uiLogicalOffset,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceName,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicName,
&uiPDumpSymbolicOffset,
&uiNextSymName);
if (eErr != PVRSRV_OK)
{
return eErr;
}
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:%s:0x%llX :%s:0x%08X",aszMemspaceName, aszSymbolicName,
uiPDumpSymbolicOffset, pszPDumpRegName, ui32Reg);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpRegLabelToMem64
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a memory write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToMem64(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
PMR *psPMR,
IMG_DEVMEM_OFFSET_T uiLogicalOffset,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
IMG_DEVMEM_OFFSET_T uiNextSymName;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpRegLabelToMem64"));
eErr = PMR_PDumpSymbolicAddr(psPMR,
uiLogicalOffset,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceName,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicName,
&uiPDumpSymbolicOffset,
&uiNextSymName);
if (eErr != PVRSRV_OK)
{
return eErr;
}
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:%s:0x%llX :%s:0x%08X",aszMemspaceName, aszSymbolicName,
uiPDumpSymbolicOffset, pszPDumpRegName, ui32Reg);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpMemLabelToInternalVar
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents an internal var write using a memory label
**************************************************************************/
PVRSRV_ERROR PDumpMemLabelToInternalVar(IMG_CHAR *pszInternalVar,
PMR *psPMR,
IMG_DEVMEM_OFFSET_T uiLogicalOffset,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
IMG_DEVMEM_OFFSET_T uiNextSymName;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpMemLabelToInternalVar"));
eErr = PMR_PDumpSymbolicAddr(psPMR,
uiLogicalOffset,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceName,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicName,
&uiPDumpSymbolicOffset,
&uiNextSymName);
if (eErr != PVRSRV_OK)
{
return eErr;
}
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW %s :%s:%s:0x%llX", pszInternalVar,
aszMemspaceName, aszSymbolicName, uiPDumpSymbolicOffset);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*!
******************************************************************************
@Function PDumpWriteRegANDValueOp
@Description
Emits the PDump commands for the logical OR operation
Var <- Var OR Value
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR PDumpWriteVarORValueOp (const IMG_CHAR *pszInternalVariable,
const IMG_UINT64 ui64Value,
const IMG_UINT32 ui32PDumpFlags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"OR %s %s 0x%llX",
pszInternalVariable,
pszInternalVariable,
ui64Value);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*******************************************************************************************************
* Function Name : PDumpRegLabelToInternalVar
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which writes a register label into an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpRegLabelToInternalVar(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
IMG_CHAR *pszInternalVar,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpRegLabelToInternalVar"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW %s :%s:0x%08X", pszInternalVar, pszPDumpRegName, ui32Reg);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*******************************************************************************************************
* Function Name : PDumpInternalVarToReg32
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a register write from an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpInternalVarToReg32(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
IMG_CHAR *pszInternalVar,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpInternalVarToReg32"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:0x%08X %s", pszPDumpRegName, ui32Reg, pszInternalVar);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*******************************************************************************************************
* Function Name : PDumpInternalVarToReg64
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a register write from an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpInternalVarToReg64(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32Reg,
IMG_CHAR *pszInternalVar,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpInternalVarToReg64"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X %s", pszPDumpRegName, ui32Reg, pszInternalVar);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*******************************************************************************************************
* Function Name : PDumpMemLabelToMem32
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a memory write from a memory label
********************************************************************************************************/
PVRSRV_ERROR PDumpMemLabelToMem32(PMR *psPMRSource,
PMR *psPMRDest,
IMG_DEVMEM_OFFSET_T uiLogicalOffsetSource,
IMG_DEVMEM_OFFSET_T uiLogicalOffsetDest,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
IMG_CHAR aszMemspaceNameSource[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicNameSource[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_CHAR aszMemspaceNameDest[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicNameDest[PHYSMEM_PDUMP_MEMSPNAME_SYMB_ADDR_MAX_LENGTH];
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetSource;
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetDest;
IMG_DEVMEM_OFFSET_T uiNextSymNameSource;
IMG_DEVMEM_OFFSET_T uiNextSymNameDest;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpMemLabelToMem32"));
eErr = PMR_PDumpSymbolicAddr(psPMRSource,
uiLogicalOffsetSource,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceNameSource,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicNameSource,
&uiPDumpSymbolicOffsetSource,
&uiNextSymNameSource);
if (eErr != PVRSRV_OK)
{
return eErr;
}
eErr = PMR_PDumpSymbolicAddr(psPMRDest,
uiLogicalOffsetDest,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceNameDest,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicNameDest,
&uiPDumpSymbolicOffsetDest,
&uiNextSymNameDest);
if (eErr != PVRSRV_OK)
{
return eErr;
}
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:%s:0x%llX :%s:%s:0x%llX",aszMemspaceNameDest, aszSymbolicNameDest,
uiPDumpSymbolicOffsetDest, aszMemspaceNameSource, aszSymbolicNameSource,
uiPDumpSymbolicOffsetSource);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*******************************************************************************************************
* Function Name : PDumpMemLabelToMem64
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Create a PDUMP string, which represents a memory write from a memory label
********************************************************************************************************/
PVRSRV_ERROR PDumpMemLabelToMem64(PMR *psPMRSource,
PMR *psPMRDest,
IMG_DEVMEM_OFFSET_T uiLogicalOffsetSource,
IMG_DEVMEM_OFFSET_T uiLogicalOffsetDest,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
IMG_CHAR aszMemspaceNameSource[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicNameSource[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_CHAR aszMemspaceNameDest[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
IMG_CHAR aszSymbolicNameDest[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetSource;
IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetDest;
IMG_DEVMEM_OFFSET_T uiNextSymNameSource;
IMG_DEVMEM_OFFSET_T uiNextSymNameDest;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpMemLabelToMem64"));
eErr = PMR_PDumpSymbolicAddr(psPMRSource,
uiLogicalOffsetSource,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceNameSource,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicNameSource,
&uiPDumpSymbolicOffsetSource,
&uiNextSymNameSource);
if (eErr != PVRSRV_OK)
{
return eErr;
}
eErr = PMR_PDumpSymbolicAddr(psPMRDest,
uiLogicalOffsetDest,
PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
aszMemspaceNameDest,
PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
aszSymbolicNameDest,
&uiPDumpSymbolicOffsetDest,
&uiNextSymNameDest);
if (eErr != PVRSRV_OK)
{
return eErr;
}
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:%s:0x%llX :%s:%s:0x%llX",aszMemspaceNameDest, aszSymbolicNameDest,
uiPDumpSymbolicOffsetDest, aszMemspaceNameSource, aszSymbolicNameSource,
uiPDumpSymbolicOffsetSource);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*!
******************************************************************************
@Function PDumpWriteVarSHRValueOp
@Description
Emits the PDump commands for the logical SHR operation
Var <- Var SHR Value
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR PDumpWriteVarSHRValueOp (const IMG_CHAR *pszInternalVariable,
const IMG_UINT64 ui64Value,
const IMG_UINT32 ui32PDumpFlags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SHR %s %s 0x%llX",
pszInternalVariable,
pszInternalVariable,
ui64Value);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*!
******************************************************************************
@Function PDumpWriteRegANDValueOp
@Description
Emits the PDump commands for the logical AND operation
Var <- Var AND Value
@Return PVRSRV_ERROR
******************************************************************************/
PVRSRV_ERROR PDumpWriteVarANDValueOp (const IMG_CHAR *pszInternalVariable,
const IMG_UINT64 ui64Value,
const IMG_UINT32 ui32PDumpFlags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"AND %s %s 0x%llX",
pszInternalVariable,
pszInternalVariable,
ui64Value);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpSAW
* Inputs : pszDevSpaceName -- device space from which to output
* ui32Offset -- offset value from register base
* ui32NumSaveBytes -- number of bytes to output
* pszOutfileName -- name of file to output to
* ui32OutfileOffsetByte -- offset into output file to write
* uiPDumpFlags -- flags to pass to PDumpOSWriteScript
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : Dumps the contents of a register bank into a file
* NB: ui32NumSaveBytes must be divisible by 4
**************************************************************************/
PVRSRV_ERROR PDumpSAW(IMG_CHAR *pszDevSpaceName,
IMG_UINT32 ui32HPOffsetBytes,
IMG_UINT32 ui32NumSaveBytes,
IMG_CHAR *pszOutfileName,
IMG_UINT32 ui32OutfileOffsetByte,
PDUMP_FLAGS_T uiPDumpFlags)
{
PVRSRV_ERROR eError;
PDUMP_GET_SCRIPT_STRING()
PVR_DPF((PVR_DBG_ERROR, "PDumpSAW\n"));
PDUMP_LOCK();
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SAW :%s:0x%x 0x%x 0x%x %s\n",
pszDevSpaceName,
ui32HPOffsetBytes,
ui32NumSaveBytes / (IMG_UINT32)sizeof(IMG_UINT32),
ui32OutfileOffsetByte,
pszOutfileName);
if(eError != PVRSRV_OK)
{
PVR_DPF((PVR_DBG_ERROR, "PDumpSAW PDumpOSBufprintf failed: eError=%u\n", eError));
PDUMP_UNLOCK();
return eError;
}
if(! PDumpWriteScript(hScript, uiPDumpFlags))
{
PVR_DPF((PVR_DBG_ERROR, "PDumpSAW PDumpWriteScript failed!\n"));
}
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpRegPolKM
* Inputs : Description of what this register read is trying to do
* pszPDumpDevName
* Register offset
* expected value
* mask for that value
* Outputs : None
* Returns : None
* Description : Create a PDUMP string which represents a register read
* with the expected value
**************************************************************************/
PVRSRV_ERROR PDumpRegPolKM(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32RegAddr,
IMG_UINT32 ui32RegValue,
IMG_UINT32 ui32Mask,
IMG_UINT32 ui32Flags,
PDUMP_POLL_OPERATOR eOperator)
{
/* Timings correct for linux and XP */
/* Timings should be passed in */
#define POLL_DELAY 1000U
#define POLL_COUNT_LONG (2000000000U / POLL_DELAY)
#define POLL_COUNT_SHORT (1000000U / POLL_DELAY)
PVRSRV_ERROR eErr;
IMG_UINT32 ui32PollCount;
PDUMP_GET_SCRIPT_STRING();
PDUMP_DBG(("PDumpRegPolKM"));
ui32PollCount = POLL_COUNT_LONG;
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "POL :%s:0x%08X 0x%08X 0x%08X %d %u %d",
pszPDumpRegName, ui32RegAddr, ui32RegValue,
ui32Mask, eOperator, ui32PollCount, POLL_DELAY);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/* Never call direct, needs caller to hold OS Lock.
* Use PDumpCommentWithFlags() from within the server.
* Clients call this via the bridge and PDumpCommentKM().
*/
static PVRSRV_ERROR _PDumpWriteComment(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
#if defined(PDUMP_DEBUG_OUTFILES)
IMG_CHAR pszTemp[256];
#endif
PDUMP_GET_SCRIPT_STRING();
PDUMP_DBG(("PDumpCommentKM"));
if((pszComment == NULL) || (PDumpOSBuflen(pszComment, ui32MaxLen) == 0))
{
/* PDumpOSVerifyLineEnding silently fails if pszComment is too short to
actually hold the line endings that it's trying to enforce, so
short circuit it and force safety */
pszComment = "\n";
}
else
{
/* Put line ending sequence at the end if it isn't already there */
PDumpOSVerifyLineEnding(pszComment, ui32MaxLen);
}
#if defined(PDUMP_DEBUG_OUTFILES)
/* Prefix comment with PID and line number */
eErr = PDumpOSSprintf(pszTemp, 256, "%u %u:%lu %s: %s",
g_ui32EveryLineCounter,
OSGetCurrentClientProcessIDKM(),
(unsigned long)OSGetCurrentClientThreadIDKM(),
OSGetCurrentClientProcessNameKM(),
pszComment);
/* Append the comment to the script stream */
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- %s",
pszTemp);
#else
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- %s",
pszComment);
#endif
if( (eErr != PVRSRV_OK) &&
(eErr != PVRSRV_ERROR_PDUMP_BUF_OVERFLOW))
{
PVR_LOGG_IF_ERROR(eErr, "PDumpOSBufprintf", ErrUnlock);
}
if (!PDumpWriteScript(hScript, ui32Flags))
{
if(PDUMP_IS_CONTINUOUS(ui32Flags))
{
eErr = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
PVR_LOGG_IF_ERROR(eErr, "PDumpWriteScript", ErrUnlock);
}
else
{
eErr = PVRSRV_ERROR_CMD_NOT_PROCESSED;
PVR_LOGG_IF_ERROR(eErr, "PDumpWriteScript", ErrUnlock);
}
}
ErrUnlock:
return eErr;
}
/**************************************************************************
* Function Name : PDumpCommentKM
* Inputs : pszComment, ui32Flags
* Outputs : None
* Returns : None
* Description : Dumps a pre-formatted comment, primarily called from the
* : bridge.
**************************************************************************/
PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr = PVRSRV_OK;
PDUMP_LOCK();
eErr = _PDumpWriteComment(pszComment, ui32Flags);
PDUMP_UNLOCK();
return eErr;
}
/**************************************************************************
* Function Name : PDumpCommentWithFlags
* Inputs : psPDev - PDev for PDump device
* : pszFormat - format string for comment
* : ... - args for format string
* Outputs : None
* Returns : None
* Description : PDumps a comments
**************************************************************************/
PVRSRV_ERROR PDumpCommentWithFlags(IMG_UINT32 ui32Flags, IMG_CHAR * pszFormat, ...)
{
PVRSRV_ERROR eErr = PVRSRV_OK;
va_list args;
va_start(args, pszFormat);
PDumpCommentWithFlagsVA(ui32Flags, pszFormat, args);
va_end(args);
return eErr;
}
/**************************************************************************
* Function Name : PDumpCommentWithFlagsVA
* Inputs : psPDev - PDev for PDump device
* : pszFormat - format string for comment
* : args - pre-started va_list args for format string
* Outputs : None
* Returns : None
* Description : PDumps a comments
**************************************************************************/
PVRSRV_ERROR PDumpCommentWithFlagsVA(IMG_UINT32 ui32Flags, const IMG_CHAR * pszFormat, va_list args)
{
PVRSRV_ERROR eErr = PVRSRV_OK;
PDUMP_GET_MSG_STRING();
PDUMP_LOCK();
/* Construct the string */
eErr = PDumpOSVSprintf(pszMsg, ui32MaxLen, pszFormat, args);
if(eErr != PVRSRV_OK)
{
goto Unlock;
}
eErr = _PDumpWriteComment(pszMsg, ui32Flags);
Unlock:
PDUMP_UNLOCK();
return eErr;
}
/*************************************************************************/ /*!
* Function Name : PDumpPanic
* Inputs : ui32PanicNo - Unique number for panic condition
* : pszPanicMsg - Panic reason message limited to ~90 chars
* : pszPPFunc - Function name string where panic occurred
* : ui32PPline - Source line number where panic occurred
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : PDumps a panic assertion. Used when the host driver
* : detects a condition that will lead to an invalid PDump
* : script that cannot be played back off-line.
*/ /*************************************************************************/
PVRSRV_ERROR PDumpPanic(IMG_UINT32 ui32PanicNo,
IMG_CHAR* pszPanicMsg,
const IMG_CHAR* pszPPFunc,
IMG_UINT32 ui32PPline)
{
PVRSRV_ERROR eError = PVRSRV_OK;
PDUMP_FLAGS_T uiPDumpFlags = PDUMP_FLAGS_CONTINUOUS;
IMG_CHAR pszConsoleMsg[] =
"COM ***************************************************************************\n"
"COM Script invalid and not compatible with off-line playback. Check test \n"
"COM parameters and driver configuration, stop imminent.\n"
"COM ***************************************************************************\n";
PDUMP_GET_SCRIPT_STRING();
/* Log the panic condition to the live kern.log in both REL and DEB mode
* to aid user PDump trouble shooting. */
PVR_LOG(("PDUMP PANIC %08x: %s", ui32PanicNo, pszPanicMsg));
PVR_DPF((PVR_DBG_MESSAGE, "PDUMP PANIC start %s:%d", pszPPFunc, ui32PPline));
/* Check the supplied panic reason string is within length limits */
PVR_ASSERT(OSStringLength(pszPanicMsg)+sizeof("PANIC ") < PVRSRV_PDUMP_MAX_COMMENT_SIZE-1);
/* Obtain lock to keep the multi-line
* panic statement together in a single atomic write */
PDUMP_LOCK();
/* Write -- Panic start (Function:line) */
eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- Panic start (%s:%d)", pszPPFunc, ui32PPline);
PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
(void)PDumpWriteScript(hScript, uiPDumpFlags);
/* Write COM <message> x4 */
eError = PDumpOSBufprintf(hScript, ui32MaxLen, pszConsoleMsg);
PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
(void)PDumpWriteScript(hScript, uiPDumpFlags);
/* Write PANIC no msg command */
eError = PDumpOSBufprintf(hScript, ui32MaxLen, "PANIC %08x %s", ui32PanicNo, pszPanicMsg);
PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
(void)PDumpWriteScript(hScript, uiPDumpFlags);
/* Write -- Panic end */
eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- Panic end");
PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
(void)PDumpWriteScript(hScript, uiPDumpFlags);
e1:
PDUMP_UNLOCK();
return eError;
}
/*************************************************************************/ /*!
* Function Name : PDumpCaptureError
* Inputs : ui32ErrorNo - Unique number for panic condition
* : pszErrorMsg - Panic reason message limited to ~90 chars
* : pszPPFunc - Function name string where panic occurred
* : ui32PPline - Source line number where panic occurred
* Outputs : None
* Returns : PVRSRV_ERROR
* Description : PDumps an error string to the script file to interrupt
* : play back to inform user of a fatal issue that occurred
* : during PDump capture.
*/ /*************************************************************************/
PVRSRV_ERROR PDumpCaptureError(PVRSRV_ERROR ui32ErrorNo,
IMG_CHAR* pszErrorMsg,
const IMG_CHAR* pszPPFunc,
IMG_UINT32 ui32PPline)
{
IMG_CHAR* pszFormatStr = "DRIVER_ERROR: %3d: %s";
PDUMP_FLAGS_T uiPDumpFlags = PDUMP_FLAGS_CONTINUOUS;
/* Need to return an error using this macro */
PDUMP_GET_SCRIPT_STRING();
/* Check the supplied panic reason string is within length limits */
PVR_ASSERT(OSStringLength(pszErrorMsg)+sizeof(pszFormatStr) < PVRSRV_PDUMP_MAX_COMMENT_SIZE-1);
/* Obtain lock to keep the multi-line
* panic statement together in a single atomic write */
PDUMP_LOCK();
/* Write driver error message to the script file */
(void) PDumpOSBufprintf(hScript, ui32MaxLen, pszFormatStr, ui32ErrorNo, pszErrorMsg);
(void) PDumpWriteScript(hScript, uiPDumpFlags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*!
******************************************************************************
@Function PDumpBitmapKM
@Description
Dumps a bitmap from device memory to a file
@Input psDevId
@Input pszFileName
@Input ui32FileOffset
@Input ui32Width
@Input ui32Height
@Input ui32StrideInBytes
@Input sDevBaseAddr
@Input ui32Size
@Input ePixelFormat
@Input eMemFormat
@Input ui32PDumpFlags
@Return PVRSRV_ERROR :
******************************************************************************/
PVRSRV_ERROR PDumpBitmapKM( PVRSRV_DEVICE_NODE *psDeviceNode,
IMG_CHAR *pszFileName,
IMG_UINT32 ui32FileOffset,
IMG_UINT32 ui32Width,
IMG_UINT32 ui32Height,
IMG_UINT32 ui32StrideInBytes,
IMG_DEV_VIRTADDR sDevBaseAddr,
IMG_UINT32 ui32MMUContextID,
IMG_UINT32 ui32Size,
PDUMP_PIXEL_FORMAT ePixelFormat,
IMG_UINT32 ui32AddrMode,
IMG_UINT32 ui32PDumpFlags)
{
PVRSRV_DEVICE_IDENTIFIER *psDevId = &psDeviceNode->sDevId;
PVRSRV_ERROR eErr=0;
PDUMP_GET_SCRIPT_STRING();
PDumpCommentWithFlags(ui32PDumpFlags, "Dump bitmap of render.");
switch (ePixelFormat)
{
case PVRSRV_PDUMP_PIXEL_FORMAT_YUV8:
{
PDumpCommentWithFlags(ui32PDumpFlags, "YUV data. Switching from SII to SAB. Width=0x%08X Height=0x%08X Stride=0x%08X",
ui32Width, ui32Height, ui32StrideInBytes);
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SAB :%s:v%x:0x%010llX 0x%08X 0x%08X %s.bin\n",
psDevId->pszPDumpDevName,
ui32MMUContextID,
sDevBaseAddr.uiAddr,
ui32Size,
ui32FileOffset,
pszFileName);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
break;
}
case PVRSRV_PDUMP_PIXEL_FORMAT_420PL12YUV8: // YUV420 2 planes
{
const IMG_UINT32 ui32Plane0Size = ui32StrideInBytes*ui32Height;
const IMG_UINT32 ui32Plane1Size = ui32Plane0Size>>1; // YUV420
const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32Plane0Size;
const IMG_UINT32 ui32Plane1MemOffset = ui32Plane0Size;
PDumpCommentWithFlags(ui32PDumpFlags, "YUV420 2-plane. Width=0x%08X Height=0x%08X Stride=0x%08X",
ui32Width, ui32Height, ui32StrideInBytes);
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SII %s %s.bin :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
pszFileName,
pszFileName,
// Plane 0 (Y)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // Context id
sDevBaseAddr.uiAddr, // virtaddr
ui32Plane0Size, // size
ui32FileOffset, // fileoffset
// Plane 1 (UV)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // Context id
sDevBaseAddr.uiAddr+ui32Plane1MemOffset, // virtaddr
ui32Plane1Size, // size
ui32Plane1FileOffset, // fileoffset
ePixelFormat,
ui32Width,
ui32Height,
ui32StrideInBytes,
ui32AddrMode);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
break;
}
case PVRSRV_PDUMP_PIXEL_FORMAT_YUV_YV12: // YUV420 3 planes
{
const IMG_UINT32 ui32Plane0Size = ui32StrideInBytes*ui32Height;
const IMG_UINT32 ui32Plane1Size = ui32Plane0Size>>2; // YUV420
const IMG_UINT32 ui32Plane2Size = ui32Plane1Size;
const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32Plane0Size;
const IMG_UINT32 ui32Plane2FileOffset = ui32Plane1FileOffset + ui32Plane1Size;
const IMG_UINT32 ui32Plane1MemOffset = ui32Plane0Size;
const IMG_UINT32 ui32Plane2MemOffset = ui32Plane0Size+ui32Plane1Size;
PDumpCommentWithFlags(ui32PDumpFlags, "YUV420 3-plane. Width=0x%08X Height=0x%08X Stride=0x%08X",
ui32Width, ui32Height, ui32StrideInBytes);
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SII %s %s.bin :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
pszFileName,
pszFileName,
// Plane 0 (Y)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr, // virtaddr
ui32Plane0Size, // size
ui32FileOffset, // fileoffset
// Plane 1 (U)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane1MemOffset, // virtaddr
ui32Plane1Size, // size
ui32Plane1FileOffset, // fileoffset
// Plane 2 (V)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane2MemOffset, // virtaddr
ui32Plane2Size, // size
ui32Plane2FileOffset, // fileoffset
ePixelFormat,
ui32Width,
ui32Height,
ui32StrideInBytes,
ui32AddrMode);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
break;
}
case PVRSRV_PDUMP_PIXEL_FORMAT_YUV_YV32: // YV32 - 4 contiguous planes in the order VUYA, stride can be > width.
{
const IMG_UINT32 ui32PlaneSize = ui32StrideInBytes*ui32Height; // All 4 planes are the same size
const IMG_UINT32 ui32Plane0FileOffset = ui32FileOffset + (ui32PlaneSize<<1); // SII plane 0 is Y, which is YV32 plane 2
const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32PlaneSize; // SII plane 1 is U, which is YV32 plane 1
const IMG_UINT32 ui32Plane2FileOffset = ui32FileOffset; // SII plane 2 is V, which is YV32 plane 0
const IMG_UINT32 ui32Plane3FileOffset = ui32Plane0FileOffset + ui32PlaneSize; // SII plane 3 is A, which is YV32 plane 3
const IMG_UINT32 ui32Plane0MemOffset = ui32PlaneSize<<1;
const IMG_UINT32 ui32Plane1MemOffset = ui32PlaneSize;
const IMG_UINT32 ui32Plane2MemOffset = 0;
const IMG_UINT32 ui32Plane3MemOffset = ui32Plane0MemOffset + ui32PlaneSize;
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 4 planes. Width=0x%08X Height=0x%08X Stride=0x%08X",
ui32Width, ui32Height, ui32StrideInBytes);
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 plane size is 0x%08X", ui32PlaneSize);
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 0 Mem Offset=0x%08X", ui32Plane0MemOffset);
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 1 Mem Offset=0x%08X", ui32Plane1MemOffset);
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 2 Mem Offset=0x%08X", ui32Plane2MemOffset);
PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 3 Mem Offset=0x%08X", ui32Plane3MemOffset);
/*
SII <imageset> <filename> :<memsp1>:v<id1>:<virtaddr1> <size1> <fileoffset1> Y
:<memsp2>:v<id2>:<virtaddr2> <size2> <fileoffset2> U
:<memsp3>:v<id3>:<virtaddr3> <size3> <fileoffset3> V
:<memsp4>:v<id4>:<virtaddr4> <size4> <fileoffset4> A
<pixfmt> <width> <height> <stride> <addrmode>
*/
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SII %s %s.bin :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X :%s:v%x:0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
pszFileName,
pszFileName,
// Plane 0 (V)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane0MemOffset, // virtaddr
ui32PlaneSize, // size
ui32Plane0FileOffset, // fileoffset
// Plane 1 (U)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane1MemOffset, // virtaddr
ui32PlaneSize, // size
ui32Plane1FileOffset, // fileoffset
// Plane 2 (Y)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane2MemOffset, // virtaddr
ui32PlaneSize, // size
ui32Plane2FileOffset, // fileoffset
// Plane 3 (A)
psDevId->pszPDumpDevName, // memsp
ui32MMUContextID, // MMU context id
sDevBaseAddr.uiAddr+ui32Plane3MemOffset, // virtaddr
ui32PlaneSize, // size
ui32Plane3FileOffset, // fileoffset
ePixelFormat,
ui32Width,
ui32Height,
ui32StrideInBytes,
ui32AddrMode);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
break;
}
default: // Single plane formats
{
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SII %s %s.bin :%s:v%x:0x%010llX 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
pszFileName,
pszFileName,
psDevId->pszPDumpDevName,
ui32MMUContextID,
sDevBaseAddr.uiAddr,
ui32Size,
ui32FileOffset,
ePixelFormat,
ui32Width,
ui32Height,
ui32StrideInBytes,
ui32AddrMode);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
break;
}
}
return PVRSRV_OK;
}
/*!
******************************************************************************
@Function PDumpReadRegKM
@Description
Dumps a read from a device register to a file
@Input psConnection : connection info
@Input pszFileName
@Input ui32FileOffset
@Input ui32Address
@Input ui32Size
@Input ui32PDumpFlags
@Return PVRSRV_ERROR :
******************************************************************************/
PVRSRV_ERROR PDumpReadRegKM ( IMG_CHAR *pszPDumpRegName,
IMG_CHAR *pszFileName,
IMG_UINT32 ui32FileOffset,
IMG_UINT32 ui32Address,
IMG_UINT32 ui32Size,
IMG_UINT32 ui32PDumpFlags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PVR_UNREFERENCED_PARAMETER(ui32Size);
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SAB :%s:0x%08X 0x%08X %s",
pszPDumpRegName,
ui32Address,
ui32FileOffset,
pszFileName);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript( hScript, ui32PDumpFlags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*****************************************************************************
@name PDumpRegRead32
@brief Dump 32-bit register read to script
@param pszPDumpDevName - pdump device name
@param ui32RegOffset - register offset
@param ui32Flags - pdump flags
@return Error
*****************************************************************************/
PVRSRV_ERROR PDumpRegRead32(IMG_CHAR *pszPDumpRegName,
const IMG_UINT32 ui32RegOffset,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "RDW :%s:0x%X",
pszPDumpRegName,
ui32RegOffset);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*****************************************************************************
@name PDumpRegRead64
@brief Dump 64-bit register read to script
@param pszPDumpDevName - pdump device name
@param ui32RegOffset - register offset
@param ui32Flags - pdump flags
@return Error
*****************************************************************************/
PVRSRV_ERROR PDumpRegRead64(IMG_CHAR *pszPDumpRegName,
const IMG_UINT32 ui32RegOffset,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "RDW64 :%s:0x%X",
pszPDumpRegName,
ui32RegOffset);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/*****************************************************************************
FUNCTION : PDumpWriteShiftedMaskedValue
PURPOSE : Emits the PDump commands for writing a masked shifted address
into another location
PARAMETERS : PDump symbolic name and offset of target word
PDump symbolic name and offset of source address
right shift amount
left shift amount
mask
RETURNS : None
*****************************************************************************/
PVRSRV_ERROR
PDumpWriteShiftedMaskedValue(const IMG_CHAR *pszDestRegspaceName,
const IMG_CHAR *pszDestSymbolicName,
IMG_DEVMEM_OFFSET_T uiDestOffset,
const IMG_CHAR *pszRefRegspaceName,
const IMG_CHAR *pszRefSymbolicName,
IMG_DEVMEM_OFFSET_T uiRefOffset,
IMG_UINT32 uiSHRAmount,
IMG_UINT32 uiSHLAmount,
IMG_UINT32 uiMask,
IMG_DEVMEM_SIZE_T uiWordSize,
IMG_UINT32 uiPDumpFlags)
{
PVRSRV_ERROR eError;
/* Suffix of WRW command in PDump (i.e. WRW or WRW64) */
const IMG_CHAR *pszWrwSuffix;
/* Internal PDump register used for interim calculation */
const IMG_CHAR *pszPDumpIntRegSpace;
IMG_UINT32 uiPDumpIntRegNum;
PDUMP_GET_SCRIPT_STRING();
if ((uiWordSize != 4) && (uiWordSize != 8))
{
return PVRSRV_ERROR_NOT_SUPPORTED;
}
pszWrwSuffix = (uiWordSize == 8) ? "64" : "";
/* Should really "Acquire" a pdump register here */
pszPDumpIntRegSpace = pszDestRegspaceName;
uiPDumpIntRegNum = 1;
PDUMP_LOCK();
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
/* Should this be "MOV" instead? */
"WRW :%s:$%d :%s:%s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
/* dest */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src */
pszRefRegspaceName,
pszRefSymbolicName,
uiRefOffset);
if (eError != PVRSRV_OK)
{
goto ErrUnlock;
}
PDumpWriteScript(hScript, uiPDumpFlags);
if (uiSHRAmount > 0)
{
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SHR :%s:$%d :%s:$%d 0x%X\n",
/* dest */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src A */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src B */
uiSHRAmount);
if (eError != PVRSRV_OK)
{
goto ErrUnlock;
}
PDumpWriteScript(hScript, uiPDumpFlags);
}
if (uiSHLAmount > 0)
{
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SHL :%s:$%d :%s:$%d 0x%X\n",
/* dest */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src A */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src B */
uiSHLAmount);
if (eError != PVRSRV_OK)
{
goto ErrUnlock;
}
PDumpWriteScript(hScript, uiPDumpFlags);
}
if (uiMask != (1ULL << (8*uiWordSize))-1)
{
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"AND :%s:$%d :%s:$%d 0x%X\n",
/* dest */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src A */
pszPDumpIntRegSpace,
uiPDumpIntRegNum,
/* src B */
uiMask);
if (eError != PVRSRV_OK)
{
goto ErrUnlock;
}
PDumpWriteScript(hScript, uiPDumpFlags);
}
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"WRW%s :%s:%s:" IMG_DEVMEM_OFFSET_FMTSPEC " :%s:$%d\n",
pszWrwSuffix,
/* dest */
pszDestRegspaceName,
pszDestSymbolicName,
uiDestOffset,
/* src */
pszPDumpIntRegSpace,
uiPDumpIntRegNum);
if(eError != PVRSRV_OK)
{
goto ErrUnlock;
}
PDumpWriteScript(hScript, uiPDumpFlags);
ErrUnlock:
PDUMP_UNLOCK();
return eError;
}
PVRSRV_ERROR
PDumpWriteSymbAddress(const IMG_CHAR *pszDestSpaceName,
IMG_DEVMEM_OFFSET_T uiDestOffset,
const IMG_CHAR *pszRefSymbolicName,
IMG_DEVMEM_OFFSET_T uiRefOffset,
const IMG_CHAR *pszPDumpDevName,
IMG_UINT32 ui32WordSize,
IMG_UINT32 ui32AlignShift,
IMG_UINT32 ui32Shift,
IMG_UINT32 uiPDumpFlags)
{
const IMG_CHAR *pszWrwSuffix = "";
PVRSRV_ERROR eError = PVRSRV_OK;
PDUMP_GET_SCRIPT_STRING();
if (ui32WordSize == 8)
{
pszWrwSuffix = "64";
}
PDUMP_LOCK();
if (ui32AlignShift != ui32Shift)
{
/* Write physical address into a variable */
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"WRW%s :%s:$1 %s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
pszWrwSuffix,
/* dest */
pszPDumpDevName,
/* src */
pszRefSymbolicName,
uiRefOffset);
if (eError != PVRSRV_OK)
{
goto symbAddress_error;
}
PDumpWriteScript(hScript, uiPDumpFlags);
/* apply address alignment */
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SHR :%s:$1 :%s:$1 0x%X",
/* dest */
pszPDumpDevName,
/* src A */
pszPDumpDevName,
/* src B */
ui32AlignShift);
if (eError != PVRSRV_OK)
{
goto symbAddress_error;
}
PDumpWriteScript(hScript, uiPDumpFlags);
/* apply address shift */
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"SHL :%s:$1 :%s:$1 0x%X",
/* dest */
pszPDumpDevName,
/* src A */
pszPDumpDevName,
/* src B */
ui32Shift);
if (eError != PVRSRV_OK)
{
goto symbAddress_error;
}
PDumpWriteScript(hScript, uiPDumpFlags);
/* write result to register */
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"WRW%s :%s:0x%08X :%s:$1",
pszWrwSuffix,
pszDestSpaceName,
(IMG_UINT32)uiDestOffset,
pszPDumpDevName);
if (eError != PVRSRV_OK)
{
goto symbAddress_error;
}
PDumpWriteScript(hScript, uiPDumpFlags);
}
else
{
eError = PDumpOSBufprintf(hScript,
ui32MaxLen,
"WRW%s :%s:" IMG_DEVMEM_OFFSET_FMTSPEC " %s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
pszWrwSuffix,
/* dest */
pszDestSpaceName,
uiDestOffset,
/* src */
pszRefSymbolicName,
uiRefOffset);
if (eError != PVRSRV_OK)
{
goto symbAddress_error;
}
PDumpWriteScript(hScript, uiPDumpFlags);
}
symbAddress_error:
PDUMP_UNLOCK();
return eError;
}
/**************************************************************************
* Function Name : PDumpIDLWithFlags
* Inputs : Idle time in clocks
* Outputs : None
* Returns : Error
* Description : Dump IDL command to script
**************************************************************************/
PVRSRV_ERROR PDumpIDLWithFlags(IMG_UINT32 ui32Clocks, IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_DBG(("PDumpIDLWithFlags"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "IDL %u", ui32Clocks);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpIDL
* Inputs : Idle time in clocks
* Outputs : None
* Returns : Error
* Description : Dump IDL command to script
**************************************************************************/
PVRSRV_ERROR PDumpIDL(IMG_UINT32 ui32Clocks)
{
return PDumpIDLWithFlags(ui32Clocks, PDUMP_FLAGS_CONTINUOUS);
}
/*****************************************************************************
FUNCTION : PDumpRegBasedCBP
PURPOSE : Dump CBP command to script
PARAMETERS :
RETURNS : None
*****************************************************************************/
PVRSRV_ERROR PDumpRegBasedCBP(IMG_CHAR *pszPDumpRegName,
IMG_UINT32 ui32RegOffset,
IMG_UINT32 ui32WPosVal,
IMG_UINT32 ui32PacketSize,
IMG_UINT32 ui32BufferSize,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript,
ui32MaxLen,
"CBP :%s:0x%08X 0x%08X 0x%08X 0x%08X",
pszPDumpRegName,
ui32RegOffset,
ui32WPosVal,
ui32PacketSize,
ui32BufferSize);
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
PVRSRV_ERROR PDumpTRG(IMG_CHAR *pszMemSpace,
IMG_UINT32 ui32MMUCtxID,
IMG_UINT32 ui32RegionID,
IMG_BOOL bEnable,
IMG_UINT64 ui64VAddr,
IMG_UINT64 ui64LenBytes,
IMG_UINT32 ui32XStride,
IMG_UINT32 ui32Flags)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING();
PDUMP_LOCK();
if(bEnable)
{
eErr = PDumpOSBufprintf(hScript, ui32MaxLen,
"TRG :%s:v%u %u 0x%08llX 0x%08llX %u",
pszMemSpace, ui32MMUCtxID, ui32RegionID,
ui64VAddr, ui64LenBytes, ui32XStride);
}
else
{
eErr = PDumpOSBufprintf(hScript, ui32MaxLen,
"TRG :%s:v%u %u",
pszMemSpace, ui32MMUCtxID, ui32RegionID);
}
if(eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, ui32Flags);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpConnectionNotify
* Description : Called by the srvcore to tell PDump core that the
* PDump capture and control client has connected
**************************************************************************/
void PDumpConnectionNotify(void)
{
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
PVRSRV_DEVICE_NODE *psThis;
/* Give PDump control a chance to end the init phase, depends on OS */
if (!PDumpCtrlInitPhaseComplete())
{
PDumpStopInitPhase(IMG_TRUE, IMG_FALSE);
}
g_ConnectionCount++;
PVR_LOG(("PDump has connected (%u)", g_ConnectionCount));
/* Reset the parameter file attributes */
g_PDumpParameters.sWOff.ui32Main = g_PDumpParameters.sWOff.ui32Init;
g_PDumpParameters.ui32FileIdx = 0;
/* Loop over all known devices */
psThis = psPVRSRVData->psDeviceNodeList;
while (psThis)
{
if (psThis->pfnPDumpInitDevice)
{
/* Reset pdump according to connected device */
psThis->pfnPDumpInitDevice(psThis);
}
psThis = psThis->psNext;
}
}
/**************************************************************************
* Function Name : PDumpDisconnectionNotify
* Description : Called by the connection_server to tell PDump core that
* the PDump capture and control client has disconnected
**************************************************************************/
void PDumpDisconnectionNotify(void)
{
PVRSRV_ERROR eErr;
if (PDumpCtrlCaptureOn())
{
PVR_LOG(("PDump killed, output files may be invalid or incomplete!"));
/* Disable capture in server, in case PDump client was killed and did
* not get a chance to reset the capture parameters.
*/
eErr = PDumpSetDefaultCaptureParamsKM( DEBUG_CAPMODE_FRAMED,
FRAME_UNSET, FRAME_UNSET, 1, 0);
PVR_LOG_IF_ERROR(eErr, "PVRSRVPDumpSetDefaultCaptureParams");
}
else
{
PVR_LOG(("PDump disconnected"));
}
}
/**************************************************************************
* Function Name : PDumpIfKM
* Inputs : pszPDumpCond - string for condition
* Outputs : None
* Returns : None
* Description : Create a PDUMP string which represents IF command
with condition.
**************************************************************************/
PVRSRV_ERROR PDumpIfKM(IMG_CHAR *pszPDumpCond)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpIfKM"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "IF %s\n", pszPDumpCond);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpElseKM
* Inputs : pszPDumpCond - string for condition
* Outputs : None
* Returns : None
* Description : Create a PDUMP string which represents ELSE command
with condition.
**************************************************************************/
PVRSRV_ERROR PDumpElseKM(IMG_CHAR *pszPDumpCond)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpElseKM"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "ELSE %s\n", pszPDumpCond);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
/**************************************************************************
* Function Name : PDumpFiKM
* Inputs : pszPDumpCond - string for condition
* Outputs : None
* Returns : None
* Description : Create a PDUMP string which represents FI command
with condition.
**************************************************************************/
PVRSRV_ERROR PDumpFiKM(IMG_CHAR *pszPDumpCond)
{
PVRSRV_ERROR eErr;
PDUMP_GET_SCRIPT_STRING()
PDUMP_DBG(("PDumpFiKM"));
PDUMP_LOCK();
eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "FI %s\n", pszPDumpCond);
if (eErr != PVRSRV_OK)
{
PDUMP_UNLOCK();
return eErr;
}
PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
PDUMP_UNLOCK();
return PVRSRV_OK;
}
PVRSRV_ERROR PDumpCreateLockKM(void)
{
return PDumpOSCreateLock();
}
void PDumpDestroyLockKM(void)
{
PDumpOSDestroyLock();
}
void PDumpLock(void)
{
PDumpOSLock();
}
void PDumpUnlock(void)
{
PDumpOSUnlock();
}
#if defined(PVR_TESTING_UTILS)
extern void PDumpOSDumpState(void);
#if !defined(LINUX)
void PDumpOSDumpState(IMG_BOOL bDumpOSLayerState)
{
PVR_UNREFERENCED_PARAMETER(bDumpOSLayerState);
}
#endif
void PDumpCommonDumpState(IMG_BOOL bDumpOSLayerState)
{
PVR_LOG(("--- PDUMP COMMON: g_PDumpInitialised( %d )",
g_PDumpInitialised) );
PVR_LOG(("--- PDUMP COMMON: g_PDumpScript.sCh.hInit( %p ) g_PDumpScript.sCh.hMain( %p ) g_PDumpScript.sCh.hDeinit( %p )",
g_PDumpScript.sCh.hInit, g_PDumpScript.sCh.hMain, g_PDumpScript.sCh.hDeinit) );
PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.sCh.hInit( %p ) g_PDumpParameters.sCh.hMain( %p ) g_PDumpParameters.sCh.hDeinit( %p )",
g_PDumpParameters.sCh.hInit, g_PDumpParameters.sCh.hMain, g_PDumpParameters.sCh.hDeinit) );
PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.sWOff.ui32Init( %d ) g_PDumpParameters.sWOff.ui32Main( %d ) g_PDumpParameters.sWOff.ui32Deinit( %d )",
g_PDumpParameters.sWOff.ui32Init, g_PDumpParameters.sWOff.ui32Main, g_PDumpParameters.sWOff.ui32Deinit) );
PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.ui32FileIdx( %d )",
g_PDumpParameters.ui32FileIdx) );
PVR_LOG(("--- PDUMP COMMON: g_PDumpCtrl( %p ) bInitPhaseActive( %d ) ui32Flags( %x )",
&g_PDumpCtrl, g_PDumpCtrl.bInitPhaseActive, g_PDumpCtrl.ui32Flags) );
PVR_LOG(("--- PDUMP COMMON: ui32DefaultCapMode( %d ) ui32CurrentFrame( %d )",
g_PDumpCtrl.ui32DefaultCapMode, g_PDumpCtrl.ui32CurrentFrame) );
PVR_LOG(("--- PDUMP COMMON: sCaptureRange.ui32Start( %x ) sCaptureRange.ui32End( %x ) sCaptureRange.ui32Interval( %u )",
g_PDumpCtrl.sCaptureRange.ui32Start, g_PDumpCtrl.sCaptureRange.ui32End, g_PDumpCtrl.sCaptureRange.ui32Interval) );
PVR_LOG(("--- PDUMP COMMON: bCaptureOn( %d ) bSuspended( %d ) bInPowerTransition( %d )",
g_PDumpCtrl.bCaptureOn, g_PDumpCtrl.bSuspended, g_PDumpCtrl.bInPowerTransition) );
if (bDumpOSLayerState)
{
PDumpOSDumpState();
}
}
#endif
PVRSRV_ERROR PDumpRegisterConnection(SYNC_CONNECTION_DATA *psSyncConnectionData,
PDUMP_CONNECTION_DATA **ppsPDumpConnectionData)
{
PDUMP_CONNECTION_DATA *psPDumpConnectionData;
PVRSRV_ERROR eError;
PVR_ASSERT(ppsPDumpConnectionData != NULL);
psPDumpConnectionData = OSAllocMem(sizeof(*psPDumpConnectionData));
if (psPDumpConnectionData == NULL)
{
eError = PVRSRV_ERROR_OUT_OF_MEMORY;
goto fail_alloc;
}
eError = OSLockCreate(&psPDumpConnectionData->hLock, LOCK_TYPE_PASSIVE);
if (eError != PVRSRV_OK)
{
goto fail_lockcreate;
}
dllist_init(&psPDumpConnectionData->sListHead);
psPDumpConnectionData->ui32RefCount = 1;
psPDumpConnectionData->bLastInto = IMG_FALSE;
psPDumpConnectionData->ui32LastSetFrameNumber = FRAME_UNSET;
psPDumpConnectionData->bLastTransitionFailed = IMG_FALSE;
/*
* Although we don't take a ref count here, handle base destruction
* will ensure that any resource that might trigger us to do a
* Transition will have been freed before the sync blocks which
* are keeping the sync connection data alive.
*/
psPDumpConnectionData->psSyncConnectionData = psSyncConnectionData;
*ppsPDumpConnectionData = psPDumpConnectionData;
return PVRSRV_OK;
fail_lockcreate:
OSFreeMem(psPDumpConnectionData);
fail_alloc:
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
void PDumpUnregisterConnection(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
_PDumpConnectionRelease(psPDumpConnectionData);
}
#else /* defined(PDUMP) */
/* disable warning about empty module */
#ifdef _WIN32
#pragma warning (disable:4206)
#endif
#endif /* defined(PDUMP) */
/*****************************************************************************
End of file (pdump_common.c)
*****************************************************************************/