Commit 41d8a933 authored by Daejun Park's avatar Daejun Park Committed by Martin K. Petersen
Browse files

scsi: ufs: ufshpb: Add HPB 2.0 support

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: default avatarCan Guo <cang@codeaurora.org>
Tested-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarCan Guo <cang@codeaurora.org>
Reviewed-by: default avatarBean Huo <beanhuo@micron.com>
Reviewed-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Signed-off-by: default avatarDaejun Park <daejun7.park@samsung.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2fff76f8
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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,
};

@@ -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);
@@ -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,
+2 −1
Original line number Diff line number Diff line
@@ -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,
+21 −4
Original line number Diff line number Diff line
@@ -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);

@@ -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)
{
@@ -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);
@@ -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,
@@ -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,
};
+7 −0
Original line number Diff line number Diff line
@@ -650,6 +650,8 @@ 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;
@@ -657,6 +659,8 @@ struct ufshpb_dev_info {
	int srgn_size;
	atomic_t slave_conf_cnt;
	bool hpb_disabled;
	u8 max_hpb_single_cmd;
	bool is_legacy;
};
#endif

@@ -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,
Loading