diff options
author | Subhash Jadavani <subhashj@codeaurora.org> | 2016-10-18 18:30:55 -0700 |
---|---|---|
committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-10-24 11:43:34 -0700 |
commit | badf0ba0b466a9c7ee4f6cac7f0279a136508ff7 (patch) | |
tree | 3c74a422bce5dc61ac2a5a3265931c0b1b453788 /drivers/scsi | |
parent | 1ff56658f3493b9e56cb30d1ddcd7e6646d14c85 (diff) |
scsi: ufs: handle LINERESET during hibern8
If LINERESET was detected during Hibern8 operation, link moves to
default PWM-G1 mode hence full reinit is required to move link to
HS speeds.
Change-Id: I4cdcbd31b5fa5ceac0eea7c743ea9286f231b80b
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 34 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 2 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshci.h | 1 |
3 files changed, 32 insertions, 5 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 862d56e78086..b5d08cfaa694 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4132,7 +4132,13 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", ktime_to_us(ktime_sub(ktime_get(), start)), ret); - if (ret) { + /* + * Do full reinit if enter failed or if LINERESET was detected during + * Hibern8 operation. After LINERESET, link moves to default PWM-G1 + * mode hence full reinit is required to move link to HS speeds. + */ + if (ret || hba->full_init_linereset) { + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER); dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", __func__, ret); @@ -4175,8 +4181,13 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", ktime_to_us(ktime_sub(ktime_get(), start)), ret); - - if (ret) { + /* + * Do full reinit if exit failed or if LINERESET was detected during + * Hibern8 operation. After LINERESET, link moves to default PWM-G1 + * mode hence full reinit is required to move link to HS speeds. + */ + if (ret || hba->full_init_linereset) { + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT); dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d", __func__, ret); @@ -5827,9 +5838,8 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) /* PHY layer lane error */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { + (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. @@ -5837,6 +5847,20 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n", __func__, reg); ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); + + /* Don't ignore LINERESET indication during hibern8 operation */ + if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { + struct uic_command *cmd = hba->active_uic_cmd; + + if (cmd) { + if ((cmd->command == UIC_CMD_DME_HIBER_ENTER) + || (cmd->command == UIC_CMD_DME_HIBER_EXIT)) { + dev_err(hba->dev, "%s: LINERESET during hibern8, reg 0x%x\n", + __func__, reg); + hba->full_init_linereset = true; + } + } + } } /* PA_INIT_ERROR is fatal and needs UIC reset */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c0714b7bea72..94d6d7b67ca6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -902,6 +902,8 @@ struct ufs_hba { bool no_ref_clk_gating; int scsi_block_reqs_cnt; + + bool full_init_linereset; }; /* Returns true if clocks can be gated. Otherwise false */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index d65dad03bdd2..c0e4650a75ad 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -190,6 +190,7 @@ enum { /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ #define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31) +#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR UFS_BIT(4) #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F #define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF |