From b0b23bcbfd0695f512fb0696d359ea4d8abc221f Mon Sep 17 00:00:00 2001 From: Ram Kumar Dwivedi Date: Fri, 8 Sep 2023 05:30:41 -0700 Subject: [PATCH] ufs: ufs-qcom: Defer ufs probe if phy drvdata is not initialized During ufs probe, the phy drvdata is read to get the phy version information. But in some rare cases, the ufs driver tries to read it before the phy parameters are fully initialized, which causes kernel panic. So, defer the ufs probe if phy drvdata is not fully initialized. Call trace: ufs_qcom_phy_save_controller_version+0x4/0x18 [phy_qcom_ufs] ufshcd_variant_hba_init+0x40/0x98 ufshcd_init+0x388/0xc64 ufshcd_pltfrm_init+0x324/0x42c ufs_qcom_probe+0x108/0x248 [ufs_qcom] platform_probe+0xc0/0xec really_probe+0x190/0x384 __driver_probe_device+0xa0/0x12c driver_probe_device+0x44/0x210 __driver_attach+0x108/0x1d4 bus_for_each_dev+0x98/0xe8 driver_attach+0x24/0x34 bus_add_driver+0x10c/0x1fc driver_register+0x78/0x118 __platform_driver_register+0x24/0x34 init_module+0x20/0xfe4 [ufs_qcom] do_one_initcall+0xdc/0x314 do_init_module+0x48/0x1dc load_module+0x1348/0x152c __arm64_sys_finit_module+0xc0/0x110 invoke_syscall+0x58/0x11c el0_svc_common+0xb4/0xf4 do_el0_svc+0x2c/0xb0 el0_svc+0x2c/0xa4 el0t_64_sync_handler+0x68/0xb4 el0t_64_sync+0x1a4/0x1a8 ---[ end trace 0000000000000000 ]---. Change-Id: Ia5783cdfed68d54a38340ca2234b6273c43b2b06 Signed-off-by: Ram Kumar Dwivedi --- drivers/phy/qualcomm/phy-qcom-ufs.c | 6 +++++- drivers/ufs/host/ufs-qcom.c | 6 +++++- include/linux/phy/phy-qcom-ufs.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index b8ce268eda52..431e777a6bfd 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -708,14 +708,18 @@ void ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes) } EXPORT_SYMBOL(ufs_qcom_phy_set_tx_lane_enable); -void ufs_qcom_phy_save_controller_version(struct phy *generic_phy, +int ufs_qcom_phy_save_controller_version(struct phy *generic_phy, u8 major, u16 minor, u16 step) { struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + if (!ufs_qcom_phy) + return -EPROBE_DEFER; + ufs_qcom_phy->host_ctrl_rev_major = major; ufs_qcom_phy->host_ctrl_rev_minor = minor; ufs_qcom_phy->host_ctrl_rev_step = step; + return 0; } EXPORT_SYMBOL(ufs_qcom_phy_save_controller_version); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index c10a4e2f6058..d602926029a0 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -3793,9 +3793,13 @@ static int ufs_qcom_init(struct ufs_hba *hba) &host->vdd_hba_reg_nb); /* update phy revision information before calling phy_init() */ - ufs_qcom_phy_save_controller_version(host->generic_phy, host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); + if (err == -EPROBE_DEFER) { + pr_err("%s: phy device probe is not completed yet\n", + __func__); + goto out_variant_clear; + } err = ufs_qcom_parse_reg_info(host, "qcom,vddp-ref-clk", &host->vddp_ref_clk); diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h index f54bc722051f..311407583c43 100644 --- a/include/linux/phy/phy-qcom-ufs.h +++ b/include/linux/phy/phy-qcom-ufs.h @@ -16,7 +16,7 @@ void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy); void ufs_qcom_phy_dbg_register_save(struct phy *generic_phy); void ufs_qcom_phy_set_src_clk_h8_enter(struct phy *generic_phy); void ufs_qcom_phy_set_src_clk_h8_exit(struct phy *generic_phy); -void ufs_qcom_phy_save_controller_version(struct phy *generic_phy, +int ufs_qcom_phy_save_controller_version(struct phy *generic_phy, u8 major, u16 minor, u16 step); #endif /* PHY_QCOM_UFS_H_ */