Trace GPU activity

The firmware supports putting events (like when it starts/stops
processing activity) into a ringbuffer. Hook up tracing to the code that
reads and processes those events.

Bug: 13267

Change-Id: I2cc36bc1c322011ae9d8182355f5477f8f4bcb5d
diff --git a/BUILD.gn b/BUILD.gn
index af6ced5..01ad5ae 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -97,6 +97,7 @@
   "services/server/env/fuchsia/pmr_os.cc",
   "services/server/env/fuchsia/pvr_bridge_k.cc",
   "services/server/env/fuchsia/pvr_debug.cc",
+  "services/server/env/fuchsia/pvr_gputrace.cc",
   "services/system/common/env/fuchsia/dma_support.cc",
   "services/system/fuchsia/sysconfig.cc",
 ]
diff --git a/fuchsia/msd_img_device.cc b/fuchsia/msd_img_device.cc
index 09f2959..bcdac29 100644
--- a/fuchsia/msd_img_device.cc
+++ b/fuchsia/msd_img_device.cc
@@ -16,6 +16,7 @@
 #include "process_stats.h"
 #include "pvrsrv.h"
 #include "pvrsrv_error.h"
+#include "pvr_gputrace.h"
 #include "rgxdevice.h"
 #include "rgxinit.h"
 #include "srvcore.h"
@@ -55,8 +56,18 @@
 		SORgxGpuUtilStatsUnregister(stats_user_);
 	}
 #endif
+#if defined(SUPPORT_GPUTRACE_EVENTS)
+	if (trace_observer_)
+	{
+		trace_observer_.reset();
+		PVRGpuTraceEnabledSet(IMG_FALSE);
+	}
+#endif
 	if (device_node_)
 	{
+#if defined(SUPPORT_GPUTRACE_EVENTS)
+		PVRGpuTraceDeInitDevice(device_node_);
+#endif
 		PVRSRVDeviceDestroy(device_node_);
 	}
 	if (g_driver_initialized)
@@ -141,6 +152,24 @@
 		return DRETF(false, "Failed to initialize stats: %d", srv_err);
 	}
 #endif
+#if defined(SUPPORT_GPUTRACE_EVENTS)
+	srv_err = PVRGpuTraceInitDevice(device_node_);
+	if (srv_err != 0)
+	{
+		return DRETF(false, "Failed to initialize GPU tracing: %d", srv_err);
+	}
+	trace_observer_ = magma::PlatformTraceObserver::Create();
+	if (!trace_observer_)
+	{
+		return DRETF(false, "Failed to make trace observer");
+	}
+	trace_observer_->SetObserver([](bool enabled) {
+		PVRGpuTraceEnabledSet(static_cast<IMG_BOOL>(enabled));
+		// Don't enable UFO or Firmware activity notifications, since they seem
+		// pretty chatty.
+	});
+
+#endif
 	return true;
 }
 
diff --git a/fuchsia/msd_img_device.h b/fuchsia/msd_img_device.h
index de6612c..a92065c 100644
--- a/fuchsia/msd_img_device.h
+++ b/fuchsia/msd_img_device.h
@@ -13,6 +13,7 @@
 #include "msd_img_connection.h"
 #include "platform_bus_mapper.h"
 #include "platform_device.h"
+#include "platform_trace.h"
 
 typedef struct _PVRSRV_DEVICE_NODE_ PVRSRV_DEVICE_NODE;
 typedef void* IMG_HANDLE;
@@ -85,6 +86,7 @@
 #if !defined(NO_HARDWARE)
 	IMG_HANDLE stats_user_ = nullptr;
 #endif
+	std::unique_ptr<magma::PlatformTraceObserver> trace_observer_;
 
 	std::unique_ptr<FuchsiaSysInfo> sys_info_;
 };
diff --git a/include/config_kernel_fuchsia_mt8167.h b/include/config_kernel_fuchsia_mt8167.h
index 548acd3..dc6e1e5 100644
--- a/include/config_kernel_fuchsia_mt8167.h
+++ b/include/config_kernel_fuchsia_mt8167.h
@@ -127,6 +127,7 @@
 
 #define PVRSRV_ENABLE_PROCESS_STATS
 #define SUPPORT_DEVICEMEMHISTORY_BRIDGE
+#define SUPPORT_GPUTRACE_EVENTS 1
 #define SUPPORT_PAGE_FAULT_DEBUG
 #define PVRSRV_ENABLE_CCCB_UTILISATION_INFO
 #define PVRSRV_ENABLE_CCCB_UTILISATION_INFO_THRESHOLD 90
diff --git a/include/config_kernel_fuchsia_no_hardware.h b/include/config_kernel_fuchsia_no_hardware.h
index 2d5cae0..d6bf156 100644
--- a/include/config_kernel_fuchsia_no_hardware.h
+++ b/include/config_kernel_fuchsia_no_hardware.h
@@ -127,6 +127,7 @@
 #define RGX_FW_HEAP_SHIFT 25
 #define SUPPORT_DBGDRV_EVENT_OBJECTS
 #define SUPPORT_DEVICEMEMHISTORY_BRIDGE
