Skip to contentSkip to conversation

Add Multi Circular Queue Support

PATCH Superseded Asutosh Das 4 participants 40 messages Sep 23, 2022 – Oct 4, 2022

Subsystems (5)

v1 of 13 Superseded Latest is v13 →

lore
Share & tools
lore
#0 lore raw

cover Add Multi Circular Queue Support

UFS Multi-Circular Queue (MCQ) has been added in UFSHCI v4.0 to improve storage performance. This patch series is a RFC implementation of this.

This is the initial driver implementation and it has been verified by booting on an emulation platform. During testing, all low power modes were disabled and it was in HS-G1 mode.

Please take a look and let us know your thoughts.

v1:
- Split the changes
- Addressed Bart's comments
- Addressed Bean's comments

* RFC versions:
v2 -> v3:
- Split the changes based on functionality
- Addressed queue configuration issues
- Faster SQE tail pointer increments
- Addressed comments from Bart and Manivannan

v1 -> v2:
- Enabled host_tagset
- Added queue num configuration support
- Added one more vops to allow vendor provide the wanted MAC
- Determine nutrs and can_queue by considering both MAC, bqueuedepth and EXT_IID support
- Postponed MCQ initialization and scsi_add_host() to async probe
- Used (EXT_IID, Task Tag) tuple to support up to 4096 tasks (theoretically)

Asutosh Das (16):
ufs: core: Probe for ext_iid support
ufs: core: Introduce Multi-circular queue capability
ufs: core: Defer adding host to scsi if mcq is supported
ufs: core: mcq: Introduce Multi Circular Queue
ufs: core: mcq: Configure resource regions
ufs: core: mcq: Calculate queue depth
ufs: core: mcq: Allocate memory for mcq mode
ufs: core: mcq: Configure operation and runtime interface
ufs: core: mcq: Use shared tags for MCQ mode
ufs: core: Prepare ufshcd_send_command for mcq
ufs: core: mcq: Find hardware queue to queue request
ufs: core: Prepare for completion in mcq
ufs: mcq: Add completion support of a cqe
ufs: core: mcq: Add completion support in poll
ufs: core: mcq: Enable Multi Circular Queue
ufs: qcom-host: Enable multi circular queue capability

 drivers/ufs/core/Makefile      |   2 +-
 drivers/ufs/core/ufs-mcq.c     | 511 +++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  84 ++++++-
 drivers/ufs/core/ufshcd.c      | 322 +++++++++++++++++++++-----
 drivers/ufs/host/ufs-qcom.c    |  49 ++++
 drivers/ufs/host/ufs-qcom.h    |   4 +
 include/ufs/ufs.h              |   6 +
 include/ufs/ufshcd.h           | 136 +++++++++++
 include/ufs/ufshci.h           |  63 +++++
 9 files changed, 1117 insertions(+), 60 deletions(-)
 create mode 100644 drivers/ufs/core/ufs-mcq.c
Signature · 1 line
2.7.4
#1 lore raw

PATCH 1/16 ufs: core: Probe for ext_iid support

Task Tag is limited to 8 bits and this restricts the number of active IOs to 255.
In Multi-circular queue mode, this may not be enough. The specification provides EXT_IID which can be used to increase the number of IOs if the UFS device and UFSHC support it. This patch adds support to probe for ext_iid support in ufs device and UFSHC.

---
 drivers/ufs/core/ufshcd.c | 32 ++++++++++++++++++++++++++++++++
 include/ufs/ufs.h         |  4 ++++
 include/ufs/ufshcd.h      |  4 ++++
 include/ufs/ufshci.h      |  7 +++++++
 4 files changed, 47 insertions(+)
drivers/ufs/core/ufshcd.c +32 -0
index f4f8ded..4b9ae83 100644
@@ -88,6 +88,7 @@
 /* Polling time to wait for fDeviceInit */
 #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
 
+#define EXT_IID_CAP_SHIFT 10
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\
 	({                                                              \
 		int _ret;                                               \
@@ -2239,6 +2240,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
 	if (err)
 		dev_err(hba->dev, "crypto setup failed\n");
 
+	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);
+	hba->ext_iid_sup = (hba->mcq_capabilities & MASK_EXT_IID_SUPPORT) >>
+		EXT_IID_CAP_SHIFT;
+
 	return err;
 }
 
@@ -7664,6 +7669,30 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf)
 	}
 }
 
+static void ufshcd_ext_iid_probe(struct ufs_hba *hba, u8 *desc_buf)
+{
+	struct ufs_dev_info *dev_info = &hba->dev_info;
+	u32 ext_ufs_feature;
+	u32 ext_iid_en = 0;
+	int err;
+
+	if (dev_info->wspecversion < 0x400)
+		goto out;
+
+	ext_ufs_feature = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+
+	if (!(ext_ufs_feature & UFS_DEV_EXT_IID_SUP))
+		goto out;
+
+	err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+				      QUERY_ATTR_IDN_EXT_IID_EN, 0, 0, &ext_iid_en);
+	if (err)
+		dev_err(hba->dev, "failed reading bEXTIIDEn. err = %d\n", err);
+
+out:
+	dev_info->b_ext_iid_en = !!ext_iid_en;
+}
+
 void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
 			     const struct ufs_dev_quirk *fixups)
 {
@@ -7762,6 +7791,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
 
 	ufshcd_temp_notif_probe(hba, desc_buf);
 
+	if (hba->ext_iid_sup)
+		ufshcd_ext_iid_probe(hba, desc_buf);
+
 	/*
 	 * ufshcd_read_string_desc returns size of the string
 	 * reset the error value
include/ufs/ufs.h +4 -0
index 1bba3fe..ba2a1d8 100644
@@ -165,6 +165,7 @@ 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_EXT_IID_EN		= 0x2A,
 };
 
 /* Descriptor idn for Query requests */
@@ -352,6 +353,7 @@ enum {
 	UFS_DEV_EXT_TEMP_NOTIF		= BIT(6),
 	UFS_DEV_HPB_SUPPORT		= BIT(7),
 	UFS_DEV_WRITE_BOOSTER_SUP	= BIT(8),
+	UFS_DEV_EXT_IID_SUP		= BIT(16),
 };
 #define UFS_DEV_HPB_SUPPORT_VERSION		0x310
 
@@ -601,6 +603,8 @@ struct ufs_dev_info {
 
 	bool	b_rpm_dev_flush_capable;
 	u8	b_presrv_uspc_en;
+	/* UFS EXT_IID Enable */
+	bool	b_ext_iid_en;
 };
 
 /*
include/ufs/ufshcd.h +4 -0
index 7fe1a92..da1eb8a 100644
@@ -737,6 +737,7 @@ struct ufs_hba_monitor {
  * @outstanding_lock: Protects @outstanding_reqs.
  * @outstanding_reqs: Bits representing outstanding transfer requests
  * @capabilities: UFS Controller Capabilities
+ * @mcq_capabilities: UFS Multi Command Queue capabilities
  * @nutrs: Transfer Request Queue depth supported by controller
  * @nutmrs: Task Management Queue depth supported by controller
  * @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock.
@@ -818,6 +819,7 @@ struct ufs_hba_monitor {
  *	device
  * @complete_put: whether or not to call ufshcd_rpm_put() from inside
  *	ufshcd_resume_complete()
+ * @ext_iid_sup: is EXT_IID is supported by UFSHC
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -859,6 +861,7 @@ struct ufs_hba {
 
 	u32 capabilities;
 	int nutrs;
+	u32 mcq_capabilities;
 	int nutmrs;
 	u32 reserved_slot;
 	u32 ufs_version;
@@ -965,6 +968,7 @@ struct ufs_hba {
 #endif
 	u32 luns_avail;
 	bool complete_put;
+	bool ext_iid_sup;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
include/ufs/ufshci.h +7 -0
index f81aa95..ef5c3a8 100644
@@ -22,6 +22,7 @@ enum {
 /* UFSHCI Registers */
 enum {
 	REG_CONTROLLER_CAPABILITIES		= 0x00,
+	REG_MCQCAP				= 0x04,
 	REG_UFS_VERSION				= 0x08,
 	REG_CONTROLLER_DEV_ID			= 0x10,
 	REG_CONTROLLER_PROD_ID			= 0x14,
@@ -68,6 +69,12 @@ enum {
 	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
 	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
 	MASK_CRYPTO_SUPPORT			= 0x10000000,
+	MASK_MCQ_SUPPORT			= 0x40000000,
+};
+
+/* MCQ capability mask */
+enum {
+	MASK_EXT_IID_SUPPORT = 0x00000400,
 };
 
 #define UFS_MASK(mask, offset)		((mask) << (offset))
Signature · 1 line
2.7.4
#2 lore raw

Re: [PATCH v1 01/16] ufs: core: Probe for ext_iid support

Quoted 31 lines · Asutosh Das

Task Tag is limited to 8 bits and this restricts the number of active IOs to 255.
In Multi-circular queue mode, this may not be enough. The specification provides EXT_IID which can be used to increase the number of IOs if the UFS device and UFSHC support it. This patch adds support to probe for ext_iid support in ufs device and UFSHC.

---
 drivers/ufs/core/ufshcd.c | 32 ++++++++++++++++++++++++++++++++
 include/ufs/ufs.h         |  4 ++++
 include/ufs/ufshcd.h      |  4 ++++
 include/ufs/ufshci.h      |  7 +++++++
 4 files changed, 47 insertions(+)
drivers/ufs/core/ufshcd.c +1 -0
index f4f8ded..4b9ae83 100644
@@ -88,6 +88,7 @@
 /* Polling time to wait for fDeviceInit */
 #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
 
+#define EXT_IID_CAP_SHIFT 10
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\
 	({                                                              \
 		int _ret;                                               \

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) · line 2246

Quoted 7 lines
drivers/ufs/core/ufshcd.c +4 -0
@@ -2239,6 +2240,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
 	if (err)
 		dev_err(hba->dev, "crypto setup failed\n");
 
+	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);
+	hba->ext_iid_sup = (hba->mcq_capabilities & MASK_EXT_IID_SUPPORT) >>
+		EXT_IID_CAP_SHIFT;
+

Can you use FIELD_* macros for the field manipulations throughout the series? This will avoid the use of additional _SHIFT macros.

drivers/ufs/core/ufshcd.c static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf) · line 7672

Quoted 8 lines
drivers/ufs/core/ufshcd.c +1 -0
 	return err;
 }
 
@@ -7664,6 +7669,30 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf)
 	}
 }
 
+static void ufshcd_ext_iid_probe(struct ufs_hba *hba, u8 *desc_buf)

ufshcd_device_ext_iid_probe?

drivers/ufs/core/ufshcd.c static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf) · line 7683

Quoted 11 lines
drivers/ufs/core/ufshcd.c +11 -0
+{
+	struct ufs_dev_info *dev_info = &hba->dev_info;
+	u32 ext_ufs_feature;
+	u32 ext_iid_en = 0;
+	int err;
+
+	if (dev_info->wspecversion < 0x400)
+		goto out;
+
+	ext_ufs_feature = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+

No need of a newline

Thanks,
Mani

Quoted 118 lines
drivers/ufs/core/ufshcd.c +15 -0
+	if (!(ext_ufs_feature & UFS_DEV_EXT_IID_SUP))
+		goto out;
+
+	err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+				      QUERY_ATTR_IDN_EXT_IID_EN, 0, 0, &ext_iid_en);
+	if (err)
+		dev_err(hba->dev, "failed reading bEXTIIDEn. err = %d\n", err);
+
+out:
+	dev_info->b_ext_iid_en = !!ext_iid_en;
+}
+
 void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
 			     const struct ufs_dev_quirk *fixups)
 {
@@ -7762,6 +7791,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
 
 	ufshcd_temp_notif_probe(hba, desc_buf);
 
+	if (hba->ext_iid_sup)
+		ufshcd_ext_iid_probe(hba, desc_buf);
+
 	/*
 	 * ufshcd_read_string_desc returns size of the string
 	 * reset the error value
include/ufs/ufs.h +4 -0
index 1bba3fe..ba2a1d8 100644
@@ -165,6 +165,7 @@ 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_EXT_IID_EN		= 0x2A,
 };
 
 /* Descriptor idn for Query requests */
@@ -352,6 +353,7 @@ enum {
 	UFS_DEV_EXT_TEMP_NOTIF		= BIT(6),
 	UFS_DEV_HPB_SUPPORT		= BIT(7),
 	UFS_DEV_WRITE_BOOSTER_SUP	= BIT(8),
+	UFS_DEV_EXT_IID_SUP		= BIT(16),
 };
 #define UFS_DEV_HPB_SUPPORT_VERSION		0x310
 
@@ -601,6 +603,8 @@ struct ufs_dev_info {
 
 	bool	b_rpm_dev_flush_capable;
 	u8	b_presrv_uspc_en;
+	/* UFS EXT_IID Enable */
+	bool	b_ext_iid_en;
 };
 
 /*
include/ufs/ufshcd.h +4 -0
index 7fe1a92..da1eb8a 100644
@@ -737,6 +737,7 @@ struct ufs_hba_monitor {
  * @outstanding_lock: Protects @outstanding_reqs.
  * @outstanding_reqs: Bits representing outstanding transfer requests
  * @capabilities: UFS Controller Capabilities
+ * @mcq_capabilities: UFS Multi Command Queue capabilities
  * @nutrs: Transfer Request Queue depth supported by controller
  * @nutmrs: Task Management Queue depth supported by controller
  * @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock.
@@ -818,6 +819,7 @@ struct ufs_hba_monitor {
  *	device
  * @complete_put: whether or not to call ufshcd_rpm_put() from inside
  *	ufshcd_resume_complete()
+ * @ext_iid_sup: is EXT_IID is supported by UFSHC
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -859,6 +861,7 @@ struct ufs_hba {
 
 	u32 capabilities;
 	int nutrs;
+	u32 mcq_capabilities;
 	int nutmrs;
 	u32 reserved_slot;
 	u32 ufs_version;
@@ -965,6 +968,7 @@ struct ufs_hba {
 #endif
 	u32 luns_avail;
 	bool complete_put;
+	bool ext_iid_sup;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
include/ufs/ufshci.h +7 -0
index f81aa95..ef5c3a8 100644
@@ -22,6 +22,7 @@ enum {
 /* UFSHCI Registers */
 enum {
 	REG_CONTROLLER_CAPABILITIES		= 0x00,
+	REG_MCQCAP				= 0x04,
 	REG_UFS_VERSION				= 0x08,
 	REG_CONTROLLER_DEV_ID			= 0x10,
 	REG_CONTROLLER_PROD_ID			= 0x14,
@@ -68,6 +69,12 @@ enum {
 	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
 	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
 	MASK_CRYPTO_SUPPORT			= 0x10000000,
+	MASK_MCQ_SUPPORT			= 0x40000000,
+};
+
+/* MCQ capability mask */
+enum {
+	MASK_EXT_IID_SUPPORT = 0x00000400,
 };
 
 #define UFS_MASK(mask, offset)		((mask) << (offset))
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#3 lore raw

Re: [PATCH v1 01/16] ufs: core: Probe for ext_iid support

In reply to Asutosh Das

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) · line 2243

Quoted 1 line · Asutosh Das
drivers/ufs/core/ufshcd.c +1 -0
+	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);

What value is reported when reading the REG_MCQCAP register on an UFSHCI 3.0 controller? -1 or 0?

Quoted 2 lines
drivers/ufs/core/ufshcd.c +2 -0
+	hba->ext_iid_sup = (hba->mcq_capabilities & MASK_EXT_IID_SUPPORT) >>
+		EXT_IID_CAP_SHIFT;

[ ... ]

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (dev_info->wspecversion < 0x400)
+		goto out;

Isn't this version check superfluous? Only UFSHCI 4.0 controllers should support the extended IID feature.

drivers/ufs/core/ufshcd.c static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf) · line 7682

Quoted 1 line
drivers/ufs/core/ufshcd.c +1 -0
+	ext_ufs_feature = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);

The above change introduces a third instance of this code. Please introduce a helper function that does something like the following and replace the above line with a call to that helper function:

	if (hba->desc_size[QUERY_DESC_IDN_DEVICE] <
	    DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4)
		return 0;

	return get_unaligned_be32(desc_buf +
				 DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);

drivers/ufs/core/ufshcd.c static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf) · line 7693

Quoted 2 lines
drivers/ufs/core/ufshcd.c +2 -0
+out:
+	dev_info->b_ext_iid_en = !!ext_iid_en;

Please remove "!!". This conversion happens implicitly when assigning to a boolean variable.

Thanks,

Bart.

#4 lore raw

Re: [PATCH v1 01/16] ufs: core: Probe for ext_iid support

Quoted 5 lines · Bart Van Assche

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) · line 2243

Quoted 1 line · Asutosh Das
drivers/ufs/core/ufshcd.c +1 -0
+	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);

What value is reported when reading the REG_MCQCAP register on an UFSHCI 3.0 controller? -1 or 0?

It reads 0.

#5 lore raw

PATCH 2/16 ufs: core: Introduce Multi-circular queue capability

In reply to Asutosh Das

Adds support to check for MCQ capability in the UFSHC. This capability can be used by host drivers to control MCQ enablement.

---
 drivers/ufs/core/ufshcd.c |  5 +++++
 include/ufs/ufshcd.h      | 13 +++++++++++++
 2 files changed, 18 insertions(+)
