2020-05-14 15:05:47

by Stanley Chu

[permalink] [raw]
Subject: [PATCH v2 0/4] scsi: ufs: Fix WriteBooster and cleanup UFS driver

Hi,

This patch set fixes some WriteBooster issues and do small cleanup in UFS driver

v1 -> v2
- Remove dummy new line in patch [4] (Asutosh)
- Add more limitation to allow WriteBooster flush during Hibern8 in runtime-suspend. Now the device power mode is kept as Active power mode only if link is put in Hibern8 or Auto-Hibern8 is enabled during runtime-suspend (Asutosh)

Stanley Chu (4):
scsi: ufs: Remove unnecessary memset for dev_info
scsi: ufs: Allow WriteBooster on UFS 2.2 devices
scsi: ufs: Fix index of attributes query for WriteBooster feature
scsi: ufs: Fix WriteBooster flush during runtime suspend

drivers/scsi/ufs/ufs-sysfs.c | 13 ++++++--
drivers/scsi/ufs/ufs.h | 1 -
drivers/scsi/ufs/ufshcd.c | 62 +++++++++++++++++++-----------------
drivers/scsi/ufs/ufshcd.h | 2 +-
4 files changed, 45 insertions(+), 33 deletions(-)

--
2.18.0


2020-05-14 15:06:02

by Stanley Chu

[permalink] [raw]
Subject: [PATCH v2 4/4] scsi: ufs: Fix WriteBooster flush during runtime suspend

Currently UFS host driver promises VCC supply if UFS device
needs to do WriteBooster flush during runtime suspend.

However the UFS specification mentions,

"While the flushing operation is in progress, the device is
in Active power mode."

Therefore UFS host driver needs to promise more: Keep UFS
device as "Active power mode", otherwise UFS device shall not
do any flush if device enters Sleep or PowerDown power mode.

Fix this by not changing device power mode if WriteBooster
flush is required in ufshcd_suspend().

Signed-off-by: Stanley Chu <[email protected]>
---
drivers/scsi/ufs/ufs.h | 1 -
drivers/scsi/ufs/ufshcd.c | 42 ++++++++++++++++++++-------------------
2 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index b3135344ab3f..9e4bc2e97ada 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -577,7 +577,6 @@ struct ufs_dev_info {
u32 d_ext_ufs_feature_sup;
u8 b_wb_buffer_type;
u32 d_wb_alloc_units;
- bool keep_vcc_on;
u8 b_presrv_uspc_en;
};

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 169a3379e468..b9f7744ca2b4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8101,8 +8101,7 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
!hba->dev_info.is_lu_power_on_wp) {
ufshcd_setup_vreg(hba, false);
} else if (!ufshcd_is_ufs_dev_active(hba)) {
- if (!hba->dev_info.keep_vcc_on)
- ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
+ ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
if (!ufshcd_is_link_active(hba)) {
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq);
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2);
@@ -8172,6 +8171,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
enum ufs_pm_level pm_lvl;
enum ufs_dev_pwr_mode req_dev_pwr_mode;
enum uic_link_state req_link_state;
+ bool keep_curr_dev_pwr_mode = false;

hba->pm_op_in_progress = 1;
if (!ufshcd_is_shutdown_pm(pm_op)) {
@@ -8227,27 +8227,29 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
ufshcd_disable_auto_bkops(hba);
}
/*
- * With wb enabled, if the bkops is enabled or if the
- * configured WB type is 70% full, keep vcc ON
- * for the device to flush the wb buffer
+ * If device needs to do BKOP or WB buffer flush during
+ * Hibern8, keep device power mode as "active power mode"
+ * and VCC supply.
*/
- if ((hba->auto_bkops_enabled && ufshcd_is_wb_allowed(hba)) ||
- ufshcd_wb_keep_vcc_on(hba))
- hba->dev_info.keep_vcc_on = true;
- else
- hba->dev_info.keep_vcc_on = false;
- } else {
- hba->dev_info.keep_vcc_on = false;
+ keep_curr_dev_pwr_mode = hba->auto_bkops_enabled ||
+ (((req_link_state == UIC_LINK_HIBERN8_STATE) ||
+ ((req_link_state == UIC_LINK_ACTIVE_STATE) &&
+ ufshcd_is_auto_hibern8_enabled(hba))) &&
+ ufshcd_wb_keep_vcc_on(hba));
}

- if ((req_dev_pwr_mode != hba->curr_dev_pwr_mode) &&
- ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
- !ufshcd_is_runtime_pm(pm_op))) {
- /* ensure that bkops is disabled */
- ufshcd_disable_auto_bkops(hba);
- ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
- if (ret)
- goto enable_gating;
+ if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
+ if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
+ !ufshcd_is_runtime_pm(pm_op)) {
+ /* ensure that bkops is disabled */
+ ufshcd_disable_auto_bkops(hba);
+ }
+
+ if (!keep_curr_dev_pwr_mode) {
+ ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
+ if (ret)
+ goto enable_gating;
+ }
}

flush_work(&hba->eeh_work);
--
2.18.0

2020-05-14 15:06:31

by Stanley Chu

