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

scsi: ufs: pltfrm: Disable runtime PM during removal of glue drivers

When the UFSHCD platform glue drivers are removed, runtime PM should be
disabled using pm_runtime_disable() to balance the enablement done in
ufshcd_pltfrm_init(). This is also reported by PM core when the glue driver
is removed and inserted again:

ufshcd-qcom 1d84000.ufshc: Unbalanced pm_runtime_enable!

So disable runtime PM using a new helper API ufshcd_pltfrm_remove(), that
also takes care of removing ufshcd. This helper should be called during the
remove() stage of glue drivers.

Cc: stable@vger.kernel.org # 3.12
Fixes: 62694735ca95 ("[SCSI] ufs: Add runtime PM support for UFS host controller driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Link: https://lore.kernel.org/r/20241111-ufs_bug_fix-v1-3-45ad8b62f02e@linaro.org
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Manivannan Sadhasivam and committed by
Martin K. Petersen
d3326e6a 64506b3d

+22 -20
+1 -3
drivers/ufs/host/cdns-pltfrm.c
··· 307 307 */ 308 308 static void cdns_ufs_pltfrm_remove(struct platform_device *pdev) 309 309 { 310 - struct ufs_hba *hba = platform_get_drvdata(pdev); 311 - 312 - ufshcd_remove(hba); 310 + ufshcd_pltfrm_remove(pdev); 313 311 } 314 312 315 313 static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
+1 -3
drivers/ufs/host/tc-dwc-g210-pltfrm.c
··· 76 76 */ 77 77 static void tc_dwc_g210_pltfm_remove(struct platform_device *pdev) 78 78 { 79 - struct ufs_hba *hba = platform_get_drvdata(pdev); 80 - 81 79 pm_runtime_get_sync(&(pdev)->dev); 82 - ufshcd_remove(hba); 80 + ufshcd_pltfrm_remove(pdev); 83 81 } 84 82 85 83 static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = {
+1 -1
drivers/ufs/host/ufs-exynos.c
··· 1993 1993 struct exynos_ufs *ufs = ufshcd_get_variant(hba); 1994 1994 1995 1995 pm_runtime_get_sync(&(pdev)->dev); 1996 - ufshcd_remove(hba); 1996 + ufshcd_pltfrm_remove(pdev); 1997 1997 1998 1998 phy_power_off(ufs->phy); 1999 1999 phy_exit(ufs->phy);
+1 -3
drivers/ufs/host/ufs-hisi.c
··· 576 576 577 577 static void ufs_hisi_remove(struct platform_device *pdev) 578 578 { 579 - struct ufs_hba *hba = platform_get_drvdata(pdev); 580 - 581 - ufshcd_remove(hba); 579 + ufshcd_pltfrm_remove(pdev); 582 580 } 583 581 584 582 static const struct dev_pm_ops ufs_hisi_pm_ops = {
+1 -3
drivers/ufs/host/ufs-mediatek.c
··· 1879 1879 */ 1880 1880 static void ufs_mtk_remove(struct platform_device *pdev) 1881 1881 { 1882 - struct ufs_hba *hba = platform_get_drvdata(pdev); 1883 - 1884 1882 pm_runtime_get_sync(&(pdev)->dev); 1885 - ufshcd_remove(hba); 1883 + ufshcd_pltfrm_remove(pdev); 1886 1884 } 1887 1885 1888 1886 #ifdef CONFIG_PM_SLEEP
+1 -1
drivers/ufs/host/ufs-qcom.c
··· 1864 1864 struct ufs_qcom_host *host = ufshcd_get_variant(hba); 1865 1865 1866 1866 pm_runtime_get_sync(&(pdev)->dev); 1867 - ufshcd_remove(hba); 1867 + ufshcd_pltfrm_remove(pdev); 1868 1868 if (host->esi_enabled) 1869 1869 platform_device_msi_free_irqs_all(hba->dev); 1870 1870 }
+1 -3
drivers/ufs/host/ufs-renesas.c
··· 397 397 398 398 static void ufs_renesas_remove(struct platform_device *pdev) 399 399 { 400 - struct ufs_hba *hba = platform_get_drvdata(pdev); 401 - 402 - ufshcd_remove(hba); 400 + ufshcd_pltfrm_remove(pdev); 403 401 } 404 402 405 403 static struct platform_driver ufs_renesas_platform = {
+1 -3
drivers/ufs/host/ufs-sprd.c
··· 427 427 428 428 static void ufs_sprd_remove(struct platform_device *pdev) 429 429 { 430 - struct ufs_hba *hba = platform_get_drvdata(pdev); 431 - 432 430 pm_runtime_get_sync(&(pdev)->dev); 433 - ufshcd_remove(hba); 431 + ufshcd_pltfrm_remove(pdev); 434 432 } 435 433 436 434 static const struct dev_pm_ops ufs_sprd_pm_ops = {
+13
drivers/ufs/host/ufshcd-pltfrm.c
··· 524 524 } 525 525 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); 526 526 527 + /** 528 + * ufshcd_pltfrm_remove - Remove ufshcd platform 529 + * @pdev: pointer to Platform device handle 530 + */ 531 + void ufshcd_pltfrm_remove(struct platform_device *pdev) 532 + { 533 + struct ufs_hba *hba = platform_get_drvdata(pdev); 534 + 535 + ufshcd_remove(hba); 536 + pm_runtime_disable(&pdev->dev); 537 + } 538 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_remove); 539 + 527 540 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); 528 541 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); 529 542 MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
+1
drivers/ufs/host/ufshcd-pltfrm.h
··· 31 31 void ufshcd_init_host_params(struct ufs_host_params *host_params); 32 32 int ufshcd_pltfrm_init(struct platform_device *pdev, 33 33 const struct ufs_hba_variant_ops *vops); 34 + void ufshcd_pltfrm_remove(struct platform_device *pdev); 34 35 int ufshcd_populate_vreg(struct device *dev, const char *name, 35 36 struct ufs_vreg **out_vreg, bool skip_current); 36 37