drivers/ufs/core/ufshcd.c +5 -0
index 4b9ae83..24661fc 100644
@@ -89,6 +89,7 @@
 #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
 
 #define EXT_IID_CAP_SHIFT 10
+#define MCQ_SUPP_SHIFT 30
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\
 	({                                                              \
 		int _ret;                                               \
@@ -2240,6 +2241,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
 	if (err)
 		dev_err(hba->dev, "crypto setup failed\n");
 
+	hba->mcq_sup = (hba->capabilities & MASK_MCQ_SUPPORT) >> MCQ_SUPP_SHIFT;
+	if (!hba->mcq_sup)
+		return err;
+
 	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);
 	hba->ext_iid_sup = (hba->mcq_capabilities & MASK_EXT_IID_SUPPORT) >>
 		EXT_IID_CAP_SHIFT;
include/ufs/ufshcd.h +13 -0
index da1eb8a..da7ec0c 100644
@@ -660,6 +660,12 @@ enum ufshcd_caps {
 	 * notification if it is supported by the UFS device.
 	 */
 	UFSHCD_CAP_TEMP_NOTIF				= 1 << 11,
+
+	/*
+	 * This capability allows the host controller driver to turn on/off
+	 * MCQ mode. MCQ mode may be used to increase performance.
+	 */
+	UFSHCD_CAP_MCQ_EN				= 1 << 12,
 };
 
 struct ufs_hba_variant_params {
@@ -820,6 +826,7 @@ struct ufs_hba_monitor {
  * @complete_put: whether or not to call ufshcd_rpm_put() from inside
  *	ufshcd_resume_complete()
  * @ext_iid_sup: is EXT_IID is supported by UFSHC
+ * @mcq_sup: is mcq supported by UFSHC
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -969,8 +976,14 @@ struct ufs_hba {
 	u32 luns_avail;
 	bool complete_put;
 	bool ext_iid_sup;
+	bool mcq_sup;
 };
 
+static inline bool is_mcq_supported(struct ufs_hba *hba)
+{
+	return hba->mcq_sup && (hba->caps & UFSHCD_CAP_MCQ_EN);
+}
+
 /* Returns true if clocks can be gated. Otherwise false */
 static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
 {
Signature · 1 line
2.7.4
reviewer
#6 lore raw

RE: [PATCH v1 02/16] ufs: core: Introduce Multi-circular queue capability

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct · line 2246

Quoted 13 lines

#define EXT_IID_CAP_SHIFT 10

drivers/ufs/core/ufshcd.c +2 -0
+#define MCQ_SUPP_SHIFT 30
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)                           \
        ({                                                              \
                int _ret;                                               \
@@ -2240,6 +2241,10 @@ static inline int ufshcd_hba_capabilities(struct
 ufs_hba *hba)
        if (err)
                dev_err(hba->dev, "crypto setup failed\n");
 
+       hba->mcq_sup = (hba->capabilities & MASK_MCQ_SUPPORT) >>
 MCQ_SUPP_SHIFT;

Since you are just testing for bit30, MASK_MCQ_SUPPORT is not really needed. Maybe just:
hba->mcq_sup = (hba->capabilities >> MCQ_SUPP_SHIFT) & 1;

Thanks,
Avri

#7 lore raw

Re: [PATCH v1 02/16] ufs: core: Introduce Multi-circular queue capability

Quoted 7 lines · Avri Altman
Quoted 3 lines

+ hba->mcq_sup = (hba->capabilities & MASK_MCQ_SUPPORT) >>
MCQ_SUPP_SHIFT;

Since you are just testing for bit30, MASK_MCQ_SUPPORT is not really needed. Maybe just:
hba->mcq_sup = (hba->capabilities >> MCQ_SUPP_SHIFT) & 1;

Thanks. Yeah, Mani suggested FIELD* macros as an option too. Let me check that as well and address this in the next version.

-asd

#8 lore raw

Re: [PATCH v1 02/16] ufs: core: Introduce Multi-circular queue capability

In reply to Asutosh Das
Quoted 25 lines · Asutosh Das

Adds support to check for MCQ capability in the UFSHC. This capability can be used by host drivers to control MCQ enablement.

---
 drivers/ufs/core/ufshcd.c |  5 +++++
 include/ufs/ufshcd.h      | 13 +++++++++++++
 2 files changed, 18 insertions(+)
drivers/ufs/core/ufshcd.c +1 -0
index 4b9ae83..24661fc 100644
@@ -89,6 +89,7 @@
 #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
 
 #define EXT_IID_CAP_SHIFT 10
+#define MCQ_SUPP_SHIFT 30
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)				\
 	({                                                              \
 		int _ret;                                               \

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) · line 2244

Quoted 4 lines
drivers/ufs/core/ufshcd.c +1 -0
@@ -2240,6 +2241,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
 	if (err)
 		dev_err(hba->dev, "crypto setup failed\n");
 
+	hba->mcq_sup = (hba->capabilities & MASK_MCQ_SUPPORT) >> MCQ_SUPP_SHIFT;

Again, if you use FIELD_* macro, addtional *_SHIFT macro is not needed.

drivers/ufs/core/ufshcd.c static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) · line 2246

Quoted 2 lines
drivers/ufs/core/ufshcd.c +2 -0
+	if (!hba->mcq_sup)
+		return err;

Since this is not an error case, you can return 0 explicitly.

Quoted 30 lines
drivers/ufs/core/ufshcd.c +1 -0
+
 	hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);
 	hba->ext_iid_sup = (hba->mcq_capabilities & MASK_EXT_IID_SUPPORT) >>
 		EXT_IID_CAP_SHIFT;
include/ufs/ufshcd.h +7 -0
index da1eb8a..da7ec0c 100644
@@ -660,6 +660,12 @@ enum ufshcd_caps {
 	 * notification if it is supported by the UFS device.
 	 */
 	UFSHCD_CAP_TEMP_NOTIF				= 1 << 11,
+
+	/*
+	 * This capability allows the host controller driver to turn on/off
+	 * MCQ mode. MCQ mode may be used to increase performance.
+	 */
+	UFSHCD_CAP_MCQ_EN				= 1 << 12,
 };
 
 struct ufs_hba_variant_params {
@@ -820,6 +826,7 @@ struct ufs_hba_monitor {
  * @complete_put: whether or not to call ufshcd_rpm_put() from inside
  *	ufshcd_resume_complete()
  * @ext_iid_sup: is EXT_IID is supported by UFSHC
+ * @mcq_sup: is mcq supported by UFSHC
  */
 struct ufs_hba {
 	void __iomem *mmio_base;

include/ufs/ufshcd.h struct ufs_hba { · line 982

Quoted 7 lines
include/ufs/ufshcd.h +2 -0
@@ -969,8 +976,14 @@ struct ufs_hba {
 	u32 luns_avail;
 	bool complete_put;
 	bool ext_iid_sup;
+	bool mcq_sup;
 };
 
+static inline bool is_mcq_supported(struct ufs_hba *hba)

No inline please. Compiler is the best judge.

Thanks,
Mani

Quoted 10 lines
include/ufs/ufshcd.h +4 -0
+{
+	return hba->mcq_sup && (hba->caps & UFSHCD_CAP_MCQ_EN);
+}
+
 /* Returns true if clocks can be gated. Otherwise false */
 static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
 {
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#9 lore raw

PATCH 3/16 ufs: core: Defer adding host to scsi if mcq is supported

In reply to Asutosh Das

If MCQ support is present, then enabling it would need reallocating tags and memory. It would also free up the already allocated memory in Single Doorbell Mode. So defer invoking scsi_add_host() until MCQ is configured.

---
 drivers/ufs/core/ufshcd.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/ufs/core/ufshcd.c +15 -4
index 24661fc..426867b 100644
@@ -8184,6 +8184,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
 	int ret;
 	unsigned long flags;
 	ktime_t start = ktime_get();
+	struct Scsi_Host *host = hba->host;
 
 	hba->ufshcd_state = UFSHCD_STATE_RESET;
 
@@ -8218,6 +8219,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
 		ret = ufshcd_device_params_init(hba);
 		if (ret)
 			goto out;
+
+		if (is_mcq_supported(hba)) {
+			ret = scsi_add_host(host, hba->dev);
+			if (ret) {
+				dev_err(hba->dev, "scsi_add_host failed\n");
+				goto out;
+			}
+		}
 	}
 
 	ufshcd_tune_unipro_params(hba);
@@ -9764,10 +9773,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 		hba->is_irq_enabled = true;
 	}
 
-	err = scsi_add_host(host, hba->dev);
-	if (err) {
-		dev_err(hba->dev, "scsi_add_host failed\n");
-		goto out_disable;
+	if (!is_mcq_supported(hba)) {
+		err = scsi_add_host(host, hba->dev);
+		if (err) {
+			dev_err(hba->dev, "scsi_add_host failed\n");
+			goto out_disable;
+		}
 	}
 
 	hba->tmf_tag_set = (struct blk_mq_tag_set) {
Signature · 1 line
2.7.4
#10 lore raw

Re: [PATCH v1 03/16] ufs: core: Defer adding host to scsi if mcq is supported

drivers/ufs/core/ufshcd.c static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) · line 8230

Quoted 13 lines · Asutosh Das
drivers/ufs/core/ufshcd.c +8 -0
@@ -8218,6 +8219,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
  		ret = ufshcd_device_params_init(hba);
  		if (ret)
  			goto out;
+
+		if (is_mcq_supported(hba)) {
+			ret = scsi_add_host(host, hba->dev);
+			if (ret) {
+				dev_err(hba->dev, "scsi_add_host failed\n");
+				goto out;
+			}
+		}
  	}

Calling scsi_add_host() from ufshcd_probe_hba() seems wrong to me since that function is not only called when probing a host controller but also when resetting a host controller. See also ufshcd_host_reset_and_restore().

Quoted 9 lines
drivers/ufs/core/ufshcd.c +0 -3
  	ufshcd_tune_unipro_params(hba);
@@ -9764,10 +9773,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
  		hba->is_irq_enabled = true;
  	}
 
-	err = scsi_add_host(host, hba->dev);
-	if (err) {
-		dev_err(hba->dev, "scsi_add_host failed\n");

drivers/ufs/core/ufshcd.c int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) · line 9784

Quoted 10 lines
drivers/ufs/core/ufshcd.c +6 -1
-		goto out_disable;
+	if (!is_mcq_supported(hba)) {
+		err = scsi_add_host(host, hba->dev);
+		if (err) {
+			dev_err(hba->dev, "scsi_add_host failed\n");
+			goto out_disable;
+		}
  	}
 
  	hba->tmf_tag_set = (struct blk_mq_tag_set) {

Please make sure there is only a single scsi_add_host() call in the UFS host controller driver.

Thanks,

Bart.

#11 lore raw

Re: [PATCH v1 03/16] ufs: core: Defer adding host to scsi if mcq is supported

Quoted 17 lines · Bart Van Assche

drivers/ufs/core/ufshcd.c static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) · line 8230

Quoted 13 lines · Asutosh Das
drivers/ufs/core/ufshcd.c +8 -0
@@ -8218,6 +8219,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
 		ret = ufshcd_device_params_init(hba);
 		if (ret)
 			goto out;
+
+		if (is_mcq_supported(hba)) {
+			ret = scsi_add_host(host, hba->dev);
+			if (ret) {
+				dev_err(hba->dev, "scsi_add_host failed\n");
+				goto out;
+			}
+		}
 	}

Calling scsi_add_host() from ufshcd_probe_hba() seems wrong to me since that function is not only called when probing a host controller but also when resetting a host controller. See also ufshcd_host_reset_and_restore().

The scsi_add_host() is only invoked from ufshcd_probe_hba() if init_dev_params is true. That flag is false when ufshcd_probe_hba() is invoked from ufshcd_host_reset_and_restore(). So scsi_add_host() won't be invoked from ufshcd_host_reset_and_restore(). Even ufshcd_device_params_init() is invoked the same way now.

Quoted 10 lines
Quoted 10 lines
drivers/ufs/core/ufshcd.c +2 -4
 	ufshcd_tune_unipro_params(hba);
@@ -9764,10 +9773,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 		hba->is_irq_enabled = true;
 	}
-	err = scsi_add_host(host, hba->dev);
-	if (err) {
-		dev_err(hba->dev, "scsi_add_host failed\n");
-		goto out_disable;
+	if (!is_mcq_supported(hba)) {
+		err = scsi_add_host(host, hba->dev);
Quoted 9 lines

drivers/ufs/core/ufshcd.c int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) · line 9784

Quoted 6 lines
drivers/ufs/core/ufshcd.c +4 -0
+		if (err) {
+			dev_err(hba->dev, "scsi_add_host failed\n");
+			goto out_disable;
+		}
 	}
 	hba->tmf_tag_set = (struct blk_mq_tag_set) {

Please make sure there is only a single scsi_add_host() call in the UFS host controller driver.

One way would be to move the scsi_add_host() to ufshcd_probe_hba(). PLMK if you think this is not OK.

Quoted 3 lines

Thanks,

Bart.

#12 lore raw

PATCH 4/16 ufs: core: mcq: Introduce Multi Circular Queue

In reply to Asutosh Das

Introduce multi-circular queue (MCQ) which has been added in UFSHC v4.0 standard in addition to the Single Doorbell mode. The MCQ mode supports multiple submission and completion queues. Add support to configure the number of queues.

---
 drivers/ufs/core/Makefile      |   2 +-
 drivers/ufs/core/ufs-mcq.c     | 132 +++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |   1 +
 drivers/ufs/core/ufshcd.c      |  12 ++++
 include/ufs/ufshcd.h           |   4 ++
 5 files changed, 150 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ufs/core/ufs-mcq.c
drivers/ufs/core/Makefile +1 -1
index 62f38c5..4d02e0f 100644
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_SCSI_UFSHCD)		+= ufshcd-core.o
-ufshcd-core-y				+= ufshcd.o ufs-sysfs.o
+ufshcd-core-y				+= ufshcd.o ufs-sysfs.o ufs-mcq.o
 ufshcd-core-$(CONFIG_DEBUG_FS)		+= ufs-debugfs.o
 ufshcd-core-$(CONFIG_SCSI_UFS_BSG)	+= ufs_bsg.o
 ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO)	+= ufshcd-crypto.o
drivers/ufs/core/ufs-mcq.c new file +132 -0

132 lines not on this page · raw message

drivers/ufs/core/ufshcd-priv.h +1 -0
index 8f67db2..cf6bdd8e 100644
@@ -50,6 +50,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
+int ufshcd_mcq_init(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
drivers/ufs/core/ufshcd.c +12 -0
index 426867b..f4bb402 100644
@@ -8172,6 +8172,15 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 	return ret;
 }
 
+static int ufshcd_config_mcq(struct ufs_hba *hba)
+{
+	int ret;
+
+	ret = ufshcd_mcq_init(hba);
+
+	return ret;
+}
+
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize it
  * @hba: per-adapter instance
@@ -8221,6 +8230,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
 			goto out;
 
 		if (is_mcq_supported(hba)) {
+			ret = ufshcd_config_mcq(hba);
+			if (ret)
+				goto out;
 			ret = scsi_add_host(host, hba->dev);
 			if (ret) {
 				dev_err(hba->dev, "scsi_add_host failed\n");
include/ufs/ufshcd.h +4 -0
index da7ec0c..298e103 100644
@@ -827,6 +827,8 @@ struct ufs_hba_monitor {
  *	ufshcd_resume_complete()
  * @ext_iid_sup: is EXT_IID is supported by UFSHC
  * @mcq_sup: is mcq supported by UFSHC
+ * @nr_hw_queues: number of hardware queues configured
+ * @nr_queues: number of Queues of different queue types
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -977,6 +979,8 @@ struct ufs_hba {
 	bool complete_put;
 	bool ext_iid_sup;
 	bool mcq_sup;
+	unsigned int nr_hw_queues;
+	unsigned int nr_queues[HCTX_MAX_TYPES];
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
Signature · 1 line
2.7.4
#13 lore raw

Re: [PATCH v1 04/16] ufs: core: mcq: Introduce Multi Circular Queue

Quoted 46 lines · Asutosh Das

Introduce multi-circular queue (MCQ) which has been added in UFSHC v4.0 standard in addition to the Single Doorbell mode. The MCQ mode supports multiple submission and completion queues. Add support to configure the number of queues.

---
 drivers/ufs/core/Makefile      |   2 +-
 drivers/ufs/core/ufs-mcq.c     | 132 +++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |   1 +
 drivers/ufs/core/ufshcd.c      |  12 ++++
 include/ufs/ufshcd.h           |   4 ++
 5 files changed, 150 insertions(+), 1 deletion(-)
 create mode 100644 drivers/ufs/core/ufs-mcq.c
drivers/ufs/core/Makefile +1 -1
index 62f38c5..4d02e0f 100644
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_SCSI_UFSHCD)		+= ufshcd-core.o
-ufshcd-core-y				+= ufshcd.o ufs-sysfs.o
+ufshcd-core-y				+= ufshcd.o ufs-sysfs.o ufs-mcq.o
 ufshcd-core-$(CONFIG_DEBUG_FS)		+= ufs-debugfs.o
 ufshcd-core-$(CONFIG_SCSI_UFS_BSG)	+= ufs_bsg.o
 ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO)	+= ufshcd-crypto.o
drivers/ufs/core/ufs-mcq.c new file +10 -0
new file mode 100644
index 0000000..934556f
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center. All rights reserved.
+ *
+ * Authors:
+ *	Asutosh Das <[email protected]>
+ *	Can Guo <[email protected]>
+ */
+
+#include <asm/unaligned.h>

drivers/ufs/core/ufs-mcq.c line 20

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "ufshcd-priv.h"
+
+#define UFS_MCQ_MIN_RW_QUEUES 2
+#define UFS_MCQ_MIN_READ_QUEUES 0
+#define UFS_MCQ_MIN_POLL_QUEUES 0
+
+static unsigned int dev_cmd_queue = 1;

This looks like a constant, so consider switching to a macro.

drivers/ufs/core/ufs-mcq.c line 27

Quoted 7 lines
drivers/ufs/core/ufs-mcq.c new file +7 -0
+
+static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+	unsigned int n;
+	int ret;
+
+	ret = kstrtouint(val, 10, &n);

n is not used? While fixing, please use a better name.

drivers/ufs/core/ufs-mcq.c line 29

Quoted 2 lines
drivers/ufs/core/ufs-mcq.c new file +2 -0
+	if (ret)
+		return ret;

Newline

Quoted 12 lines
drivers/ufs/core/ufs-mcq.c new file +12 -0
+	return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_RW_QUEUES,
+				     num_possible_cpus());
+}
+
+static const struct kernel_param_ops rw_queue_count_ops = {
+	.set = rw_queue_count_set,
+	.get = param_get_uint,
+};
+
+static unsigned int rw_queues;
+module_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644);
+MODULE_PARM_DESC(rw_queues,

drivers/ufs/core/ufs-mcq.c line 51

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+		 "Number of interrupt driven I/O queues used for rw. Default value is nr_cpus");
+
+static int read_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+	unsigned int n;
+	int ret;
+
+	ret = kstrtouint(val, 10, &n);
+	if (ret)
+		return ret;

Same as above

Quoted 12 lines
drivers/ufs/core/ufs-mcq.c new file +12 -0
+	return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_READ_QUEUES,
+				     num_possible_cpus());
+}
+
+static const struct kernel_param_ops read_queue_count_ops = {
+	.set = read_queue_count_set,
+	.get = param_get_uint,
+};
+
+static unsigned int read_queues;
+module_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644);
+MODULE_PARM_DESC(read_queues,

drivers/ufs/core/ufs-mcq.c line 73

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+		 "Number of interrupt driven read queues used for read. Default value is 0");
+
+static int poll_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+	unsigned int n;
+	int ret;
+
+	ret = kstrtouint(val, 10, &n);
+	if (ret)
+		return ret;

