diff options
| author | Martin K. Petersen <martin.petersen@oracle.com> | 2026-07-16 22:27:24 -0400 |
|---|---|---|
| committer | Martin K. Petersen <martin.petersen@oracle.com> | 2026-07-16 22:27:24 -0400 |
| commit | c8744e71c8f1178b7936172ead26917d5949c5a9 (patch) | |
| tree | 7bfaa063e780aad584b325cd2733a06949403a0c | |
| parent | 760fc6f0e25a72832c2fcf37ecf5f1b770ec8374 (diff) | |
| parent | f13faec1d4c16b3705d1eccffb8ba6723f1102ff (diff) | |
Merge patch series "scsi: ufs: Harden TX EQTR error handling paths"
Can Guo <can.guo@oss.qualcomm.com> says:
TX Equalization training currently has a few error-path gaps that can
make the flow brittle and can leave variant/device cleanup incomplete.
This series hardens TX EQTR in three places:
1. ufs-qcom: route SW FOM setup failures through the shared cleanup
path so temporary device TX EQ settings are restored and link
recovery is always attempted before exit.
2. core: treat RX_FOM DME read failures as best effort so TX EQTR can
continue, and force failed lanes to deterministic 0 FOM.
3. core: always run tx_eqtr POST_CHANGE notify once PRE_CHANGE
succeeds, even when TX EQTR fails, so variant cleanup is not
skipped.
Together these changes improve TX EQTR robustness without changing the
normal success path.
Link: https://patch.msgid.link/20260625121306.1655467-1-can.guo@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
| -rw-r--r-- | drivers/ufs/core/ufs-txeq.c | 33 | ||||
| -rw-r--r-- | drivers/ufs/host/ufs-qcom.c | 9 |
2 files changed, 28 insertions, 14 deletions
diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c index a083094a0465..fa5f539632eb 100644 --- a/drivers/ufs/core/ufs-txeq.c +++ b/drivers/ufs/core/ufs-txeq.c @@ -482,7 +482,8 @@ static void ufshcd_evaluate_tx_eqtr_fom(struct ufs_hba *hba, * @h_iter: host TX EQTR iterator data structure * @d_iter: device TX EQTR iterator data structure * - * Returns 0 on success, negative error code otherwise + * Returns 0 on success, negative error code if get_rx_fom vops fails. + * RX_FOM DME get failures are logged and treated as 0 FOM for that lane. */ static int ufshcd_get_rx_fom(struct ufs_hba *hba, struct ufs_pa_layer_attr *pwr_mode, @@ -497,8 +498,12 @@ static int ufshcd_get_rx_fom(struct ufs_hba *hba, ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB_SEL(RX_FOM, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), &fom); - if (ret) - return ret; + if (ret) { + h_iter->fom[lane] = 0; + dev_dbg(hba->dev, "Failed to get FOM for Host TX Lane %d: %d\n", + lane, ret); + continue; + } h_iter->fom[lane] = (u8)fom; } @@ -508,8 +513,12 @@ static int ufshcd_get_rx_fom(struct ufs_hba *hba, ret = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(RX_FOM, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane)), &fom); - if (ret) - return ret; + if (ret) { + d_iter->fom[lane] = 0; + dev_dbg(hba->dev, "Failed to get FOM for Device TX Lane %d: %d\n", + lane, ret); + continue; + } d_iter->fom[lane] = (u8)fom; } @@ -1218,6 +1227,7 @@ static int ufshcd_tx_eqtr(struct ufs_hba *hba, { struct ufs_pa_layer_attr old_pwr_info; unsigned int noio_flag; + int notify_ret; int ret; /* @@ -1247,14 +1257,19 @@ static int ufshcd_tx_eqtr(struct ufs_hba *hba, } ret = ufshcd_vops_tx_eqtr_notify(hba, PRE_CHANGE, pwr_mode); - if (ret) + if (ret) { + dev_err(hba->dev, "TX EQTR PRE_CHANGE notify failed: %d\n", ret); goto out_unprepare; + } ret = __ufshcd_tx_eqtr(hba, params, pwr_mode); - if (ret) - goto out_unprepare; - ret = ufshcd_vops_tx_eqtr_notify(hba, POST_CHANGE, pwr_mode); + notify_ret = ufshcd_vops_tx_eqtr_notify(hba, POST_CHANGE, pwr_mode); + if (notify_ret) + dev_err(hba->dev, "TX EQTR POST_CHANGE notify failed: %d\n", notify_ret); + + if (!ret) + ret = notify_ret; out_unprepare: if (ret) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 291c43448764..0500320545c4 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -2794,7 +2794,7 @@ static int ufs_qcom_get_rx_fom(struct ufs_hba *hba, if (ret) { dev_err(hba->dev, "%s: Failed to apply TX EQ settings for HS-G%u: %d\n", __func__, gear, ret); - return ret; + goto link_recover_and_restore; } /* Force PMC to target HS Gear to use new TX Equalization settings. */ @@ -2802,16 +2802,15 @@ static int ufs_qcom_get_rx_fom(struct ufs_hba *hba, if (ret) { dev_err(hba->dev, "%s: Failed to change power mode to HS-G%u, Rate-%s: %d\n", __func__, gear, ufs_hs_rate_to_str(rate), ret); - return ret; + goto link_recover_and_restore; } ret = ufs_qcom_host_sw_rx_fom(hba, pwr_mode->lane_rx, fom); - if (ret) { + if (ret) dev_err(hba->dev, "Failed to get SW FOM of TX (PreShoot: %u, DeEmphasis: %u): %d\n", d_iter->preshoot, d_iter->deemphasis, ret); - return ret; - } +link_recover_and_restore: /* Restore Device's TX Equalization settings. */ ret = ufshcd_apply_tx_eq_settings(hba, &hba->tx_eq_params[gear - 1], gear); if (ret) { |
