Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0fec7f5 authored by Jordan Crouse's avatar Jordan Crouse Committed by Rob Clark
Browse files

drm/msm/gpu: Capture the GPU state on a GPU hang



Capture the GPU state on a GPU hang and store it for later playback
via the devcoredump facility. Only one crash state is stored at a
time on the assumption that the first hang is usually the most
interesting. The existing crash state can be cleared after capturing
it and then a new one will be captured on the next hang.

Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 65a3c274
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ config DRM_MSM
	select SHMEM
	select TMPFS
	select QCOM_SCM
	select WANT_DEV_COREDUMP
	select SND_SOC_HDMI_CODEC if SND_SOC
	select SYNC_FILE
	select PM_OPP
+1 −1
Original line number Diff line number Diff line
@@ -454,7 +454,7 @@ static const struct adreno_gpu_funcs funcs = {
		.active_ring = adreno_active_ring,
		.irq = a3xx_irq,
		.destroy = a3xx_destroy,
#ifdef CONFIG_DEBUG_FS
#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
		.show = adreno_show,
#endif
		.gpu_state_get = a3xx_gpu_state_get,
+1 −1
Original line number Diff line number Diff line
@@ -540,7 +540,7 @@ static const struct adreno_gpu_funcs funcs = {
		.active_ring = adreno_active_ring,
		.irq = a4xx_irq,
		.destroy = a4xx_destroy,
#ifdef CONFIG_DEBUG_FS
#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
		.show = adreno_show,
#endif
		.gpu_state_get = a4xx_gpu_state_get,
+3 −1
Original line number Diff line number Diff line
@@ -1243,8 +1243,10 @@ static const struct adreno_gpu_funcs funcs = {
		.active_ring = a5xx_active_ring,
		.irq = a5xx_irq,
		.destroy = a5xx_destroy,
#ifdef CONFIG_DEBUG_FS
#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
		.show = adreno_show,
#endif
#if defined(CONFIG_DEBUG_FS)
		.debugfs_init = a5xx_debugfs_init,
#endif
		.gpu_busy = a5xx_gpu_busy,
+24 −12
Original line number Diff line number Diff line
@@ -378,6 +378,8 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu)
	if (!state)
		return ERR_PTR(-ENOMEM);

	kref_init(&state->ref);

	do_gettimeofday(&state->time);

	for (i = 0; i < gpu->nr_rings; i++) {
@@ -414,18 +416,28 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu)
	return state;
}

void adreno_gpu_state_put(struct msm_gpu_state *state)
static void adreno_gpu_state_destroy(struct kref *kref)
{
	if (IS_ERR_OR_NULL(state))
		return;
	struct msm_gpu_state *state = container_of(kref,
		struct msm_gpu_state, ref);

	kfree(state->comm);
	kfree(state->cmd);
	kfree(state->registers);
	kfree(state);
}

#ifdef CONFIG_DEBUG_FS
int adreno_gpu_state_put(struct msm_gpu_state *state)
{
	if (IS_ERR_OR_NULL(state))
		return 1;

	return kref_put(&state->ref, adreno_gpu_state_destroy);
}

#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
		struct seq_file *m)
		struct drm_printer *p)
{
	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
	int i;
@@ -433,23 +445,23 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
	if (IS_ERR_OR_NULL(state))
		return;

	seq_printf(m, "status:   %08x\n", state->rbbm_status);
	seq_printf(m, "revision: %d (%d.%d.%d.%d)\n",
	drm_printf(p, "status:   %08x\n", state->rbbm_status);
	drm_printf(p, "revision: %d (%d.%d.%d.%d)\n",
			adreno_gpu->info->revn, adreno_gpu->rev.core,
			adreno_gpu->rev.major, adreno_gpu->rev.minor,
			adreno_gpu->rev.patchid);

	for (i = 0; i < gpu->nr_rings; i++) {
		seq_printf(m, "rb %d: fence:    %d/%d\n", i,
		drm_printf(p, "rb %d: fence:    %d/%d\n", i,
			state->ring[i].fence, state->ring[i].seqno);

		seq_printf(m, "      rptr:     %d\n", state->ring[i].rptr);
		seq_printf(m, "rb wptr:  %d\n", state->ring[i].wptr);
		drm_printf(p, "      rptr:     %d\n", state->ring[i].rptr);
		drm_printf(p, "rb wptr:  %d\n", state->ring[i].wptr);
	}

	seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
	drm_printf(p, "IO:region %s 00000000 00020000\n", gpu->name);
	for (i = 0; i < state->nr_registers; i++) {
		seq_printf(m, "IO:R %08x %08x\n",
		drm_printf(p, "IO:R %08x %08x\n",
			state->registers[i * 2] << 2,
			state->registers[(i * 2) + 1]);
	}
Loading