Same as above

Quoted 11 lines
drivers/ufs/core/ufs-mcq.c new file +11 -0
+	return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_POLL_QUEUES,
+				     num_possible_cpus());
+}
+
+static const struct kernel_param_ops poll_queue_count_ops = {
+	.set = poll_queue_count_set,
+	.get = param_get_uint,
+};
+
+static unsigned int poll_queues = 1;
+module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);

drivers/ufs/core/ufs-mcq.c line 94

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+MODULE_PARM_DESC(poll_queues,
+		 "Number of poll queues used for r/w. Default value is 1");
+
+static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
+{
+	int i, rem;
+	u32 hbaq_cap, cmp, tot_queues;
+	struct Scsi_Host *host = hba->host;
+
+	hbaq_cap = hba->mcq_capabilities & 0xff;

Define 0xff

hbaq_cap should be named after the define used for 0xff. It is not quite understandable now.

Quoted 8 lines
drivers/ufs/core/ufs-mcq.c new file +8 -0
+
+	if (!rw_queues)
+		rw_queues = num_possible_cpus();
+
+	tot_queues = dev_cmd_queue + read_queues + poll_queues + rw_queues;
+	if (hbaq_cap < tot_queues) {
+		dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n",
+			tot_queues, hbaq_cap);

drivers/ufs/core/ufs-mcq.c line 112

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+		return -EOPNOTSUPP;
+	}
+
+	rem = hbaq_cap - dev_cmd_queue;
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(cmp, rw_queues,
+						 num_possible_cpus());
+	rem -= hba->nr_queues[HCTX_TYPE_DEFAULT];
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_POLL] = min(cmp, poll_queues);

Hmm, so the driver is not using the number of queues set by the user? If the number varies, I don't think it should be configurable.

Thanks,
Mani

Quoted 87 lines
drivers/ufs/core/ufs-mcq.c new file +20 -0
+	rem -= hba->nr_queues[HCTX_TYPE_POLL];
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_READ] = min(cmp, read_queues);
+
+	for (i = 0; i < HCTX_MAX_TYPES; i++)
+		host->nr_hw_queues += hba->nr_queues[i];
+
+	hba->nr_hw_queues = host->nr_hw_queues + dev_cmd_queue;
+	return 0;
+}
+
+int ufshcd_mcq_init(struct ufs_hba *hba)
+{
+	int ret;
+
+	ret = ufshcd_mcq_config_nr_queues(hba);
+
+	return ret;
+}
+
drivers/ufs/core/ufshcd-priv.h +1 -0
index 8f67db2..cf6bdd8e 100644
@@ -50,6 +50,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
+int ufshcd_mcq_init(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
drivers/ufs/core/ufshcd.c +12 -0
index 426867b..f4bb402 100644
@@ -8172,6 +8172,15 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 	return ret;
 }
 
+static int ufshcd_config_mcq(struct ufs_hba *hba)
+{
+	int ret;
+
+	ret = ufshcd_mcq_init(hba);
+
+	return ret;
+}
+
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize it
  * @hba: per-adapter instance
@@ -8221,6 +8230,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
 			goto out;
 
 		if (is_mcq_supported(hba)) {
+			ret = ufshcd_config_mcq(hba);
+			if (ret)
+				goto out;
 			ret = scsi_add_host(host, hba->dev);
 			if (ret) {
 				dev_err(hba->dev, "scsi_add_host failed\n");
include/ufs/ufshcd.h +4 -0
index da7ec0c..298e103 100644
@@ -827,6 +827,8 @@ struct ufs_hba_monitor {
  *	ufshcd_resume_complete()
  * @ext_iid_sup: is EXT_IID is supported by UFSHC
  * @mcq_sup: is mcq supported by UFSHC
+ * @nr_hw_queues: number of hardware queues configured
+ * @nr_queues: number of Queues of different queue types
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -977,6 +979,8 @@ struct ufs_hba {
 	bool complete_put;
 	bool ext_iid_sup;
 	bool mcq_sup;
+	unsigned int nr_hw_queues;
+	unsigned int nr_queues[HCTX_MAX_TYPES];
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#14 lore raw

Re: [PATCH v1 04/16] ufs: core: mcq: Introduce Multi Circular Queue

Quoted 1 line · Manivannan Sadhasivam

On Thu, Sep 22, 2022 at 06:05:11PM -0700, Asutosh Das wrote:

[...]

Quoted 5 lines
Quoted 5 lines
drivers/ufs/core/ufs-mcq.c new file +0 -0
new file mode 100644
index 0000000..934556f

[...]

Quoted 10 lines

drivers/ufs/core/ufs-mcq.c line 94

Quoted 7 lines
drivers/ufs/core/ufs-mcq.c new file +7 -0
+static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
+{
+	int i, rem;
+	u32 hbaq_cap, cmp, tot_queues;
+	struct Scsi_Host *host = hba->host;
+
+	hbaq_cap = hba->mcq_capabilities & 0xff;

Define 0xff

Quoted 3 lines

hbaq_cap should be named after the define used for 0xff. It is not quite understandable now.

Ok. I think you want the name hbaq_cap to be changed to what 0xff signifies. Is that understanding correct?

Quoted 13 lines
Quoted 13 lines
drivers/ufs/core/ufs-mcq.c new file +13 -0
+
+	if (!rw_queues)
+		rw_queues = num_possible_cpus();
+
+	tot_queues = dev_cmd_queue + read_queues + poll_queues + rw_queues;
+	if (hbaq_cap < tot_queues) {
+		dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n",
+			tot_queues, hbaq_cap);
+		return -EOPNOTSUPP;
+	}
+
+	rem = hbaq_cap - dev_cmd_queue;
+	cmp = rem;
Quoted 9 lines

drivers/ufs/core/ufs-mcq.c line 112

Quoted 5 lines
drivers/ufs/core/ufs-mcq.c new file +5 -0
+	hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(cmp, rw_queues,
+						 num_possible_cpus());
+	rem -= hba->nr_queues[HCTX_TYPE_DEFAULT];
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_POLL] = min(cmp, poll_queues);

Hmm, so the driver is not using the number of queues set by the user? If the number varies, I don't think it should be configurable.

I think the driver would use the number of queues set by the user. Because there's a check(hbaq_cap < tot_queues) above that ensures that the HBA has enough queues for the given configuration.

-asd

Quoted 1 line
#15 lore raw

Re: [PATCH v1 04/16] ufs: core: mcq: Introduce Multi Circular Queue

In reply to Asutosh Das
Quoted 25 lines · Asutosh Das
drivers/ufs/core/ufs-mcq.c new file +25 -0
+static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
+{
+	int i, rem;
+	u32 hbaq_cap, cmp, tot_queues;
+	struct Scsi_Host *host = hba->host;
+
+	hbaq_cap = hba->mcq_capabilities & 0xff;
+
+	if (!rw_queues)
+		rw_queues = num_possible_cpus();
+
+	tot_queues = dev_cmd_queue + read_queues + poll_queues + rw_queues;
+	if (hbaq_cap < tot_queues) {
+		dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n",
+			tot_queues, hbaq_cap);
+		return -EOPNOTSUPP;
+	}
+
+	rem = hbaq_cap - dev_cmd_queue;
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(cmp, rw_queues,
+						 num_possible_cpus());
+	rem -= hba->nr_queues[HCTX_TYPE_DEFAULT];
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_POLL] = min(cmp, poll_queues);

drivers/ufs/core/ufs-mcq.c line 122

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c new file +10 -0
+	rem -= hba->nr_queues[HCTX_TYPE_POLL];
+	cmp = rem;
+	hba->nr_queues[HCTX_TYPE_READ] = min(cmp, read_queues);
+
+	for (i = 0; i < HCTX_MAX_TYPES; i++)
+		host->nr_hw_queues += hba->nr_queues[i];
+
+	hba->nr_hw_queues = host->nr_hw_queues + dev_cmd_queue;
+	return 0;
+}

Please consider removing the variable 'cmp' and instead use min_t() or a type cast.

Thanks,

Bart.

#16 lore raw

PATCH 5/16 ufs: core: mcq: Configure resource regions

In reply to Asutosh Das

Define the mcq resources and add support to ioremap the resource regions.

---
 drivers/ufs/core/ufs-mcq.c | 100 ++++++++++++++++++++++++++++++++++++++++++++-
 include/ufs/ufshcd.h       |  28 +++++++++++++
 2 files changed, 127 insertions(+), 1 deletion(-)
drivers/ufs/core/ufs-mcq.c +99 -1
index 934556f..e5cc7ab 100644
@@ -17,6 +17,12 @@
 #define UFS_MCQ_MIN_READ_QUEUES 0
 #define UFS_MCQ_MIN_POLL_QUEUES 0
 
+#define MCQ_QCFGPTR_MASK	GENMASK(7, 0)
+#define MCQ_QCFGPTR_UNIT	0x200
+#define MCQ_SQATTR_OFFSET(c) \
+	((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
+#define MCQ_QCFG_SIZE	0x40
+
 static unsigned int dev_cmd_queue = 1;
 
 static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
@@ -85,6 +91,96 @@ module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);
 MODULE_PARM_DESC(poll_queues,
 		 "Number of poll queues used for r/w. Default value is 1");
 
+/* Resources */
+static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
+	{.name = "ufs_mem", .resource = NULL, .base = NULL},
+	{.name = "mcq", .resource = NULL, .base = NULL},
+	/* Submission Queue DAO */
+	{.name = "mcq_sqd", .resource = NULL, .base = NULL},
+	/* Submission Queue Interrupt Status */
+	{.name = "mcq_sqis", .resource = NULL, .base = NULL},
+	/* Completion Queue DAO */
+	{.name = "mcq_cqd", .resource = NULL, .base = NULL},
+	/* Completion Queue Interrupt Status */
+	{.name = "mcq_cqis", .resource = NULL, .base = NULL},
+	/* MCQ vendor specific */
+	{.name = "mcq_vs", .resource = NULL, .base = NULL},
+};
+
+static int ufshcd_mcq_config_resource(struct ufs_hba *hba)
+{
+	struct platform_device *pdev = to_platform_device(hba->dev);
+	struct ufshcd_res_info_t *res;
+	struct resource *res_mem, *res_mcq;
+	int i, ret = 0;
+
+	memcpy(hba->res, ufshcd_res_info, sizeof(ufshcd_res_info));
+
+	for (i = 0; i < RES_MAX; i++) {
+		res = &hba->res[i];
+		res->resource = platform_get_resource_byname(pdev,
+							     IORESOURCE_MEM,
+							     res->name);
+		if (!res->resource) {
+			dev_info(hba->dev, "Resource %s not provided\n", res->name);
+			if (i == RES_MEM)
+				return -ENOMEM;
+			continue;
+		} else if (i == RES_MEM) {
+			res_mem = res->resource;
+			res->base = hba->mmio_base;
+			continue;
+		}
+
+		res->base = devm_ioremap_resource(hba->dev, res->resource);
+		if (IS_ERR(res->base)) {
+			dev_err(hba->dev, "Failed to map res %s, err=%d\n",
+					 res->name, (int)PTR_ERR(res->base));
+			res->base = NULL;
+			ret = PTR_ERR(res->base);
+			return ret;
+		}
+	}
+
+	res = &hba->res[RES_MCQ];
+	/* MCQ resource provided in DT */
+	if (res->base)
+		goto out;
+
+	/* Manually allocate MCQ resource */
+	res_mcq = res->resource;
+	res_mcq = devm_kzalloc(hba->dev, sizeof(*res_mcq), GFP_KERNEL);
+	if (!res_mcq) {
+		dev_err(hba->dev, "Failed to alloate MCQ resource\n");
+		return ret;
+	}
+
+	res_mcq->start = res_mem->start +
+			 MCQ_SQATTR_OFFSET(hba->mcq_capabilities);
+	res_mcq->end = res_mcq->start + hba->nr_hw_queues * MCQ_QCFG_SIZE - 1;
+	res_mcq->flags = res_mem->flags;
+	res_mcq->name = "mcq";
+
+	ret = insert_resource(&iomem_resource, res_mcq);
+	if (ret) {
+		dev_err(hba->dev, "Failed to insert MCQ resource %d\n", ret);
+		return ret;
+	}
+
+	res->base = devm_ioremap_resource(hba->dev, res_mcq);
+	if (IS_ERR(res->base)) {
+		dev_err(hba->dev, "Map MCQ registers failed, err=%d\n",
+			(int)PTR_ERR(res->base));
+		ret = PTR_ERR(res->base);
+		res->base = NULL;
+		return ret;
+	}
+
+out:
+	hba->mcq_base = res->base;
+	return 0;
+}
+
 static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
 {
 	int i, rem;
@@ -126,7 +222,9 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 	int ret;
 
 	ret = ufshcd_mcq_config_nr_queues(hba);
-
+	if (ret)
+		return ret;
+	ret = ufshcd_mcq_config_resource(hba);
 	return ret;
 }
 
include/ufs/ufshcd.h +28 -0
index 298e103..54d742a 100644
@@ -720,6 +720,30 @@ struct ufs_hba_monitor {
 };
 
 /**
+ * struct ufshcd_res_info_t - MCQ related resource regions
+ *
+ * @name: resource name
+ * @resource: pointer to resource region
+ * @base: register base address
+ */
+struct ufshcd_res_info_t {
+	const char *name;
+	struct resource *resource;
+	void __iomem *base;
+};
+
+enum ufshcd_res {
+	RES_MEM,
+	RES_MCQ,
+	RES_MCQ_SQD,
+	RES_MCQ_SQIS,
+	RES_MCQ_CQD,
+	RES_MCQ_CQIS,
+	RES_MCQ_VS,
+	RES_MAX,
+};
+
+/**
  * struct ufs_hba - per adapter private structure
  * @mmio_base: UFSHCI base register address
  * @ucdl_base_addr: UFS Command Descriptor base address
@@ -829,6 +853,8 @@ struct ufs_hba_monitor {
  * @mcq_sup: is mcq supported by UFSHC
  * @nr_hw_queues: number of hardware queues configured
  * @nr_queues: number of Queues of different queue types
+ * @res: array of resource info of MCQ registers
+ * @mcq_base: Multi circular queue registers base address
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -981,6 +1007,8 @@ struct ufs_hba {
 	bool mcq_sup;
 	unsigned int nr_hw_queues;
 	unsigned int nr_queues[HCTX_MAX_TYPES];
+	struct ufshcd_res_info_t res[RES_MAX];
+	void __iomem *mcq_base;
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
Signature · 1 line
2.7.4
#17 lore raw

Re: [PATCH v1 05/16] ufs: core: mcq: Configure resource regions

Quoted 54 lines · Asutosh Das

Define the mcq resources and add support to ioremap the resource regions.

---
 drivers/ufs/core/ufs-mcq.c | 100 ++++++++++++++++++++++++++++++++++++++++++++-
 include/ufs/ufshcd.h       |  28 +++++++++++++
 2 files changed, 127 insertions(+), 1 deletion(-)
drivers/ufs/core/ufs-mcq.c +28 -0
index 934556f..e5cc7ab 100644
@@ -17,6 +17,12 @@
 #define UFS_MCQ_MIN_READ_QUEUES 0
 #define UFS_MCQ_MIN_POLL_QUEUES 0
 
+#define MCQ_QCFGPTR_MASK	GENMASK(7, 0)
+#define MCQ_QCFGPTR_UNIT	0x200
+#define MCQ_SQATTR_OFFSET(c) \
+	((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
+#define MCQ_QCFG_SIZE	0x40
+
 static unsigned int dev_cmd_queue = 1;
 
 static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
@@ -85,6 +91,96 @@ module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);
 MODULE_PARM_DESC(poll_queues,
 		 "Number of poll queues used for r/w. Default value is 1");
 
+/* Resources */
+static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
+	{.name = "ufs_mem", .resource = NULL, .base = NULL},
+	{.name = "mcq", .resource = NULL, .base = NULL},
+	/* Submission Queue DAO */
+	{.name = "mcq_sqd", .resource = NULL, .base = NULL},
+	/* Submission Queue Interrupt Status */
+	{.name = "mcq_sqis", .resource = NULL, .base = NULL},
+	/* Completion Queue DAO */
+	{.name = "mcq_cqd", .resource = NULL, .base = NULL},
+	/* Completion Queue Interrupt Status */
+	{.name = "mcq_cqis", .resource = NULL, .base = NULL},
+	/* MCQ vendor specific */
+	{.name = "mcq_vs", .resource = NULL, .base = NULL},
+};
+
+static int ufshcd_mcq_config_resource(struct ufs_hba *hba)
+{
+	struct platform_device *pdev = to_platform_device(hba->dev);
+	struct ufshcd_res_info_t *res;
+	struct resource *res_mem, *res_mcq;
+	int i, ret = 0;

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 125

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c +10 -0
+
+	memcpy(hba->res, ufshcd_res_info, sizeof(ufshcd_res_info));
+
+	for (i = 0; i < RES_MAX; i++) {
+		res = &hba->res[i];
+		res->resource = platform_get_resource_byname(pdev,
+							     IORESOURCE_MEM,
+							     res->name);
+		if (!res->resource) {
+			dev_info(hba->dev, "Resource %s not provided\n", res->name);

This is an error if below condition gets satisfied.

Quoted 11 lines
drivers/ufs/core/ufs-mcq.c +11 -0
+			if (i == RES_MEM)
+				return -ENOMEM;
+			continue;
+		} else if (i == RES_MEM) {
+			res_mem = res->resource;
+			res->base = hba->mmio_base;
+			continue;
+		}
+
+		res->base = devm_ioremap_resource(hba->dev, res->resource);
+		if (IS_ERR(res->base)) {

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 146

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c +10 -0
+			dev_err(hba->dev, "Failed to map res %s, err=%d\n",
+					 res->name, (int)PTR_ERR(res->base));
+			res->base = NULL;
+			ret = PTR_ERR(res->base);
+			return ret;
+		}
+	}
+
+	res = &hba->res[RES_MCQ];
+	/* MCQ resource provided in DT */

Perhaps move the comment above and use, "Bail out if MCQ resource is provided by the platform".

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 150

Quoted 4 lines
drivers/ufs/core/ufs-mcq.c +4 -0
+	if (res->base)
+		goto out;
+
+	/* Manually allocate MCQ resource */

/* Manually allocate "mcq" resource from "ufs_mem" */

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 154

Quoted 4 lines
drivers/ufs/core/ufs-mcq.c +4 -0
+	res_mcq = res->resource;
+	res_mcq = devm_kzalloc(hba->dev, sizeof(*res_mcq), GFP_KERNEL);
+	if (!res_mcq) {
+		dev_err(hba->dev, "Failed to alloate MCQ resource\n");

allocate

Quoted 8 lines
drivers/ufs/core/ufs-mcq.c +8 -0
+		return ret;
+	}
+
+	res_mcq->start = res_mem->start +
+			 MCQ_SQATTR_OFFSET(hba->mcq_capabilities);
+	res_mcq->end = res_mcq->start + hba->nr_hw_queues * MCQ_QCFG_SIZE - 1;
+	res_mcq->flags = res_mem->flags;
+	res_mcq->name = "mcq";

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 172

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c +10 -0
+
+	ret = insert_resource(&iomem_resource, res_mcq);
+	if (ret) {
+		dev_err(hba->dev, "Failed to insert MCQ resource %d\n", ret);
+		return ret;
+	}
+
+	res->base = devm_ioremap_resource(hba->dev, res_mcq);
+	if (IS_ERR(res->base)) {
+		dev_err(hba->dev, "Map MCQ registers failed, err=%d\n",

"MCQ registers mapping failed, err=%d"

Quoted 15 lines
drivers/ufs/core/ufs-mcq.c +11 -0
+			(int)PTR_ERR(res->base));
+		ret = PTR_ERR(res->base);
+		res->base = NULL;
+		return ret;
+	}
+
+out:
+	hba->mcq_base = res->base;
+	return 0;
+}
+
 static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
 {
 	int i, rem;

drivers/ufs/core/ufs-mcq.c int ufshcd_mcq_init(struct ufs_hba *hba) · line 226

Quoted 6 lines
drivers/ufs/core/ufs-mcq.c +2 -1
@@ -126,7 +222,9 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 	int ret;
 
 	ret = ufshcd_mcq_config_nr_queues(hba);
-
+	if (ret)
+		return ret;

Newline

Quoted 16 lines
drivers/ufs/core/ufs-mcq.c +1 -0
+	ret = ufshcd_mcq_config_resource(hba);
 	return ret;
 }
 
