]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
msm/drm/a6xx: Turn off the GMU if resume fails
authorJordan Crouse <jcrouse@codeaurora.org>
Mon, 4 Feb 2019 16:15:43 +0000 (09:15 -0700)
committerRob Clark <robdclark@chromium.org>
Fri, 19 Apr 2019 18:50:06 +0000 (11:50 -0700)
Currently if the GMU resume function fails all we try to do is clear the
BOOT_SLUMBER oob which usually times out and ends up in a cycle of death.
If the resume function fails at any point remove any RPMh votes that might
have been added and try to shut down the GMU hardware cleanly.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@chromium.org>
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_device.c

index b3bc2a5c28e6ad8ce92ee615a5d74c8e41433e51..9155dafae2a9043871f849770ab2464bba573c66 100644 (file)
@@ -648,20 +648,6 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
         A6XX_GMU_AO_HOST_INTERRUPT_STATUS_HOST_AHB_BUS_ERROR | \
         A6XX_GMU_AO_HOST_INTERRUPT_STATUS_FENCE_ERR)
 
-static void a6xx_gmu_irq_enable(struct a6xx_gmu *gmu)
-{
-       gmu_write(gmu, REG_A6XX_GMU_AO_HOST_INTERRUPT_CLR, ~0);
-       gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_CLR, ~0);
-
-       gmu_write(gmu, REG_A6XX_GMU_AO_HOST_INTERRUPT_MASK,
-               ~A6XX_GMU_IRQ_MASK);
-       gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK,
-               ~A6XX_HFI_IRQ_MASK);
-
-       enable_irq(gmu->gmu_irq);
-       enable_irq(gmu->hfi_irq);
-}
-
 static void a6xx_gmu_irq_disable(struct a6xx_gmu *gmu)
 {
        disable_irq(gmu->gmu_irq);
@@ -671,11 +657,24 @@ static void a6xx_gmu_irq_disable(struct a6xx_gmu *gmu)
        gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK, ~0);
 }
 
-/* Force the GMU off in case it isn't responsive */
-static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
+static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
 {
        u32 val;
 
+       /* Make sure there are no outstanding RPMh votes */
+       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val,
+               (val & 1), 100, 10000);
+       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val,
+               (val & 1), 100, 10000);
+       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val,
+               (val & 1), 100, 10000);
+       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val,
+               (val & 1), 100, 1000);
+}
+
+/* Force the GMU off in case it isn't responsive */
+static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
+{
        /* Flush all the queues */
        a6xx_hfi_stop(gmu);
 
@@ -686,14 +685,7 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
        a6xx_sptprac_disable(gmu);
 
        /* Make sure there are no outstanding RPMh votes */
-       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS0_DRV0_STATUS, val,
-               (val & 1), 100, 10000);
-       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS1_DRV0_STATUS, val,
-               (val & 1), 100, 10000);
-       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS2_DRV0_STATUS, val,
-               (val & 1), 100, 10000);
-       gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val,
-               (val & 1), 100, 1000);
+       a6xx_gmu_rpmh_off(gmu);
 }
 
 int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
@@ -714,13 +706,18 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
        /* Use a known rate to bring up the GMU */
        clk_set_rate(gmu->core_clk, 200000000);
        ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks);
-       if (ret)
-               goto out;
+       if (ret) {
+               pm_runtime_put(gmu->dev);
+               return ret;
+       }
 
        /* Set the bus quota to a reasonable value for boot */
        icc_set_bw(gpu->icc_path, 0, MBps_to_icc(3072));
 
-       a6xx_gmu_irq_enable(gmu);
+       /* Enable the GMU interrupt */
+       gmu_write(gmu, REG_A6XX_GMU_AO_HOST_INTERRUPT_CLR, ~0);
+       gmu_write(gmu, REG_A6XX_GMU_AO_HOST_INTERRUPT_MASK, ~A6XX_GMU_IRQ_MASK);
+       enable_irq(gmu->gmu_irq);
 
        /* Check to see if we are doing a cold or warm boot */
        status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ?
@@ -731,6 +728,16 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
                goto out;
 
        ret = a6xx_hfi_start(gmu, status);
+       if (ret)
+               goto out;
+
+       /*
+        * Turn on the GMU firmware fault interrupt after we know the boot
+        * sequence is successful
+        */
+       gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_CLR, ~0);
+       gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK, ~A6XX_HFI_IRQ_MASK);
+       enable_irq(gmu->hfi_irq);
 
        /* Set the GPU to the highest power frequency */
        __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
@@ -744,9 +751,12 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
                pm_runtime_get(gmu->gxpd);
 
 out:
-       /* Make sure to turn off the boot OOB request on error */
-       if (ret)
-               a6xx_gmu_clear_oob(gmu, GMU_OOB_BOOT_SLUMBER);
+       /* On failure, shut down the GMU to leave it in a good state */
+       if (ret) {
+               disable_irq(gmu->gmu_irq);
+               a6xx_rpmh_stop(gmu);
+               pm_runtime_put(gmu->dev);
+       }
 
        return ret;
 }
@@ -769,6 +779,9 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu)
 /* Gracefully try to shut down the GMU and by extension the GPU */
 static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
 {
+       struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
+       struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
+       struct msm_gpu *gpu = &adreno_gpu->base;
        u32 val;
 
        /*
@@ -786,6 +799,12 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
                        return;
                }
 
+               /* Clear the VBIF pipe before shutting down */
+               gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf);
+               spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & 0xf)
+                       == 0xf);
+               gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0);
+
                /* tell the GMU we want to slumber */
                a6xx_gmu_notify_slumber(gmu);
 
@@ -824,6 +843,9 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
        struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
        struct msm_gpu *gpu = &a6xx_gpu->base.base;
 
+       if (!pm_runtime_active(gmu->dev))
+               return 0;
+
        /*
         * Force the GMU off if we detected a hang, otherwise try to shut it
         * down gracefully
index f76d8cd06f9350fe2c272b00d536ebfa8cab40d1..576559a3a523b5d0ac0f843d0bc08fe230917aa1 100644 (file)
@@ -678,13 +678,15 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)
        struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
        int ret;
 
-       ret = a6xx_gmu_resume(a6xx_gpu);
-
        gpu->needs_hw_init = true;
 
+       ret = a6xx_gmu_resume(a6xx_gpu);
+       if (ret)
+               return ret;
+
        msm_gpu_resume_devfreq(gpu);
 
-       return ret;
+       return 0;
 }
 
 static int a6xx_pm_suspend(struct msm_gpu *gpu)
@@ -694,18 +696,6 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
 
        devfreq_suspend_device(gpu->devfreq.devfreq);
 
-       /*
-        * Make sure the GMU is idle before continuing (because some transitions
-        * may use VBIF
-        */
-       a6xx_gmu_wait_for_idle(&a6xx_gpu->gmu);
-
-       /* Clear the VBIF pipe before shutting down */
-       /* FIXME: This accesses the GPU - do we need to make sure it is on? */
-       gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf);
-       spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & 0xf) == 0xf);
-       gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0);
-
        return a6xx_gmu_stop(a6xx_gpu);
 }
 
index 714ed6505e47bda1d107412e058d2c00c5877afa..0d87db75b7107a39b86eebb084e3699302320d40 100644 (file)
@@ -229,6 +229,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
 
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
+               pm_runtime_put_sync(&pdev->dev);
                DRM_DEV_ERROR(dev->dev, "Couldn't power up the GPU: %d\n", ret);
                return NULL;
        }