[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250407085143.173-1-tanghuan@vivo.com>
Date: Mon, 7 Apr 2025 16:51:43 +0800
From: Huan Tang <tanghuan@...o.com>
To: alim.akhtar@...sung.com,
avri.altman@....com,
bvanassche@....org,
James.Bottomley@...senPartnership.com,
martin.petersen@...cle.com,
beanhuo@...ron.com,
luhongfei@...o.com,
quic_cang@...cinc.com,
keosung.park@...sung.com,
viro@...iv.linux.org.uk,
quic_mnaresh@...cinc.com,
peter.wang@...iatek.com,
manivannan.sadhasivam@...aro.org,
quic_nguyenb@...cinc.com,
linux@...ssschuh.net,
ebiggers@...gle.com,
minwoo.im@...sung.com,
linux-kernel@...r.kernel.org,
linux-scsi@...r.kernel.org
Cc: opensource.kernel@...o.com,
Huan Tang <tanghuan@...o.com>
Subject: [PATCH v9] ufs: core: Add WB buffer resize support
Follow JESD220G, support WB buffer resize feature through sysfs;
Query bit0 of ext_wb_sup to determine whether the device supports
WB resize;Query wb_resize_hint and wb_resize_status to get the
device's resize hint and resize status; Set wb_resize_enable to
enable resize operation. To achieve this goals, four sysfs nodes
have been added:
1. ext_wb_sup
2. wb_resize_enable
3. wb_resize_hint
4. wb_resize_status
The detailed definition of the four nodes can be found in the sysfs
documentation.
Changelog
===
v8 - > v9:
1.Add "ext_wb_sup" node
2.Fix some coding errors,for example: "gerneral" -> "general"
3.Add a check bit0 of ext_wb_sup
4.Following Bean's advice: use enum in ufshcd_wb_set_resize_en
v7 - > v8:
1.Optimized the description in the sysfs-driver-ufs file
2.Replace uppercase with lowercase, for example: "KEEP" -> "keep"
3.Fix coding style issues with switch/case statements
v6 - > v7:
1.Use "xxxx_to_string" for string convert
2.Use uppercase characters, for example: "keep" -> "KEEP"
3.Resize enable mode support "IDLE"
v5 - > v6:
1.Fix mistake: obtain the return value of "sysfs_emit"
v4 - > v5:
1.For the three new attributes: use words in sysfs instead of numbers
v3 - > v4:
1.modify three attributes name and description in document
2.add enum wb_resize_en in ufs.h
3.modify function name and parameters in ufs-sysfs.c, ufshcd.h, ufshcd.c
v2 - > v3:
Remove needless code:
drivers/ufs/core/ufs-sysfs.c:441:2:
index = ufshcd_wb_get_query_index(hba)
v1 - > v2:
Remove unused variable "u8 index",
drivers/ufs/core/ufs-sysfs.c:419:12: warning: variable 'index'
set but not used.
v1
https://lore.kernel.org/all/20241025085924.4855-1-tanghuan@vivo.com/
v2
https://lore.kernel.org/all/20241026004423.135-1-tanghuan@vivo.com/
v3
https://lore.kernel.org/all/20241028135205.188-1-tanghuan@vivo.com/
v4
https://lore.kernel.org/all/20241101093318.825-1-tanghuan@vivo.com/
v5
https://lore.kernel.org/all/20241104134612.178-1-tanghuan@vivo.com/
v6
https://lore.kernel.org/all/20241104142437.234-1-tanghuan@vivo.com/
v7
https://lore.kernel.org/all/20250402014536.162-1-tanghuan@vivo.com/
v8
https://lore.kernel.org/all/20250402075710.224-1-tanghuan@vivo.com/
Signed-off-by: Huan Tang <tanghuan@...o.com>
Signed-off-by: Lu Hongfei <luhongfei@...o.com>
---
Documentation/ABI/testing/sysfs-driver-ufs | 59 +++++++++
drivers/ufs/core/ufs-sysfs.c | 144 +++++++++++++++++++++
drivers/ufs/core/ufshcd.c | 18 +++
include/ufs/ufs.h | 34 ++++-
include/ufs/ufshcd.h | 1 +
5 files changed, 255 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs
index ae0191295d29..ea9d6186cefd 100644
--- a/Documentation/ABI/testing/sysfs-driver-ufs
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -1604,3 +1604,62 @@ Description:
prevent the UFS from frequently performing clock gating/ungating.
The attribute is read/write.
+
+What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/ext_wb_sup
+What: /sys/bus/platform/devices/*.ufs/device_descriptor/ext_wb_sup
+Date: April 2025
+Contact: Huan Tang <tanghuan@...o.com>
+Description:
+ This file shows extended WriteBooster features supported by
+ the device.
+
+ The file is read only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/wb_resize_enable
+What: /sys/bus/platform/devices/*.ufs/wb_resize_enable
+Date: April 2025
+Contact: Huan Tang <tanghuan@...o.com>
+Description:
+ The host can enable the WriteBooster buffer resize by setting this
+ attribute.
+
+ ======== ======================================
+ idle There is no resize operation
+ decrease Decrease WriteBooster buffer size
+ increase Increase WriteBooster buffer size
+ ======== ======================================
+
+ The file is write only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_hint
+What: /sys/bus/platform/devices/*.ufs/attributes/wb_resize_hint
+Date: April 2025
+Contact: Huan Tang <tanghuan@...o.com>
+Description:
+ wb_resize_hint indicates hint information about which type of resize
+ for WriteBooster buffer is recommended by the device.
+
+ ========= ======================================
+ keep Recommend keep the buffer size
+ decrease Recommend to decrease the buffer size
+ increase Recommend to increase the buffer size
+ ========= ======================================
+
+ The file is read only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_status
+What: /sys/bus/platform/devices/*.ufs/attributes/wb_resize_status
+Date: April 2025
+Contact: Huan Tang <tanghuan@...o.com>
+Description:
+ The host can check the resize operation status of the WriteBooster
+ buffer by reading this attribute.
+
+ ================ ========================================
+ idle Resize operation is not issued
+ in_progress Resize operation in progress
+ complete_success Resize operation completed successfully
+ general_fail Resize operation general failure
+ ================ ========================================
+
+ The file is read only.
diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c
index 90b5ab60f5ae..71e8454d07d1 100644
--- a/drivers/ufs/core/ufs-sysfs.c
+++ b/drivers/ufs/core/ufs-sysfs.c
@@ -57,6 +57,36 @@ static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear)
}
}
+static const char *ufs_wb_resize_hint_to_string(enum wb_resize_hint hint)
+{
+ switch (hint) {
+ case WB_RESIZE_HINT_KEEP:
+ return "keep";
+ case WB_RESIZE_HINT_DECREASE:
+ return "decrease";
+ case WB_RESIZE_HINT_INCREASE:
+ return "increase";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *ufs_wb_resize_status_to_string(enum wb_resize_status status)
+{
+ switch (status) {
+ case WB_RESIZE_STATUS_IDLE:
+ return "idle";
+ case WB_RESIZE_STATUS_IN_PROGRESS:
+ return "in_progress";
+ case WB_RESIZE_STATUS_COMPLETE_SUCCESS:
+ return "complete_success";
+ case WB_RESIZE_STATUS_GENERAL_FAIL:
+ return "general_fail";
+ default:
+ return "unknown";
+ }
+}
+
static const char *ufshcd_uic_link_state_to_string(
enum uic_link_state state)
{
@@ -411,6 +441,44 @@ static ssize_t wb_flush_threshold_store(struct device *dev,
return count;
}
+static const char * const wb_resize_en_mode[] = {
+ [WB_RESIZE_EN_IDLE] = "idle",
+ [WB_RESIZE_EN_DECREASE] = "decrease",
+ [WB_RESIZE_EN_INCREASE] = "increase",
+};
+
+static ssize_t wb_resize_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int mode;
+ ssize_t res;
+
+ if (!ufshcd_is_wb_allowed(hba) || !hba->dev_info.wb_enabled
+ || !hba->dev_info.b_presrv_uspc_en
+ || !(hba->dev_info.ext_wb_sup & UFS_DEV_WB_BUF_RESIZE))
+ return -EOPNOTSUPP;
+
+ mode = sysfs_match_string(wb_resize_en_mode, buf);
+ if (mode < 0)
+ 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_set_resize_en(hba, mode);
+ ufshcd_rpm_put_sync(hba);
+
+out:
+ up(&hba->host_sem);
+ return res < 0 ? res : count;
+}
+
/**
* pm_qos_enable_show - sysfs handler to show pm qos enable value
* @dev: device associated with the UFS controller
@@ -476,6 +544,7 @@ static DEVICE_ATTR_RW(auto_hibern8);
static DEVICE_ATTR_RW(wb_on);
static DEVICE_ATTR_RW(enable_wb_buf_flush);
static DEVICE_ATTR_RW(wb_flush_threshold);
+static DEVICE_ATTR_WO(wb_resize_enable);
static DEVICE_ATTR_RW(rtc_update_ms);
static DEVICE_ATTR_RW(pm_qos_enable);
static DEVICE_ATTR_RO(critical_health);
@@ -491,6 +560,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
&dev_attr_wb_on.attr,
&dev_attr_enable_wb_buf_flush.attr,
&dev_attr_wb_flush_threshold.attr,
+ &dev_attr_wb_resize_enable.attr,
&dev_attr_rtc_update_ms.attr,
&dev_attr_pm_qos_enable.attr,
&dev_attr_critical_health.attr,
@@ -991,6 +1061,7 @@ UFS_DEVICE_DESC_PARAM(device_version, _DEV_VER, 2);
UFS_DEVICE_DESC_PARAM(number_of_secure_wpa, _NUM_SEC_WPA, 1);
UFS_DEVICE_DESC_PARAM(psa_max_data_size, _PSA_MAX_DATA, 4);
UFS_DEVICE_DESC_PARAM(psa_state_timeout, _PSA_TMT, 1);
+UFS_DEVICE_DESC_PARAM(ext_wb_sup, _EXT_WB_SUP, 2);
UFS_DEVICE_DESC_PARAM(ext_feature_sup, _EXT_UFS_FEATURE_SUP, 4);
UFS_DEVICE_DESC_PARAM(wb_presv_us_en, _WB_PRESRV_USRSPC_EN, 1);
UFS_DEVICE_DESC_PARAM(wb_type, _WB_TYPE, 1);
@@ -1023,6 +1094,7 @@ static struct attribute *ufs_sysfs_device_descriptor[] = {
&dev_attr_number_of_secure_wpa.attr,
&dev_attr_psa_max_data_size.attr,
&dev_attr_psa_state_timeout.attr,
+ &dev_attr_ext_wb_sup.attr,
&dev_attr_ext_feature_sup.attr,
&dev_attr_wb_presv_us_en.attr,
&dev_attr_wb_type.attr,
@@ -1495,6 +1567,76 @@ static inline bool ufshcd_is_wb_attrs(enum attr_idn idn)
idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE;
}
+static int wb_read_resize_attrs(struct ufs_hba *hba,
+ enum attr_idn idn, u32 *attr_val)
+{
+ u8 index = 0;
+ int ret;
+
+ if (!ufshcd_is_wb_allowed(hba) || !hba->dev_info.wb_enabled
+ || !hba->dev_info.b_presrv_uspc_en
+ || !(hba->dev_info.ext_wb_sup & UFS_DEV_WB_BUF_RESIZE))
+ return -EOPNOTSUPP;
+
+ down(&hba->host_sem);
+ if (!ufshcd_is_user_access_allowed(hba)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ index = ufshcd_wb_get_query_index(hba);
+ ufshcd_rpm_get_sync(hba);
+ ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ idn, index, 0, attr_val);
+ ufshcd_rpm_put_sync(hba);
+ if (ret)
+ ret = -EINVAL;
+
+out:
+ up(&hba->host_sem);
+ return ret;
+}
+
+static ssize_t wb_resize_hint_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret;
+ u32 value;
+
+ ret = wb_read_resize_attrs(hba,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT, &value);
+ if (ret)
+ goto out;
+
+ ret = sysfs_emit(buf, "%s\n", ufs_wb_resize_hint_to_string(value));
+
+out:
+ return ret;
+}
+
+static DEVICE_ATTR_RO(wb_resize_hint);
+
+static ssize_t wb_resize_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret;
+ u32 value;
+
+ ret = wb_read_resize_attrs(hba,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS, &value);
+ if (ret)
+ goto out;
+
+ ret = sysfs_emit(buf, "%s\n", ufs_wb_resize_status_to_string(value));
+
+out:
+ return ret;
+}
+
+static DEVICE_ATTR_RO(wb_resize_status);
+
#define UFS_ATTRIBUTE(_name, _uname) \
static ssize_t _name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -1568,6 +1710,8 @@ static struct attribute *ufs_sysfs_attributes[] = {
&dev_attr_wb_avail_buf.attr,
&dev_attr_wb_life_time_est.attr,
&dev_attr_wb_cur_buf.attr,
+ &dev_attr_wb_resize_hint.attr,
+ &dev_attr_wb_resize_status.attr,
NULL,
};
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 83b092cbb864..a73838062ddf 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -6068,6 +6068,21 @@ int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable)
return ret;
}
+int ufshcd_wb_set_resize_en(struct ufs_hba *hba, enum wb_resize_en en_mode)
+{
+ int ret;
+ u8 index;
+
+ index = ufshcd_wb_get_query_index(hba);
+ ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_EN, index, 0, &en_mode);
+ if (ret)
+ dev_err(hba->dev, "%s: Enable WB buf resize operation failed %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba,
u32 avail_buf)
{
@@ -8067,6 +8082,9 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, const u8 *desc_buf)
*/
dev_info->wb_buffer_type = desc_buf[DEVICE_DESC_PARAM_WB_TYPE];
+ dev_info->ext_wb_sup = get_unaligned_be16(desc_buf +
+ DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+
dev_info->b_presrv_uspc_en =
desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN];
diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h
index 8a24ed59ec46..9dc8b872b24d 100644
--- a/include/ufs/ufs.h
+++ b/include/ufs/ufs.h
@@ -180,7 +180,10 @@ enum attr_idn {
QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
- QUERY_ATTR_IDN_TIMESTAMP = 0x30
+ QUERY_ATTR_IDN_TIMESTAMP = 0x30,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT = 0x3C,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_EN = 0x3D,
+ QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS = 0x3E,
};
/* Descriptor idn for Query requests */
@@ -289,6 +292,7 @@ enum device_desc_param {
DEVICE_DESC_PARAM_PRDCT_REV = 0x2A,
DEVICE_DESC_PARAM_HPB_VER = 0x40,
DEVICE_DESC_PARAM_HPB_CONTROL = 0x42,
+ DEVICE_DESC_PARAM_EXT_WB_SUP = 0x4D,
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F,
DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53,
DEVICE_DESC_PARAM_WB_TYPE = 0x54,
@@ -383,6 +387,11 @@ enum {
UFSHCD_AMP = 3,
};
+/* Possible values for wExtendedWriteBoosterSupport */
+enum {
+ UFS_DEV_WB_BUF_RESIZE = BIT(0),
+};
+
/* Possible values for dExtendedUFSFeaturesSupport */
enum {
UFS_DEV_HIGH_TEMP_NOTIF = BIT(4),
@@ -454,6 +463,28 @@ enum ufs_ref_clk_freq {
REF_CLK_FREQ_INVAL = -1,
};
+/* bWriteBoosterBufferResizeEn attribute */
+enum wb_resize_en {
+ WB_RESIZE_EN_IDLE = 0,
+ WB_RESIZE_EN_DECREASE = 1,
+ WB_RESIZE_EN_INCREASE = 2,
+};
+
+/* bWriteBoosterBufferResizeHint attribute */
+enum wb_resize_hint {
+ WB_RESIZE_HINT_KEEP = 0,
+ WB_RESIZE_HINT_DECREASE = 1,
+ WB_RESIZE_HINT_INCREASE = 2,
+};
+
+/* bWriteBoosterBufferResizeStatus attribute */
+enum wb_resize_status {
+ WB_RESIZE_STATUS_IDLE = 0,
+ WB_RESIZE_STATUS_IN_PROGRESS = 1,
+ WB_RESIZE_STATUS_COMPLETE_SUCCESS = 2,
+ WB_RESIZE_STATUS_GENERAL_FAIL = 3,
+};
+
/* Query response result code */
enum {
QUERY_RESULT_SUCCESS = 0x00,
@@ -578,6 +609,7 @@ struct ufs_dev_info {
bool wb_buf_flush_enabled;
u8 wb_dedicated_lu;
u8 wb_buffer_type;
+ u16 ext_wb_sup;
bool b_rpm_dev_flush_capable;
u8 b_presrv_uspc_en;
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index f56050ce9445..722307182630 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1471,6 +1471,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r
struct scatterlist *sg_list, enum dma_data_direction dir);
int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable);
+int ufshcd_wb_set_resize_en(struct ufs_hba *hba, enum wb_resize_en en_mode);
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.39.0
Powered by blists - more mailing lists