include/ufs/ufshcd.h +4 -0
index 298e103..54d742a 100644
@@ -720,6 +720,30 @@ struct ufs_hba_monitor {
 };
 
 /**
+ * struct ufshcd_res_info_t - MCQ related resource regions
+ *
+ * @name: resource name
+ * @resource: pointer to resource region

include/ufs/ufshcd.h struct ufs_hba_monitor { · line 736

Quoted 10 lines
include/ufs/ufshcd.h +10 -0
+ * @base: register base address
+ */
+struct ufshcd_res_info_t {
+	const char *name;
+	struct resource *resource;
+	void __iomem *base;
+};
+
+enum ufshcd_res {
+	RES_MEM,

RES_UFS since the resource name is "ufs_mem"?

Thanks,
Mani

Quoted 34 lines
include/ufs/ufshcd.h +14 -0
+	RES_MCQ,
+	RES_MCQ_SQD,
+	RES_MCQ_SQIS,
+	RES_MCQ_CQD,
+	RES_MCQ_CQIS,
+	RES_MCQ_VS,
+	RES_MAX,
+};
+
+/**
  * struct ufs_hba - per adapter private structure
  * @mmio_base: UFSHCI base register address
  * @ucdl_base_addr: UFS Command Descriptor base address
@@ -829,6 +853,8 @@ struct ufs_hba_monitor {
  * @mcq_sup: is mcq supported by UFSHC
  * @nr_hw_queues: number of hardware queues configured
  * @nr_queues: number of Queues of different queue types
+ * @res: array of resource info of MCQ registers
+ * @mcq_base: Multi circular queue registers base address
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -981,6 +1007,8 @@ struct ufs_hba {
 	bool mcq_sup;
 	unsigned int nr_hw_queues;
 	unsigned int nr_queues[HCTX_MAX_TYPES];
+	struct ufshcd_res_info_t res[RES_MAX];
+	void __iomem *mcq_base;
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#18 lore raw

Re: [PATCH v1 05/16] ufs: core: mcq: Configure resource regions

In reply to Asutosh Das
Quoted 5 lines · Asutosh Das
drivers/ufs/core/ufs-mcq.c +5 -0
+/* Resources */
+static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
+	{.name = "ufs_mem", .resource = NULL, .base = NULL},
+	{.name = "mcq", .resource = NULL, .base = NULL},
+	/* Submission Queue DAO */

drivers/ufs/core/ufs-mcq.c module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); · line 108

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c +10 -0
+	{.name = "mcq_sqd", .resource = NULL, .base = NULL},
+	/* Submission Queue Interrupt Status */
+	{.name = "mcq_sqis", .resource = NULL, .base = NULL},
+	/* Completion Queue DAO */
+	{.name = "mcq_cqd", .resource = NULL, .base = NULL},
+	/* Completion Queue Interrupt Status */
+	{.name = "mcq_cqis", .resource = NULL, .base = NULL},
+	/* MCQ vendor specific */
+	{.name = "mcq_vs", .resource = NULL, .base = NULL},
+};

Please leave out the members that are NULL (.resource and .base) since the compiler will initialize these for you.

include/ufs/ufshcd.h struct ufs_hba_monitor { · line 733

Quoted 12 lines

/**
+ * struct ufshcd_res_info_t - MCQ related resource regions
+ *
+ * @name: resource name
+ * @resource: pointer to resource region
+ * @base: register base address
+ */

include/ufs/ufshcd.h +5 -0
+struct ufshcd_res_info_t {
+	const char *name;
+	struct resource *resource;
+	void __iomem *base;
+};

Please remove the suffix "_t" since that suffix is typically used for typedefs and not for data structures.

Thanks,

Bart.

#19 lore raw

PATCH 6/16 ufs: core: mcq: Calculate queue depth

In reply to Asutosh Das

The ufs device defines the supported queuedepth by bqueuedepth which has a max value of 256.
The HC defines MAC (Max Active Commands) that define the max number of commands that in flight to the ufs device.
Calculate and configure the nutrs based on both these values.

---
 drivers/ufs/core/ufs-mcq.c     | 34 ++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  9 +++++++++
 drivers/ufs/core/ufshcd.c      | 10 ++++++++--
 drivers/ufs/host/ufs-qcom.c    |  8 ++++++++
 include/ufs/ufs.h              |  2 ++
 include/ufs/ufshcd.h           |  2 ++
 include/ufs/ufshci.h           |  1 +
 7 files changed, 64 insertions(+), 2 deletions(-)
drivers/ufs/core/ufs-mcq.c +34 -0
index e5cc7ab..e52066e 100644
@@ -17,6 +17,8 @@
 #define UFS_MCQ_MIN_READ_QUEUES 0
 #define UFS_MCQ_MIN_POLL_QUEUES 0
 
+#define MCQ_CFG_MAC_OFFSET	8
+#define MCQ_CFG_MAC_MASK	UFS_MASK(0x1ff, MCQ_CFG_MAC_OFFSET)
 #define MCQ_QCFGPTR_MASK	GENMASK(7, 0)
 #define MCQ_QCFGPTR_UNIT	0x200
 #define MCQ_SQATTR_OFFSET(c) \
@@ -107,6 +109,38 @@ static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
 	{.name = "mcq_vs", .resource = NULL, .base = NULL},
 };
 
+/**
+ * ufshcd_mcq_decide_queue_depth - decide the queue depth
+ * @hba - per adapter instance
+ *
+ * MAC - Max. Active Command of the Host Controller (HC)
+ * HC wouldn't send more than this commands to the device.
+ * The default MAC is 32, but the max. value may vary with
+ * vendor implementation.
+ * Calculates and adjusts the queue depth based on the depth
+ * supported by the HC and ufs device.
+ */
+u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba)
+{
+	u32 qd, val;
+	int mac;
+
+	mac = ufshcd_mcq_vops_get_hba_mac(hba);
+	if (mac < 0) {
+		val = ufshcd_readl(hba, REG_UFS_MCQ_CFG);
+		mac = (val & MCQ_CFG_MAC_MASK) >> MCQ_CFG_MAC_OFFSET;
+	}
+
+	/*  MAC is a 0 based value. */
+	mac += 1;
+	/* max. value of bqueuedepth = 256, mac is host dependent */
+	qd = min_t(u32, mac, hba->dev_info.bqueuedepth);
+	if (!qd)
+		qd = mac;
+
+	return qd;
+}
+
 static int ufshcd_mcq_config_resource(struct ufs_hba *hba)
 {
 	struct platform_device *pdev = to_platform_device(hba->dev);
drivers/ufs/core/ufshcd-priv.h +9 -0
index cf6bdd8e..6d16beb 100644
@@ -51,6 +51,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
+u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
@@ -216,6 +217,14 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
 		hba->vops->config_scaling_param(hba, p, data);
 }
 
+static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba)
+{
+	if (hba->vops && hba->vops->get_hba_mac)
+		return hba->vops->get_hba_mac(hba);
+
+	return -EOPNOTSUPP;
+}
+
 extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[];
 
 /**
drivers/ufs/core/ufshcd.c +8 -2
index f4bb402..a71b57e 100644
@@ -7759,6 +7759,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
 	/* getting Specification Version in big endian format */
 	dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 |
 				      desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1];
+	dev_info->bqueuedepth = desc_buf[DEVICE_DESC_PARAM_Q_DPTH];
 	b_ufs_feature_sup = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT];
 
 	model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
@@ -8175,10 +8176,15 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 static int ufshcd_config_mcq(struct ufs_hba *hba)
 {
 	int ret;
+	int old_nutrs = hba->nutrs;
 
+	hba->nutrs = ufshcd_mcq_decide_queue_depth(hba);
 	ret = ufshcd_mcq_init(hba);
-
-	return ret;
+	if (ret) {
+		hba->nutrs = old_nutrs;
+		return ret;
+	}
+	return 0;
 }
 
 /**
drivers/ufs/host/ufs-qcom.c +8 -0
index 473fad8..643a915 100644
@@ -25,6 +25,7 @@
 #define UFS_QCOM_DEFAULT_DBG_PRINT_EN	\
 	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
+#define	MAX_SUPP_MAC	63
 enum {
 	TSTBUS_UAWM,
 	TSTBUS_UARM,
@@ -1424,6 +1425,12 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
 }
 #endif
 
+static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
+{
+	/* Default is 32, but Qualcomm HC supports upto 64 */
+	return MAX_SUPP_MAC;
+}
+
 /*
  * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
  *
@@ -1447,6 +1454,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.device_reset		= ufs_qcom_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
+	.get_hba_mac		= ufs_qcom_get_hba_mac,
 };
 
 /**
include/ufs/ufs.h +2 -0
index ba2a1d8..5112418 100644
@@ -591,6 +591,8 @@ struct ufs_dev_info {
 	u8	*model;
 	u16	wspecversion;
 	u32	clk_gating_wait_us;
+	/* Stores the depth of queue in UFS device */
+	u8	bqueuedepth;
 
 	/* UFS HPB related flag */
 	bool	hpb_enabled;
include/ufs/ufshcd.h +2 -0
index 54d742a..630a0eb 100644
@@ -293,6 +293,7 @@ struct ufs_pwr_mode_info {
  * @config_scaling_param: called to configure clock scaling parameters
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
+ * @get_hba_mac: called to get vendor specific mac value
  */
 struct ufs_hba_variant_ops {
 	const char *name;
@@ -331,6 +332,7 @@ struct ufs_hba_variant_ops {
 			       const union ufs_crypto_cfg_entry *cfg, int slot);
 	void	(*event_notify)(struct ufs_hba *hba,
 				enum ufs_event_type evt, void *data);
+	int	(*get_hba_mac)(struct ufs_hba *hba);
 };
 
 /* clock gating state  */
include/ufs/ufshci.h +1 -0
index ef5c3a8..ca7db49d 100644
@@ -57,6 +57,7 @@ enum {
 	REG_UFS_CCAP				= 0x100,
 	REG_UFS_CRYPTOCAP			= 0x104,
 
+	REG_UFS_MCQ_CFG				= 0x380,
 	UFSHCI_CRYPTO_REG_SPACE_SIZE		= 0x400,
 };
 
Signature · 1 line
2.7.4
#20 lore raw

Re: [PATCH v1 06/16] ufs: core: mcq: Calculate queue depth

Quoted 26 lines · Asutosh Das

The ufs device defines the supported queuedepth by bqueuedepth which has a max value of 256.
The HC defines MAC (Max Active Commands) that define the max number of commands that in flight to the ufs device.
Calculate and configure the nutrs based on both these values.

---
 drivers/ufs/core/ufs-mcq.c     | 34 ++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  9 +++++++++
 drivers/ufs/core/ufshcd.c      | 10 ++++++++--
 drivers/ufs/host/ufs-qcom.c    |  8 ++++++++
 include/ufs/ufs.h              |  2 ++
 include/ufs/ufshcd.h           |  2 ++
 include/ufs/ufshci.h           |  1 +
 7 files changed, 64 insertions(+), 2 deletions(-)
drivers/ufs/core/ufs-mcq.c +0 -0
index e5cc7ab..e52066e 100644

drivers/ufs/core/ufs-mcq.c line 21

Quoted 5 lines
drivers/ufs/core/ufs-mcq.c +2 -0
@@ -17,6 +17,8 @@
 #define UFS_MCQ_MIN_READ_QUEUES 0
 #define UFS_MCQ_MIN_POLL_QUEUES 0
 
+#define MCQ_CFG_MAC_OFFSET	8
+#define MCQ_CFG_MAC_MASK	UFS_MASK(0x1ff, MCQ_CFG_MAC_OFFSET)

Define 0x1ff

drivers/ufs/core/ufs-mcq.c static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = { · line 113

Quoted 9 lines
drivers/ufs/core/ufs-mcq.c +2 -0
 #define MCQ_QCFGPTR_MASK	GENMASK(7, 0)
 #define MCQ_QCFGPTR_UNIT	0x200
 #define MCQ_SQATTR_OFFSET(c) \
@@ -107,6 +109,38 @@ static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
 	{.name = "mcq_vs", .resource = NULL, .base = NULL},
 };
 
+/**
+ * ufshcd_mcq_decide_queue_depth - decide the queue depth

ufshcd_mcq_calc_queue_depth - Calculate MCQ queue depth

Quoted 46 lines
drivers/ufs/core/ufs-mcq.c +30 -0
+ * @hba - per adapter instance
+ *
+ * MAC - Max. Active Command of the Host Controller (HC)
+ * HC wouldn't send more than this commands to the device.
+ * The default MAC is 32, but the max. value may vary with
+ * vendor implementation.
+ * Calculates and adjusts the queue depth based on the depth
+ * supported by the HC and ufs device.
+ */
+u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba)
+{
+	u32 qd, val;
+	int mac;
+
+	mac = ufshcd_mcq_vops_get_hba_mac(hba);
+	if (mac < 0) {
+		val = ufshcd_readl(hba, REG_UFS_MCQ_CFG);
+		mac = (val & MCQ_CFG_MAC_MASK) >> MCQ_CFG_MAC_OFFSET;
+	}
+
+	/*  MAC is a 0 based value. */
+	mac += 1;
+	/* max. value of bqueuedepth = 256, mac is host dependent */
+	qd = min_t(u32, mac, hba->dev_info.bqueuedepth);
+	if (!qd)
+		qd = mac;
+
+	return qd;
+}
+
 static int ufshcd_mcq_config_resource(struct ufs_hba *hba)
 {
 	struct platform_device *pdev = to_platform_device(hba->dev);
drivers/ufs/core/ufshcd-priv.h +1 -0
index cf6bdd8e..6d16beb 100644
@@ -51,6 +51,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
+u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false

drivers/ufs/core/ufshcd-priv.h static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba, · line 220

Quoted 4 lines
drivers/ufs/core/ufshcd-priv.h +1 -0
@@ -216,6 +217,14 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
 		hba->vops->config_scaling_param(hba, p, data);
 }
 
