diff options
author | Jinyoung Choi <j-young.choi@samsung.com> | 2022-01-27 06:00:25 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2022-02-01 00:44:57 +0300 |
commit | f681d1078d456ef4aea8da1bf5ccbd4081b0fbed (patch) | |
tree | cd8ead4325be86044e6ca8e1b7180dcb6a01eee6 | |
parent | 0790797aca037d002448ea7ec28d0f286f7b615e (diff) | |
download | linux-f681d1078d456ef4aea8da1bf5ccbd4081b0fbed.tar.xz |
scsi: ufs: Add checking lifetime attribute for WriteBooster
Because WB performs writes in SLC mode, it is not possible to use
WriteBooster indefinitely. Vendors can set a lifetime limit in the device.
If the lifetime exceeds this limit, the device ican disable the WB feature.
The feature is defined in the "bWriteBoosterBufferLifeTimeEst (IDN = 1E)"
attribute.
With lifetime exceeding the limit value, the current driver continuously
performs the following query:
- Write Flag: WB_ENABLE / DISABLE
- Read attr: Available Buffer Size
- Read attr: Current Buffer Size
This patch recognizes that WriteBooster is no longer supported by the
device, and prevents unnecessary queries.
Link: https://lore.kernel.org/r/1891546521.01643252701746.JavaMail.epsvc@epcpadp3
Reviewed-by: Asutosh Das <quic_asutoshd@quicinc.com>
Acked-by: Avri Altman <avri.altman@wdc.com>
Signed-off-by: Jinyoung Choi <j-young.choi@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/ufs/ufs.h | 6 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 52 |
2 files changed, 58 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 0bfdca3e648e..4a00c24a3209 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -43,6 +43,12 @@ /* WriteBooster buffer is available only for the logical unit from 0 to 7 */ #define UFS_UPIU_MAX_WB_LUN_ID 8 +/* + * WriteBooster buffer lifetime has a limit setted by vendor. + * If it is over the limit, WriteBooster feature will be disabled. + */ +#define UFS_WB_EXCEED_LIFETIME 0x0B + /* Well known logical unit id in LUN field of UPIU */ enum { UFS_UPIU_REPORT_LUNS_WLUN = 0x81, diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 460d2b440d2e..41d85b69fa50 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5778,6 +5778,47 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba, return false; } +static void ufshcd_wb_force_disable(struct ufs_hba *hba) +{ + if (!(hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL)) + ufshcd_wb_toggle_flush(hba, false); + + ufshcd_wb_toggle_flush_during_h8(hba, false); + ufshcd_wb_toggle(hba, false); + hba->caps &= ~UFSHCD_CAP_WB_EN; + + dev_info(hba->dev, "%s: WB force disabled\n", __func__); +} + +static bool ufshcd_is_wb_buf_lifetime_available(struct ufs_hba *hba) +{ + u32 lifetime; + int ret; + u8 index; + + index = ufshcd_wb_get_query_index(hba); + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + index, 0, &lifetime); + if (ret) { + dev_err(hba->dev, + "%s: bWriteBoosterBufferLifeTimeEst read failed %d\n", + __func__, ret); + return false; + } + + if (lifetime == UFS_WB_EXCEED_LIFETIME) { + dev_err(hba->dev, "%s: WB buf lifetime is exhausted 0x%02X\n", + __func__, lifetime); + return false; + } + + dev_dbg(hba->dev, "%s: WB buf lifetime is 0x%02X\n", + __func__, lifetime); + + return true; +} + static bool ufshcd_wb_need_flush(struct ufs_hba *hba) { int ret; @@ -5786,6 +5827,12 @@ static bool ufshcd_wb_need_flush(struct ufs_hba *hba) if (!ufshcd_is_wb_allowed(hba)) return false; + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) { + ufshcd_wb_force_disable(hba); + return false; + } + /* * The ufs device needs the vcc to be ON to flush. * With user-space reduction enabled, it's enough to enable flush @@ -7486,6 +7533,7 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!ufshcd_is_wb_allowed(hba)) return; + /* * Probe WB only for UFS-2.2 and UFS-3.1 (and later) devices or * UFS devices with quirk UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES @@ -7537,6 +7585,10 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!d_lu_wb_buf_alloc) goto wb_disabled; } + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) + goto wb_disabled; + return; wb_disabled: |