aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c112
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.h4
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.h3
4 files changed, 56 insertions, 65 deletions
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index f804cfe7407c..b3bc2a5c28e6 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -10,6 +10,24 @@
10#include "a6xx_gpu.h" 10#include "a6xx_gpu.h"
11#include "a6xx_gmu.xml.h" 11#include "a6xx_gmu.xml.h"
12 12
13static void a6xx_gmu_fault(struct a6xx_gmu *gmu)
14{
15 struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
16 struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
17 struct msm_gpu *gpu = &adreno_gpu->base;
18 struct drm_device *dev = gpu->dev;
19 struct msm_drm_private *priv = dev->dev_private;
20
21 /* FIXME: add a banner here */
22 gmu->hung = true;
23
24 /* Turn off the hangcheck timer while we are resetting */
25 del_timer(&gpu->hangcheck_timer);
26
27 /* Queue the GPU handler because we need to treat this as a recovery */
28 queue_work(priv->wq, &gpu->recover_work);
29}
30
13static irqreturn_t a6xx_gmu_irq(int irq, void *data) 31static irqreturn_t a6xx_gmu_irq(int irq, void *data)
14{ 32{
15 struct a6xx_gmu *gmu = data; 33 struct a6xx_gmu *gmu = data;
@@ -21,8 +39,7 @@ static irqreturn_t a6xx_gmu_irq(int irq, void *data)
21 if (status & A6XX_GMU_AO_HOST_INTERRUPT_STATUS_WDOG_BITE) { 39 if (status & A6XX_GMU_AO_HOST_INTERRUPT_STATUS_WDOG_BITE) {
22 dev_err_ratelimited(gmu->dev, "GMU watchdog expired\n"); 40 dev_err_ratelimited(gmu->dev, "GMU watchdog expired\n");
23 41
24 /* Temporary until we can recover safely */ 42 a6xx_gmu_fault(gmu);
25 BUG();
26 } 43 }
27 44
28 if (status & A6XX_GMU_AO_HOST_INTERRUPT_STATUS_HOST_AHB_BUS_ERROR) 45 if (status & A6XX_GMU_AO_HOST_INTERRUPT_STATUS_HOST_AHB_BUS_ERROR)
@@ -46,8 +63,7 @@ static irqreturn_t a6xx_hfi_irq(int irq, void *data)
46 if (status & A6XX_GMU_GMU2HOST_INTR_INFO_CM3_FAULT) { 63 if (status & A6XX_GMU_GMU2HOST_INTR_INFO_CM3_FAULT) {
47 dev_err_ratelimited(gmu->dev, "GMU firmware fault\n"); 64 dev_err_ratelimited(gmu->dev, "GMU firmware fault\n");
48 65
49 /* Temporary until we can recover safely */ 66 a6xx_gmu_fault(gmu);
50 BUG();
51 } 67 }
52 68
53 return IRQ_HANDLED; 69 return IRQ_HANDLED;
@@ -166,10 +182,8 @@ static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
166} 182}
167 183
168/* Wait for the GMU to get to its most idle state */ 184/* Wait for the GMU to get to its most idle state */
169int a6xx_gmu_wait_for_idle(struct a6xx_gpu *a6xx_gpu) 185int a6xx_gmu_wait_for_idle(struct a6xx_gmu *gmu)
170{ 186{
171 struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
172
173 return spin_until(a6xx_gmu_check_idle_level(gmu)); 187 return spin_until(a6xx_gmu_check_idle_level(gmu));
174} 188}
175 189
@@ -568,7 +582,7 @@ static int a6xx_gmu_fw_start(struct a6xx_gmu *gmu, unsigned int state)
568 if (!rpmh_init) { 582 if (!rpmh_init) {
569 a6xx_gmu_rpmh_init(gmu); 583 a6xx_gmu_rpmh_init(gmu);
570 rpmh_init = true; 584 rpmh_init = true;
571 } else if (state != GMU_RESET) { 585 } else {
572 ret = a6xx_rpmh_start(gmu); 586 ret = a6xx_rpmh_start(gmu);
573 if (ret) 587 if (ret)
574 return ret; 588 return ret;
@@ -657,10 +671,9 @@ static void a6xx_gmu_irq_disable(struct a6xx_gmu *gmu)
657 gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK, ~0); 671 gmu_write(gmu, REG_A6XX_GMU_GMU2HOST_INTR_MASK, ~0);
658} 672}
659 673
660int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu) 674/* Force the GMU off in case it isn't responsive */
675static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
661{ 676{
662 struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
663 int ret;
664 u32 val; 677 u32 val;
665 678
666 /* Flush all the queues */ 679 /* Flush all the queues */
@@ -681,44 +694,6 @@ int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu)
681 (val & 1), 100, 10000); 694 (val & 1), 100, 10000);
682 gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val, 695 gmu_poll_timeout(gmu, REG_A6XX_RSCC_TCS3_DRV0_STATUS, val,
683 (val & 1), 100, 1000); 696 (val & 1), 100, 1000);
684
685 /*
686 * Depending on the state of the GMU at this point the GX domain might
687 * have been left on. Hardware sequencing rules state that the GX has to
688 * be turned off before the CX domain so this is that one time that
689 * that calling pm_runtime_put_sync() is expected to do something useful
690 * (turn off the headswitch)
691 */
692 if (!IS_ERR(gmu->gxpd))
693 pm_runtime_put_sync(gmu->gxpd);
694
695 /* Disable the resources */
696 clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks);
697 pm_runtime_put_sync(gmu->dev);
698
699 /* Re-enable the resources */
700 pm_runtime_get_sync(gmu->dev);
701
702 /* Use a known rate to bring up the GMU */
703 clk_set_rate(gmu->core_clk, 200000000);
704 ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks);
705 if (ret)
706 goto out;
707
708 a6xx_gmu_irq_enable(gmu);
709
710 ret = a6xx_gmu_fw_start(gmu, GMU_RESET);
711 if (!ret)
712 ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT);
713
714 /* Set the GPU back to the highest power frequency */
715 __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
716
717out:
718 if (ret)
719 a6xx_gmu_clear_oob(gmu, GMU_OOB_BOOT_SLUMBER);
720
721 return ret;
722} 697}
723 698
724int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) 699int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
@@ -731,6 +706,8 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
731 if (WARN(!gmu->mmio, "The GMU is not set up yet\n")) 706 if (WARN(!gmu->mmio, "The GMU is not set up yet\n"))
732 return 0; 707 return 0;
733 708
709 gmu->hung = false;
710
734 /* Turn on the resources */ 711 /* Turn on the resources */
735 pm_runtime_get_sync(gmu->dev); 712 pm_runtime_get_sync(gmu->dev);
736 713
@@ -789,11 +766,9 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu)
789 return true; 766 return true;
790} 767}
791 768
792int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) 769/* Gracefully try to shut down the GMU and by extension the GPU */
770static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
793{ 771{
794 struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
795 struct msm_gpu *gpu = &adreno_gpu->base;
796 struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
797 u32 val; 772 u32 val;
798 773
799 /* 774 /*
@@ -803,10 +778,13 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
803 val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE); 778 val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE);
804 779
805 if (val != 0xf) { 780 if (val != 0xf) {
806 int ret = a6xx_gmu_wait_for_idle(a6xx_gpu); 781 int ret = a6xx_gmu_wait_for_idle(gmu);
807 782
808 /* Temporary until we can recover safely */ 783 /* If the GMU isn't responding assume it is hung */
809 BUG_ON(ret); 784 if (ret) {
785 a6xx_gmu_force_off(gmu);
786 return;
787 }
810 788
811 /* tell the GMU we want to slumber */ 789 /* tell the GMU we want to slumber */
812 a6xx_gmu_notify_slumber(gmu); 790 a6xx_gmu_notify_slumber(gmu);
@@ -838,14 +816,30 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
838 816
839 /* Tell RPMh to power off the GPU */ 817 /* Tell RPMh to power off the GPU */
840 a6xx_rpmh_stop(gmu); 818 a6xx_rpmh_stop(gmu);
819}
820
821
822int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
823{
824 struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
825 struct msm_gpu *gpu = &a6xx_gpu->base.base;
826
827 /*
828 * Force the GMU off if we detected a hang, otherwise try to shut it
829 * down gracefully
830 */
831 if (gmu->hung)
832 a6xx_gmu_force_off(gmu);
833 else
834 a6xx_gmu_shutdown(gmu);
841 835
842 /* Remove the bus vote */ 836 /* Remove the bus vote */
843 icc_set_bw(gpu->icc_path, 0, 0); 837 icc_set_bw(gpu->icc_path, 0, 0);
844 838
845 /* 839 /*
846 * Mark the GPU power domain as off. During the shutdown process the GMU 840 * Make sure the GX domain is off before turning off the GMU (CX)
847 * should actually turn off the power so this is really just a 841 * domain. Usually the GMU does this but only if the shutdown sequence
848 * houskeeping step 842 * was successful
849 */ 843 */
850 if (!IS_ERR(gmu->gxpd)) 844 if (!IS_ERR(gmu->gxpd))
851 pm_runtime_put_sync(gmu->gxpd); 845 pm_runtime_put_sync(gmu->gxpd);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 078d418c8179..c5b1887f259f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -27,9 +27,6 @@ struct a6xx_gmu_bo {
27/* the GMU is coming up for the first time or back from a power collapse */ 27/* the GMU is coming up for the first time or back from a power collapse */
28#define GMU_COLD_BOOT 1 28#define GMU_COLD_BOOT 1
29 29
30/* The GMU is being soft reset after a fault */
31#define GMU_RESET 2
32
33/* 30/*
34 * These define the level of control that the GMU has - the higher the number 31 * These define the level of control that the GMU has - the higher the number
35 * the more things that the GMU hardware controls on its own. 32 * the more things that the GMU hardware controls on its own.
@@ -79,6 +76,7 @@ struct a6xx_gmu {
79 struct a6xx_hfi_queue queues[2]; 76 struct a6xx_hfi_queue queues[2];
80 77
81 struct tasklet_struct hfi_tasklet; 78 struct tasklet_struct hfi_tasklet;
79 bool hung;
82}; 80};
83 81
84static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset) 82static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index fefe773c989e..f76d8cd06f93 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -698,7 +698,7 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
698 * Make sure the GMU is idle before continuing (because some transitions 698 * Make sure the GMU is idle before continuing (because some transitions
699 * may use VBIF 699 * may use VBIF
700 */ 700 */
701 a6xx_gmu_wait_for_idle(a6xx_gpu); 701 a6xx_gmu_wait_for_idle(&a6xx_gpu->gmu);
702 702
703 /* Clear the VBIF pipe before shutting down */ 703 /* Clear the VBIF pipe before shutting down */
704 /* FIXME: This accesses the GPU - do we need to make sure it is on? */ 704 /* FIXME: This accesses the GPU - do we need to make sure it is on? */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 528a4cfe07cd..b46279eb18c5 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -46,9 +46,8 @@ struct a6xx_gpu {
46int a6xx_gmu_resume(struct a6xx_gpu *gpu); 46int a6xx_gmu_resume(struct a6xx_gpu *gpu);
47int a6xx_gmu_stop(struct a6xx_gpu *gpu); 47int a6xx_gmu_stop(struct a6xx_gpu *gpu);
48 48
49int a6xx_gmu_wait_for_idle(struct a6xx_gpu *gpu); 49int a6xx_gmu_wait_for_idle(struct a6xx_gmu *gmu);
50 50
51int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu);
52bool a6xx_gmu_isidle(struct a6xx_gmu *gmu); 51bool a6xx_gmu_isidle(struct a6xx_gmu *gmu);
53 52
54int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state); 53int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);