+static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba)

No inline

Quoted 26 lines
drivers/ufs/core/ufshcd-priv.h +7 -0
+{
+	if (hba->vops && hba->vops->get_hba_mac)
+		return hba->vops->get_hba_mac(hba);
+
+	return -EOPNOTSUPP;
+}
+
 extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[];
 
 /**
drivers/ufs/core/ufshcd.c +1 -0
index f4bb402..a71b57e 100644
@@ -7759,6 +7759,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
 	/* getting Specification Version in big endian format */
 	dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 |
 				      desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1];
+	dev_info->bqueuedepth = desc_buf[DEVICE_DESC_PARAM_Q_DPTH];
 	b_ufs_feature_sup = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT];
 
 	model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
@@ -8175,10 +8176,15 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 static int ufshcd_config_mcq(struct ufs_hba *hba)
 {
 	int ret;

drivers/ufs/core/ufshcd.c static int ufshcd_add_lus(struct ufs_hba *hba) · line 8186

Quoted 10 lines
drivers/ufs/core/ufshcd.c +6 -2
+	int old_nutrs = hba->nutrs;
 
+	hba->nutrs = ufshcd_mcq_decide_queue_depth(hba);
 	ret = ufshcd_mcq_init(hba);
-
-	return ret;
+	if (ret) {
+		hba->nutrs = old_nutrs;
+		return ret;
+	}

Newline

drivers/ufs/host/ufs-qcom.c line 28

Quoted 13 lines
drivers/ufs/core/ufshcd.c +1 -0
+	return 0;
 }
 
 /**
drivers/ufs/host/ufs-qcom.c +1 -0
index 473fad8..643a915 100644
@@ -25,6 +25,7 @@
 #define UFS_QCOM_DEFAULT_DBG_PRINT_EN	\
 	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
 
+#define	MAX_SUPP_MAC	63

Just use a single space after #define to align with other definitions.

drivers/ufs/host/ufs-qcom.c static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, · line 1430

Quoted 10 lines
drivers/ufs/host/ufs-qcom.c +3 -0
 enum {
 	TSTBUS_UAWM,
 	TSTBUS_UARM,
@@ -1424,6 +1425,12 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
 }
 #endif
 
+static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
+{
+	/* Default is 32, but Qualcomm HC supports upto 64 */

Hmm, then this should come from ufshcd, no?

Thanks,
Mani

Quoted 62 lines
drivers/ufs/host/ufs-qcom.c +4 -0
+	return MAX_SUPP_MAC;
+}
+
 /*
  * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
  *
@@ -1447,6 +1454,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.device_reset		= ufs_qcom_device_reset,
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
+	.get_hba_mac		= ufs_qcom_get_hba_mac,
 };
 
 /**
include/ufs/ufs.h +2 -0
index ba2a1d8..5112418 100644
@@ -591,6 +591,8 @@ struct ufs_dev_info {
 	u8	*model;
 	u16	wspecversion;
 	u32	clk_gating_wait_us;
+	/* Stores the depth of queue in UFS device */
+	u8	bqueuedepth;
 
 	/* UFS HPB related flag */
 	bool	hpb_enabled;
