Skip to content

Commit

Permalink
scsi: ufs: ufshpb: Add HPB 2.0 support
Browse files Browse the repository at this point in the history
Version 2.0 of HBP supports reads of varying sizes from 4KB to 1MB.

A read operation <= 32KB is supported as single HPB read. A read between
36KB and 1MB is supported by a combination of write buffer command and HPB
read command to deliver more PPN. The write buffer commands may not be
issued immediately due to busy tags. To use HPB read more aggressively, the
driver can requeue the write buffer command. The requeue threshold is
implemented as timeout and can be modified with requeue_timeout_ms entry in
sysfs.

[mkp: REQ_OP_DRV_* and blk_rq_is_passthrough()]

Link: https://lore.kernel.org/r/20210712090025epcms2p3b3d94f6f1b2cfa394e3d9ba130ca0fa7@epcms2p3
Tested-by: Can Guo <cang@codeaurora.org>
Tested-by: Stanley Chu <stanley.chu@mediatek.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Can Guo <cang@codeaurora.org>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Daejun Park authored and Martin K. Petersen committed Aug 1, 2021
1 parent 2fff76f commit 41d8a93
Show file tree
Hide file tree
Showing 7 changed files with 682 additions and 74 deletions.
35 changes: 35 additions & 0 deletions Documentation/ABI/testing/sysfs-driver-ufs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,3 +1425,38 @@ Description: This entry shows the number of read buffer commands for
activating sub-regions recommended by response UPIUs.

The file is read only.

What: /sys/class/scsi_device/*/device/hpb_params/requeue_timeout_ms
Date: June 2021
Contact: Daejun Park <daejun7.park@samsung.com>
Description: This entry shows the requeue timeout threshold for write buffer
command in ms. The value can be changed by writing an integer to
this entry.

What: /sys/bus/platform/drivers/ufshcd/*/attributes/max_data_size_hpb_single_cmd
Date: June 2021
Contact: Daejun Park <daejun7.park@samsung.com>
Description: This entry shows the maximum HPB data size for using a single HPB
command.

=== ========
00h 4KB
01h 8KB
02h 12KB
...
FFh 1024KB
=== ========

The file is read only.

What: /sys/bus/platform/drivers/ufshcd/*/flags/wb_enable
Date: June 2021
Contact: Daejun Park <daejun7.park@samsung.com>
Description: This entry shows the status of HPB.

== ============================
0 HPB is not enabled.
1 HPB is enabled
== ============================

The file is read only.
4 changes: 4 additions & 0 deletions drivers/scsi/ufs/ufs-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,7 @@ UFS_FLAG(disable_fw_update, _PERMANENTLY_DISABLE_FW_UPDATE);
UFS_FLAG(wb_enable, _WB_EN);
UFS_FLAG(wb_flush_en, _WB_BUFF_FLUSH_EN);
UFS_FLAG(wb_flush_during_h8, _WB_BUFF_FLUSH_DURING_HIBERN8);
UFS_FLAG(hpb_enable, _HPB_EN);

static struct attribute *ufs_sysfs_device_flags[] = {
&dev_attr_device_init.attr,
Expand All @@ -1031,6 +1032,7 @@ static struct attribute *ufs_sysfs_device_flags[] = {
&dev_attr_wb_enable.attr,
&dev_attr_wb_flush_en.attr,
&dev_attr_wb_flush_during_h8.attr,
&dev_attr_hpb_enable.attr,
NULL,
};

Expand Down Expand Up @@ -1077,6 +1079,7 @@ out: \
static DEVICE_ATTR_RO(_name)

UFS_ATTRIBUTE(boot_lun_enabled, _BOOT_LU_EN);
UFS_ATTRIBUTE(max_data_size_hpb_single_cmd, _MAX_HPB_SINGLE_CMD);
UFS_ATTRIBUTE(current_power_mode, _POWER_MODE);
UFS_ATTRIBUTE(active_icc_level, _ACTIVE_ICC_LVL);
UFS_ATTRIBUTE(ooo_data_enabled, _OOO_DATA_EN);
Expand All @@ -1100,6 +1103,7 @@ UFS_ATTRIBUTE(wb_cur_buf, _CURR_WB_BUFF_SIZE);

static struct attribute *ufs_sysfs_attributes[] = {
&dev_attr_boot_lun_enabled.attr,
&dev_attr_max_data_size_hpb_single_cmd.attr,
&dev_attr_current_power_mode.attr,
&dev_attr_active_icc_level.attr,
&dev_attr_ooo_data_enabled.attr,
Expand Down
3 changes: 2 additions & 1 deletion drivers/scsi/ufs/ufs.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,13 @@ enum flag_idn {
QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F,
QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10,
QUERY_FLAG_IDN_HPB_RESET = 0x11,
QUERY_FLAG_IDN_HPB_EN = 0x12,
};

/* Attribute idn for Query requests */
enum attr_idn {
QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
QUERY_ATTR_IDN_RESERVED = 0x01,
QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD = 0x01,
QUERY_ATTR_IDN_POWER_MODE = 0x02,
QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
Expand Down
25 changes: 21 additions & 4 deletions drivers/scsi/ufs/ufshcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2788,7 +2788,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)