+#define SUPPORT_GPUTRACE_EVENTS 1
 #define SUPPORT_MMU_PENDING_FAULT_PROTECTION
 #define SUPPORT_PAGE_FAULT_DEBUG
 #define SUPPORT_PERCONTEXT_FREELIST
diff --git a/services/server/env/fuchsia/pvr_gputrace.cc b/services/server/env/fuchsia/pvr_gputrace.cc
new file mode 100644
index 0000000..bef7af5
--- /dev/null
+++ b/services/server/env/fuchsia/pvr_gputrace.cc
@@ -0,0 +1,170 @@
+/*************************************************************************/ /*!
+@File           pvr_gputrace.c
+@Title          PVR GPU Trace module Linux implementation
+@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License        MIT
+
+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.
+
+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.
+*/ /**************************************************************************/
+
+extern "C"
+{
+#include "device.h"
+#include "pvr_debug.h"
+#include "pvr_gputrace.h"
+#include "pvrsrv_apphint.h"
+#include "pvrsrv_error.h"
+#include "rgxhwperf.h"
+}
+
+#include "platform_trace.h"
+
+
+/******************************************************************************
+ Module In-bound API
+******************************************************************************/
+
+uint64_t
+GetFlowId(const IMG_UINT32 ui32CtxId, const IMG_UINT32 ui32JobId)
+{
+	return (static_cast<uint64_t>(ui32CtxId) << 32) | ui32JobId;
+}
+
+void
+PVRGpuTraceClientWork(PVRSRV_DEVICE_NODE *psDevNode,
+		      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));
+
+	TRACE_INSTANT("magma", "Kick", TRACE_SCOPE_THREAD, "type", pszKickType, "ui32CtxId", ui32CtxId, "ui32JobId",
+		      ui32JobId);
+	TRACE_FLOW_BEGIN("magma", "work", GetFlowId(ui32CtxId, ui32JobId));
+}
+
+void
+PVRGpuTraceWorkSwitch(IMG_UINT64 ui64HWTimestampInOSTimeNs,
+		      const IMG_UINT32 ui32CtxId,
+		      const IMG_UINT32 ui32CtxPriority,
+		      const IMG_UINT32 ui32JobId,
+		      const IMG_CHAR *pszWorkType,
+		      PVR_GPUTRACE_SWITCH_TYPE eSwType)
+{
+	PVR_ASSERT(pszWorkType);
+
+	// ui64HWTimestampInOSTime is in ns.
+	uint64_t ticks = ui64HWTimestampInOSTimeNs * zx_ticks_per_second() / 1000000000;
+
+	if (eSwType == PVR_GPUTRACE_SWITCH_TYPE_BEGIN)
+	{
+		TRACE_VTHREAD_DURATION_BEGIN("magma", pszWorkType, "GPU", 0, ticks, "ui32CtxId", ui32CtxId, "ui32CtxPriority",
+					     ui32CtxPriority, "ui32JobId", ui32JobId);
+		TRACE_VTHREAD_FLOW_END("magma", "work", "GPU", 0, GetFlowId(ui32CtxId, ui32JobId), ticks);
+	}
+	else if (eSwType == PVR_GPUTRACE_SWITCH_TYPE_END)
+	{
+		TRACE_VTHREAD_DURATION_END("magma", pszWorkType, "GPU", 0, ticks, "ui32CtxId", ui32CtxId, "ui32CtxPriority",
+					   ui32CtxPriority, "ui32JobId", ui32JobId);
+	}
+	else
+	{
+		TRACE_VTHREAD_DURATION_BEGIN("magma", pszWorkType, "GPU", 0, ticks, "ui32CtxId", ui32CtxId, "ui32CtxPriority",
+					     ui32CtxPriority, "ui32JobId", ui32JobId);
+		TRACE_VTHREAD_DURATION_END("magma", pszWorkType, "GPU", 0, ticks, "ui32CtxId", ui32CtxId, "ui32CtxPriority",
+					   ui32CtxPriority, "ui32JobId", ui32JobId);
+	}
+}
+
+void
+PVRGpuTraceUfo(IMG_UINT64 ui64OSTimestampNs,
+	       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)
+{
+	// Never enabled.
+}
+
+void
+PVRGpuTraceFirmware(IMG_UINT64 ui64HWTimestampInOSTimeNs, const IMG_CHAR *pszWorkType, PVR_GPUTRACE_SWITCH_TYPE eSwType)
+{
+	// Never enabled.
+}
+
+void
+PVRGpuTraceEventsLost(const RGX_HWPERF_STREAM_ID eStreamId, const IMG_UINT32 ui32LastOrdinal, const IMG_UINT32 ui32CurrOrdinal)
+{
+	// Ignore
+}
+
+PVRSRV_ERROR
+PVRGpuTraceSupportInit(void)
+{
+	PVRSRV_ERROR eError;
+
+	eError = RGXHWPerfFTraceGPUInitSupport();
+	PVR_LOGR_IF_ERROR(eError, "RGXHWPerfFTraceGPUSupportInit");
+
+	return PVRSRV_OK;
+}
+
+void
+PVRGpuTraceSupportDeInit(void)
+{
+	RGXHWPerfFTraceGPUDeInitSupport();
+}
+
+PVRSRV_ERROR
+PVRGpuTraceInitDevice(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+	PVRSRV_ERROR eError;
+
+	eError = RGXHWPerfFTraceGPUInitDevice(psDeviceNode);
+	PVR_LOGG_IF_ERROR(eError, "RGXHWPerfFTraceGPUInitDevice", e0);
+
+	return PVRSRV_OK;
+
+e0:
+	RGXHWPerfFTraceGPUDeInitDevice(psDeviceNode);
+	return eError;
+}
+
+void
+PVRGpuTraceDeInitDevice(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+	RGXHWPerfFTraceGPUDeInitDevice(psDeviceNode);
+}
+
+
+/******************************************************************************
+ End of file (pvr_gputrace.c)
+******************************************************************************/
diff --git a/services/server/env/fuchsia/pvr_gputrace.h b/services/server/env/fuchsia/pvr_gputrace.h
new file mode 100644
index 0000000..7a54889
--- /dev/null
+++ b/services/server/env/fuchsia/pvr_gputrace.h
@@ -0,0 +1,121 @@
+/*************************************************************************/ /*!
+@File           pvr_gputrace.h
+@Title          PVR GPU Trace module common environment interface
+@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License        MIT
+
+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.
+
+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.
+*/ /**************************************************************************/
+
+#ifndef PVR_GPUTRACE_H_
+#define PVR_GPUTRACE_H_
+
+#include "img_types.h"
+#include "rgx_hwperf.h"
+#include "device.h"
+
+
+/******************************************************************************
+ Module out-bound API
+******************************************************************************/
+
+/*
+  The device layer of the KM driver defines these two APIs to allow a
+  platform module to set and retrieve the feature's on/off state.
+*/
+extern PVRSRV_ERROR
+PVRGpuTraceEnabledSet(IMG_BOOL bNewValue);
+extern PVRSRV_ERROR
+PVRGpuTraceEnabledSetNoBridgeLock(PVRSRV_DEVICE_NODE *psDeviceNode, IMG_BOOL bNewValue);
+
+/******************************************************************************
+ Module In-bound API
+******************************************************************************/
+
+typedef enum
+{
+	PVR_GPUTRACE_SWITCH_TYPE_UNDEF = 0,
+
+	PVR_GPUTRACE_SWITCH_TYPE_BEGIN = 1,
+	PVR_GPUTRACE_SWITCH_TYPE_END = 2
+
+} PVR_GPUTRACE_SWITCH_TYPE;
+
+void
+PVRGpuTraceClientWork(PVRSRV_DEVICE_NODE *psDevNode,
+		      const IMG_UINT32 ui32ExtJobRef,
+		      const IMG_UINT32 ui32IntJobRef,
+		      const IMG_CHAR *pszKickType);
+
+
+void
+PVRGpuTraceWorkSwitch(IMG_UINT64 ui64OSTimestamp,
+		      const IMG_UINT32 ui32ContextId,
+		      const IMG_UINT32 ui32CtxPriority,
+		      const IMG_UINT32 ui32JobId,
+		      const IMG_CHAR *pszWorkType,
+		      PVR_GPUTRACE_SWITCH_TYPE eSwType);
+
+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);
+
+void
+PVRGpuTraceFirmware(IMG_UINT64 ui64HWTimestampInOSTime, const IMG_CHAR *pszWorkType, PVR_GPUTRACE_SWITCH_TYPE eSwType);
+
+void
+PVRGpuTraceEventsLost(const RGX_HWPERF_STREAM_ID eStreamId,
+		      const IMG_UINT32 ui32LastOrdinal,
+		      const IMG_UINT32 ui32CurrOrdinal);
+
+/* Early initialisation of GPU Ftrace events logic.
+ * This function initialises some necessary structures. */
+PVRSRV_ERROR
+PVRGpuTraceSupportInit(void);
+void
+PVRGpuTraceSupportDeInit(void);
+
+PVRSRV_ERROR
+PVRGpuTraceInitDevice(PVRSRV_DEVICE_NODE *psDeviceNode);
+void
+PVRGpuTraceDeInitDevice(PVRSRV_DEVICE_NODE *psDeviceNode);
+
+/* FTrace events callbacks interface */
+
+void
+PVRGpuTraceEnableUfoCallback(void);
+void
+PVRGpuTraceDisableUfoCallback(void);
+
+void
+PVRGpuTraceEnableFirmwareActivityCallback(void);
+void
+PVRGpuTraceDisableFirmwareActivityCallback(void);
+
+#endif /* PVR_GPUTRACE_H_ */