@@ -1559,3 +1559,54 @@ Description:
Symbol - HCMID. This file shows the UFSHCD manufacturer id.
The Manufacturer ID is defined by JEDEC in JEDEC-JEP106.
The file is read only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/wb_resize_enable
+What: /sys/bus/platform/devices/*.ufs/wb_resize_enable
+Date: Nov 2024
+Contact: Huan Tang <tanghuan@vivo.com>
+Description:
+ The host can decrease or increase the WriteBooster Buffer size by setting
+ this attribute.
+
+ ======== ======================================
+ decrease Decrease WriteBooster Buffer Size
+ increase Increase WriteBooster Buffer Size
+ Others Reserved
+ ======== ======================================
+
+ The attribute is write only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_hint
+What: /sys/bus/platform/devices/*.ufs/attributes/wb_resize_hint
+Date: Nov 2024
+Contact: Huan Tang <tanghuan@vivo.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
+ Others Reserved
+ ========= ======================================
+
+ The attribute is read only.
+
+What: /sys/bus/platform/drivers/ufshcd/*/attributes/wb_resize_status
+What: /sys/bus/platform/devices/*.ufs/attributes/wb_resize_status
+Date: Nov 2024
+Contact: Huan Tang <tanghuan@vivo.com>
+Description:
+ The host can check the Resize operation status of the WriteBooster Buffer
+ by reading this attribute.
+
+ ================ ========================================
+ idle Idle (resize operation is not issued)
+ in-progress Resize operation in progress
+ complete-success Resize operation completed successfully
+ general-fail Resize operation general failure
+ Others Reserved
+ ================ ========================================
+
+ The attribute is read only.
@@ -411,6 +411,43 @@ static ssize_t wb_flush_threshold_store(struct device *dev,
return count;
}
+static const char * const 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)
+ return -EOPNOTSUPP;
+
+ mode = sysfs_match_string(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, (u32)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
@@ -468,6 +505,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);
@@ -482,6 +520,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,
NULL
@@ -1476,6 +1515,96 @@ 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)
+ 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 const char * const resize_hint_info[] = {
+ [WB_RESIZE_HINT_KEEP] = "keep",
+ [WB_RESIZE_HINT_DECREASE] = "decrease",
+ [WB_RESIZE_HINT_INCREASE] = "increase",
+};
+
+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;
+
+ if (value >= WB_RESIZE_HINT_KEEP &&
+ value <= WB_RESIZE_HINT_INCREASE)
+ ret = sysfs_emit(buf, "%s\n", resize_hint_info[value]);
+ else
+ ret = -EINVAL;
+
+out:
+ return ret;
+}
+
+static DEVICE_ATTR_RO(wb_resize_hint);
+
+static const char * const resize_status[] = {
+ [WB_RESIZE_STATUS_IDLE] = "idle",
+ [WB_RESIZE_STATUS_IN_PROGRESS] = "in-progress",
+ [WB_RESIZE_STATUS_COMPLETE_SUCCESS] = "complete-success",
+ [WB_RESIZE_STATUS_GENERAL_FAIL] = "general-fail",
+};
+
+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;
+
+ if (value >= WB_RESIZE_STATUS_IDLE &&
+ value <= WB_RESIZE_STATUS_GENERAL_FAIL)
+ ret = sysfs_emit(buf, "%s\n", resize_status[value]);
+ else
+ ret = -EINVAL;
+
+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) \
@@ -1549,6 +1678,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,
};
@@ -6167,6 +6167,21 @@ static bool ufshcd_wb_need_flush(struct ufs_hba *hba)
return ufshcd_wb_presrv_usrspc_keep_vcc_on(hba, avail_buf);
}
+int ufshcd_wb_set_resize_en(struct ufs_hba *hba, u32 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 void ufshcd_rpm_dev_flush_recheck_work(struct work_struct *work)
{
struct ufs_hba *hba = container_of(to_delayed_work(work),
@@ -181,7 +181,10 @@ enum attr_idn {
QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
QUERY_ATTR_IDN_EXT_IID_EN = 0x2A,
- 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 */
@@ -455,6 +458,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,
@@ -1454,6 +1454,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, u32 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);