* [PATCH 1/2] drm/msm: Report no GPU time for a submit killed by hangcheck
2026-11-01 2:32 [PATCH 0/2] drm/msm: Per-submission GPU time on A5xx Fabricio Akio via B4 Relay
@ 2026-11-01 2:32 ` Fabricio Akio via B4 Relay
2026-11-01 2:32 ` [PATCH 2/2] drm/msm/a5xx: Record per-submission GPU time and cycles Fabricio Akio via B4 Relay
1 sibling, 0 replies; 3+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-01 2:32 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, Jordan Crouse
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
recover_worker() advances the fence over the submit it treats as hung
and retires it through retire_submit(), which computes its elapsed time
and cycles from the stats slot the CP writes after the submit's IBs.
That submit may not have written its end stamps, leaving an older
submit's or zero; the subtraction then wraps, and about 3 years of GPU
time is added to the context's fdinfo drm-engine-gpu and reported in
msm_gpu_submit_retired.
Set the end stamps of the submit the fence is advanced over to its
start stamps, so that it reports no time. Do it after the GPU is reset,
when the CP can no longer write the slot.
Fixes: 4241db42e474 ("drm/msm/gpu: Add trace events for tracking GPU submissions")
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
Charging the time until the failed submit was retired, as panfrost
does, would need the stamps' counter read at recovery, and that
differs by generation: a6xx stamps CP_ALWAYS_ON_CONTEXT while its
get_timestamp() reads another counter, and a2xx/a3xx have none. So
this reports zero.
---
drivers/gpu/drm/msm/msm_gpu.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 0c2c35636251..40d658a63540 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -468,9 +468,11 @@ static void recover_worker(struct kthread_work *work)
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_submit *submit;
struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu);
+ volatile struct msm_gpu_submit_stats *stats;
char *comm = NULL, *cmd = NULL;
unsigned int noreclaim_flag;
struct task_struct *task;
+ uint32_t hung_fence = 0;
int i;
mutex_lock(&gpu->lock);
@@ -548,8 +550,10 @@ static void recover_worker(struct kthread_work *work)
* For the current (faulting?) ring/submit advance the fence by
* one more to clear the faulting submit
*/
- if (ring == cur_ring)
+ if (ring == cur_ring) {
ring->memptrs->fence = ++fence;
+ hung_fence = fence;
+ }
msm_update_fence(ring->fctx, fence);
}
@@ -558,6 +562,15 @@ static void recover_worker(struct kthread_work *work)
gpu->funcs->recover(gpu);
+ /*
+ * The submit retired in place of completing may not have written its
+ * end stamps, leaving an older submit's or zero. Now that the GPU is
+ * reset, set them to its start stamps, so that it reports no time.
+ */
+ stats = &cur_ring->memptrs->stats[hung_fence % MSM_GPU_SUBMIT_STATS_COUNT];
+ stats->alwayson_end = stats->alwayson_start;
+ stats->cpcycles_end = stats->cpcycles_start;
+
/* retire completed submits, plus the one that hung: */
retire_submits(gpu);
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] drm/msm/a5xx: Record per-submission GPU time and cycles
2026-11-01 2:32 [PATCH 0/2] drm/msm: Per-submission GPU time on A5xx Fabricio Akio via B4 Relay
2026-11-01 2:32 ` [PATCH 1/2] drm/msm: Report no GPU time for a submit killed by hangcheck Fabricio Akio via B4 Relay
@ 2026-11-01 2:32 ` Fabricio Akio via B4 Relay
1 sibling, 0 replies; 3+ messages in thread
From: Fabricio Akio via B4 Relay @ 2026-11-01 2:32 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, Jordan Crouse
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Fabricio Akio
From: Fabricio Akio <fabricioakio@gmail.com>
The GPU time and cycles msm records for each submission, reported in
the msm_gpu_submit_retired trace event and added to fdinfo's
drm-engine-gpu and drm-cycles-gpu, come from counters the CP copies to
memory around each submission. a6xx_submit() emits those copies;
a5xx_submit() does not, so on A5xx all of them read zero.
Copy the CP cycle counter and the always-on counter before and after
the submission's IBs, as a6xx does.
Signed-off-by: Fabricio Akio <fabricioakio@gmail.com>
---
The counters are copied outside the IBs, so a preemption inside a
submission, at a yield point in its IBs, would count the other ring's
time in it. Switches between submissions were tested.
---
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 16c7335c4b1f..7d4a9db0a3de 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -124,8 +124,20 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit
msm_gpu_retire(gpu);
}
+static void get_stats_counter(struct msm_ringbuffer *ring, u32 counter,
+ u64 iova)
+{
+ OUT_PKT7(ring, CP_REG_TO_MEM, 3);
+ OUT_RING(ring, CP_REG_TO_MEM_0_REG(counter) |
+ CP_REG_TO_MEM_0_CNT(2) |
+ CP_REG_TO_MEM_0_IS_64B);
+ OUT_RING(ring, lower_32_bits(iova));
+ OUT_RING(ring, upper_32_bits(iova));
+}
+
static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
{
+ unsigned int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
struct msm_ringbuffer *ring = submit->ring;
@@ -167,6 +179,11 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_PKT7(ring, CP_YIELD_ENABLE, 1);
OUT_RING(ring, 0x02);
+ get_stats_counter(ring, REG_A5XX_RBBM_PERFCTR_CP_0_LO,
+ rbmemptr_stats(ring, index, cpcycles_start));
+ get_stats_counter(ring, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO,
+ rbmemptr_stats(ring, index, alwayson_start));
+
/* Submit the commands */
for (i = 0; i < submit->nr_cmds; i++) {
switch (submit->cmd[i].type) {
@@ -208,6 +225,11 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, 0);
OUT_RING(ring, 0);
+ get_stats_counter(ring, REG_A5XX_RBBM_PERFCTR_CP_0_LO,
+ rbmemptr_stats(ring, index, cpcycles_end));
+ get_stats_counter(ring, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO,
+ rbmemptr_stats(ring, index, alwayson_end));
+
/* Turn off IB level preemptions */
OUT_PKT7(ring, CP_YIELD_ENABLE, 1);
OUT_RING(ring, 0x01);
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread