/*************************************************************************/ /*!
|
@File pvr_gputrace.c
|
@Title PVR GPU Trace module Linux implementation
|
@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.
|
*/ /**************************************************************************/
|
|
#include "pvrsrv_error.h"
|
#include "srvkm.h"
|
#include "pvr_debug.h"
|
#include "pvr_debugfs.h"
|
#include "pvr_uaccess.h"
|
|
#include "pvr_gputrace.h"
|
#include "rgxhwperf.h"
|
|
#include "trace_events.h"
|
#define CREATE_TRACE_POINTS
|
#include <trace/events/gpu.h>
|
#include "rogue_trace_events.h"
|
|
|
|
/******************************************************************************
|
Module internal implementation
|
******************************************************************************/
|
|
/* DebugFS entry for the feature's on/off file */
|
static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSGpuTracingOnEntry = NULL;
|
|
/* This variable is set when the gpu tracing is enabled but the HWPerf
|
* resources have not been initialised yet. This may most likely happen
|
* if the driver was built with SUPPORT_KERNEL_SRVINIT=1.
|
* If this variable is IMG_TRUE it means that the gpu tracing was enabled
|
* but the full initialisation is yet to be done. */
|
static IMG_BOOL gbFTraceGPUEventsPreEnabled = IMG_FALSE;
|
/* When this variable is IMG_TRUE it means that the gpu tracing has been fully
|
* initialised and enabled. */
|
static IMG_BOOL gbFTraceGPUEventsEnabled = IMG_FALSE;
|
|
/*
|
If SUPPORT_GPUTRACE_EVENTS is defined the drive is built with support
|
to route RGX HWPerf packets to the Linux FTrace mechanism. To allow
|
this routing feature to be switched on and off at run-time the following
|
debugfs entry is created:
|
/sys/kernel/debug/pvr/gpu_tracing_on
|
To enable GPU events in the FTrace log type the following on the target:
|
echo Y > /sys/kernel/debug/pvr/gpu_tracing_on
|
To disable, type:
|
echo N > /sys/kernel/debug/pvr/gpu_tracing_on
|
|
It is also possible to enable this feature at driver load by setting the
|
default application hint "EnableFTraceGPU=1" in /etc/powervr.ini.
|
*/
|
|
static void *GpuTracingSeqStart(struct seq_file *psSeqFile, loff_t *puiPosition)
|
{
|
if (*puiPosition == 0)
|
{
|
/* We want only one entry in the sequence, one call to show() */
|
return (void*)1;
|
}
|
|
return NULL;
|
}
|
|
|
static void GpuTracingSeqStop(struct seq_file *psSeqFile, void *pvData)
|
{
|
PVR_UNREFERENCED_PARAMETER(psSeqFile);
|
}
|
|
|
static void *GpuTracingSeqNext(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
|
{
|
PVR_UNREFERENCED_PARAMETER(psSeqFile);
|
return NULL;
|
}
|
|
|
static int GpuTracingSeqShow(struct seq_file *psSeqFile, void *pvData)
|
{
|
const IMG_CHAR *pszInit = "N\n";
|
|
if (gbFTraceGPUEventsEnabled)
|
// fully operational
|
pszInit = "Y\n";
|
else if (gbFTraceGPUEventsPreEnabled)
|
// partially initialised (probably HWPerf not initialised yet)
|
pszInit = "P\n";
|
|
PVR_UNREFERENCED_PARAMETER(pvData);
|
|
seq_puts(psSeqFile, pszInit);
|
return 0;
|
}
|
|
|
static struct seq_operations gsGpuTracingReadOps =
|
{
|
.start = GpuTracingSeqStart,
|
.stop = GpuTracingSeqStop,
|
.next = GpuTracingSeqNext,
|
.show = GpuTracingSeqShow,
|
};
|
|
|
static IMG_INT GpuTracingSet(const IMG_CHAR *buffer, size_t count, loff_t uiPosition, void *data)
|
{
|
IMG_CHAR cFirstChar;
|
|
PVR_UNREFERENCED_PARAMETER(uiPosition);
|
PVR_UNREFERENCED_PARAMETER(data);
|
|
if (!count)
|
{
|
return -EINVAL;
|
}
|
|
if (pvr_copy_from_user(&cFirstChar, buffer, 1))
|
{
|
return -EFAULT;
|
}
|
|
switch (cFirstChar)
|
{
|
case '0':
|
case 'n':
|
case 'N':
|
{
|
PVRGpuTraceEnabledSet(IMG_FALSE);
|
PVR_TRACE(("DISABLED GPU FTrace"));
|
break;
|
}
|
case '1':
|
case 'y':
|
case 'Y':
|
{
|
if (PVRGpuTraceEnabledSet(IMG_TRUE) == PVRSRV_OK)
|
{
|
PVR_TRACE(("ENABLED GPU FTrace"));
|
}
|
else
|
{
|
PVR_TRACE(("FAILED to enable GPU FTrace"));
|
}
|
break;
|
}
|
}
|
|
return count;
|
}
|
|
|
/******************************************************************************
|
Module In-bound API
|
******************************************************************************/
|
|
|
void PVRGpuTraceClientWork(
|
const IMG_UINT32 ui32CtxId,
|
const IMG_UINT32 ui32JobId,
|
const IMG_CHAR* pszKickType)
|
{
|
PVR_ASSERT(pszKickType);
|
|
PVR_DPF((PVR_DBG_VERBOSE, "PVRGpuTraceClientKick(%s): contextId %u, "
|
"jobId %u", pszKickType, ui32CtxId, ui32JobId));
|
|
if (PVRGpuTraceEnabled())
|
{
|
trace_gpu_job_enqueue(ui32CtxId, ui32JobId, pszKickType);
|
}
|
}
|
|
|
void PVRGpuTraceWorkSwitch(
|
IMG_UINT64 ui64HWTimestampInOSTime,
|
const IMG_UINT32 ui32CtxId,
|
const IMG_UINT32 ui32CtxPriority,
|
const IMG_UINT32 ui32JobId,
|
const IMG_CHAR* pszWorkType,
|
PVR_GPUTRACE_SWITCH_TYPE eSwType)
|
{
|
PVR_ASSERT(pszWorkType);
|
|
/* Invert the priority cause this is what systrace expects. Lower values
|
* convey a higher priority to systrace. */
|
trace_gpu_sched_switch(pszWorkType, ui64HWTimestampInOSTime,
|
eSwType == PVR_GPUTRACE_SWITCH_TYPE_END ? 0 : ui32CtxId,
|
2-ui32CtxPriority, ui32JobId);
|
}
|
|
void PVRGpuTraceUfo(
|
IMG_UINT64 ui64OSTimestamp,
|
const RGX_HWPERF_UFO_EV eEvType,
|
const IMG_UINT32 ui32ExtJobRef,
|
const IMG_UINT32 ui32CtxId,
|
const IMG_UINT32 ui32JobId,
|
const IMG_UINT32 ui32UFOCount,
|
const RGX_HWPERF_UFO_DATA_ELEMENT *puData)
|
{
|
switch (eEvType) {
|
case RGX_HWPERF_UFO_EV_UPDATE:
|
trace_rogue_ufo_updates(ui64OSTimestamp, ui32CtxId,
|
ui32JobId, ui32UFOCount, puData);
|
break;
|
case RGX_HWPERF_UFO_EV_CHECK_SUCCESS:
|
trace_rogue_ufo_checks_success(ui64OSTimestamp, ui32CtxId,
|
ui32JobId, IMG_FALSE, ui32UFOCount, puData);
|
break;
|
case RGX_HWPERF_UFO_EV_PRCHECK_SUCCESS:
|
trace_rogue_ufo_checks_success(ui64OSTimestamp, ui32CtxId,
|
ui32JobId, IMG_TRUE, ui32UFOCount, puData);
|
break;
|
case RGX_HWPERF_UFO_EV_CHECK_FAIL:
|
trace_rogue_ufo_checks_fail(ui64OSTimestamp, ui32CtxId,
|
ui32JobId, IMG_FALSE, ui32UFOCount, puData);
|
break;
|
case RGX_HWPERF_UFO_EV_PRCHECK_FAIL:
|
trace_rogue_ufo_checks_fail(ui64OSTimestamp, ui32CtxId,
|
ui32JobId, IMG_TRUE, ui32UFOCount, puData);
|
break;
|
default:
|
break;
|
}
|
}
|
|
void PVRGpuTraceFirmware(
|
IMG_UINT64 ui64HWTimestampInOSTime,
|
const IMG_CHAR* pszWorkType,
|
PVR_GPUTRACE_SWITCH_TYPE eSwType)
|
{
|
trace_rogue_firmware_activity(ui64HWTimestampInOSTime, pszWorkType, eSwType);
|
}
|
|
void PVRGpuTraceEventsLost(
|
const RGX_HWPERF_STREAM_ID eStreamId,
|
const IMG_UINT32 ui32LastOrdinal,
|
const IMG_UINT32 ui32CurrOrdinal)
|
{
|
trace_rogue_events_lost(eStreamId, ui32LastOrdinal, ui32CurrOrdinal);
|
}
|
|
PVRSRV_ERROR PVRGpuTraceInit(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
PVRSRV_ERROR eError;
|
|
eError = RGXHWPerfFTraceGPUInit(psDeviceNode);
|
if (eError != PVRSRV_OK)
|
return eError;
|
|
eError = PVRDebugFSCreateEntry("gpu_tracing_on", NULL, &gsGpuTracingReadOps,
|
(PVRSRV_ENTRY_WRITE_FUNC *)GpuTracingSet,
|
NULL, NULL, NULL,
|
&gpsPVRDebugFSGpuTracingOnEntry);
|
if (eError != PVRSRV_OK)
|
{
|
RGXHWPerfFTraceGPUDeInit(psDeviceNode);
|
return eError;
|
}
|
|
return PVRSRV_OK;
|
}
|
|
void PVRGpuTraceDeInit(PVRSRV_DEVICE_NODE *psDeviceNode)
|
{
|
/* gbFTraceGPUEventsEnabled and gbFTraceGPUEventsPreEnabled are cleared
|
* in this function. */
|
PVRGpuTraceEnabledSet(IMG_FALSE);
|
|
RGXHWPerfFTraceGPUDeInit(psDeviceNode);
|
|
/* Can be NULL if driver startup failed */
|
if (gpsPVRDebugFSGpuTracingOnEntry)
|
{
|
PVRDebugFSRemoveEntry(&gpsPVRDebugFSGpuTracingOnEntry);
|
}
|
}
|
|
IMG_BOOL PVRGpuTraceEnabled(void)
|
{
|
return gbFTraceGPUEventsEnabled;
|
}
|
|
void PVRGpuTraceSetEnabled(IMG_BOOL bEnabled)
|
{
|
gbFTraceGPUEventsEnabled = bEnabled;
|
}
|
|
IMG_BOOL PVRGpuTracePreEnabled(void)
|
{
|
return gbFTraceGPUEventsPreEnabled;
|
}
|
|
void PVRGpuTraceSetPreEnabled(IMG_BOOL bEnabled)
|
{
|
gbFTraceGPUEventsPreEnabled = bEnabled;
|
}
|
|
/******************************************************************************
|
End of file (pvr_gputrace.c)
|
******************************************************************************/
|