Blob Blame History Raw
From: Jordan Crouse <jcrouse@codeaurora.org>
Date: Tue, 24 Jul 2018 10:33:29 -0600
Subject: drm/msm/adreno: Add ringbuffer data to the GPU state
Git-commit: 43a56687d15db09f3cf7b9d53b182bdef86c17c0
Patch-mainline: v4.19-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Add the contents of each ringbuffer to the GPU state and dump the
data in the crash file encoded with ascii85. To save space only
the used portions of the ringbuffer are dumped.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 Documentation/gpu/msm-crash-dump.rst    |    7 +++++
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |   39 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/msm_gpu.h           |    2 +
 3 files changed, 48 insertions(+)

--- a/Documentation/gpu/msm-crash-dump.rst
+++ b/Documentation/gpu/msm-crash-dump.rst
@@ -59,6 +59,13 @@ ringbuffer
 	wptr
 		The current write pointer (wptr) for the ringbuffer.
 
+	size
+		Maximum size of the ringbuffer programmed in the hardware.
+
+	data
+		The contents of the ring encoded as ascii85.  Only the used
+		portions of the ring will be printed.
+
 registers
 	Set of registers values. Each entry is on its own line enclosed
 	by brackets { }.
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -17,6 +17,7 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/ascii85.h>
 #include <linux/pm_opp.h>
 #include "adreno_gpu.h"
 #include "msm_gem.h"
@@ -383,11 +384,29 @@ struct msm_gpu_state *adreno_gpu_state_g
 	do_gettimeofday(&state->time);
 
 	for (i = 0; i < gpu->nr_rings; i++) {
+		int size = 0, j;
+
 		state->ring[i].fence = gpu->rb[i]->memptrs->fence;
 		state->ring[i].iova = gpu->rb[i]->iova;
 		state->ring[i].seqno = gpu->rb[i]->seqno;
 		state->ring[i].rptr = get_rptr(adreno_gpu, gpu->rb[i]);
 		state->ring[i].wptr = get_wptr(gpu->rb[i]);
+
+		/* Copy at least 'wptr' dwords of the data */
+		size = state->ring[i].wptr;
+
+		/* After wptr find the last non zero dword to save space */
+		for (j = state->ring[i].wptr; j < MSM_GPU_RINGBUFFER_SZ >> 2; j++)
+			if (gpu->rb[i]->start[j])
+				size = j + 1;
+
+		if (size) {
+			state->ring[i].data = kmalloc(size << 2, GFP_KERNEL);
+			if (state->ring[i].data) {
+				memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2);
+				state->ring[i].data_size = size << 2;
+			}
+		}
 	}
 
 	/* Count the number of registers */
@@ -418,9 +437,13 @@ struct msm_gpu_state *adreno_gpu_state_g
 
 static void adreno_gpu_state_destroy(struct kref *kref)
 {
+	int i;
 	struct msm_gpu_state *state = container_of(kref,
 		struct msm_gpu_state, ref);
 
+	for (i = 0; i < ARRAY_SIZE(state->ring); i++)
+		kfree(state->ring[i].data);
+
 	kfree(state->comm);
 	kfree(state->cmd);
 	kfree(state->registers);
@@ -461,6 +484,22 @@ void adreno_show(struct msm_gpu *gpu, st
 		drm_printf(p, "    retired-fence: %d\n", state->ring[i].fence);
 		drm_printf(p, "    rptr: %d\n", state->ring[i].rptr);
 		drm_printf(p, "    wptr: %d\n", state->ring[i].wptr);
+		drm_printf(p, "    size: %d\n", MSM_GPU_RINGBUFFER_SZ);
+
+		if (state->ring[i].data && state->ring[i].data_size) {
+			u32 *ptr = (u32 *) state->ring[i].data;
+			char out[ASCII85_BUFSZ];
+			long len = ascii85_encode_len(state->ring[i].data_size);
+			int j;
+
+			drm_printf(p, "    data: !!ascii85 |\n");
+			drm_printf(p, "     ");
+
+			for (j = 0; j < len; j++)
+				drm_printf(p, ascii85_encode(ptr[j], out));
+
+			drm_printf(p, "\n");
+		}
 	}
 
 	drm_puts(p, "registers:\n");
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -191,6 +191,8 @@ struct msm_gpu_state {
 		u32 seqno;
 		u32 rptr;
 		u32 wptr;
+		void *data;
+		int data_size;
 	} ring[MSM_GPU_MAX_RINGS];
 
 	int nr_registers;