From: lijiaming3 <lijiaming3@xxxxxxxxxx> add fbo module, determine whether the device supports the FBO function and initialize FBO related info Signed-off-by: lijiaming3 <lijiaming3@xxxxxxxxxx> --- drivers/ufs/core/Kconfig | 12 ++++ drivers/ufs/core/Makefile | 1 + drivers/ufs/core/ufsfbo.c | 120 ++++++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufsfbo.h | 23 ++++++++ drivers/ufs/core/ufshcd.c | 4 ++ include/ufs/ufs.h | 3 + include/ufs/ufshcd.h | 1 + 7 files changed, 164 insertions(+) create mode 100644 drivers/ufs/core/ufsfbo.c create mode 100644 drivers/ufs/core/ufsfbo.h diff --git a/drivers/ufs/core/Kconfig b/drivers/ufs/core/Kconfig index e11978171403..30d3b6f07f5b 100644 --- a/drivers/ufs/core/Kconfig +++ b/drivers/ufs/core/Kconfig @@ -58,3 +58,15 @@ config SCSI_UFS_HWMON a hardware monitoring device will be created for the UFS device. If unsure, say N. + +config SCSI_UFS_FBO + bool "Support UFS File-based Optimization" + depends on SCSI_UFSHCD + help + The UFS FBO feature improves sequential read performance. The host send + the LBA info to device first. And then instrut the device to analyse the + LBA fragment info. After the analysis, the host can instruct the device to + return the LBA's fragmented state. Then the host can decide whether to + optimize based on the fragmentation status. After the defragmentation is + concluded, it is expected that the sequential read performance will be + improved. diff --git a/drivers/ufs/core/Makefile b/drivers/ufs/core/Makefile index 62f38c5bf857..af7870126815 100644 --- a/drivers/ufs/core/Makefile +++ b/drivers/ufs/core/Makefile @@ -8,3 +8,4 @@ ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o ufshcd-core-$(CONFIG_SCSI_UFS_HPB) += ufshpb.o ufshcd-core-$(CONFIG_SCSI_UFS_FAULT_INJECTION) += ufs-fault-injection.o ufshcd-core-$(CONFIG_SCSI_UFS_HWMON) += ufs-hwmon.o +ufshcd-core-$(CONFIG_SCSI_UFS_FBO) += ufsfbo.o \ No newline at end of file diff --git a/drivers/ufs/core/ufsfbo.c b/drivers/ufs/core/ufsfbo.c new file mode 100644 index 000000000000..81326fd2fb3d --- /dev/null +++ b/drivers/ufs/core/ufsfbo.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Universal Flash Storage File-based Optimization + * + * Copyright (C) 2022 Xiaomi Mobile Software Co., Ltd + * + * Authors: + * lijiaming <lijiaming3@xxxxxxxxxx> + */ + +#include "ufshcd-priv.h" +#include "ufsfbo.h" +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <asm/unaligned.h> + +/** + * struct ufsfbo_dev_info - FBO device related info + * @fbo_version: UFS file-based optimization Version + * @fbo_rec_lrs: Recommended LBA Range Size In Bytes + * @fbo_max_lrs: The Max LBA Range Size To Be Used By The Host + * @fbo_min_lrs: The Min LBA Range Size To Be Used By The Host + * @fbo_max_lrc: The Max Number Of LBA Ranges Supported By Read/Write Buffer Cmd + * @fbo_lra: Alignment Requirement. 0 Means No Align Requirement + * @fbo_exec_threshold: the execute level of UFS file-based optimization + */ +struct ufsfbo_dev_info { + u16 fbo_version; + u32 fbo_rec_lrs; + u32 fbo_max_lrs; + u32 fbo_min_lrs; + int fbo_max_lrc; + int fbo_lra; + u8 fbo_exec_threshold; +}; +/** + * struct ufsfbo_ctrl - FBO ctrl structure + * @hba: Per adapter private structure + * @fbo_dev_info: FBO device related info + * @fbo_lba_cnt: Number of LBA required to do FBO + */ +struct ufsfbo_ctrl { + struct ufs_hba *hba; + struct ufsfbo_dev_info fbo_dev_info; + int fbo_lba_cnt; +}; + +static int ufsfbo_get_dev_info(struct ufs_hba *hba, struct ufsfbo_ctrl *fbo_ctrl) +{ + int ret; + u32 val; + u8 *desc_buf; + int buf_len; + struct ufsfbo_dev_info *fbo_info = &fbo_ctrl->fbo_dev_info; + + buf_len = hba->desc_size[QUERY_DESC_IDN_FBO]; + desc_buf = kmalloc(buf_len, GFP_KERNEL); + if (!desc_buf) + return -ENOMEM; + + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + QUERY_DESC_IDN_FBO, 0, 0, desc_buf, &buf_len); + if (ret) { + dev_err(hba->dev, "%s: Failed reading FBO Desc. ret = %d\n", + __func__, ret); + goto out; + } + + fbo_info->fbo_version = get_unaligned_be16(desc_buf + FBO_DESC_PARAM_VERSION); + fbo_info->fbo_rec_lrs = get_unaligned_be32(desc_buf + FBO_DESC_PARAM_REC_LBA_RANGE_SIZE); + fbo_info->fbo_max_lrs = get_unaligned_be32(desc_buf + FBO_DESC_PARAM_MAX_LBA_RANGE_SIZE); + fbo_info->fbo_min_lrs = get_unaligned_be32(desc_buf + FBO_DESC_PARAM_MIN_LBA_RANGE_SIZE); + fbo_info->fbo_max_lrc = desc_buf[FBO_DESC_PARAM_MAX_LBA_RANGE_CONUT]; + fbo_info->fbo_lra = get_unaligned_be16(desc_buf + FBO_DESC_PARAM_MAX_LBA_RANGE_ALIGNMENT); + + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_FBO_LEVEL_EXE, 0, 0, &val); + if (ret) { + dev_err(hba->dev, "%s: Failed reading FBO Attr. ret = %d\n", + __func__, ret); + goto out; + } + + fbo_info->fbo_exec_threshold = val; + +out: + kfree(desc_buf); + return ret; +} + +int ufsfbo_probe(struct ufs_hba *hba, const u8 *desc_buf) +{ + struct ufsfbo_ctrl *fbo_ctrl; + u32 ext_ufs_feature; + + ext_ufs_feature = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); + + if (!(ext_ufs_feature & UFS_DEV_FBO_SUP)) + return -EOPNOTSUPP; + + fbo_ctrl = kzalloc(sizeof(struct ufsfbo_ctrl), GFP_KERNEL); + if (!fbo_ctrl) + return -ENOMEM; + + if (ufsfbo_get_dev_info(hba, fbo_ctrl)) + return -EOPNOTSUPP; + + hba->fbo_ctrl = fbo_ctrl; + fbo_ctrl->hba = hba; + + return 0; +} + +void ufsfbo_remove(struct ufs_hba *hba) +{ + if (!hba->fbo_ctrl) + return; + + kfree(hba->fbo_ctrl); +} diff --git a/drivers/ufs/core/ufsfbo.h b/drivers/ufs/core/ufsfbo.h new file mode 100644 index 000000000000..843fa8a75c2c --- /dev/null +++ b/drivers/ufs/core/ufsfbo.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Universal Flash Storage File-based Optimization + * + * Copyright (C) 2022 Xiaomi Mobile Software Co., Ltd + * + * Authors: + * lijiaming <lijiaming3@xxxxxxxxxx> + */ + +#ifndef _UFSFBO_H_ +#define _UFSFBO_H_ + +#ifdef CONFIG_SCSI_UFS_FBO +int ufsfbo_probe(struct ufs_hba *hba, const u8 *desc_buf); +void ufsfbo_remove(struct ufs_hba *hba); +extern const struct attribute_group ufs_sysfs_fbo_param_group; +#else +static inline int ufsfbo_probe(struct ufs_hba *hba, const u8 *desc_buf) {} +static inline void ufsfbo_remove(struct ufs_hba *hba) {} +#endif + +#endif /* _UFSFBO_H_ */ diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 4bc5b8563a62..f769fcb72392 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -35,6 +35,7 @@ #include "ufs_bsg.h" #include "ufshcd-crypto.h" #include "ufshpb.h" +#include "ufsfbo.h" #include <asm/unaligned.h> #define CREATE_TRACE_POINTS @@ -7778,6 +7779,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufshcd_wb_probe(hba, desc_buf); + ufsfbo_probe(hba, desc_buf); + ufshcd_temp_notif_probe(hba, desc_buf); /* @@ -9534,6 +9537,7 @@ void ufshcd_remove(struct ufs_hba *hba) ufs_hwmon_remove(hba); ufs_bsg_remove(hba); ufshpb_remove(hba); + ufsfbo_remove(hba); ufs_sysfs_remove_nodes(hba->dev); blk_mq_destroy_queue(hba->tmf_queue); blk_mq_free_tag_set(&hba->tmf_tag_set); diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index c3fd954ce005..2ab79760dafe 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -165,6 +165,9 @@ enum attr_idn { QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F, + QUERY_ATTR_IDN_FBO_CONTROL = 0x31, + QUERY_ATTR_IDN_FBO_LEVEL_EXE = 0X32, + QUERY_ATTR_IDN_FBO_PROG_STATE = 0x33, }; /* Descriptor idn for Query requests */ diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 9f28349ebcff..5c7367a54bbb 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -973,6 +973,7 @@ struct ufs_hba { struct delayed_work debugfs_ee_work; u32 debugfs_ee_rate_limit_ms; #endif + struct ufsfbo_ctrl *fbo_ctrl; u32 luns_avail; bool complete_put; }; -- 2.38.1