Message ID | 20200503060351.10572-7-stanley.chu@mediatek.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | scsi: ufs: support LU Dedicated buffer mode for WriteBooster | expand |
> - 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 < hba->dev_info.max_lu_supported; lun++) { max_lu_supported is determined according to bMaxNumberLU in the geometry descriptor, which can be 32. WB buffer however, is only valid only for LU 0, ..., LU7. Better to add this new limit to ufs.h. > + ret = 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 (ret) > + goto wb_disabled; I think you should just continue here, as it is ok for the query to fail. The spec says: The WriteBooster Buffer is available only for the logical units from 0 to 7 which are configured as "normal memory type" (bMemoryType = 00h) and "not Boot well known logical unit" (bBootLunID = 00h), otherwise the Query Request shall fail and the Query Response field shall be set to "General Failure". Sorry for not noticing this earlier. Thanks, Avri > + 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 898883058e3a..f232a67fd9b3 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); > -- > 2.18.0
Hi Avri, On Sun, 2020-05-03 at 08:00 +0000, Avri Altman wrote: > > > - 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 < hba->dev_info.max_lu_supported; lun++) { > max_lu_supported is determined according to bMaxNumberLU in the geometry descriptor, > which can be 32. WB buffer however, is only valid only for LU 0, ..., LU7. > Better to add this new limit to ufs.h. Thanks for noticing this. I will fix it in next version. > > > + ret = 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 (ret) > > + goto wb_disabled; > I think you should just continue here, as it is ok for the query to fail. > The spec says: > The WriteBooster Buffer is available only for the logical units from 0 to 7 which are configured as > "normal memory type" (bMemoryType = 00h) and "not Boot well known logical unit" (bBootLunID = > 00h), otherwise the Query Request shall fail and the Query Response field shall be set to "General > Failure". > > Sorry for not noticing this earlier. Always appreciate your review and always not being too late : ) The spec does not mention clearly that the Query Request shall fail for Read or Write. Although I think it shall fail for Write only, i.e., fail during configuration only, it is better to let fail being skipped and check d_lu_wb_buf_alloc only anyway. I will fix this as well in next version. Thanks, Stanley Chu > > Thanks, > Avri > > + 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 898883058e3a..f232a67fd9b3 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); > > -- > > 2.18.0 > > _______________________________________________ > Linux-mediatek mailing list > Linux-mediatek@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-mediatek
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..eb3d3cebc87d 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -330,6 +330,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 +565,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 d4a9c479294c..fe093207cc45 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,10 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) { + int ret; + u8 lun; + u32 d_lu_wb_buf_alloc = 0; + if (!ufshcd_is_wb_allowed(hba)) return; @@ -6824,16 +6837,33 @@ 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 < hba->dev_info.max_lu_supported; lun++) { + ret = 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 (ret) + goto wb_disabled; + 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 898883058e3a..f232a67fd9b3 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);
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. Signed-off-by: Stanley Chu <stanley.chu@mediatek.com> --- drivers/scsi/ufs/ufs-sysfs.c | 11 +++++++- drivers/scsi/ufs/ufs.h | 7 +++++ drivers/scsi/ufs/ufshcd.c | 52 ++++++++++++++++++++++++++++-------- drivers/scsi/ufs/ufshcd.h | 7 +++++ 4 files changed, 65 insertions(+), 12 deletions(-)