Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/a6xx: Use genpd notifier to ensure cx-gdsc collapse

As per the recommended recovery sequence of adreno gpu, cx gdsc should
collapse at hardware before it is turned back ON. This helps to clear
out the stale states in hardware before it is reinitialized. Use the
genpd notifier along with the newly introduced
dev_pm_genpd_synced_poweroff() api to ensure that cx gdsc has collapsed
before we turn it back ON.

Signed-off-by: Akhil P Oommen <quic_akhilpo@quicinc.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/516472/
Link: https://lore.kernel.org/r/20230102161757.v5.5.I9e10545c6a448d5eb1b734839b871d1b3146dac3@changeid
Signed-off-by: Rob Clark <robdclark@chromium.org>

authored by

Akhil P Oommen and committed by
Rob Clark
c11fa120 d4843012

+33
+1
drivers/gpu/drm/msm/Kconfig
··· 28 28 select SYNC_FILE 29 29 select PM_OPP 30 30 select NVMEM 31 + select PM_GENERIC_DOMAINS 31 32 help 32 33 DRM/KMS driver for MSM/snapdragon. 33 34
+15
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
··· 1510 1510 gmu->initialized = false; 1511 1511 } 1512 1512 1513 + static int cxpd_notifier_cb(struct notifier_block *nb, 1514 + unsigned long action, void *data) 1515 + { 1516 + struct a6xx_gmu *gmu = container_of(nb, struct a6xx_gmu, pd_nb); 1517 + 1518 + if (action == GENPD_NOTIFY_OFF) 1519 + complete_all(&gmu->pd_gate); 1520 + 1521 + return 0; 1522 + } 1523 + 1513 1524 int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) 1514 1525 { 1515 1526 struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; ··· 1653 1642 ret = -ENODEV; 1654 1643 goto detach_cxpd; 1655 1644 } 1645 + 1646 + init_completion(&gmu->pd_gate); 1647 + complete_all(&gmu->pd_gate); 1648 + gmu->pd_nb.notifier_call = cxpd_notifier_cb; 1656 1649 1657 1650 /* 1658 1651 * Get a link to the GX power domain to reset the GPU in case of GMU
+6
drivers/gpu/drm/msm/adreno/a6xx_gmu.h
··· 4 4 #ifndef _A6XX_GMU_H_ 5 5 #define _A6XX_GMU_H_ 6 6 7 + #include <linux/completion.h> 7 8 #include <linux/iopoll.h> 8 9 #include <linux/interrupt.h> 10 + #include <linux/notifier.h> 9 11 #include "msm_drv.h" 10 12 #include "a6xx_hfi.h" 11 13 ··· 92 90 bool initialized; 93 91 bool hung; 94 92 bool legacy; /* a618 or a630 */ 93 + 94 + /* For power domain callback */ 95 + struct notifier_block pd_nb; 96 + struct completion pd_gate; 95 97 }; 96 98 97 99 static inline u32 gmu_read(struct a6xx_gmu *gmu, u32 offset)
+11
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
··· 10 10 11 11 #include <linux/bitfield.h> 12 12 #include <linux/devfreq.h> 13 + #include <linux/pm_domain.h> 13 14 #include <linux/soc/qcom/llcc-qcom.h> 14 15 15 16 #define GPU_PAS_ID 13 ··· 1259 1258 { 1260 1259 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 1261 1260 struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 1261 + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; 1262 1262 int i, active_submits; 1263 1263 1264 1264 adreno_dump_info(gpu); ··· 1298 1296 */ 1299 1297 gpu->active_submits = 0; 1300 1298 1299 + reinit_completion(&gmu->pd_gate); 1300 + dev_pm_genpd_add_notifier(gmu->cxpd, &gmu->pd_nb); 1301 + dev_pm_genpd_synced_poweroff(gmu->cxpd); 1302 + 1301 1303 /* Drop the rpm refcount from active submits */ 1302 1304 if (active_submits) 1303 1305 pm_runtime_put(&gpu->pdev->dev); 1304 1306 1305 1307 /* And the final one from recover worker */ 1306 1308 pm_runtime_put_sync(&gpu->pdev->dev); 1309 + 1310 + if (!wait_for_completion_timeout(&gmu->pd_gate, msecs_to_jiffies(1000))) 1311 + DRM_DEV_ERROR(&gpu->pdev->dev, "cx gdsc didn't collapse\n"); 1312 + 1313 + dev_pm_genpd_remove_notifier(gmu->cxpd); 1307 1314 1308 1315 pm_runtime_use_autosuspend(&gpu->pdev->dev); 1309 1316