]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/msm/a6xx: Poll AHB fence status in GPU IRQ handler
authorAkhil P Oommen <akhilpo@oss.qualcomm.com>
Mon, 8 Sep 2025 08:27:03 +0000 (13:57 +0530)
committerRob Clark <robin.clark@oss.qualcomm.com>
Mon, 8 Sep 2025 14:25:00 +0000 (07:25 -0700)
Even though the GX power domain is kept ON when there is a pending GPU
interrupt, there is a small window of potential race with GMU where it
may move the AHB fence to 'Drop' mode. Once the GMU sees the pending IRQ,
it will move back the fence state to ALLOW mode. Close this race window
by polling for AHB fence to ensure that it is in 'Allow' mode.

Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/673377/
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
drivers/gpu/drm/msm/adreno/a6xx_gpu.c

index 9494bbed9a1ff86b19acec139d7ab27697d7ec8a..40c4c0445b8e4349c9111850df9c0b1d355f0b73 100644 (file)
@@ -167,6 +167,9 @@ static inline u64 gmu_read64(struct a6xx_gmu *gmu, u32 lo, u32 hi)
 #define gmu_poll_timeout(gmu, addr, val, cond, interval, timeout) \
        readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \
                interval, timeout)
+#define gmu_poll_timeout_atomic(gmu, addr, val, cond, interval, timeout) \
+       readl_poll_timeout_atomic((gmu)->mmio + ((addr) << 2), val, cond, \
+               interval, timeout)
 
 static inline u32 gmu_read_rscc(struct a6xx_gmu *gmu, u32 offset)
 {
index 48aa07b6b2f5db4f409e3dc0b88af066b261fc54..4cdbad05affc28c370a9dd042210c20a0c20ac46 100644 (file)
@@ -1845,6 +1845,28 @@ static void a6xx_gpu_keepalive_vote(struct msm_gpu *gpu, bool on)
        gmu_write(&a6xx_gpu->gmu, REG_A6XX_GMU_GMU_PWR_COL_KEEPALIVE, on);
 }
 
+static int irq_poll_fence(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+       struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
+       u32 status;
+
+       if (adreno_has_gmu_wrapper(adreno_gpu))
+               return 0;
+
+       if (gmu_poll_timeout_atomic(gmu, REG_A6XX_GMU_AO_AHB_FENCE_CTRL, status, !status, 1, 100)) {
+               u32 rbbm_unmasked = gmu_read(gmu, REG_A6XX_GMU_RBBM_INT_UNMASKED_STATUS);
+
+               dev_err_ratelimited(&gpu->pdev->dev,
+                               "irq fence poll timeout, fence_ctrl=0x%x, unmasked_status=0x%x\n",
+                               status, rbbm_unmasked);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
 {
        struct msm_drm_private *priv = gpu->dev->dev_private;
@@ -1852,6 +1874,9 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
        /* Set keepalive vote to avoid power collapse after RBBM_INT_0_STATUS is read */
        a6xx_gpu_keepalive_vote(gpu, true);
 
+       if (irq_poll_fence(gpu))
+               goto done;
+
        u32 status = gpu_read(gpu, REG_A6XX_RBBM_INT_0_STATUS);
 
        gpu_write(gpu, REG_A6XX_RBBM_INT_CLEAR_CMD, status);
@@ -1888,6 +1913,7 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu)
        if (status & A6XX_RBBM_INT_0_MASK_CP_SW)
                a6xx_preempt_irq(gpu);
 
+done:
        a6xx_gpu_keepalive_vote(gpu, false);
 
        return IRQ_HANDLED;