lrbp->req_abort_skip = false;

ufshpb_prep(hba, lrbp);
err = ufshpb_prep(hba, lrbp);
if (err == -EAGAIN) {
lrbp->cmd = NULL;
ufshcd_release(hba);
goto out;
}

ufshcd_comp_scsi_upiu(hba, lrbp);

Expand Down Expand Up @@ -3196,7 +3201,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
*
* Returns 0 for success, non-zero in case of failure
*/
static int ufshcd_query_attr_retry(struct ufs_hba *hba,
int ufshcd_query_attr_retry(struct ufs_hba *hba,
enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector,
u32 *attr_val)
{
Expand Down Expand Up @@ -4992,7 +4997,8 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth)
static void ufshcd_hpb_destroy(struct ufs_hba *hba, struct scsi_device *sdev)
{
/* skip well-known LU */
if ((sdev->lun >= UFS_UPIU_MAX_UNIT_NUM_ID) || !ufshpb_is_allowed(hba))
if ((sdev->lun >= UFS_UPIU_MAX_UNIT_NUM_ID) ||
!(hba->dev_info.hpb_enabled) || !ufshpb_is_allowed(hba))
return;

ufshpb_destroy_lu(hba, sdev);
Expand Down Expand Up @@ -7563,8 +7569,18 @@ static int ufs_get_device_desc(struct ufs_hba *hba)

if (dev_info->wspecversion >= UFS_DEV_HPB_SUPPORT_VERSION &&
(b_ufs_feature_sup & UFS_DEV_HPB_SUPPORT)) {
dev_info->hpb_enabled = true;
bool hpb_en = false;

ufshpb_get_dev_info(hba, desc_buf);

if (!ufshpb_is_legacy(hba))
err = ufshcd_query_flag_retry(hba,
UPIU_QUERY_OPCODE_READ_FLAG,
QUERY_FLAG_IDN_HPB_EN, 0,
&hpb_en);

if (ufshpb_is_legacy(hba) || (!err && hpb_en))
dev_info->hpb_enabled = true;
}

err = ufshcd_read_string_desc(hba, model_index,
Expand Down Expand Up @@ -8143,6 +8159,7 @@ static const struct attribute_group *ufshcd_driver_groups[] = {
&ufs_sysfs_lun_attributes_group,
#ifdef CONFIG_SCSI_UFS_HPB
&ufs_sysfs_hpb_stat_group,
&ufs_sysfs_hpb_param_group,
#endif
NULL,
};
Expand Down
7 changes: 7 additions & 0 deletions drivers/scsi/ufs/ufshcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,17 @@ struct ufs_hba_variant_params {
* @srgn_size: device reported HPB sub-region size
* @slave_conf_cnt: counter to check all lu finished initialization
* @hpb_disabled: flag to check if HPB is disabled
* @max_hpb_single_cmd: device reported bMAX_DATA_SIZE_FOR_SINGLE_CMD value
* @is_legacy: flag to check HPB 1.0
*/
struct ufshpb_dev_info {
int num_lu;
int rgn_size;
int srgn_size;
atomic_t slave_conf_cnt;
bool hpb_disabled;
u8 max_hpb_single_cmd;
bool is_legacy;
};
#endif

Expand Down Expand Up @@ -1111,6 +1115,9 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
u8 param_offset,
u8 *param_read_buf,
u8 param_size);
int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode,
enum attr_idn idn, u8 index, u8 selector,
u32 *attr_val);
int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
enum attr_idn idn, u8 index, u8 selector, u32 *attr_val);
int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
Expand Down
Loading

0 comments on commit 41d8a93

Please sign in to comment.