On Sat, Oct 24, 2026 at 6:31 AM Akhil P Oommen <[email protected]> wrote:
>
> The preemption records are initialised only once at probe time. On every
> resume, a6xx_preempt_hw_init() and a8xx_preempt_hw_init() refresh only a
> subset of the fields (rptr, wptr, rptr_addr, info, data, rbase). Whatever
> else the CP wrote into the record before the GPU was power-collapsed
> is left in place and gets consumed again by the CP on the next preemption,
> now carrying stale context state.
>
> To fix this, zero the whole preemption record on suspend and fully
> initialise every field in the hw_init path.
>
> Fixes: e7ae83da4a28 ("drm/msm/a6xx: Implement preemption for a7xx targets")
> Cc: [email protected]
> Signed-off-by: Akhil P Oommen <[email protected]>

Thanks, this gets the AQE working on my glymur laptop (Slim 7x).

Tested-by: Connor Abbott <[email protected]>

> ---
>  drivers/gpu/drm/msm/adreno/a6xx_gpu.c     |  2 ++
>  drivers/gpu/drm/msm/adreno/a6xx_gpu.h     |  1 +
>  drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 37 
> ++++++++++++++++++-------------
>  drivers/gpu/drm/msm/adreno/a8xx_preempt.c | 11 ++++++---
>  4 files changed, 32 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c 
> b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 92e8c8abb86d..3e4afaa5345f 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -2248,6 +2248,7 @@ static int a6xx_gmu_pm_suspend(struct msm_gpu *gpu)
>                 for (i = 0; i < gpu->nr_rings; i++)
>                         a6xx_gpu->shadow[i] = 0;
>
> +       a6xx_preempt_record_reset(gpu);
>         gpu->suspend_count++;
>
>         return 0;
> @@ -2287,6 +2288,7 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
>                 for (i = 0; i < gpu->nr_rings; i++)
>                         a6xx_gpu->shadow[i] = 0;
>
> +       a6xx_preempt_record_reset(gpu);
>         gpu->suspend_count++;
>
>         return 0;
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h 
> b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> index 79912a33e17c..62a19e22e230 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> @@ -305,6 +305,7 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu);
>  void a6xx_preempt_trigger(struct msm_gpu *gpu);
>  void a6xx_preempt_irq(struct msm_gpu *gpu);
>  void a6xx_preempt_fini(struct msm_gpu *gpu);
> +void a6xx_preempt_record_reset(struct msm_gpu *gpu);
>  void a6xx_emit_set_pseudo_reg(struct msm_ringbuffer *ring,
>                 struct a6xx_gpu *a6xx_gpu, struct msm_gpu_submitqueue *queue);
>  int a6xx_preempt_submitqueue_setup(struct msm_gpu *gpu,
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c 
> b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
> index 1e599d4ddea1..df8d4f3e8d4c 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c
> @@ -140,12 +140,17 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu)
>         for (i = 0; i < gpu->nr_rings; i++) {
>                 struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i];
>
> -               record_ptr->wptr = 0;
> -               record_ptr->rptr = 0;
> -               record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]);
> +               record_ptr->magic = A6XX_PREEMPT_RECORD_MAGIC;
>                 record_ptr->info = 0;
> +               record_ptr->errno = 0;
>                 record_ptr->data = 0;
> +               record_ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT;
> +               record_ptr->rptr = 0;
> +               record_ptr->wptr = 0;
> +               record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]);
>                 record_ptr->rbase = gpu->rb[i]->iova;
> +               record_ptr->counter = 0;
> +               record_ptr->bv_rptr_addr = rbmemptr(gpu->rb[i], bv_rptr);
>         }
>
>         /* Write a 0 to signal that we aren't switching pagetables */
> @@ -163,6 +168,19 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu)
>         a6xx_gpu->cur_ring = gpu->rb[0];
>  }
>
> +void a6xx_preempt_record_reset(struct msm_gpu *gpu)
> +{
> +       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> +       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
> +       int i;
> +
> +       if (gpu->nr_rings == 1)
> +               return;
> +
> +       for (i = 0; i < gpu->nr_rings; i++)
> +               memset(a6xx_gpu->preempt[i], 0, 
> a6xx_gpu->preempt_bo[i]->size);
> +}
> +
>  void a6xx_preempt_trigger(struct msm_gpu *gpu)
>  {
>         struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> @@ -302,8 +320,6 @@ static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu,
>         a6xx_gpu->preempt_iova[ring->id] = iova;
>         a6xx_gpu->preempt[ring->id] = ptr;
>
> -       struct a6xx_preempt_record *record_ptr = ptr;
> -
>         ptr = msm_gem_kernel_new(gpu->dev,
>                 PREEMPT_SMMU_INFO_SIZE,
>                 MSM_BO_WC | MSM_BO_MAP_PRIV | MSM_BO_GPU_READONLY,
> @@ -329,17 +345,6 @@ static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu,
>         smmu_info_ptr->asid = 0xdecafbad;
>         smmu_info_ptr->context_idr = 0;
>
> -       /* Set up the defaults on the preemption record */
> -       record_ptr->magic = A6XX_PREEMPT_RECORD_MAGIC;
> -       record_ptr->info = 0;
> -       record_ptr->data = 0;
> -       record_ptr->rptr = 0;
> -       record_ptr->wptr = 0;
> -       record_ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT;
> -       record_ptr->rbase = ring->iova;
> -       record_ptr->counter = 0;
> -       record_ptr->bv_rptr_addr = rbmemptr(ring, bv_rptr);
> -
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/msm/adreno/a8xx_preempt.c 
> b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c
> index 6cb53a071801..0e0503ed54a1 100644
> --- a/drivers/gpu/drm/msm/adreno/a8xx_preempt.c
> +++ b/drivers/gpu/drm/msm/adreno/a8xx_preempt.c
> @@ -121,12 +121,17 @@ void a8xx_preempt_hw_init(struct msm_gpu *gpu)
>         for (i = 0; i < gpu->nr_rings; i++) {
>                 struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i];
>
> -               record_ptr->wptr = 0;
> -               record_ptr->rptr = 0;
> -               record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]);
> +               record_ptr->magic = A6XX_PREEMPT_RECORD_MAGIC;
>                 record_ptr->info = 0;
> +               record_ptr->errno = 0;
>                 record_ptr->data = 0;
> +               record_ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT;
> +               record_ptr->rptr = 0;
> +               record_ptr->wptr = 0;
> +               record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]);
>                 record_ptr->rbase = gpu->rb[i]->iova;
> +               record_ptr->counter = 0;
> +               record_ptr->bv_rptr_addr = rbmemptr(gpu->rb[i], bv_rptr);
>         }
>
>         /* Write a 0 to signal that we aren't switching pagetables */
>
> --
> 2.55.0
>

Reply via email to