include/ufs/ufshcd.h +2 -0
index 54d742a..630a0eb 100644
@@ -293,6 +293,7 @@ struct ufs_pwr_mode_info {
  * @config_scaling_param: called to configure clock scaling parameters
  * @program_key: program or evict an inline encryption key
  * @event_notify: called to notify important events
+ * @get_hba_mac: called to get vendor specific mac value
  */
 struct ufs_hba_variant_ops {
 	const char *name;
@@ -331,6 +332,7 @@ struct ufs_hba_variant_ops {
 			       const union ufs_crypto_cfg_entry *cfg, int slot);
 	void	(*event_notify)(struct ufs_hba *hba,
 				enum ufs_event_type evt, void *data);
+	int	(*get_hba_mac)(struct ufs_hba *hba);
 };
 
 /* clock gating state  */
include/ufs/ufshci.h +1 -0
index ef5c3a8..ca7db49d 100644
@@ -57,6 +57,7 @@ enum {
 	REG_UFS_CCAP				= 0x100,
 	REG_UFS_CRYPTOCAP			= 0x104,
 
+	REG_UFS_MCQ_CFG				= 0x380,
 	UFSHCI_CRYPTO_REG_SPACE_SIZE		= 0x400,
 };
 
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#21 lore raw

Re: [PATCH v1 06/16] ufs: core: mcq: Calculate queue depth

Quoted 13 lines · Manivannan Sadhasivam
Quoted 12 lines · Asutosh Das

The ufs device defines the supported queuedepth by bqueuedepth which has a max value of 256.
The HC defines MAC (Max Active Commands) that define the max number of commands that in flight to the ufs device.
Calculate and configure the nutrs based on both these values.

---

[...]

Quoted 6 lines
Quoted 3 lines

+/**
+ * ufshcd_mcq_decide_queue_depth - decide the queue depth

ufshcd_mcq_calc_queue_depth - Calculate MCQ queue depth

The name ufshcd_mcq_decide_queue_depth was suggested by Bart in his comments. I don't have a strong opinion on the name, if you do, plmk and I'd change it.

Quoted 1 line
Quoted 1 line

+ * @hba - per adapter instance

[...]

Quoted 6 lines

drivers/ufs/host/ufs-qcom.c static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, · line 1430

Quoted 3 lines
drivers/ufs/host/ufs-qcom.c +3 -0
+static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
+{
+	/* Default is 32, but Qualcomm HC supports upto 64 */

Hmm, then this should come from ufshcd, no?

I'm not sure I understand this comment, please can you elaborate?

Quoted 2 lines

Thanks,
Mani

#22 lore raw

PATCH 7/16 ufs: core: mcq: Allocate memory for mcq mode

In reply to Asutosh Das

To read the bqueuedepth, the device descriptor is fetched in Single Doorbell Mode. This allocated memory may not be enough for MCQ mode because the number of tags supported in MCQ mode may be larger than in SDB mode.
Hence, release the memory allocated in SDB mode and allocate memory for MCQ mode operation.
Defines the ufs hardware queue and Completion Queue Entry.

---
 drivers/ufs/core/ufs-mcq.c     | 59 ++++++++++++++++++++++++++++++++++++++++--
 drivers/ufs/core/ufshcd-priv.h |  1 +
 drivers/ufs/core/ufshcd.c      | 39 +++++++++++++++++++++++++---
 include/ufs/ufshcd.h           | 19 ++++++++++++++
 include/ufs/ufshci.h           | 21 +++++++++++++++
 5 files changed, 134 insertions(+), 5 deletions(-)
drivers/ufs/core/ufs-mcq.c +57 -2
index e52066e..e2854a3 100644
@@ -251,14 +251,69 @@ static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
 	return 0;
 }
 
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba)
+{
+	struct ufs_hw_queue *hwq;
+	size_t utrdl_size, cqe_size;
+	int i;
+
+	for (i = 0; i < hba->nr_hw_queues; i++) {
+		hwq = &hba->uhq[i];
+
+		utrdl_size = sizeof(struct utp_transfer_req_desc) *
+			     hwq->max_entries;
+		hwq->sqe_base_addr = dmam_alloc_coherent(hba->dev, utrdl_size,
+							 &hwq->sqe_dma_addr,
+							 GFP_KERNEL);
+		if (!hwq->sqe_dma_addr) {
+			dev_err(hba->dev, "SQE allocation failed\n");
+			return -ENOMEM;
+		}
+
+		cqe_size = sizeof(struct cq_entry) * hwq->max_entries;
+		hwq->cqe_base_addr = dmam_alloc_coherent(hba->dev, cqe_size,
+							 &hwq->cqe_dma_addr,
+							 GFP_KERNEL);
+		if (!hwq->cqe_dma_addr) {
+			dev_err(hba->dev, "CQE allocation failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 int ufshcd_mcq_init(struct ufs_hba *hba)
 {
-	int ret;
+	int ret, i;
+	struct ufs_hw_queue *hwq;
 
 	ret = ufshcd_mcq_config_nr_queues(hba);
 	if (ret)
 		return ret;
 	ret = ufshcd_mcq_config_resource(hba);
-	return ret;
+	if (ret)
+		return ret;
+
+	hba->uhq = devm_kmalloc(hba->dev,
+				hba->nr_hw_queues * sizeof(struct ufs_hw_queue),
+				GFP_KERNEL);
+	if (!hba->uhq) {
+		dev_err(hba->dev, "Alloc ufs hw queue failed\n");
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	for (i = 0; i < hba->nr_hw_queues; i++) {
+		hwq = &hba->uhq[i];
+		hwq->max_entries = hba->nutrs;
+	}
+
+	/* The very first HW queue is to serve device command */
+	hba->dev_cmd_queue = &hba->uhq[0];
+	/* Give dev_cmd_queue the minimal number of entries */
+	hba->dev_cmd_queue->max_entries = 2;
+
+	return 0;
 }
 
drivers/ufs/core/ufshcd-priv.h +1 -0
index 6d16beb..f624682 100644
@@ -52,6 +52,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
 u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
drivers/ufs/core/ufshcd.c +36 -3
index a71b57e..5fc1e5e 100644
@@ -3676,6 +3676,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
 		goto out;
 	}
 
+	if (hba->utmrdl_base_addr)
+		goto skip_utmrdl;
 	/*
 	 * Allocate memory for UTP Task Management descriptors
 	 * UFSHCI requires 1024 byte alignment of UTMRD
@@ -3692,6 +3694,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
 		goto out;
 	}
 
+skip_utmrdl:
 	/* Allocate memory for local reference block */
 	hba->lrb = devm_kcalloc(hba->dev,
 				hba->nutrs, sizeof(struct ufshcd_lrb),
@@ -8173,6 +8176,22 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 	return ret;
 }
 
+/* SDB - Single Doorbell */
+static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs)
+{
+	size_t ucdl_size, utrdl_size;
+
+	ucdl_size = sizeof(struct utp_transfer_cmd_desc) * nutrs;
+	dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr,
+			   hba->ucdl_dma_addr);
+
+	utrdl_size = sizeof(struct utp_transfer_req_desc) * nutrs;
+	dmam_free_coherent(hba->dev, utrdl_size, hba->utrdl_base_addr,
+			   hba->utrdl_dma_addr);
+
+	devm_kfree(hba->dev, hba->lrb);
+}
+
 static int ufshcd_config_mcq(struct ufs_hba *hba)
 {
 	int ret;
@@ -8180,11 +8199,25 @@ static int ufshcd_config_mcq(struct ufs_hba *hba)
 
 	hba->nutrs = ufshcd_mcq_decide_queue_depth(hba);
 	ret = ufshcd_mcq_init(hba);
-	if (ret) {
-		hba->nutrs = old_nutrs;
-		return ret;
+	if (ret)
+		goto err;
+
+	if (hba->nutrs != old_nutrs) {
+		ufshcd_release_sdb_queue(hba, old_nutrs);
+		ret = ufshcd_memory_alloc(hba);
+		if (ret)
+			goto err;
+		ufshcd_host_memory_configure(hba);
 	}
+
+	ret = ufshcd_mcq_memory_alloc(hba);
+	if (ret)
+		goto err;
+
 	return 0;
+err:
+	hba->nutrs = old_nutrs;
+	return ret;
 }
 
 /**
include/ufs/ufshcd.h +19 -0
index 630a0eb..e54d624 100644
@@ -857,6 +857,8 @@ enum ufshcd_res {
  * @nr_queues: number of Queues of different queue types
  * @res: array of resource info of MCQ registers
  * @mcq_base: Multi circular queue registers base address
+ * @uhq: array of supported hardware queues
+ * @dev_cmd_queue: Queue for issuing device management commands
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -1011,6 +1013,23 @@ struct ufs_hba {
 	unsigned int nr_queues[HCTX_MAX_TYPES];
 	struct ufshcd_res_info_t res[RES_MAX];
 	void __iomem *mcq_base;
+	struct ufs_hw_queue *uhq;
+	struct ufs_hw_queue *dev_cmd_queue;
+};
+
+/**
+ * @sqe_base_addr: submission queue entry base address
+ * @sqe_dma_addr: submission queue dma address
+ * @cqe_base_addr: completion queue base address
+ * @cqe_dma_addr: completion queue dma address
+ * @max_entries: max number of slots in this hardware queue
+ */
+struct ufs_hw_queue {
+	void *sqe_base_addr;
+	dma_addr_t sqe_dma_addr;
+	struct cq_entry *cqe_base_addr;
+	dma_addr_t cqe_dma_addr;
+	u32 max_entries;
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
include/ufs/ufshci.h +21 -0
index ca7db49d..7fa8faf 100644
@@ -490,6 +490,27 @@ struct utp_transfer_req_desc {
 	__le16  prd_table_offset;
 };
 
+struct cq_entry {
+	/* DW 0-1 */
+	__le64 command_desc_base_addr;
+
+	/* DW 2 */
+	__le16  response_upiu_length;
+	__le16  response_upiu_offset;
+
+	/* DW 3 */
+	__le16  prd_table_length;
+	__le16  prd_table_offset;
+
+	/* DW 4 */
+	__le32 status;
+
+	/* DW 5-7 */
+	u32 reserved[3];
+};
+
+static_assert(sizeof(struct cq_entry) == 32);
+
 /*
  * UTMRD structure.
  */
Signature · 1 line
2.7.4
#23 lore raw

Re: [PATCH v1 07/16] ufs: core: mcq: Allocate memory for mcq mode

Quoted 68 lines · Asutosh Das

To read the bqueuedepth, the device descriptor is fetched in Single Doorbell Mode. This allocated memory may not be enough for MCQ mode because the number of tags supported in MCQ mode may be larger than in SDB mode.
Hence, release the memory allocated in SDB mode and allocate memory for MCQ mode operation.
Defines the ufs hardware queue and Completion Queue Entry.

---
 drivers/ufs/core/ufs-mcq.c     | 59 ++++++++++++++++++++++++++++++++++++++++--
 drivers/ufs/core/ufshcd-priv.h |  1 +
 drivers/ufs/core/ufshcd.c      | 39 +++++++++++++++++++++++++---
 include/ufs/ufshcd.h           | 19 ++++++++++++++
 include/ufs/ufshci.h           | 21 +++++++++++++++
 5 files changed, 134 insertions(+), 5 deletions(-)
drivers/ufs/core/ufs-mcq.c +34 -1
index e52066e..e2854a3 100644
@@ -251,14 +251,69 @@ static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
 	return 0;
 }
 
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba)
+{
+	struct ufs_hw_queue *hwq;
+	size_t utrdl_size, cqe_size;
+	int i;
+
+	for (i = 0; i < hba->nr_hw_queues; i++) {
+		hwq = &hba->uhq[i];
+
+		utrdl_size = sizeof(struct utp_transfer_req_desc) *
+			     hwq->max_entries;
+		hwq->sqe_base_addr = dmam_alloc_coherent(hba->dev, utrdl_size,
+							 &hwq->sqe_dma_addr,
+							 GFP_KERNEL);
+		if (!hwq->sqe_dma_addr) {
+			dev_err(hba->dev, "SQE allocation failed\n");
+			return -ENOMEM;
+		}
+
+		cqe_size = sizeof(struct cq_entry) * hwq->max_entries;
+		hwq->cqe_base_addr = dmam_alloc_coherent(hba->dev, cqe_size,
+							 &hwq->cqe_dma_addr,
+							 GFP_KERNEL);
+		if (!hwq->cqe_dma_addr) {
+			dev_err(hba->dev, "CQE allocation failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 int ufshcd_mcq_init(struct ufs_hba *hba)
 {
-	int ret;
+	int ret, i;
+	struct ufs_hw_queue *hwq;
 
 	ret = ufshcd_mcq_config_nr_queues(hba);
 	if (ret)
 		return ret;

drivers/ufs/core/ufs-mcq.c static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) · line 302

Quoted 10 lines
drivers/ufs/core/ufs-mcq.c +8 -1
 	ret = ufshcd_mcq_config_resource(hba);
-	return ret;
+	if (ret)
+		return ret;
+
+	hba->uhq = devm_kmalloc(hba->dev,
+				hba->nr_hw_queues * sizeof(struct ufs_hw_queue),
+				GFP_KERNEL);
+	if (!hba->uhq) {
+		dev_err(hba->dev, "Alloc ufs hw queue failed\n");

"Failed to allocate memory for UFS hw queues"

drivers/ufs/core/ufs-mcq.c static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) · line 304

Quoted 2 lines
drivers/ufs/core/ufs-mcq.c +2 -0
+		ret = -ENOMEM;
+		return ret;

return -ENOMEM

drivers/ufs/core/ufs-mcq.c static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) · line 315

Quoted 11 lines
drivers/ufs/core/ufs-mcq.c +11 -0
+	}
+
+	for (i = 0; i < hba->nr_hw_queues; i++) {
+		hwq = &hba->uhq[i];
+		hwq->max_entries = hba->nutrs;
+	}
+
+	/* The very first HW queue is to serve device command */
+	hba->dev_cmd_queue = &hba->uhq[0];
+	/* Give dev_cmd_queue the minimal number of entries */
+	hba->dev_cmd_queue->max_entries = 2;

Perhaps add a define for 2? Not a big deal but it adds readability.

Quoted 21 lines
drivers/ufs/core/ufs-mcq.c +2 -0
+
+	return 0;
 }
 
drivers/ufs/core/ufshcd-priv.h +1 -0
index 6d16beb..f624682 100644
@@ -52,6 +52,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
 u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
drivers/ufs/core/ufshcd.c +0 -0
index a71b57e..5fc1e5e 100644

drivers/ufs/core/ufshcd.c static int ufshcd_memory_alloc(struct ufs_hba *hba) · line 3680

Quoted 5 lines
drivers/ufs/core/ufshcd.c +2 -0
@@ -3676,6 +3676,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
 		goto out;
 	}
 
+	if (hba->utmrdl_base_addr)
+		goto skip_utmrdl;

Is this change belongs to this patch?

Quoted 35 lines
drivers/ufs/core/ufshcd.c +17 -0
 	/*
 	 * Allocate memory for UTP Task Management descriptors
 	 * UFSHCI requires 1024 byte alignment of UTMRD
@@ -3692,6 +3694,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
 		goto out;
 	}
 
+skip_utmrdl:
 	/* Allocate memory for local reference block */
 	hba->lrb = devm_kcalloc(hba->dev,
 				hba->nutrs, sizeof(struct ufshcd_lrb),
@@ -8173,6 +8176,22 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
 	return ret;
 }
 
+/* SDB - Single Doorbell */
+static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs)
+{
+	size_t ucdl_size, utrdl_size;
+
+	ucdl_size = sizeof(struct utp_transfer_cmd_desc) * nutrs;
+	dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr,
+			   hba->ucdl_dma_addr);
+
+	utrdl_size = sizeof(struct utp_transfer_req_desc) * nutrs;
+	dmam_free_coherent(hba->dev, utrdl_size, hba->utrdl_base_addr,
+			   hba->utrdl_dma_addr);
+
+	devm_kfree(hba->dev, hba->lrb);
+}
+
 static int ufshcd_config_mcq(struct ufs_hba *hba)
 {
 	int ret;

drivers/ufs/core/ufshcd.c static int ufshcd_config_mcq(struct ufs_hba *hba) · line 8204

Quoted 9 lines
drivers/ufs/core/ufshcd.c +3 -3
@@ -8180,11 +8199,25 @@ static int ufshcd_config_mcq(struct ufs_hba *hba)
 
 	hba->nutrs = ufshcd_mcq_decide_queue_depth(hba);
 	ret = ufshcd_mcq_init(hba);
-	if (ret) {
-		hba->nutrs = old_nutrs;
-		return ret;
+	if (ret)
+		goto err;
+

Please add a comment here on what the check is for and what the code below does.

Quoted 33 lines
drivers/ufs/core/ufshcd.c +14 -0
+	if (hba->nutrs != old_nutrs) {
+		ufshcd_release_sdb_queue(hba, old_nutrs);
+		ret = ufshcd_memory_alloc(hba);
+		if (ret)
+			goto err;
+		ufshcd_host_memory_configure(hba);
 	}
+
+	ret = ufshcd_mcq_memory_alloc(hba);
+	if (ret)
+		goto err;
+
 	return 0;
+err:
+	hba->nutrs = old_nutrs;
+	return ret;
 }
 
 /**
include/ufs/ufshcd.h +2 -0
index 630a0eb..e54d624 100644
@@ -857,6 +857,8 @@ enum ufshcd_res {
  * @nr_queues: number of Queues of different queue types
  * @res: array of resource info of MCQ registers
  * @mcq_base: Multi circular queue registers base address
+ * @uhq: array of supported hardware queues
+ * @dev_cmd_queue: Queue for issuing device management commands
  */
 struct ufs_hba {
 	void __iomem *mmio_base;

include/ufs/ufshcd.h struct ufs_hba { · line 1016

Quoted 4 lines
include/ufs/ufshcd.h +1 -0
@@ -1011,6 +1013,23 @@ struct ufs_hba {
 	unsigned int nr_queues[HCTX_MAX_TYPES];
 	struct ufshcd_res_info_t res[RES_MAX];
 	void __iomem *mcq_base;
+	struct ufs_hw_queue *uhq;

s/uhq/hw_queues

Thanks,
Mani

Quoted 54 lines
include/ufs/ufshcd.h +16 -0
+	struct ufs_hw_queue *dev_cmd_queue;
+};
+
+/**
+ * @sqe_base_addr: submission queue entry base address
+ * @sqe_dma_addr: submission queue dma address
+ * @cqe_base_addr: completion queue base address
+ * @cqe_dma_addr: completion queue dma address
+ * @max_entries: max number of slots in this hardware queue
+ */
+struct ufs_hw_queue {
+	void *sqe_base_addr;
+	dma_addr_t sqe_dma_addr;
+	struct cq_entry *cqe_base_addr;
+	dma_addr_t cqe_dma_addr;
+	u32 max_entries;
 };
 
 static inline bool is_mcq_supported(struct ufs_hba *hba)
include/ufs/ufshci.h +21 -0
index ca7db49d..7fa8faf 100644
@@ -490,6 +490,27 @@ struct utp_transfer_req_desc {
 	__le16  prd_table_offset;
 };
 
+struct cq_entry {
+	/* DW 0-1 */
+	__le64 command_desc_base_addr;
+
+	/* DW 2 */
+	__le16  response_upiu_length;
+	__le16  response_upiu_offset;
+
+	/* DW 3 */
+	__le16  prd_table_length;
+	__le16  prd_table_offset;
+
+	/* DW 4 */
+	__le32 status;
+
+	/* DW 5-7 */
+	u32 reserved[3];
+};
+
+static_assert(sizeof(struct cq_entry) == 32);
+
 /*
  * UTMRD structure.
  */
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#24 lore raw

Re: [PATCH v1 07/16] ufs: core: mcq: Allocate memory for mcq mode

Quoted 20 lines · Manivannan Sadhasivam
Quoted 19 lines · Asutosh Das

To read the bqueuedepth, the device descriptor is fetched in Single Doorbell Mode. This allocated memory may not be enough for MCQ mode because the number of tags supported in MCQ mode may be larger than in SDB mode.
Hence, release the memory allocated in SDB mode and allocate memory for MCQ mode operation.
Defines the ufs hardware queue and Completion Queue Entry.

---
 drivers/ufs/core/ufs-mcq.c     | 59 ++++++++++++++++++++++++++++++++++++++++--
 drivers/ufs/core/ufshcd-priv.h |  1 +
 drivers/ufs/core/ufshcd.c      | 39 +++++++++++++++++++++++++---
 include/ufs/ufshcd.h           | 19 ++++++++++++++
 include/ufs/ufshci.h           | 21 +++++++++++++++
 5 files changed, 134 insertions(+), 5 deletions(-)

[...]

Quoted 20 lines
Quoted 20 lines
drivers/ufs/core/ufshcd-priv.h +1 -0
index 6d16beb..f624682 100644
@@ -52,6 +52,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
 u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
drivers/ufs/core/ufshcd.c +0 -0
index a71b57e..5fc1e5e 100644
@@ -3676,6 +3676,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
 		goto out;
 	}
 
Quoted 5 lines

drivers/ufs/core/ufshcd.c static int ufshcd_memory_alloc(struct ufs_hba *hba) · line 3680

Quoted 2 lines
drivers/ufs/core/ufshcd.c +2 -0
+	if (hba->utmrdl_base_addr)
+		goto skip_utmrdl;

Is this change belongs to this patch?

Yes.
This change frees and reallocates the descriptor memory by calling ufshcd_memory_alloc() if MCQ is supported and configured, see ufshcd_config_mcq().
I will add a comment here.

-asd

Quoted 3 lines
Signature · 2 lines
-- 
மணிவண்ணன் சதாசிவம்
#25 lore raw

PATCH 8/16 ufs: core: mcq: Configure operation and runtime interface

In reply to Asutosh Das

Runtime and operation registers are defined per Submission and Completion queue.
The location of these registers is not defined in the spec; meaning the offsets and stride may vary for different HC vendors. Establish the stride, base address and doorbell address offsets from vendor host driver and program it.

---
 drivers/ufs/core/ufs-mcq.c     | 102 +++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  11 +++++
 drivers/ufs/core/ufshcd.c      |  17 +++++++
 drivers/ufs/host/ufs-qcom.c    |  24 ++++++++++
 include/ufs/ufshcd.h           |  52 +++++++++++++++++++++
 include/ufs/ufshci.h           |  31 +++++++++++++
 6 files changed, 237 insertions(+)
drivers/ufs/core/ufs-mcq.c +102 -0
index e2854a3..7e57e7e 100644
@@ -16,6 +16,8 @@
 #define UFS_MCQ_MIN_RW_QUEUES 2
 #define UFS_MCQ_MIN_READ_QUEUES 0
 #define UFS_MCQ_MIN_POLL_QUEUES 0
+#define QUEUE_EN_OFFSET 31
+#define QUEUE_ID_OFFSET 16
 
 #define MCQ_CFG_MAC_OFFSET	8
 #define MCQ_CFG_MAC_MASK	UFS_MASK(0x1ff, MCQ_CFG_MAC_OFFSET)
@@ -24,6 +26,7 @@
 #define MCQ_SQATTR_OFFSET(c) \
 	((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
 #define MCQ_QCFG_SIZE	0x40
+#define MCQ_ENTRY_SIZE_IN_DWORD	8
 
 static unsigned int dev_cmd_queue = 1;
 
@@ -141,6 +144,24 @@ u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba)
 	return qd;
 }
 
+/**
+ * ufshcd_mcq_config_mac - Set the #Max Activ Cmds.
+ * @hba - per adpater instance
+ * @max_active_cmds - maximum # of active commands to the device at any time.
+ *
+ * The controller wouldn't send more than the max_active_cmds to the device at
+ * any time.
+ */
+void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds)
+{
+	u32 val;
+
+	val = ufshcd_readl(hba, REG_UFS_MCQ_CFG);
+	val &= ~MCQ_CFG_MAC_MASK;
+	val |= FIELD_PREP(MCQ_CFG_MAC_MASK, max_active_cmds);
+	ufshcd_writel(hba, val, REG_UFS_MCQ_CFG);
+}
+
 static int ufshcd_mcq_config_resource(struct ufs_hba *hba)
 {
 	struct platform_device *pdev = to_platform_device(hba->dev);
@@ -283,6 +304,81 @@ int ufshcd_mcq_memory_alloc(struct ufs_hba *hba)
 	return 0;
 }
 
+/* Operation and runtime registers configuration */
+#define MCQ_CFG_n(r, i) \
+	((r) + MCQ_QCFG_SIZE * (i))
+#define MCQ_OPR_OFFSET_n(p, i) \
+	(hba->mcq_opr[(p)].offset + hba->mcq_opr[(p)].stride * (i))
+
+static void __iomem *mcq_opr_base(struct ufs_hba *hba,
+					 enum ufshcd_mcq_opr n, int i)
+{
+	struct ufshcd_mcq_opr_info_t *opr = &hba->mcq_opr[n];
+
+	return opr->base + opr->stride * i;
+}
+
+void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba)
+{
+	struct ufs_hw_queue *hwq;
+	u16 qsize;
+	int i;
+
+	for (i = 0; i < hba->nr_hw_queues; i++) {
+		hwq = &hba->uhq[i];
+		hwq->id = i;
+		qsize = hwq->max_entries * MCQ_ENTRY_SIZE_IN_DWORD - 1;
+
+		/* Submission Queue Lower Base Address */
+		ufsmcq_writelx(hba, lower_32_bits(hwq->sqe_dma_addr),
+			      MCQ_CFG_n(REG_SQLBA, i));
+		/* Submission Queue Upper Base Address */
+		ufsmcq_writelx(hba, upper_32_bits(hwq->sqe_dma_addr),
+			      MCQ_CFG_n(REG_SQUBA, i));
+		/* Submission Queue Doorbell Address Offset */
+		ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQD, i),
+			      MCQ_CFG_n(REG_SQDAO, i));
+		/* Submission Queue Interrupt Status Address Offset */
+		ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQIS, i),
+			      MCQ_CFG_n(REG_SQISAO, i));
+
+		/* Completion Queue Lower Base Address */
+		ufsmcq_writelx(hba, lower_32_bits(hwq->cqe_dma_addr),
+			      MCQ_CFG_n(REG_CQLBA, i));
+		/* Completion Queue Upper Base Address */
+		ufsmcq_writelx(hba, upper_32_bits(hwq->cqe_dma_addr),
+			      MCQ_CFG_n(REG_CQUBA, i));
+		/* Completion Queue Doorbell Address Offset */
+		ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQD, i),
+			      MCQ_CFG_n(REG_CQDAO, i));
+		/* Completion Queue Interrupt Status Address Offset */
+		ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQIS, i),
+			      MCQ_CFG_n(REG_CQISAO, i));
+
+		/* Save the base addresses for quicker access */
+		hwq->mcq_sq_head = mcq_opr_base(hba, OPR_SQD, i) + REG_SQHP;
+		hwq->mcq_sq_tail = mcq_opr_base(hba, OPR_SQD, i) + REG_SQTP;
+		hwq->mcq_cq_head = mcq_opr_base(hba, OPR_CQD, i) + REG_CQHP;
+		hwq->mcq_cq_tail = mcq_opr_base(hba, OPR_CQD, i) + REG_CQTP;
+
+		/* Enable Tail Entry Push Status interrupt only for non-poll queues */
+		if (i < hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL])
+			writel(1, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIE);
+
+		/* Completion Queue Enable|Size to Completion Queue Attribute */
+		ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize,
+			      MCQ_CFG_n(REG_CQATTR, i));
+
+		/*
+		 * Submission Qeueue Enable|Size|Completion Queue ID to
+		 * Submission Queue Attribute
+		 */
+		ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize |
+			      (i << QUEUE_ID_OFFSET),
+			      MCQ_CFG_n(REG_SQATTR, i));
+	}
+}
+
 int ufshcd_mcq_init(struct ufs_hba *hba)
 {
 	int ret, i;
@@ -295,6 +391,12 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 	if (ret)
 		return ret;
 
+	ret = ufshcd_mcq_vops_op_runtime_config(hba);
+	if (ret) {
+		dev_err(hba->dev, "Operation runtime config failed, ret=%d\n",
+			ret);
+		return ret;
+	}
 	hba->uhq = devm_kmalloc(hba->dev,
 				hba->nr_hw_queues * sizeof(struct ufs_hw_queue),
 				GFP_KERNEL);
drivers/ufs/core/ufshcd-priv.h +11 -0
index f624682..01026e3 100644
@@ -53,6 +53,9 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
 int ufshcd_mcq_init(struct ufs_hba *hba);
 u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
 int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
+void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba);
+void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds);
+void ufshcd_mcq_select_mcq_mode(struct ufs_hba *hba);
 
 #define SD_ASCII_STD true
 #define SD_RAW false
@@ -226,6 +229,14 @@ static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba)
 	return -EOPNOTSUPP;
 }
 
