| /*************************************************************************/ /*! |
| @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; |
| |
| OSLockAcquire(psPDumpConnectionData->hLock); |
| dllist_add_to_head(&psPDumpConnectionData->sListHead, &psData->sNode); |
| OSLockRelease(psPDumpConnectionData->hLock); |
| |
| /* 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; |
| |
| OSLockAcquire(psData->psPDumpConnectionData->hLock); |
| dllist_remove_node(&psData->sNode); |
| OSLockRelease(psData->psPDumpConnectionData->hLock); |
| _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) |
| { |
| OSLockAcquire(psPDumpConnectionData->hLock); |
| /* 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) |
| { |
| OSLockRelease(psPDumpConnectionData->hLock); |
| return eError; |
| } |
| } |
| OSLockRelease(psPDumpConnectionData->hLock); |
| |
| 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 : PDumpPhysHandleToInternalVar64 |
| * Returns : PVRSRV_ERROR |
| * Description : Create a PDUMP string, which represents an internal var |
| write using a PDump pages handle |
| **************************************************************************/ |
| PVRSRV_ERROR PDumpPhysHandleToInternalVar64(IMG_CHAR *pszInternalVar, |
| IMG_HANDLE hPdumpPages, |
| IMG_UINT32 ui32Flags) |
| { |
| PVRSRV_ERROR eErr; |
| IMG_CHAR *pszSymbolicName; |
| |
| PDUMP_GET_SCRIPT_STRING() |
| PDUMP_DBG(("PDumpPhysHandleToInternalVar64")); |
| |
| eErr = PDumpGetSymbolicAddr(hPdumpPages, |
| &pszSymbolicName); |
| if (eErr != PVRSRV_OK) |
| { |
| return eErr; |
| } |
| |
| PDUMP_LOCK(); |
| eErr = PDumpOSBufprintf(hScript, ui32MaxLen, |
| "WRW %s %s:0x%llX", |
| pszInternalVar, pszSymbolicName, 0llu); |
| if (eErr != PVRSRV_OK) |
| { |
| PDUMP_UNLOCK(); |
| return eErr; |
| } |
| |
| PDumpWriteScript(hScript, ui32Flags); |
| PDUMP_UNLOCK(); |
| |
| return PVRSRV_OK; |
| } |
| |
| /************************************************************************** |
| * Function Name : PDumpMemLabelToInternalVar64 |
| * Returns : PVRSRV_ERROR |
| * Description : Create a PDUMP string, which represents an internal var write using a memory label |
| **************************************************************************/ |
| PVRSRV_ERROR PDumpMemLabelToInternalVar64(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, "%s", 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) |
| *****************************************************************************/ |