summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinyoung Choi <j-young.choi@samsung.com>2022-08-04 16:53:54 +0900
committerMartin K. Petersen <martin.petersen@oracle.com>2022-08-22 23:15:11 -0400
commit6c4148ce7cc1d80cef60242a97b25c83c844e68c (patch)
tree0033df3b9f9141dc34282e957946432714f0bc14
parent4450a1653a935d6c0682c08c51b58cba983cf819 (diff)
scsi: ufs: wb: Add explicit flush sysfs attribute
There is the following quirk to bypass "WB 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 Flush". There are three flags that control Write Booster Feature: 1. WB ON/OFF 2. WB Hibern Flush ON/OFF (implicitly) 3. WB Flush ON/OFF (explicit) The sysfs attribute 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, "Flush" may be necessary because the Auto-Hibern8 is not supported in a specific environment. So the sysfs attribute that controls this is necessary. (3) Link: https://lore.kernel.org/r/20220804075354epcms2p8c21c894b4e28840c5fc651875b7f435f@epcms2p8 Reviewed-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--Documentation/ABI/testing/sysfs-driver-ufs9
-rw-r--r--drivers/ufs/core/ufs-sysfs.c46
-rw-r--r--drivers/ufs/core/ufshcd.c9
-rw-r--r--include/ufs/ufshcd.h1
4 files changed, 61 insertions, 4 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs
index 6b248abb1bd7..91de786f9a71 100644
--- a/Documentation/ABI/testing/sysfs-driver-ufs
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -1417,6 +1417,15 @@ Description: This node is used to set or display whether UFS WriteBooster is
platform that doesn't support UFSHCD_CAP_CLK_SCALING, we can
disable/enable WriteBooster through this sysfs node.
+What: /sys/bus/platform/drivers/ufshcd/*/enable_wb_buf_flush
+What: /sys/bus/platform/devices/*.ufs/enable_wb_buf_flush
+Date: July 2022
+Contact: Jinyoung Choi <j-young.choi@samsung.com>
+Description: This entry shows the status of WriteBooster buffer flushing
+ and it can be used to enable or disable the flushing.
+ If flushing is enabled, the device executes the flush
+ operation when the command queue is empty.
+
What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/hpb_version
What: /sys/bus/platform/devices/*.ufs/device_descriptor/hpb_version
Date: June 2021
diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c
index 7f41f2a69b04..e4ddea6ea780 100644
--- a/drivers/ufs/core/ufs-sysfs.c
+++ b/drivers/ufs/core/ufs-sysfs.c
@@ -255,6 +255,50 @@ out:
return res < 0 ? res : count;
}
+static ssize_t enable_wb_buf_flush_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 enable_wb_buf_flush_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ unsigned int enable_wb_buf_flush;
+ ssize_t res;
+
+ if (!ufshcd_is_wb_allowed(hba) ||
+ (hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL)) {
+ dev_warn(dev, "It is not allowed to configure WB buf flushing!\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (kstrtouint(buf, 0, &enable_wb_buf_flush))
+ return -EINVAL;
+
+ if (enable_wb_buf_flush != 0 && enable_wb_buf_flush != 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, enable_wb_buf_flush);
+ 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);
@@ -263,6 +307,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(enable_wb_buf_flush);
static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
&dev_attr_rpm_lvl.attr,
@@ -273,6 +318,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_enable_wb_buf_flush.attr,
NULL
};
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index e17b18a58c8e..abe06616ddc8 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -268,7 +268,6 @@ static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
static int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag);
static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba,
bool enable);
-static void ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable);
static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
@@ -5793,25 +5792,27 @@ static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba,
__func__, enable ? "enabled" : "disabled");
}
-static void ufshcd_wb_toggle_buf_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;
+ 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;
+ 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,
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index bd411f04d856..24c97e0772bb 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1226,6 +1226,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);