+static inline int ufshcd_mcq_vops_op_runtime_config(struct ufs_hba *hba)
+{
+	if (hba->vops && hba->vops->op_runtime_config)
+		return hba->vops->op_runtime_config(hba);
+
+	return -EOPNOTSUPP;
+}
+
 extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[];
 
 /**
drivers/ufs/core/ufshcd.c +17 -0
index 5fc1e5e..b1af85c 100644
@@ -42,6 +42,12 @@
 #define UFSHCD_ENABLE_INTRS	(UTP_TRANSFER_REQ_COMPL |\
 				 UTP_TASK_REQ_COMPL |\
 				 UFSHCD_ERROR_MASK)
+
+#define UFSHCD_ENABLE_MCQ_INTRS	(UTP_TASK_REQ_COMPL |\
+				 UFSHCD_ERROR_MASK |\
+				 MCQ_CQ_EVENT_STATUS)
+
+
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT	500
 
@@ -8214,6 +8220,17 @@ static int ufshcd_config_mcq(struct ufs_hba *hba)
 	if (ret)
 		goto err;
 
+	ufshcd_enable_intr(hba, UFSHCD_ENABLE_MCQ_INTRS);
+	ufshcd_mcq_make_queues_operational(hba);
+	ufshcd_mcq_config_mac(hba, hba->nutrs);
+
+	hba->host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED;
+	hba->reserved_slot = hba->nutrs - UFSHCD_NUM_RESERVED;
+	dev_info(hba->dev, "MCQ configured, nr_queues=%d, io_queues=%d, read_queue=%d, poll_queues=%d, queue_depth=%d\n",
+		 hba->nr_hw_queues, hba->nr_queues[HCTX_TYPE_DEFAULT],
+		 hba->nr_queues[HCTX_TYPE_READ], hba->nr_queues[HCTX_TYPE_POLL],
+		 hba->nutrs);
+
 	return 0;
 err:
 	hba->nutrs = old_nutrs;
drivers/ufs/host/ufs-qcom.c +24 -0
index 643a915..598c08d 100644
@@ -1425,6 +1425,29 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
 }
 #endif
 
+static int ufs_qcom_op_runtime_config(struct ufs_hba *hba)
+{
+	struct ufshcd_mcq_opr_info_t *opr;
+	struct ufshcd_res_info_t *mem_res, *sqdao_res;
+	int i;
+
+	mem_res = &hba->res[RES_MEM];
+	sqdao_res = &hba->res[RES_MCQ_SQD];
+
+	if (!mem_res->base || !sqdao_res->base)
+		return -EINVAL;
+
+	for (i = 0; i < OPR_MAX; i++) {
+		opr = &hba->mcq_opr[i];
+		opr->offset = sqdao_res->resource->start -
+			      mem_res->resource->start + 0x40 * i;
+		opr->stride = 0x100;
+		opr->base = sqdao_res->base + 0x40 * i;
+	}
+
+	return 0;
+}
+
 static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
 {
 	/* Default is 32, but Qualcomm HC supports upto 64 */
@@ -1455,6 +1478,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.config_scaling_param = ufs_qcom_config_scaling_param,
 	.program_key		= ufs_qcom_ice_program_key,
 	.get_hba_mac		= ufs_qcom_get_hba_mac,
+	.op_runtime_config	= ufs_qcom_op_runtime_config,
 };
 
 /**
include/ufs/ufshcd.h +52 -0

111 lines not on this page · raw message

include/ufs/ufshci.h +31 -0
index 7fa8faf..3d455e1 100644
@@ -57,6 +57,7 @@ enum {
 	REG_UFS_CCAP				= 0x100,
 	REG_UFS_CRYPTOCAP			= 0x104,
 
+	REG_UFS_MEM_CFG				= 0x300,
 	REG_UFS_MCQ_CFG				= 0x380,
 	UFSHCI_CRYPTO_REG_SPACE_SIZE		= 0x400,
 };
@@ -78,6 +79,35 @@ enum {
 	MASK_EXT_IID_SUPPORT = 0x00000400,
 };
 
+enum {
+	REG_SQATTR		= 0x0,
+	REG_SQLBA		= 0x4,
+	REG_SQUBA		= 0x8,
+	REG_SQDAO		= 0xC,
+	REG_SQISAO		= 0x10,
+
+	REG_CQATTR		= 0x20,
+	REG_CQLBA		= 0x24,
+	REG_CQUBA		= 0x28,
+	REG_CQDAO		= 0x2C,
+	REG_CQISAO		= 0x30,
+};
+
+enum {
+	REG_SQHP		= 0x0,
+	REG_SQTP		= 0x4,
+};
+
+enum {
+	REG_CQHP		= 0x0,
+	REG_CQTP		= 0x4,
+};
+
+enum {
+	REG_CQIS		= 0x0,
+	REG_CQIE		= 0x4,
+};
+
 #define UFS_MASK(mask, offset)		((mask) << (offset))
 
 /* UFS Version 08h */
@@ -134,6 +164,7 @@ static inline u32 ufshci_version(u32 major, u32 minor)
 #define CONTROLLER_FATAL_ERROR			0x10000
 #define SYSTEM_BUS_FATAL_ERROR			0x20000
 #define CRYPTO_ENGINE_FATAL_ERROR		0x40000
+#define MCQ_CQ_EVENT_STATUS			0x100000
 
 #define UFSHCD_UIC_HIBERN8_MASK	(UIC_HIBERNATE_ENTER |\
 				UIC_HIBERNATE_EXIT)
Signature · 1 line
2.7.4
#26 lore raw

PATCH 9/16 ufs: core: mcq: Use shared tags for MCQ mode

In reply to Asutosh Das

Enable shared taggs for MCQ. For UFS, this should not have a huge performance impact. It however simplifies the MCQ implementation and reuses most of the existing code in the issue and completion path. Also add multiple queue mapping to map_queue().

---
 drivers/ufs/core/ufs-mcq.c |  2 ++
 drivers/ufs/core/ufshcd.c  | 31 +++++++++++++++++--------------
 2 files changed, 19 insertions(+), 14 deletions(-)
drivers/ufs/core/ufs-mcq.c +2 -0
index 7e57e7e..d40b237 100644
@@ -383,6 +383,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 {
 	int ret, i;
 	struct ufs_hw_queue *hwq;
+	struct Scsi_Host *host = hba->host;
 
 	ret = ufshcd_mcq_config_nr_queues(hba);
 	if (ret)
@@ -416,6 +417,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 	/* Give dev_cmd_queue the minimal number of entries */
 	hba->dev_cmd_queue->max_entries = 2;
 
+	host->host_tagset = 1;
 	return 0;
 }
 
drivers/ufs/core/ufshcd.c +17 -14
index b1af85c..6d70065 100644
@@ -2719,25 +2719,28 @@ static inline bool is_device_wlun(struct scsi_device *sdev)
  */
 static int ufshcd_map_queues(struct Scsi_Host *shost)
 {
-	int i, ret;
+	int i, queue_offset = 0;
+	struct ufs_hba *hba = shost_priv(shost);
+
+	if (!is_mcq_supported(hba)) {
+		hba->nr_queues[HCTX_TYPE_DEFAULT] = 1;
+		hba->nr_queues[HCTX_TYPE_READ] = 0;
+		hba->nr_queues[HCTX_TYPE_POLL] = 1;
+		hba->nr_hw_queues = 1;
+	}
 
 	for (i = 0; i < shost->nr_maps; i++) {
 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
 
-		switch (i) {
-		case HCTX_TYPE_DEFAULT:
-		case HCTX_TYPE_POLL:
-			map->nr_queues = 1;
-			break;
-		case HCTX_TYPE_READ:
-			map->nr_queues = 0;
+		map->nr_queues = hba->nr_queues[i];
+		if (!map->nr_queues)
 			continue;
-		default:
-			WARN_ON_ONCE(true);
-		}
-		map->queue_offset = 0;
-		ret = blk_mq_map_queues(map);
-		WARN_ON_ONCE(ret);
+		map->queue_offset = queue_offset;
+		if (i == HCTX_TYPE_POLL && !is_mcq_supported(hba))
+			map->queue_offset = 0;
+
+		blk_mq_map_queues(map);
+		queue_offset += map->nr_queues;
 	}
 
 	return 0;
Signature · 1 line
2.7.4
#27 lore raw

PATCH 10/16 ufs: core: Prepare ufshcd_send_command for mcq

In reply to Asutosh Das

Add support to send commands using multiple submission queues in MCQ mode.
Modify the functions that use ufshcd_send_command().

---
 drivers/ufs/core/ufs-mcq.c     |  1 +
 drivers/ufs/core/ufshcd-priv.h | 10 ++++++++++
 drivers/ufs/core/ufshcd.c      | 36 ++++++++++++++++++++++++++----------
 include/ufs/ufshcd.h           |  5 +++++
 4 files changed, 42 insertions(+), 10 deletions(-)
drivers/ufs/core/ufs-mcq.c +1 -0
index d40b237..e390ea1 100644
@@ -410,6 +410,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 	for (i = 0; i < hba->nr_hw_queues; i++) {
 		hwq = &hba->uhq[i];
 		hwq->max_entries = hba->nutrs;
+		spin_lock_init(&hwq->sq_lock);
 	}
 
 	/* The very first HW queue is to serve device command */
drivers/ufs/core/ufshcd-priv.h +10 -0
index 01026e3..7df2d92 100644
@@ -317,4 +317,14 @@ static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info,
 	return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported);
 }
 
+static inline void ufshcd_inc_sq_tail(struct ufs_hw_queue *q)
+{
+	u32 mask = q->max_entries - 1;
+	u32 val;
+
+	q->sq_tail_slot = (q->sq_tail_slot + 1) & mask;
+	val = q->sq_tail_slot * sizeof(struct utp_transfer_req_desc);
+	writel(val, q->mcq_sq_tail);
+}
+
 #endif /* _UFSHCD_PRIV_H_ */
drivers/ufs/core/ufshcd.c +26 -10
index 6d70065..78b17b2 100644
@@ -2140,9 +2140,11 @@ static void ufshcd_update_monitor(struct ufs_hba *hba, const struct ufshcd_lrb *
  * ufshcd_send_command - Send SCSI or device management commands
  * @hba: per adapter instance
  * @task_tag: Task tag of the command
+ * @hwq: pointer to hardware queue instance
  */
 static inline
-void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag,
+			 struct ufs_hw_queue *hwq)
 {
 	struct ufshcd_lrb *lrbp = &hba->lrb[task_tag];
 	unsigned long flags;
@@ -2154,12 +2156,24 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 	if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
 		ufshcd_start_monitor(hba, lrbp);
 
-	spin_lock_irqsave(&hba->outstanding_lock, flags);
-	if (hba->vops && hba->vops->setup_xfer_req)
-		hba->vops->setup_xfer_req(hba, task_tag, !!lrbp->cmd);
-	__set_bit(task_tag, &hba->outstanding_reqs);
-	ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
-	spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+	if (is_mcq_enabled(hba)) {
+		int utrd_size = sizeof(struct utp_transfer_req_desc);
+
+		spin_lock(&hwq->sq_lock);
+		memcpy(hwq->sqe_base_addr + (hwq->sq_tail_slot * utrd_size),
+		       lrbp->utr_descriptor_ptr, utrd_size);
+		ufshcd_inc_sq_tail(hwq);
+		spin_unlock(&hwq->sq_lock);
+	} else {
+		spin_lock_irqsave(&hba->outstanding_lock, flags);
+		if (hba->vops && hba->vops->setup_xfer_req)
+			hba->vops->setup_xfer_req(hba, lrbp->task_tag,
+						  !!lrbp->cmd);
+		__set_bit(lrbp->task_tag, &hba->outstanding_reqs);
+		ufshcd_writel(hba, 1 << lrbp->task_tag,
+			      REG_UTP_TRANSFER_REQ_DOOR_BELL);
+		spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+	}
 }
 
 /**
@@ -2780,6 +2794,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 	int tag = scsi_cmd_to_rq(cmd)->tag;
 	struct ufshcd_lrb *lrbp;
 	int err = 0;
+	struct ufs_hw_queue *hwq = NULL;
 
 	WARN_ONCE(tag < 0 || tag >= hba->nutrs, "Invalid tag %d\n", tag);
 
@@ -2864,7 +2879,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 		goto out;
 	}
 
-	ufshcd_send_command(hba, tag);
+	ufshcd_send_command(hba, tag, hwq);
 
 out:
 	rcu_read_unlock();
@@ -3037,10 +3052,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
 		goto out;
 
 	hba->dev_cmd.complete = &wait;
+	hba->dev_cmd.cqe = NULL;
 
 	ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
 
-	ufshcd_send_command(hba, tag);
+	ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
 	err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
 	ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP,
 				    (struct utp_upiu_req *)lrbp->ucd_rsp_ptr);
@@ -6891,7 +6907,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
 
 	ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
 
-	ufshcd_send_command(hba, tag);
+	ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
 	/*
 	 * ignore the returning value here - ufshcd_check_query_response is
 	 * bound to fail since dev_cmd.query and dev_cmd.type were left empty.
include/ufs/ufshcd.h +5 -0
index 8c44d5d0..0291099 100644
@@ -218,6 +218,7 @@ struct ufs_dev_cmd {
 	struct mutex lock;
 	struct completion *complete;
 	struct ufs_query query;
+	struct cq_entry *cqe;
 };
 
 /**
@@ -1054,6 +1055,8 @@ struct ufs_hba {
  * @cqe_dma_addr: completion queue dma address
  * @max_entries: max number of slots in this hardware queue
  * @id: hardware queue ID
+ * @sq_tp_slot: current slot to which SQ tail pointer is pointing
+ * @sq_lock: serialize submission queue access
  */
 struct ufs_hw_queue {
 	void __iomem *mcq_sq_head;
@@ -1067,6 +1070,8 @@ struct ufs_hw_queue {
 	dma_addr_t cqe_dma_addr;
 	u32 max_entries;
 	u32 id;
+	u32 sq_tail_slot;
+	spinlock_t sq_lock;
 };
 
 static inline bool is_mcq_enabled(struct ufs_hba *hba)
Signature · 1 line
2.7.4
#28 lore raw

PATCH 11/16 ufs: core: mcq: Find hardware queue to queue request

In reply to Asutosh Das

Adds support to find the hardware queue on which the request would be queued.
Since the very first queue is to serve device commands, an offset of 1 is added to the index of the hardware queue.

---
 drivers/ufs/core/ufs-mcq.c     | 22 ++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  3 +++
 drivers/ufs/core/ufshcd.c      |  3 +++
 3 files changed, 28 insertions(+)
drivers/ufs/core/ufs-mcq.c +22 -0
index e390ea1..1e59668 100644
@@ -113,6 +113,28 @@ static const struct ufshcd_res_info_t ufshcd_res_info[RES_MAX] = {
 };
 
 /**
+ * ufshcd_mcq_req_to_hwq - find the hardware queue on which the
+ * request would be issued.
+ * @hba - per adapter instance
+ * @req - pointer to the request to be issued
+ *
+ * Returns the hardware queue instance on which the request would
+ * be queued.
+ */
+struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
+					 struct request *req)
+{
+	u32 utag, hwq;
+
+	utag = blk_mq_unique_tag(req);
+	hwq = blk_mq_unique_tag_to_hwq(utag);
+
+	/* uhq[0] is to serve device commands */
+	return &hba->uhq[hwq + UFSHCD_MCQ_IO_QUEUE_OFFSET];
+}
+
+
+/**
  * ufshcd_mcq_decide_queue_depth - decide the queue depth
  * @hba - per adapter instance
  *
drivers/ufs/core/ufshcd-priv.h +3 -0
index 7df2d92..44ef266 100644
@@ -56,7 +56,10 @@ int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
 void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba);
 void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds);
 void ufshcd_mcq_select_mcq_mode(struct ufs_hba *hba);
+struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
+					   struct request *req);
 
+#define UFSHCD_MCQ_IO_QUEUE_OFFSET	1
 #define SD_ASCII_STD true
 #define SD_RAW false
 int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
drivers/ufs/core/ufshcd.c +3 -0
index 78b17b2..f900c0b 100644
@@ -2879,6 +2879,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 		goto out;
 	}
 
+	if (is_mcq_enabled(hba))
+		hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd));
+
 	ufshcd_send_command(hba, tag, hwq);
 
 out:
Signature · 1 line
2.7.4
#29 lore raw

PATCH 12/16 ufs: core: Prepare for completion in mcq

In reply to Asutosh Das

Modifies completion path APIs and adds completion queue entry.

---
 drivers/ufs/core/ufshcd-priv.h |  2 ++
 drivers/ufs/core/ufshcd.c      | 80 ++++++++++++++++++++++++++----------------
 2 files changed, 52 insertions(+), 30 deletions(-)
drivers/ufs/core/ufshcd-priv.h +2 -0
index 44ef266..62ae7e51 100644
@@ -50,6 +50,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
 	enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
+void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
+			  struct cq_entry *cqe);
 int ufshcd_mcq_init(struct ufs_hba *hba);
 u32 ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
 int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
drivers/ufs/core/ufshcd.c +50 -30

128 lines not on this page · raw message

Signature · 1 line
2.7.4
#30 lore raw

Re: [PATCH v1 12/16] ufs: core: Prepare for completion in mcq

Quoted 2 lines · Asutosh Das

Modifies completion path APIs and adds completion queue entry.

Please use the imperative mood for patch descriptions.

Thanks,

Bart.

#31 lore raw

PATCH 13/16 ufs: mcq: Add completion support of a cqe

In reply to Asutosh Das

Support for completing requests from Completion Queue is added.
Some HC support vendor specific registers that provide a bit-map of all CQ's which have at least one completed CQE. This support has been added.
The MCQ specification doesn't provide the Task Tag or its equivalent in the Completion Queue Entry. So an indirect method is used to find the Task Tag from the Completion Queue Entry.

---
 drivers/ufs/core/ufs-mcq.c     | 52 ++++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h | 43 ++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd.c      | 37 ++++++++++++++++++++++++++++++
 drivers/ufs/host/ufs-qcom.c    | 16 +++++++++++++
 drivers/ufs/host/ufs-qcom.h    |  4 ++++
 include/ufs/ufshcd.h           |  7 ++++++
 include/ufs/ufshci.h           |  3 +++
 7 files changed, 162 insertions(+)
drivers/ufs/core/ufs-mcq.c +52 -0
index 1e59668..46221c4 100644
@@ -27,6 +27,7 @@
 	((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
 #define MCQ_QCFG_SIZE	0x40
 #define MCQ_ENTRY_SIZE_IN_DWORD	8
+#define CQE_UCD_BA GENMASK(63, 7)
 
 static unsigned int dev_cmd_queue = 1;
 
@@ -340,6 +341,57 @@ static void __iomem *mcq_opr_base(struct ufs_hba *hba,
 	return opr->base + opr->stride * i;
 }
 
+u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i)
+{
+	return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS);
+}
+
+void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i)
+{
+	writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS);
+}
+
+static int ufshcd_mcq_get_tag(struct ufs_hba *hba,
+				     struct ufs_hw_queue *hwq,
+				     struct cq_entry *cqe)
+{
+	dma_addr_t dma_addr;
+
+	/* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */
+	dma_addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA;
+
+	return (dma_addr - hba->ucdl_dma_addr) /
+		sizeof(struct utp_transfer_cmd_desc);
+}
+
+static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
+					    struct ufs_hw_queue *hwq)
+{
+	struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
+	int tag;
+
+	tag = ufshcd_mcq_get_tag(hba, hwq, cqe);
+	ufshcd_compl_one_cqe(hba, tag, cqe);
+}
+
+unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba,
+					 struct ufs_hw_queue *hwq)
+{
+	unsigned long completed_reqs = 0;
+
+	ufshcd_mcq_update_cq_tail_slot(hwq);
+	while (!ufshcd_mcq_is_cq_empty(hwq)) {
+		ufshcd_mcq_process_cqe(hba, hwq);
+		ufshcd_mcq_inc_cq_head_slot(hwq);
+		completed_reqs++;
+	}
+
+	if (completed_reqs)
+		ufshcd_mcq_update_cq_head(hwq);
+
+	return completed_reqs;
+}
+
 void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba)
 {
 	struct ufs_hw_queue *hwq;
drivers/ufs/core/ufshcd-priv.h +43 -0

59 lines not on this page · raw message

drivers/ufs/core/ufshcd.c +37 -0
index 87d5ed6..0705861 100644
@@ -6639,6 +6639,40 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_handle_mcq_cq_events - handle MCQ completion queue events
+ * @hba: per adapter instance
+ *
+ * Returns IRQ_HANDLED if interrupt is handled
+ */
+static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba)
+{
+	struct ufs_hw_queue *hwq;
+	unsigned long outstanding_cqs;
+	unsigned int nr_queues;
+	int i, ret;
+	u32 events;
+
+	ret = ufshcd_vops_get_outstanding_cqs(hba, &outstanding_cqs);
+	if (ret)
+		outstanding_cqs = (1U << hba->nr_hw_queues) - 1;
+
+	/* Exclude the poll queues */
+	nr_queues = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
+	for_each_set_bit(i, &outstanding_cqs, nr_queues) {
+		hwq = &hba->uhq[i];
+
+		events = ufshcd_mcq_read_cqis(hba, i);
+		if (events)
+			ufshcd_mcq_write_cqis(hba, events, i);
+
+		if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS)
+			ufshcd_mcq_poll_cqe_nolock(hba, hwq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
  * ufshcd_sl_intr - Interrupt service routine
  * @hba: per adapter instance
  * @intr_status: contains interrupts generated by the controller
@@ -6663,6 +6697,9 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 	if (intr_status & UTP_TRANSFER_REQ_COMPL)
 		retval |= ufshcd_transfer_req_compl(hba);
 
+	if (intr_status & MCQ_CQ_EVENT_STATUS)
+		retval |= ufshcd_handle_mcq_cq_events(hba);
+
 	return retval;
 }
 
drivers/ufs/host/ufs-qcom.c +16 -0
index 598c08d..df7db01 100644
@@ -1454,6 +1454,21 @@ static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
 	return MAX_SUPP_MAC;
 }
 
