summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs/ufshcd.c
diff options
context:
space:
mode:
authorStanley Chu <stanley.chu@mediatek.com>2020-05-08 16:01:13 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2020-05-11 22:48:46 -0400
commit6f8d5a6a78cff85a7cbd1f9327e9aee25b0a48b2 (patch)
tree71497159f323a006b0c20bbe3dfb77618280deda /drivers/scsi/ufs/ufshcd.c
parent1f34eedf9bc15d238aece3308aba0a21a1ef5fe2 (diff)
scsi: ufs: Add LU Dedicated buffer mode support for WriteBooster
According to UFS specification, there are two WriteBooster mode of operations: "LU dedicated buffer" mode and "shared buffer" mode. In the "LU dedicated buffer" mode, the WriteBooster Buffer is dedicated to a logical unit. If the device supports the "LU dedicated buffer" mode, this mode is configured by setting bWriteBoosterBufferType to 00h. The logical unit WriteBooster Buffer size is configured by setting the dLUNumWriteBoosterBufferAllocUnits field of the related Unit Descriptor. Only a value greater than zero enables the WriteBooster feature in the logical unit. Modify ufshcd_wb_probe() as above description to support LU Dedicated buffer mode. Note that according to UFS 3.1 specification, the valid value of bDeviceMaxWriteBoosterLUs parameter in Geometry Descriptor is 1, which means at most one LUN can have WriteBooster buffer in "LU dedicated buffer mode". Therefore this patch supports only one LUN with WriteBooster enabled. All WriteBooster related sysfs nodes are specifically mapped to the LUN with WriteBooster enabled in LU Dedicated buffer mode. Link: https://lore.kernel.org/r/20200508080115.24233-7-stanley.chu@mediatek.com Reviewed-by: Avri Altman <avri.altman@wdc.com> Reviewed-by: Bean Huo <beanhuo@micron.com> Reviewed-by: Asutosh Das <asutoshd@codeaurora.org> Signed-off-by: Stanley Chu <stanley.chu@mediatek.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r--drivers/scsi/ufs/ufshcd.c50
1 files changed, 39 insertions, 11 deletions
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: