drm/msm: Add A5XX hardware fault detection
authorJordan Crouse <jcrouse@codeaurora.org>
Thu, 27 Jul 2017 16:42:36 +0000 (10:42 -0600)
committerRob Clark <robdclark@gmail.com>
Wed, 2 Aug 2017 11:57:02 +0000 (07:57 -0400)
The A5XX GPU has really good hardware fault detection that can
detect a abnormal hardware condition and fire an interrupt in
a matter of milliseconds which is a lot better than waiting for
the hangcheck timer.

Enable the interrupt and log information before kicking off
recovery.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/a5xx_gpu.c

index 3192cbc49f67d3fac55af435e52776455d283b24..5fb991749c69c9996754f8c09c4b5327240fe82a 100644 (file)
@@ -410,6 +410,7 @@ static int a5xx_zap_shader_init(struct msm_gpu *gpu)
          A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \
          A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \
          A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \
+         A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT | \
          A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \
          A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \
          A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP)
@@ -812,6 +813,28 @@ static void a5xx_gpmu_err_irq(struct msm_gpu *gpu)
        dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n");
 }
 
+static void a5xx_fault_detect_irq(struct msm_gpu *gpu)
+{
+       struct drm_device *dev = gpu->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu);
+
+       dev_err(dev->dev, "gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n",
+               ring ? ring->id : -1, ring ? ring->seqno : 0,
+               gpu_read(gpu, REG_A5XX_RBBM_STATUS),
+               gpu_read(gpu, REG_A5XX_CP_RB_RPTR),
+               gpu_read(gpu, REG_A5XX_CP_RB_WPTR),
+               gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI),
+               gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ),
+               gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI),
+               gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ));
+
+       /* Turn off the hangcheck timer to keep it from bothering us */
+       del_timer(&gpu->hangcheck_timer);
+
+       queue_work(priv->wq, &gpu->recover_work);
+}
+
 #define RBBM_ERROR_MASK \
        (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \
        A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \
@@ -838,6 +861,9 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
        if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR)
                a5xx_cp_err_irq(gpu);
 
+       if (status & A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT)
+               a5xx_fault_detect_irq(gpu);
+
        if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS)
                a5xx_uche_err_irq(gpu);