Re: [PATCH 3/4] drm/msm/a8xx: add a memory-only GPU crash state

From: Rob Clark

Date: Mon Nov 02 2026 - 09:13:00 EST


On Sun, Nov 1, 2026 at 10:05 AM Nico Angelo Dela Cruz
<nicoangelodelacruz@xxxxxxxxx> wrote:
>
> a8xx had no gpu_state_get callback, so no devcoredump was ever
> produced when the GPU hung or faulted.
>
> Add a8xx_gpu_state_get(), a memory-only snapshot: the generic Adreno
> state from adreno_gpu_state_get() (ring buffer contents and fences,
> with rptr read from the hw_apriv shadow rather than a register), the
> GMU log/HFI/debug buffers and the HFI queue history. No register is
> read, because the GMU may be wedged and GX powered off when this runs
> from the recover worker or the SMMU fault path. As a result a8xx
> dumps always report "gpu-initialized: 0", as a6xx/a7xx dumps do when
> GX is off.
>
> The shared part moves out of a6xx_gpu_state_get() into
> a6xx_gpu_state_get_gmu(), which also runs adreno_gpu_state_get().
> It is a pure move except for a new gmu_regs parameter that gates
> a6xx_get_gmu_registers(); a6xx/a7xx pass true, so their output is
> unchanged. Reviewed with git diff --color-moved=dimmed-zebra: apart
> from the moved lines, the new code is the helper's signature, the
> "if (gmu_regs)" check, the locals the helper needs, and the call.
>
> Tested on an Adreno 830: IGT msm_recovery gpu-fault (6 of 6 runs) and
> natural GPU hangs produce dumps with the ringbuffer, gmu-log, gmu-hfi
> and queue-history sections; capture takes 1.1 to 4.0 ms.
>
> a6xx/a7xx: build and pure-move review only, Tested-by welcome.

If you are interested in a8xx gpu devcoredump support, may I suggest:

https://patchwork.freedesktop.org/series/176505/

I'm still looking for someone who has a830 who can test it

BR,
-R

> Signed-off-by: Nico Angelo Dela Cruz <nicoangelodelacruz@xxxxxxxxx>
> ---
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 7 +++
> drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 1 +
> drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 47 ++++++++++++++++-----
> 3 files changed, 45 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 92e8c8abb..0f4b0af0a 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -2918,9 +2918,16 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
> .active_ring = a6xx_active_ring,
> .irq = a8xx_irq,
> .destroy = a6xx_destroy,
> +#if defined(CONFIG_DRM_MSM_GPU_STATE)
> + .show = a6xx_show,
> +#endif
> .gpu_busy = a8xx_gpu_busy,
> .gpu_get_freq = a6xx_gmu_get_freq,
> .gpu_set_freq = a6xx_gpu_set_freq,
> +#if defined(CONFIG_DRM_MSM_GPU_STATE)
> + .gpu_state_get = a8xx_gpu_state_get,
> + .gpu_state_put = a6xx_gpu_state_put,
> +#endif
> .create_vm = a6xx_create_vm,
> .create_private_vm = a6xx_create_private_vm,
> .get_rptr = a6xx_get_rptr,
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> index 79912a33e..03432abf9 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> @@ -338,6 +338,7 @@ void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
> struct drm_printer *p);
>
> struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu);
> +struct msm_gpu_state *a8xx_gpu_state_get(struct msm_gpu *gpu);
> int a6xx_gpu_state_put(struct msm_gpu_state *state);
>
> void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off);
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
> index 26c17861c..a3751358a 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
> @@ -1629,25 +1629,19 @@ static void a7xx_get_indexed_registers(struct msm_gpu *gpu,
> return;
> }
>
> -struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
> +static void a6xx_gpu_state_get_gmu(struct msm_gpu *gpu,
> + struct a6xx_gpu_state *a6xx_state, bool gmu_regs)
> {
> - struct a6xx_crashdumper _dumper = { 0 }, *dumper = NULL;
> struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> - struct a6xx_gpu_state *a6xx_state = kzalloc_obj(*a6xx_state);
> - bool stalled;
> -
> - if (!a6xx_state)
> - return ERR_PTR(-ENOMEM);
> -
> - INIT_LIST_HEAD(&a6xx_state->objs);
>
> /* Get the generic state from the adreno core */
> adreno_gpu_state_get(gpu, &a6xx_state->base);
>
> if (!adreno_has_gmu_wrapper(adreno_gpu) &&
> !adreno_has_rgmu(adreno_gpu)) {
> - a6xx_get_gmu_registers(gpu, a6xx_state);
> + if (gmu_regs)
> + a6xx_get_gmu_registers(gpu, a6xx_state);
>
> a6xx_state->gmu_log = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.log);
> a6xx_state->gmu_hfi = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.hfi);
> @@ -1655,6 +1649,21 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
>
> a6xx_snapshot_gmu_hfi_history(gpu, a6xx_state);
> }
> +}
> +
> +struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
> +{
> + struct a6xx_crashdumper _dumper = { 0 }, *dumper = NULL;
> + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> + struct a6xx_gpu_state *a6xx_state = kzalloc_obj(*a6xx_state);
> + bool stalled;
> +
> + if (!a6xx_state)
> + return ERR_PTR(-ENOMEM);
> +
> + INIT_LIST_HEAD(&a6xx_state->objs);
> +
> + a6xx_gpu_state_get_gmu(gpu, a6xx_state, true);
>
> /* If GX isn't on the rest of the data isn't going to be accessible */
> if (!adreno_gpu->funcs->gx_is_on(adreno_gpu))
> @@ -1714,6 +1723,24 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
> return &a6xx_state->base;
> }
>
> +/*
> + * Memory-only snapshot for a8xx: no register is read, as the GMU may be
> + * wedged and GX powered off by the time this runs.
> + */
> +struct msm_gpu_state *a8xx_gpu_state_get(struct msm_gpu *gpu)
> +{
> + struct a6xx_gpu_state *a6xx_state = kzalloc_obj(*a6xx_state);
> +
> + if (!a6xx_state)
> + return ERR_PTR(-ENOMEM);
> +
> + INIT_LIST_HEAD(&a6xx_state->objs);
> +
> + a6xx_gpu_state_get_gmu(gpu, a6xx_state, false);
> +
> + return &a6xx_state->base;
> +}
> +
> static void a6xx_gpu_state_destroy(struct kref *kref)
> {
> struct a6xx_state_memobj *obj, *tmp;
> --
> 2.53.0
>