aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c11
-rw-r--r--drivers/scsi/ufs/ufs.h10
-rw-r--r--drivers/scsi/ufs/ufshcd.c50
-rw-r--r--drivers/scsi/ufs/ufshcd.h7
4 files changed, 66 insertions, 12 deletions
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index b86b6a40d7e6..a0b3763e1dc2 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -622,16 +622,25 @@ static const struct attribute_group ufs_sysfs_string_descriptors_group = {
.attrs = ufs_sysfs_string_descriptors,
};
+static inline bool ufshcd_is_wb_flags(enum flag_idn idn)
+{
+ return ((idn >= QUERY_FLAG_IDN_WB_EN) &&
+ (idn <= QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8));
+}
+
#define UFS_FLAG(_name, _uname) \
static ssize_t _name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
bool flag; \
+ u8 index = 0; \
int ret; \
struct ufs_hba *hba = dev_get_drvdata(dev); \
+ if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
+ index = ufshcd_wb_get_flag_index(hba); \
pm_runtime_get_sync(hba->dev); \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \
- QUERY_FLAG_IDN##_uname, 0, &flag); \
+ QUERY_FLAG_IDN##_uname, index, &flag); \
pm_runtime_put_sync(hba->dev); \
if (ret) \
return -EINVAL; \
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index daac5053b850..b3135344ab3f 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -64,6 +64,9 @@
#define UFS_MAX_LUNS (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
#define UFS_UPIU_WLUN_ID (1 << 7)
+/* WriteBooster buffer is available only for the logical unit from 0 to 7 */
+#define UFS_UPIU_MAX_WB_LUN_ID 8
+
/* Well known logical unit id in LUN field of UPIU */
enum {
UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
@@ -330,6 +333,12 @@ enum health_desc_param {
HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4,
};
+/* WriteBooster buffer mode */
+enum {
+ WB_BUF_MODE_LU_DEDICATED = 0x0,
+ WB_BUF_MODE_SHARED = 0x1,
+};
+
/*
* Logical Unit Write Protect
* 00h: LU not write protected
@@ -559,6 +568,7 @@ struct ufs_dev_info {
bool is_lu_power_on_wp;
/* Maximum number of general LU supported by the UFS device */
u8 max_lu_supported;
+ u8 wb_dedicated_lu;
u16 wmanufacturerid;
/*UFS device Product Name */
u8 *model;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4053d24eaafc..b6a0d77d47ac 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5205,6 +5205,7 @@ static bool ufshcd_wb_sup(struct ufs_hba *hba)
static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)
{
int ret;
+ u8 index;
enum query_opcode opcode;
if (!ufshcd_wb_sup(hba))
@@ -5217,8 +5218,9 @@ static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)
else
opcode = UPIU_QUERY_OPCODE_CLEAR_FLAG;
+ index = ufshcd_wb_get_flag_index(hba);
ret = ufshcd_query_flag_retry(hba, opcode,
- QUERY_FLAG_IDN_WB_EN, 0, NULL);
+ QUERY_FLAG_IDN_WB_EN, index, NULL);
if (ret) {
dev_err(hba->dev, "%s write booster %s failed %d\n",
__func__, enable ? "enable" : "disable", ret);
@@ -5235,15 +5237,17 @@ static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)
static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set)
{
int val;
+ u8 index;
if (set)
val = UPIU_QUERY_OPCODE_SET_FLAG;
else
val = UPIU_QUERY_OPCODE_CLEAR_FLAG;
+ index = ufshcd_wb_get_flag_index(hba);
return ufshcd_query_flag_retry(hba, val,
- QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8, 0,
- NULL);
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8,
+ index, NULL);
}
static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable)
@@ -5258,13 +5262,15 @@ static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable)
static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba)
{
int ret;
+ u8 index;
if (!ufshcd_wb_sup(hba) || hba->wb_buf_flush_enabled)
return 0;
+ index = ufshcd_wb_get_flag_index(hba);
ret = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN,
- 0, NULL);
+ index, NULL);
if (ret)
dev_err(hba->dev, "%s WB - buf flush enable failed %d\n",
__func__, ret);
@@ -5278,12 +5284,15 @@ static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba)
static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba)
{
int ret;
+ u8 index;
if (!ufshcd_wb_sup(hba) || !hba->wb_buf_flush_enabled)
return 0;
+ index = ufshcd_wb_get_flag_index(hba);
ret = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
- QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN, 0, NULL);
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN,
+ index, NULL);
if (ret) {
dev_warn(hba->dev, "%s: WB - buf flush disable failed %d\n",
__func__, ret);
@@ -6802,6 +6811,9 @@ out:
static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
{
+ u8 lun;
+ u32 d_lu_wb_buf_alloc;
+
if (!ufshcd_is_wb_allowed(hba))
return;
@@ -6824,16 +6836,32 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf)
hba->dev_info.b_wb_buffer_type =
desc_buf[DEVICE_DESC_PARAM_WB_TYPE];
- hba->dev_info.d_wb_alloc_units =
- get_unaligned_be32(desc_buf +
- DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS);
hba->dev_info.b_presrv_uspc_en =
desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN];
- if (!(hba->dev_info.b_wb_buffer_type &&
- hba->dev_info.d_wb_alloc_units))
- goto wb_disabled;
+ if (hba->dev_info.b_wb_buffer_type == WB_BUF_MODE_SHARED) {
+ hba->dev_info.d_wb_alloc_units =
+ get_unaligned_be32(desc_buf +
+ DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS);
+ if (!hba->dev_info.d_wb_alloc_units)
+ goto wb_disabled;
+ } else {
+ for (lun = 0; lun < UFS_UPIU_MAX_WB_LUN_ID; lun++) {
+ d_lu_wb_buf_alloc = 0;
+ ufshcd_read_unit_desc_param(hba,
+ lun,
+ UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS,
+ (u8 *)&d_lu_wb_buf_alloc,
+ sizeof(d_lu_wb_buf_alloc));
+ if (d_lu_wb_buf_alloc) {
+ hba->dev_info.wb_dedicated_lu = lun;
+ break;
+ }
+ }
+ if (!d_lu_wb_buf_alloc)
+ goto wb_disabled;
+ }
return;
wb_disabled:
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8262a48eb9eb..23a434c03c2a 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -861,6 +861,13 @@ static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
}
+static inline u8 ufshcd_wb_get_flag_index(struct ufs_hba *hba)
+{
+ if (hba->dev_info.b_wb_buffer_type == WB_BUF_MODE_LU_DEDICATED)
+ return hba->dev_info.wb_dedicated_lu;
+ return 0;
+}
+
extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
extern int ufshcd_runtime_resume(struct ufs_hba *hba);
extern int ufshcd_runtime_idle(struct ufs_hba *hba);