[permalink] [raw]
Subject: [PATCH v2 2/4] scsi: ufs: Allow WriteBooster on UFS 2.2 devices

According to the UFS specification, WriteBooster is officially
supported by UFS 2.2.

Since UFS 2.2 specification has been finalized in JEDEC and
such devices have also showed up in the market, modify the
checking rule for ufshcd_wb_probe() to allow these devices to enable
WriteBooster.

Signed-off-by: Stanley Chu <[email protected]>
---
drivers/scsi/ufs/ufshcd.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 41ad4501b0d0..b298bdd3e697 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6942,6 +6942,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
* UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES enabled
*/
if (dev_info->wspecversion >= 0x310 ||
+ dev_info->wspecversion == 0x220 ||
(hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES))
ufshcd_wb_probe(hba, desc_buf);

--
2.18.0

2020-05-14 17:11:46

by Asutosh Das (asd)

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] scsi: ufs: Fix WriteBooster flush during runtime suspend

On 5/14/2020 8:01 AM, Stanley Chu wrote:
> Currently UFS host driver promises VCC supply if UFS device
> needs to do WriteBooster flush during runtime suspend.
>
> However the UFS specification mentions,
>
> "While the flushing operation is in progress, the device is
> in Active power mode."
>
> Therefore UFS host driver needs to promise more: Keep UFS
> device as "Active power mode", otherwise UFS device shall not
> do any flush if device enters Sleep or PowerDown power mode.
>
> Fix this by not changing device power mode if WriteBooster
> flush is required in ufshcd_suspend().
>
> Signed-off-by: Stanley Chu <[email protected]>
> ---
> drivers/scsi/ufs/ufs.h | 1 -
> drivers/scsi/ufs/ufshcd.c | 42 ++++++++++++++++++++-------------------
> 2 files changed, 22 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
> index b3135344ab3f..9e4bc2e97ada 100644
> --- a/drivers/scsi/ufs/ufs.h
> +++ b/drivers/scsi/ufs/ufs.h
> @@ -577,7 +577,6 @@ struct ufs_dev_info {
> u32 d_ext_ufs_feature_sup;
> u8 b_wb_buffer_type;
> u32 d_wb_alloc_units;
> - bool keep_vcc_on;
> u8 b_presrv_uspc_en;
> };
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 169a3379e468..b9f7744ca2b4 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -8101,8 +8101,7 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
> !hba->dev_info.is_lu_power_on_wp) {
> ufshcd_setup_vreg(hba, false);
> } else if (!ufshcd_is_ufs_dev_active(hba)) {
> - if (!hba->dev_info.keep_vcc_on)
> - ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
> + ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
> if (!ufshcd_is_link_active(hba)) {
> ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq);
> ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2);
> @@ -8172,6 +8171,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
> enum ufs_pm_level pm_lvl;
> enum ufs_dev_pwr_mode req_dev_pwr_mode;
> enum uic_link_state req_link_state;
> + bool keep_curr_dev_pwr_mode = false;
>
> hba->pm_op_in_progress = 1;
> if (!ufshcd_is_shutdown_pm(pm_op)) {
> @@ -8227,27 +8227,29 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
> ufshcd_disable_auto_bkops(hba);
> }
> /*
> - * With wb enabled, if the bkops is enabled or if the
> - * configured WB type is 70% full, keep vcc ON
> - * for the device to flush the wb buffer
> + * If device needs to do BKOP or WB buffer flush during
> + * Hibern8, keep device power mode as "active power mode"
> + * and VCC supply.
> */
> - if ((hba->auto_bkops_enabled && ufshcd_is_wb_allowed(hba)) ||
> - ufshcd_wb_keep_vcc_on(hba))
> - hba->dev_info.keep_vcc_on = true;
> - else
> - hba->dev_info.keep_vcc_on = false;
> - } else {
> - hba->dev_info.keep_vcc_on = false;
> + keep_curr_dev_pwr_mode = hba->auto_bkops_enabled ||
> + (((req_link_state == UIC_LINK_HIBERN8_STATE) ||
> + ((req_link_state == UIC_LINK_ACTIVE_STATE) &&
> + ufshcd_is_auto_hibern8_enabled(hba))) &&
> + ufshcd_wb_keep_vcc_on(hba));
> }
>
This looks fine.
But I still think the delayed check of flush status should be done to
turn-off Vcc when flush is complete.

> - if ((req_dev_pwr_mode != hba->curr_dev_pwr_mode) &&
> - ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
> - !ufshcd_is_runtime_pm(pm_op))) {
> - /* ensure that bkops is disabled */
> - ufshcd_disable_auto_bkops(hba);
> - ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
> - if (ret)
> - goto enable_gating;
> + if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
> + if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
> + !ufshcd_is_runtime_pm(pm_op)) {
> + /* ensure that bkops is disabled */
> + ufshcd_disable_auto_bkops(hba);
> + }
> +
> + if (!keep_curr_dev_pwr_mode) {
> + ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
> + if (ret)
> + goto enable_gating;
> + }
> }
>
> flush_work(&hba->eeh_work);
>


--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
Linux Foundation Collaborative Project