[RESEND PATCH 3/4] scsi:ufs:add FBO module

From: Jiaming Li
Date: Wed Nov 02 2022 - 01:31:52 EST


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