Skip to content

Commit eadf792

Browse files
Jordan Crouserobclark
authored andcommitted
drm/msm: Check for powered down HW in the devfreq callbacks
Writing to the devfreq sysfs nodes while the GPU is powered down can result in a system crash (on a5xx) or a nasty GMU error (on a6xx): $ /sys/class/devfreq/5000000.gpu# echo 500000000 > min_freq [ 104.841625] platform 506a000.gmu: [drm:a6xx_gmu_set_oob] *ERROR* Timeout waiting for GMU OOB set GPU_DCVS: 0x0 Despite the fact that we carefully try to suspend the devfreq device when the hardware is powered down there are lots of holes in the governors that don't check for the suspend state and blindly call into the devfreq callbacks that end up triggering hardware reads in the GPU driver. Call pm_runtime_get_if_in_use() in the gpu_busy() and gpu_set_freq() callbacks to skip the hardware access if it isn't active. v3: Only check pm_runtime_get_if_in_use() for == 0 per Eric Anholt v2: Use pm_runtime_get_if_in_use() per Eric Anholt Cc: [email protected] Reviewed-by: Eric Anholt <[email protected]> Signed-off-by: Jordan Crouse <[email protected]> Signed-off-by: Rob Clark <[email protected]>
1 parent 71dc6c0 commit eadf792

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

drivers/gpu/drm/msm/adreno/a5xx_gpu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,10 @@ static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu)
14041404
{
14051405
u64 busy_cycles, busy_time;
14061406

1407+
/* Only read the gpu busy if the hardware is already active */
1408+
if (pm_runtime_get_if_in_use(&gpu->pdev->dev) == 0)
1409+
return 0;
1410+
14071411
busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
14081412
REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
14091413

@@ -1412,6 +1416,8 @@ static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu)
14121416

14131417
gpu->devfreq.busy_cycles = busy_cycles;
14141418

1419+
pm_runtime_put(&gpu->pdev->dev);
1420+
14151421
if (WARN_ON(busy_time > ~0LU))
14161422
return ~0LU;
14171423

drivers/gpu/drm/msm/adreno/a6xx_gmu.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
108108
struct msm_gpu *gpu = &adreno_gpu->base;
109109
int ret;
110110

111+
/*
112+
* This can get called from devfreq while the hardware is idle. Don't
113+
* bring up the power if it isn't already active
114+
*/
115+
if (pm_runtime_get_if_in_use(gmu->dev) == 0)
116+
return;
117+
111118
gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0);
112119

113120
gmu_write(gmu, REG_A6XX_GMU_DCVS_PERF_SETTING,
@@ -134,6 +141,7 @@ static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
134141
* for now leave it at max so that the performance is nominal.
135142
*/
136143
icc_set_bw(gpu->icc_path, 0, MBps_to_icc(7216));
144+
pm_runtime_put(gmu->dev);
137145
}
138146

139147
void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq)

drivers/gpu/drm/msm/adreno/a6xx_gpu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,11 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)
810810
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
811811
u64 busy_cycles, busy_time;
812812

813+
814+
/* Only read the gpu busy if the hardware is already active */
815+
if (pm_runtime_get_if_in_use(a6xx_gpu->gmu.dev) == 0)
816+
return 0;
817+
813818
busy_cycles = gmu_read64(&a6xx_gpu->gmu,
814819
REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
815820
REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H);
@@ -819,6 +824,8 @@ static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)
819824

820825
gpu->devfreq.busy_cycles = busy_cycles;
821826

827+
pm_runtime_put(a6xx_gpu->gmu.dev);
828+
822829
if (WARN_ON(busy_time > ~0LU))
823830
return ~0LU;
824831

0 commit comments

Comments
 (0)