> There is the following quirk to bypass "WB Manual Flush" in Write Booster. > > - UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL > > If this quirk is not set, there is no knob that can control "WB Manual Flush". > > There are three flags that control Write Booster Feature. > 1. WB ON/OFF > 2. WB Hibern Flush ON/OFF > 3. WB Flush ON/OFF > > The sysfs that controls the WB was implemented. (1) > > In the case of "Hibern Flush", it is always good to turn on. > Control may not be required. (2) > > Finally, "Manual flush" may be necessary because the Auto-Hibern8 is not > supported in a specific environment. > So the sysfs that controls this is necessary. (3) > > In addition, toggle functions for controlling the above flags are cleaned. This patch should be divided into min 2 patches, probably 3: One is all the renaming & cleanups - no functional change. And the other is adding the sysfs entry. Thanks, Avri > > V2: > - modify commit message > - move & modify err messages > - remove unnesscessary debug messages > > Signed-off-by: Jinyoung Choi <j-young.choi@xxxxxxxxxxx> > --- > drivers/ufs/core/ufs-sysfs.c | 46 +++++++++++++++++++++++- > drivers/ufs/core/ufshcd.c | 69 +++++++++++++++++------------------- > include/ufs/ufshcd.h | 7 ++++ > 3 files changed, 84 insertions(+), 38 deletions(-) > > diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c > index 0a088b47d557..b1c51d8df9f4 100644 > --- a/drivers/ufs/core/ufs-sysfs.c > +++ b/drivers/ufs/core/ufs-sysfs.c > @@ -230,7 +230,7 @@ static ssize_t wb_on_store(struct device *dev, struct > device_attribute *attr, > * If the platform supports UFSHCD_CAP_CLK_SCALING, turn WB > * on/off will be done while clock scaling up/down. > */ > - dev_warn(dev, "To control WB through wb_on is not allowed!\n"); > + dev_warn(dev, "It is not allowed to control WB!\n"); > return -EOPNOTSUPP; > } > > @@ -254,6 +254,48 @@ static ssize_t wb_on_store(struct device *dev, struct > device_attribute *attr, > return res < 0 ? res : count; > } > > +static ssize_t wb_buf_flush_en_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct ufs_hba *hba = dev_get_drvdata(dev); > + > + return sysfs_emit(buf, "%d\n", hba->dev_info.wb_buf_flush_enabled); > +} > + > +static ssize_t wb_buf_flush_en_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct ufs_hba *hba = dev_get_drvdata(dev); > + unsigned int wb_buf_flush_en; > + ssize_t res; > + > + if (!ufshcd_is_wb_buf_flush_allowed(hba)) { > + dev_warn(dev, "It is not allowed to control WB buf flush!\n"); > + return -EOPNOTSUPP; > + } > + > + if (kstrtouint(buf, 0, &wb_buf_flush_en)) > + return -EINVAL; > + > + if (wb_buf_flush_en != 0 && wb_buf_flush_en != 1) > + return -EINVAL; > + > + down(&hba->host_sem); > + if (!ufshcd_is_user_access_allowed(hba)) { > + res = -EBUSY; > + goto out; > + } > + > + ufshcd_rpm_get_sync(hba); > + res = ufshcd_wb_toggle_buf_flush(hba, wb_buf_flush_en); > + ufshcd_rpm_put_sync(hba); > +out: > + up(&hba->host_sem); > + return res < 0 ? res : count; > +} > + > static DEVICE_ATTR_RW(rpm_lvl); > static DEVICE_ATTR_RO(rpm_target_dev_state); > static DEVICE_ATTR_RO(rpm_target_link_state); > @@ -262,6 +304,7 @@ static DEVICE_ATTR_RO(spm_target_dev_state); > static DEVICE_ATTR_RO(spm_target_link_state); > static DEVICE_ATTR_RW(auto_hibern8); > static DEVICE_ATTR_RW(wb_on); > +static DEVICE_ATTR_RW(wb_buf_flush_en); > > static struct attribute *ufs_sysfs_ufshcd_attrs[] = { > &dev_attr_rpm_lvl.attr, > @@ -272,6 +315,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { > &dev_attr_spm_target_link_state.attr, > &dev_attr_auto_hibern8.attr, > &dev_attr_wb_on.attr, > + &dev_attr_wb_buf_flush_en.attr, > NULL > }; > > diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c > index f5d5dde497ac..439f6cb15084 100644 > --- a/drivers/ufs/core/ufshcd.c > +++ b/drivers/ufs/core/ufshcd.c > @@ -268,8 +268,7 @@ static int ufshcd_setup_vreg(struct ufs_hba *hba, > bool on); > static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, > struct ufs_vreg *vreg); > static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag); > -static void ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool > set); > -static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable); > +static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba, > bool set); > static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); > static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); > > @@ -289,16 +288,16 @@ static inline void ufshcd_disable_irq(struct ufs_hba > *hba) > } > } > > -static inline void ufshcd_wb_config(struct ufs_hba *hba) > +static void ufshcd_wb_set_default_flags(struct ufs_hba *hba) > { > if (!ufshcd_is_wb_allowed(hba)) > return; > > ufshcd_wb_toggle(hba, true); > + ufshcd_wb_toggle_buf_flush_during_h8(hba, true); > > - ufshcd_wb_toggle_flush_during_h8(hba, true); > - if (!(hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL)) > - ufshcd_wb_toggle_flush(hba, true); > + if (ufshcd_is_wb_buf_flush_allowed(hba)) > + ufshcd_wb_toggle_buf_flush(hba, true); > } > > static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba) > @@ -1289,9 +1288,10 @@ static int ufshcd_devfreq_scale(struct ufs_hba > *hba, bool scale_up) > } > } > > - /* Enable Write Booster if we have scaled up else disable it */ > downgrade_write(&hba->clk_scaling_lock); > is_writelock = false; > + > + /* Enable Write Booster if we have scaled up else disable it */ > ufshcd_wb_toggle(hba, scale_up); > > out_unprepare: > @@ -5714,6 +5714,9 @@ static int __ufshcd_wb_toggle(struct ufs_hba *hba, > bool set, enum flag_idn idn) > enum query_opcode opcode = set ? UPIU_QUERY_OPCODE_SET_FLAG : > UPIU_QUERY_OPCODE_CLEAR_FLAG; > > + if (!ufshcd_is_wb_allowed(hba)) > + return -EPERM; > + > index = ufshcd_wb_get_query_index(hba); > return ufshcd_query_flag_retry(hba, opcode, idn, index, NULL); > } > @@ -5722,60 +5725,50 @@ int ufshcd_wb_toggle(struct ufs_hba *hba, bool > enable) > { > int ret; > > - if (!ufshcd_is_wb_allowed(hba)) > - return 0; > - > - if (!(enable ^ hba->dev_info.wb_enabled)) > + if (hba->dev_info.wb_enabled == enable) > return 0; > > ret = __ufshcd_wb_toggle(hba, enable, QUERY_FLAG_IDN_WB_EN); > if (ret) { > - dev_err(hba->dev, "%s Write Booster %s failed %d\n", > + dev_err(hba->dev, "%s: failed to %s WB %d\n", > __func__, enable ? "enable" : "disable", ret); > return ret; > } > > hba->dev_info.wb_enabled = enable; > - dev_info(hba->dev, "%s Write Booster %s\n", > - __func__, enable ? "enabled" : "disabled"); > > return ret; > } > > -static void ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool > set) > +static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba, > + bool enable) > { > int ret; > > - ret = __ufshcd_wb_toggle(hba, set, > - QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8); > - if (ret) { > - dev_err(hba->dev, "%s: WB-Buf Flush during H8 %s failed: %d\n", > - __func__, set ? "enable" : "disable", ret); > - return; > - } > - dev_dbg(hba->dev, "%s WB-Buf Flush during H8 %s\n", > - __func__, set ? "enabled" : "disabled"); > + ret = __ufshcd_wb_toggle(hba, enable, > + QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8); > + if (ret) > + dev_err(hba->dev, "%s: failed to %s WB buf flush during H8 %d\n", > + __func__, enable ? "enable" : "disable", ret); > } > > -static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable) > +int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable) > { > int ret; > > - if (!ufshcd_is_wb_allowed(hba) || > - hba->dev_info.wb_buf_flush_enabled == enable) > - return; > + if (hba->dev_info.wb_buf_flush_enabled == enable) > + return 0; > > ret = __ufshcd_wb_toggle(hba, enable, > QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN); > if (ret) { > - dev_err(hba->dev, "%s WB-Buf Flush %s failed %d\n", __func__, > - enable ? "enable" : "disable", ret); > - return; > + dev_err(hba->dev, "%s: failed to %s WB buf flush %d\n", > + __func__, enable ? "enable" : "disable", ret); > + return ret; > } > > hba->dev_info.wb_buf_flush_enabled = enable; > > - dev_dbg(hba->dev, "%s WB-Buf Flush %s\n", > - __func__, enable ? "enabled" : "disabled"); > + return ret; > } > > static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba, > @@ -5806,10 +5799,10 @@ static bool > ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba, > > 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); > + if (ufshcd_is_wb_buf_flush_allowed(hba)) > + ufshcd_wb_toggle_buf_flush(hba, false); > > - ufshcd_wb_toggle_flush_during_h8(hba, false); > + ufshcd_wb_toggle_buf_flush_during_h8(hba, false); > ufshcd_wb_toggle(hba, false); > hba->caps &= ~UFSHCD_CAP_WB_EN; > > @@ -8195,7 +8188,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, > bool init_dev_params) > */ > ufshcd_set_active_icc_lvl(hba); > > - ufshcd_wb_config(hba); > + /* Enable UFS Write Booster if supported */ > + ufshcd_wb_set_default_flags(hba); > + > if (hba->ee_usr_mask) > ufshcd_write_ee_control(hba); > /* Enable Auto-Hibernate if configured */ > diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h > index b5c9064a11d9..8c9461d45606 100644 > --- a/include/ufs/ufshcd.h > +++ b/include/ufs/ufshcd.h > @@ -1017,6 +1017,12 @@ static inline bool ufshcd_is_wb_allowed(struct > ufs_hba *hba) > return hba->caps & UFSHCD_CAP_WB_EN; > } > > +static inline bool ufshcd_is_wb_buf_flush_allowed(struct ufs_hba *hba) > +{ > + return ufshcd_is_wb_allowed(hba) && > + !(hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL); > +} > + > #define ufshcd_writel(hba, val, reg) \ > writel((val), (hba)->mmio_base + (reg)) > #define ufshcd_readl(hba, reg) \ > @@ -1211,6 +1217,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba > *hba, > enum query_opcode desc_op); > > int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); > +int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable); > int ufshcd_suspend_prepare(struct device *dev); > int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); > void ufshcd_resume_complete(struct device *dev); > -- > 2.25.1