[PATCH] drm/msm/a5xx: don't read the GPMU registers on GPUs without a GPMU
From: Dmitry Baryshkov
Date: Sun Sep 20 2026 - 07:09:08 EST
Only a530/a540 have a GPMU. On the other a5xx parts, reading the
0xa800-0xac60 GPMU aperture during a crashdump resets the board -- on
sda660 (a512) a GPU hang thus reboots the SoC instead of recovering.
Split the GPMU block into its own array and collect it only when a GPMU
is present.
Fixes: e20c9284c8f2 ("drm/msm/adreno: Add support for Adreno 510 GPU")
Assisted-by: LLM
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 49 ++++++++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 5d96b8f63156..3974aaf6fd33 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1337,9 +1337,14 @@ static const u32 a5xx_registers[] = {
0xE800, 0xE806, 0xE810, 0xE89A, 0xE8A0, 0xE8A4, 0xE8AA, 0xE8EB,
0xE900, 0xE905, 0xEB80, 0xEB8F, 0xEBB0, 0xEBB0, 0xEC00, 0xEC05,
0xEC08, 0xECE9, 0xECF0, 0xECF0, 0xEA80, 0xEA80, 0xEA82, 0xEAA3,
- 0xEAA5, 0xEAC2, 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D,
- 0XA880, 0xA88D, 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5,
- 0xAC60, 0xAC60, ~0,
+ 0xEAA5, 0xEAC2, ~0,
+};
+
+/* GPMU registers, only valid on parts with a GPMU (a530/a540) */
+static const u32 a5xx_gpmu_registers[] = {
+ 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D, 0xA880, 0xA88D,
+ 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5, 0xAC60, 0xAC60,
+ ~0,
};
static void a5xx_dump(struct msm_gpu *gpu)
@@ -1448,6 +1453,7 @@ struct a5xx_crashdumper {
struct a5xx_gpu_state {
struct msm_gpu_state base;
u32 *hlsqregs;
+ u32 *gpmuregs;
};
static int a5xx_crashdumper_init(struct msm_gpu *gpu,
@@ -1565,8 +1571,30 @@ static void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu,
msm_gem_kernel_put(dumper.bo, gpu->vm);
}
+static void a5xx_gpu_state_get_gpmu_regs(struct msm_gpu *gpu,
+ struct a5xx_gpu_state *a5xx_state)
+{
+ u32 count = 0, pos = 0;
+ int i;
+
+ for (i = 0; a5xx_gpmu_registers[i] != ~0; i += 2)
+ count += a5xx_gpmu_registers[i + 1] - a5xx_gpmu_registers[i] + 1;
+
+ a5xx_state->gpmuregs = kcalloc(count, sizeof(u32), GFP_KERNEL);
+ if (!a5xx_state->gpmuregs)
+ return;
+
+ for (i = 0; a5xx_gpmu_registers[i] != ~0; i += 2) {
+ u32 addr;
+
+ for (addr = a5xx_gpmu_registers[i]; addr <= a5xx_gpmu_registers[i + 1]; addr++)
+ a5xx_state->gpmuregs[pos++] = gpu_read(gpu, addr);
+ }
+}
+
static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a5xx_gpu_state *a5xx_state = kzalloc_obj(*a5xx_state);
bool stalled = !!(gpu_read(gpu, REG_A5XX_RBBM_STATUS3) & BIT(24));
@@ -1581,6 +1609,9 @@ static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu)
a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS);
+ if (adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu))
+ a5xx_gpu_state_get_gpmu_regs(gpu, a5xx_state);
+
/*
* Get the HLSQ regs with the help of the crashdumper, but only if
* we are not stalled in an iommu fault (in which case the crashdumper
@@ -1602,6 +1633,7 @@ static void a5xx_gpu_state_destroy(struct kref *kref)
struct a5xx_gpu_state, base);
kfree(a5xx_state->hlsqregs);
+ kfree(a5xx_state->gpmuregs);
adreno_gpu_state_destroy(state);
kfree(a5xx_state);
@@ -1630,6 +1662,17 @@ static void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state,
adreno_show(gpu, state, p);
+ if (a5xx_state->gpmuregs) {
+ u32 o, pos = 0;
+
+ drm_printf(p, "registers-gpmu:\n");
+
+ for (i = 0; a5xx_gpmu_registers[i] != ~0; i += 2)
+ for (o = a5xx_gpmu_registers[i]; o <= a5xx_gpmu_registers[i + 1]; o++)
+ drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n",
+ o << 2, a5xx_state->gpmuregs[pos++]);
+ }
+
/* Dump the additional a5xx HLSQ registers */
if (!a5xx_state->hlsqregs)
return;
---
base-commit: a15fac810c76397ec9f62a6fc26c4d7ab6e238a7
change-id: 20260920-a5xx-no-gpmu-128218b739bf
Best regards,
--
With best wishes
Dmitry