+static int ufs_qcom_get_outstanding_cqs(struct ufs_hba *hba,
+					unsigned long *ocqs)
+{
+	u32 cqis_vs;
+	struct ufshcd_res_info_t *mcq_vs_res = &hba->res[RES_MCQ_VS];
+
+	if (!mcq_vs_res->base)
+		return -EINVAL;
+
+	cqis_vs = readl(mcq_vs_res->base + UFS_MEM_CQIS_VS);
+	*ocqs = cqis_vs;
+
+	return 0;
+}
+
 /*
  * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
  *
@@ -1479,6 +1494,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
 	.program_key		= ufs_qcom_ice_program_key,
 	.get_hba_mac		= ufs_qcom_get_hba_mac,
 	.op_runtime_config	= ufs_qcom_op_runtime_config,
+	.get_outstanding_cqs	= ufs_qcom_get_outstanding_cqs,
 };
 
 /**
drivers/ufs/host/ufs-qcom.h +4 -0
index 44466a3..7769f03 100644
@@ -72,6 +72,10 @@ enum {
 	UFS_UFS_DBG_RD_EDTL_RAM			= 0x1900,
 };
 
+enum {
+	UFS_MEM_CQIS_VS		= 0x8,
+};
+
 #define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x)	(0x000 + x)
 #define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x)	(0x400 + x)
 
include/ufs/ufshcd.h +7 -0
index 0291099..5731c01 100644
@@ -296,6 +296,7 @@ struct ufs_pwr_mode_info {
  * @event_notify: called to notify important events
  * @get_hba_mac: called to get vendor specific mac value
  * @op_runtime_config: called to config Operation and runtime regs Pointers
+ * @get_outstanding_cqs: called to get outstanding completion queues
  */
 struct ufs_hba_variant_ops {
 	const char *name;
@@ -336,6 +337,8 @@ struct ufs_hba_variant_ops {
 				enum ufs_event_type evt, void *data);
 	int	(*get_hba_mac)(struct ufs_hba *hba);
 	int	(*op_runtime_config)(struct ufs_hba *hba);
+	int	(*get_outstanding_cqs)(struct ufs_hba *hba,
+				       unsigned long *ocqs);
 };
 
 /* clock gating state  */
@@ -1057,6 +1060,8 @@ struct ufs_hba {
  * @id: hardware queue ID
  * @sq_tp_slot: current slot to which SQ tail pointer is pointing
  * @sq_lock: serialize submission queue access
+ * @cq_tail_slot: current slot to which CQ tail pointer is pointing
+ * @cq_head_slot: current slot to which CQ head pointer is pointing
  */
 struct ufs_hw_queue {
 	void __iomem *mcq_sq_head;
@@ -1072,6 +1077,8 @@ struct ufs_hw_queue {
 	u32 id;
 	u32 sq_tail_slot;
 	spinlock_t sq_lock;
+	u32 cq_tail_slot;
+	u32 cq_head_slot;
 };
 
 static inline bool is_mcq_enabled(struct ufs_hba *hba)
include/ufs/ufshci.h +3 -0
index 3d455e1..f3b3f42 100644
@@ -266,6 +266,9 @@ enum {
 /* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
 #define UTP_TASK_REQ_LIST_RUN_STOP_BIT		0x1
 
+/* CQISy - CQ y Interrupt Status Register  */
+#define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS	0x1
+
 /* UICCMD - UIC Command */
 #define COMMAND_OPCODE_MASK		0xFF
 #define GEN_SELECTOR_INDEX_MASK		0xFFFF
Signature · 1 line
2.7.4
#32 lore raw

Re: [PATCH v1 13/16] ufs: mcq: Add completion support of a cqe

drivers/ufs/core/ufs-mcq.c static void __iomem *mcq_opr_base(struct ufs_hba *hba, · line 365

Quoted 12 lines · Asutosh Das
drivers/ufs/core/ufs-mcq.c +12 -0
+static int ufshcd_mcq_get_tag(struct ufs_hba *hba,
+				     struct ufs_hw_queue *hwq,
+				     struct cq_entry *cqe)
+{
+	dma_addr_t dma_addr;
+
+	/* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */
+	dma_addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA;
+
+	return (dma_addr - hba->ucdl_dma_addr) /
+		sizeof(struct utp_transfer_cmd_desc);
+}

Since the above code only works correctly if the size of struct utp_transfer_cmd_desc is a multiple of 1 << 7, please add a BUILD_BUG_ON() statement that verifies that the size of utp_transfer_cmd_desc is a multiple of 128.

Thanks,

Bart.

#33 lore raw

PATCH 14/16 ufs: core: mcq: Add completion support in poll

In reply to Asutosh Das

Complete cqe requests in poll. Assumption is that several poll completion may happen in different CPUs for the same Completion Queue. Hence a spin lock protection is added.

---
 drivers/ufs/core/ufs-mcq.c     | 13 +++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  2 ++
 drivers/ufs/core/ufshcd.c      |  7 +++++++
 include/ufs/ufshcd.h           |  2 ++
 4 files changed, 24 insertions(+)
drivers/ufs/core/ufs-mcq.c +13 -0
index 46221c4..a8ca4c9 100644
@@ -392,6 +392,18 @@ unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba,
 	return completed_reqs;
 }
 
+unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba,
+				       struct ufs_hw_queue *hwq)
+{
+	unsigned long completed_reqs;
+
+	spin_lock(&hwq->cq_lock);
+	completed_reqs = ufshcd_mcq_poll_cqe_nolock(hba, hwq);
+	spin_unlock(&hwq->cq_lock);
+
+	return completed_reqs;
+}
+
 void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba)
 {
 	struct ufs_hw_queue *hwq;
@@ -485,6 +497,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba)
 		hwq = &hba->uhq[i];
 		hwq->max_entries = hba->nutrs;
 		spin_lock_init(&hwq->sq_lock);
+		spin_lock_init(&hwq->cq_lock);
 	}
 
 	/* The very first HW queue is to serve device command */
drivers/ufs/core/ufshcd-priv.h +2 -0
index 417e2ca..6e9bec6 100644
@@ -64,6 +64,8 @@ unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba,
 					 struct ufs_hw_queue *hwq);
 struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
 					   struct request *req);
+unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba,
+				       struct ufs_hw_queue *hwq);
 
 #define UFSHCD_MCQ_IO_QUEUE_OFFSET	1
 #define SD_ASCII_STD true
drivers/ufs/core/ufshcd.c +7 -0
index 0705861..44b6c0b 100644
@@ -5426,6 +5426,13 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num)
 	struct ufs_hba *hba = shost_priv(shost);
 	unsigned long completed_reqs, flags;
 	u32 tr_doorbell;
+	struct ufs_hw_queue *hwq;
+
+	if (is_mcq_enabled(hba)) {
+		hwq = &hba->uhq[queue_num + UFSHCD_MCQ_IO_QUEUE_OFFSET];
+
+		return ufshcd_mcq_poll_cqe_lock(hba, hwq);
+	}
 
 	spin_lock_irqsave(&hba->outstanding_lock, flags);
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
include/ufs/ufshcd.h +2 -0
index 5731c01..efaa7c2 100644
@@ -1062,6 +1062,7 @@ struct ufs_hba {
  * @sq_lock: serialize submission queue access
  * @cq_tail_slot: current slot to which CQ tail pointer is pointing
  * @cq_head_slot: current slot to which CQ head pointer is pointing
+ * @cq_lock: Synchronize between multiple polling instances
  */
 struct ufs_hw_queue {
 	void __iomem *mcq_sq_head;
@@ -1079,6 +1080,7 @@ struct ufs_hw_queue {
 	spinlock_t sq_lock;
 	u32 cq_tail_slot;
 	u32 cq_head_slot;
+	spinlock_t cq_lock;
 };
 
 static inline bool is_mcq_enabled(struct ufs_hba *hba)
Signature · 1 line
2.7.4
#34 lore raw

PATCH 15/16 ufs: core: mcq: Enable Multi Circular Queue

In reply to Asutosh Das

MCQ is enabled in the Host Controller.

---
 drivers/ufs/core/ufshcd.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/ufs/core/ufshcd.c +4 -0
index 44b6c0b..a230897 100644
@@ -8312,6 +8312,10 @@ static int ufshcd_config_mcq(struct ufs_hba *hba)
 
 	hba->host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED;
 	hba->reserved_slot = hba->nutrs - UFSHCD_NUM_RESERVED;
+	/* Select MCQ mode */
+	ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1,
+		      REG_UFS_MEM_CFG);
+	hba->mcq_enabled = true;
 	dev_info(hba->dev, "MCQ configured, nr_queues=%d, io_queues=%d, read_queue=%d, poll_queues=%d, queue_depth=%d\n",
 		 hba->nr_hw_queues, hba->nr_queues[HCTX_TYPE_DEFAULT],
 		 hba->nr_queues[HCTX_TYPE_READ], hba->nr_queues[HCTX_TYPE_POLL],
Signature · 1 line
2.7.4
#35 lore raw

Re: [PATCH v1 15/16] ufs: core: mcq: Enable Multi Circular Queue

Quoted 1 line · Asutosh Das

MCQ is enabled in the Host Controller.

Patch descriptions should be written in the imperative mood so please change the above into something like the following:

Enable MCQ in the host controller.

Thanks,

Bart.

#36 lore raw

PATCH 16/16 ufs: qcom-host: Enable multi circular queue capability

In reply to Asutosh Das

Enable MCQ for Qualcomm UFS controllers

---
 drivers/ufs/host/ufs-qcom.c | 1 +
 1 file changed, 1 insertion(+)
drivers/ufs/host/ufs-qcom.c +1 -0
index df7db01..69d35ee 100644
@@ -853,6 +853,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
 	hba->caps |= UFSHCD_CAP_CRYPTO;
 	hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE;
 	hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
+	hba->caps |= UFSHCD_CAP_MCQ_EN;
 
 	if (host->hw_ver.major >= 0x2) {
 		host->caps = UFS_QCOM_CAP_QUNIPRO |
Signature · 1 line
2.7.4
#37 lore raw
In reply to Asutosh Das
Quoted 3 lines · Asutosh Das

UFS Multi-Circular Queue (MCQ) has been added in UFSHCI v4.0 to improve storage performance. This patch series is a RFC implementation of this.

This is no more an RFC series. Also, it would be good if you can provide a summary on how the implementation has been done.

Thanks,
Mani

Quoted 59 lines

This is the initial driver implementation and it has been verified by booting on an emulation platform. During testing, all low power modes were disabled and it was in HS-G1 mode.

Please take a look and let us know your thoughts.

v1:
- Split the changes
- Addressed Bart's comments
- Addressed Bean's comments

* RFC versions:
v2 -> v3:
- Split the changes based on functionality
- Addressed queue configuration issues
- Faster SQE tail pointer increments
- Addressed comments from Bart and Manivannan

v1 -> v2:
- Enabled host_tagset
- Added queue num configuration support
- Added one more vops to allow vendor provide the wanted MAC
- Determine nutrs and can_queue by considering both MAC, bqueuedepth and EXT_IID support
- Postponed MCQ initialization and scsi_add_host() to async probe
- Used (EXT_IID, Task Tag) tuple to support up to 4096 tasks (theoretically)

Asutosh Das (16):
ufs: core: Probe for ext_iid support
ufs: core: Introduce Multi-circular queue capability
ufs: core: Defer adding host to scsi if mcq is supported
ufs: core: mcq: Introduce Multi Circular Queue
ufs: core: mcq: Configure resource regions
ufs: core: mcq: Calculate queue depth
ufs: core: mcq: Allocate memory for mcq mode
ufs: core: mcq: Configure operation and runtime interface
ufs: core: mcq: Use shared tags for MCQ mode
ufs: core: Prepare ufshcd_send_command for mcq
ufs: core: mcq: Find hardware queue to queue request
ufs: core: Prepare for completion in mcq
ufs: mcq: Add completion support of a cqe
ufs: core: mcq: Add completion support in poll
ufs: core: mcq: Enable Multi Circular Queue
ufs: qcom-host: Enable multi circular queue capability

 drivers/ufs/core/Makefile      |   2 +-
 drivers/ufs/core/ufs-mcq.c     | 511 +++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/core/ufshcd-priv.h |  84 ++++++-
 drivers/ufs/core/ufshcd.c      | 322 +++++++++++++++++++++-----
 drivers/ufs/host/ufs-qcom.c    |  49 ++++
 drivers/ufs/host/ufs-qcom.h    |   4 +
 include/ufs/ufs.h              |   6 +
 include/ufs/ufshcd.h           | 136 +++++++++++
 include/ufs/ufshci.h           |  63 +++++
 9 files changed, 1117 insertions(+), 60 deletions(-)
 create mode 100644 drivers/ufs/core/ufs-mcq.c
Signature · 1 line
2.7.4
Signature · 1 line
மணிவண்ணன் சதாசிவம்
#38 lore raw

Hello Mani,
Thanks for taking a look at the series.

Quoted 8 lines · Manivannan Sadhasivam
Quoted 3 lines · Asutosh Das

UFS Multi-Circular Queue (MCQ) has been added in UFSHCI v4.0 to improve storage performance. This patch series is a RFC implementation of this.

This is no more an RFC series. Also, it would be good if you can provide a summary on how the implementation has been done.

Sure, I will add it.
I shall wait for more comments from others for some more time before pushing the next version.

-asd