* [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512
@ 2026-11-07 20:26 Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 1/4] drm/msm: Resume devfreq from each GPU's resume callback Fabricio Akio via B4 Relay
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-07 20:26 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Paul Sajna,
Fabricio Akio, Dmitry Baryshkov
Changes to how the A508, A509 and A512 power up and down, found running
a phone shell on an SDM630 phone.
The second resets the GPU on every resume: on SDM630, SDM660 and
MSM8998 the device tree attaches the GPU's GX power domain to its SMMU,
so a GPU resumed soon after suspending keeps its state, and its CP runs
stale ringbuffer contents and hangs. The reset clears the busy counter
devfreq samples, so the first lets each GPU resume devfreq from its own
resume callback, and the second resumes it after the reset.
The third holds a CPU latency request while the GPU is powered, as the
downstream driver does: on SDM630 the GPU stops executing while the SoC
is in system-level power collapse, so a submission overlapping such a
state would stall and trip the hang detector. Mainline does not
describe that state yet, so the request blocks nothing until it does.
The fourth powers these GPUs down after downstream's 80 ms idle instead
of the A530's 250 ms, so the request is released when downstream
releases it.
Each patch builds on the one before it.
Tested on a Motorola Moto X4 (SDM630, A508), whose board file is not
in mainline yet, on sdm660-mainline's 7.2 kernel. The stall the third
patch prevents was measured with SDM630's system-level idle state from
a series not yet sent.
---
Changes in v3:
- New patch 1: resume devfreq from each GPU's resume callback (Akhil)
- Patch 2: say that the device tree attaches GX to the SMMU, whose own
domain is CX (Konrad, Akhil); resume devfreq after the reset instead
of taking its baseline again (Akhil); dropped Dmitry's Tested-by
- Patch 3: take 2336 us, which leaves every CPU and cluster idle state
available, instead of downstream's 424 and 518 us, which also kept
every CPU out of power collapse (Dmitry); drop the request on destroy
after adreno_gpu_cleanup(), which stops runtime PM and the GPU
worker, so nothing can take it again before it is freed (Sashiko)
- Link to v2: https://patch.msgid.link/20261019-a5xx-gpu-pm-v2-0-457aafbb28da@gmail.com
Changes in v2:
- Patch 1: take devfreq's busy-cycle baseline again after the reset,
which clears the busy counter (Sashiko)
- Link to v1: https://patch.msgid.link/20261019-a5xx-gpu-pm-v1-0-1d0c313a1412@gmail.com
---
Fabricio Akio (4):
drm/msm: Resume devfreq from each GPU's resume callback
drm/msm/a5xx: Reset the GPU when resuming it
drm/msm/a5xx: Hold a CPU latency request while the GPU is powered
drm/msm/a5xx: Use the downstream GPU idle timeout on A508, A509 and A512
drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 15 ++++++++++++++-
drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 2 ++
drivers/gpu/drm/msm/adreno/a5xx_catalog.c | 21 ++++++---------------
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 29 +++++++++++++++++++++++++++++
drivers/gpu/drm/msm/adreno/a5xx_gpu.h | 4 ++++
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 5 +++++
drivers/gpu/drm/msm/msm_gpu.c | 2 --
7 files changed, 60 insertions(+), 18 deletions(-)
---
base-commit: a39c950806213f6861d00f90729acaaa21f2d95a
change-id: 20261019-a5xx-gpu-pm-f58bc4ee2387
Best regards,
--
Fabricio Akio <fabricioakio@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/4] drm/msm: Resume devfreq from each GPU's resume callback
2026-11-07 20:26 [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512 Fabricio Akio via B4 Relay
@ 2026-11-07 20:26 ` Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 2/4] drm/msm/a5xx: Reset the GPU when resuming it Fabricio Akio via B4 Relay
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-07 20:26 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Paul Sajna,
Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
msm_gpu_pm_resume() resumes devfreq, which samples the GPU's busy
counter as the baseline of its next poll. A resume callback that resets
the GPU after msm_gpu_pm_resume() clears that counter, and the next
poll then subtracts the old count from the new one and wraps.
Move the call out of msm_gpu_pm_resume() into the resume callbacks that
use it, as A6xx already does, so that each GPU can resume devfreq once
its hardware is ready. The A3xx, A4xx and A5xx callbacks call it right
after msm_gpu_pm_resume(), where it ran before, so nothing changes yet.
A2xx has no gpu_busy callback, so it has no devfreq.
Suggested-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
New in v3.
Tested on A508 only; the A3xx and A4xx callbacks call it where
msm_gpu_pm_resume() did.
---
drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 15 ++++++++++++++-
drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 2 ++
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 2 ++
drivers/gpu/drm/msm/msm_gpu.c | 2 --
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index 160d302e16a3..a3aa4ae1fdb0 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -534,6 +534,19 @@ static int a3xx_pm_suspend(struct msm_gpu *gpu)
return msm_gpu_pm_suspend(gpu);
}
+static int a3xx_pm_resume(struct msm_gpu *gpu)
+{
+ int ret;
+
+ ret = msm_gpu_pm_resume(gpu);
+ if (ret)
+ return ret;
+
+ msm_devfreq_resume(gpu);
+
+ return 0;
+}
+
static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
@@ -637,7 +650,7 @@ const struct adreno_gpu_funcs a3xx_gpu_funcs = {
.set_param = adreno_set_param,
.hw_init = a3xx_hw_init,
.pm_suspend = a3xx_pm_suspend,
- .pm_resume = msm_gpu_pm_resume,
+ .pm_resume = a3xx_pm_resume,
.recover = a3xx_recover,
.submit = a3xx_submit,
.active_ring = adreno_active_ring,
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index 6392126f48f2..289204d53311 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -577,6 +577,8 @@ static int a4xx_pm_resume(struct msm_gpu *gpu) {
if (ret)
return ret;
+ msm_devfreq_resume(gpu);
+
if (adreno_is_a430(adreno_gpu)) {
unsigned int reg;
/* Set the default register values; set SW_COLLAPSE to 0 */
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 16c7335c4b1f..c81f67c639c8 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1367,6 +1367,8 @@ static int a5xx_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
+ msm_devfreq_resume(gpu);
+
/* Adreno 505, 506, 508, 509, 510, 512 needs manual RBBM sus/res control */
if (!(adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu))) {
/* Halt the sp_input_clk at HM level */
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 0c2c35636251..d33612fb3e53 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -116,8 +116,6 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
- msm_devfreq_resume(gpu);
-
gpu->needs_hw_init = true;
return 0;
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 2/4] drm/msm/a5xx: Reset the GPU when resuming it
2026-11-07 20:26 [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512 Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 1/4] drm/msm: Resume devfreq from each GPU's resume callback Fabricio Akio via B4 Relay
@ 2026-11-07 20:26 ` Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 3/4] drm/msm/a5xx: Hold a CPU latency request while the GPU is powered Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 4/4] drm/msm/a5xx: Use the downstream GPU idle timeout on A508, A509 and A512 Fabricio Akio via B4 Relay
3 siblings, 0 replies; 5+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-07 20:26 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Paul Sajna,
Dmitry Baryshkov, Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
On SDM630, SDM660 and MSM8998 the device tree attaches the GPU's GX
power domain to its SMMU, whose own domain is CX, so GX switches off
only once the SMMU suspends as well. A GPU resumed with GX still on
keeps its state, and the CP keeps its ringbuffer read pointer.
a5xx_hw_init() then rewinds the ringbuffer and writes CP_ME_INIT at its
start, while the CP goes on from its old position, executes stale
ringbuffer contents and hangs:
timeout waiting to drain ringbuffer 0 rptr/wptr = 23/C
Soft reset the GPU in a5xx_pm_resume() once it is powered, so that
every resume starts from the reset state. The downstream driver resets
only when it finds the GPU's power left on; resetting a GPU that was
powered off changes nothing, and on A508 the reset takes about 2 us of
a resume of about 1.5 ms, so do it every time.
The reset also clears the busy counter devfreq samples as the baseline
of its next poll, so resume devfreq after it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
Changes in v3:
- Say that the device tree attaches GX to the SMMU, whose own domain
is CX (Konrad, Akhil)
- Resume devfreq after the reset instead of taking its baseline again,
on the previous patch (Akhil)
- Dropped Dmitry's Tested-by: devfreq now resumes after the reset
instead of resampling the busy counter
Changes in v2:
- Take devfreq's busy-cycle baseline again after the reset, which
clears the busy counter (Sashiko)
Downstream resets when it finds a GPU regulator left on, and resumes
its frequency scaling only after that:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/adreno.c#L1336-L1351
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/kgsl_pwrctrl.c#L2596-L2606
A stall with the same signature, the CP's read pointer past the write
pointer just after CP_ME_INIT, was reported on an A509:
https://lore.kernel.org/linux-arm-msm/20260308-adreno-ringbuffer-drain-timeout-recovery-v1-1-985a33faf108@postmarketos.org/
Tested on A508 only; the reset runs on every A5xx.
---
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index c81f67c639c8..5b5429033986 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1367,6 +1367,19 @@ static int a5xx_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
+ /*
+ * The GX power domain is not necessarily switched off while we are
+ * suspended: on SDM630, SDM660 and MSM8998 the device tree attaches it
+ * to the GPU's SMMU rather than the GPU. If it stayed on, the CP still
+ * holds its old ringbuffer read pointer and would execute stale
+ * ringbuffer contents once hw_init restarts it. Soft reset the GPU so
+ * that it always resumes from its reset state.
+ */
+ gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 1);
+ gpu_read(gpu, REG_A5XX_RBBM_SW_RESET_CMD);
+ gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 0);
+
+ /* devfreq samples the busy counter, which the reset clears */
msm_devfreq_resume(gpu);
/* Adreno 505, 506, 508, 509, 510, 512 needs manual RBBM sus/res control */
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 3/4] drm/msm/a5xx: Hold a CPU latency request while the GPU is powered
2026-11-07 20:26 [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512 Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 1/4] drm/msm: Resume devfreq from each GPU's resume callback Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 2/4] drm/msm/a5xx: Reset the GPU when resuming it Fabricio Akio via B4 Relay
@ 2026-11-07 20:26 ` Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 4/4] drm/msm/a5xx: Use the downstream GPU idle timeout on A508, A509 and A512 Fabricio Akio via B4 Relay
3 siblings, 0 replies; 5+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-07 20:26 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Paul Sajna,
Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
On SDM630 the GPU was observed to stop executing while the SoC is in
system-level power collapse, and to continue once the SoC wakes. Its
interrupts have no wakeup route through the MPM, so it cannot wake the
SoC itself. A submission overlapping such a state would stall until a
CPU wakes, and a stall longer than the hang detector's threshold makes
the driver recover the GPU, which can lose a frame.
Qualcomm's downstream driver holds a CPU latency request while the GPU
is active, qcom,pm-qos-active-latency. Do the same: take the request
when the GPU resumes and drop it when it suspends, so the state is
available again once the GPU has gone idle, and on destroy, which
unbind reaches even when suspending the GPU failed.
The limit is a per-GPU catalog value. Only the system-level state needs
blocking, so the A508 in SDM630, the A509 in SDM636 and the A512 in
SDM660 take 2336 us, the largest entry plus exit latency of the CPU and
cluster idle states these SoCs share: every one of those states stays
available while the GPU is powered. Mainline does not describe the
system-level state yet, so until it does the request blocks nothing.
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
Changes in v3:
- Take 2336 us instead of downstream's 424 and 518 us, which also
kept every CPU out of power collapse (Dmitry)
- Drop the request on destroy after adreno_gpu_cleanup(), which stops
runtime PM and the GPU worker, so nothing can take it again before
it is freed (Sashiko)
The system-level state comes from a series not yet sent, which adds
SDM630's cluster and system power domains; its entry plus exit latency
is 14773 us, and any limit from 2336 us to just under that blocks the
same states. With it, on an A508, no request gave 205 and 272 hang
detections in 585 and 634 jobs, and 2336 us none in 416 and 479.
Downstream's MPM map lists the GPU's interrupt, SPI 300, as 332 with no
pin:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi#L62
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm630-pm.dtsi#L585
Downstream's 424 and 518 us:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi#L117
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi#L126
It reads the value at probe, applies it when the GPU starts and drops
it when the GPU slumbers:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/adreno.c#L887
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/adreno.c#L1451
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/kgsl_pwrctrl.c#L2753
Tested on an A508 only; the A509 and A512 share its CPU and cluster
idle states.
---
drivers/gpu/drm/msm/adreno/a5xx_catalog.c | 3 +++
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 14 ++++++++++++++
drivers/gpu/drm/msm/adreno/a5xx_gpu.h | 4 ++++
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 5 +++++
4 files changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
index babd320f3b73..ae9127940a22 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
@@ -55,6 +55,7 @@ static const struct adreno_info a5xx_gpus[] = {
* the GDSC which appears to make it grumpy
*/
.inactive_period = 250,
+ .cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
.zapfw = "a508_zap.mdt",
@@ -72,6 +73,7 @@ static const struct adreno_info a5xx_gpus[] = {
* the GDSC which appears to make it grumpy
*/
.inactive_period = 250,
+ .cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
/* Adreno 509 uses the same ZAP as 512 */
@@ -105,6 +107,7 @@ static const struct adreno_info a5xx_gpus[] = {
* the GDSC which appears to make it grumpy
*/
.inactive_period = 250,
+ .cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
.zapfw = "a512_zap.mdt",
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 5b5429033986..b3f9bbf997c9 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1061,6 +1061,11 @@ static void a5xx_destroy(struct msm_gpu *gpu)
}
adreno_gpu_cleanup(adreno_gpu);
+
+ /* Still held if suspending the GPU failed before it was destroyed */
+ if (cpu_latency_qos_request_active(&a5xx_gpu->pm_qos_req))
+ cpu_latency_qos_remove_request(&a5xx_gpu->pm_qos_req);
+
kfree(a5xx_gpu);
}
@@ -1360,6 +1365,7 @@ static void a5xx_dump(struct msm_gpu *gpu)
static int a5xx_pm_resume(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
int ret;
/* Turn on the core power */
@@ -1367,6 +1373,11 @@ static int a5xx_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
+ if (adreno_gpu->info->cpu_latency_us &&
+ !cpu_latency_qos_request_active(&a5xx_gpu->pm_qos_req))
+ cpu_latency_qos_add_request(&a5xx_gpu->pm_qos_req,
+ adreno_gpu->info->cpu_latency_us);
+
/*
* The GX power domain is not necessarily switched off while we are
* suspended: on SDM630, SDM660 and MSM8998 the device tree attaches it
@@ -1450,6 +1461,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu)
if (ret)
return ret;
+ if (cpu_latency_qos_request_active(&a5xx_gpu->pm_qos_req))
+ cpu_latency_qos_remove_request(&a5xx_gpu->pm_qos_req);
+
if (a5xx_gpu->has_whereami)
for (i = 0; i < gpu->nr_rings; i++)
a5xx_gpu->shadow[i] = 0;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index fb05f1ca3e81..07a36c05be25 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -4,6 +4,8 @@
#ifndef __A5XX_GPU_H__
#define __A5XX_GPU_H__
+#include <linux/pm_qos.h>
+
#include "adreno_gpu.h"
/* Bringing over the hack from the previous targets */
@@ -48,6 +50,8 @@ struct a5xx_gpu {
/* True if the microcode supports the WHERE_AM_I opcode */
bool has_whereami;
+
+ struct pm_qos_request pm_qos_req;
};
#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 4b2156825bdf..fcc382f4a9a1 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -118,6 +118,11 @@ struct adreno_info {
const struct adreno_gpu_funcs *funcs;
const char *zapfw;
u32 inactive_period;
+ /**
+ * @cpu_latency_us: CPU latency limit to hold while the GPU is
+ * powered, in microseconds, or 0 for none
+ */
+ u32 cpu_latency_us;
union {
const struct a6xx_info *a6xx;
};
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 4/4] drm/msm/a5xx: Use the downstream GPU idle timeout on A508, A509 and A512
2026-11-07 20:26 [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512 Fabricio Akio via B4 Relay
` (2 preceding siblings ...)
2026-11-07 20:26 ` [PATCH v3 3/4] drm/msm/a5xx: Hold a CPU latency request while the GPU is powered Fabricio Akio via B4 Relay
@ 2026-11-07 20:26 ` Fabricio Akio via B4 Relay
3 siblings, 0 replies; 5+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-07 20:26 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Paul Sajna,
Dmitry Baryshkov, Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
The A508, A509 and A512 took the 250 ms runtime-PM autosuspend delay
of the A530, raised there because quickly cycling that GPU's power
hung the system. Qualcomm's downstream driver powers these GPUs down
after 80 ms idle, qcom,idle-timeout, on SDM630, SDM636 and SDM660
alike.
Use 80 ms for these three, so the GPU powers down, and releases its
CPU latency request, sooner after its last work.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
The value is downstream's idle timeout for these SoCs:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi#L71
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi#L73
SDM636 includes sdm660.dtsi:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/arch/arm/boot/dts/qcom/sdm636.dtsi#L13
Downstream reads it at probe, restarts the idle timer when the last
work completes, and slumbers the GPU when it fires, dropping its CPU
latency request:
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/adreno.c#L901
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/kgsl_pwrctrl.c#L2981
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/kgsl_pwrctrl.c#L2467
https://github.com/LineageOS/android_kernel_motorola_msm8998/blob/ce9ea8f125c7302ae9b2fec84f23a69271e957c3/drivers/gpu/msm/kgsl_pwrctrl.c#L2753
Tested on an A508 with the previous patch: 784 GPU power-ups at gaps
from 90 ms to 2 s without a fault. The A509 and A512 values are
downstream's for SDM636 and SDM660; tested on an A508 only.
---
drivers/gpu/drm/msm/adreno/a5xx_catalog.c | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
index ae9127940a22..285502356823 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_catalog.c
@@ -50,11 +50,7 @@ static const struct adreno_info a5xx_gpus[] = {
[ADRENO_FW_PFP] = "a530_pfp.fw",
},
.gmem = (SZ_128K + SZ_8K),
- /*
- * Increase inactive period to 250 to avoid bouncing
- * the GDSC which appears to make it grumpy
- */
- .inactive_period = 250,
+ .inactive_period = 80,
.cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
@@ -68,11 +64,7 @@ static const struct adreno_info a5xx_gpus[] = {
[ADRENO_FW_PFP] = "a530_pfp.fw",
},
.gmem = (SZ_256K + SZ_16K),
- /*
- * Increase inactive period to 250 to avoid bouncing
- * the GDSC which appears to make it grumpy
- */
- .inactive_period = 250,
+ .inactive_period = 80,
.cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
@@ -102,11 +94,7 @@ static const struct adreno_info a5xx_gpus[] = {
[ADRENO_FW_PFP] = "a530_pfp.fw",
},
.gmem = (SZ_256K + SZ_16K),
- /*
- * Increase inactive period to 250 to avoid bouncing
- * the GDSC which appears to make it grumpy
- */
- .inactive_period = 250,
+ .inactive_period = 80,
.cpu_latency_us = 2336,
.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
.funcs = &a5xx_gpu_funcs,
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-07 20:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07 20:26 [PATCH v3 0/4] drm/msm/a5xx: Fix GPU stalls on A508, A509 and A512 Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 1/4] drm/msm: Resume devfreq from each GPU's resume callback Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 2/4] drm/msm/a5xx: Reset the GPU when resuming it Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 3/4] drm/msm/a5xx: Hold a CPU latency request while the GPU is powered Fabricio Akio via B4 Relay
2026-11-07 20:26 ` [PATCH v3 4/4] drm/msm/a5xx: Use the downstream GPU idle timeout on A508, A509 and A512 Fabricio Akio via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®