[PATCH 10/11] drivers: bus: mhi: host: Add support for MHI MAX TRB capability

Sivareddy Surasani posted 11 patches 2 months ago
[PATCH 10/11] drivers: bus: mhi: host: Add support for MHI MAX TRB capability
Posted by Sivareddy Surasani 2 months ago
From: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>

Read the MHI capability for MAX TRB length if device is supporting.
Use this information to send MHI data with a higher TRB length, as
supported by the device.

Signed-off-by: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
Signed-off-by: Sivareddy Surasani <sivareddy.surasani@oss.qualcomm.com>
---
 drivers/bus/mhi/common.h    |  9 ++++++++-
 drivers/bus/mhi/host/init.c | 21 +++++++++++++++++++++
 drivers/bus/mhi/host/main.c | 17 ++++++++++++++---
 include/linux/mhi.h         |  2 ++
 4 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
index 3b3ecbc6169f..4962035f4693 100644
--- a/drivers/bus/mhi/common.h
+++ b/drivers/bus/mhi/common.h
@@ -158,6 +158,8 @@
 #define MHI_TRE_GET_EV_PTR(tre)		le64_to_cpu((tre)->ptr)
 #define MHI_TRE_GET_EV_CODE(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
 #define MHI_TRE_GET_EV_LEN(tre)		FIELD_GET(GENMASK(15, 0), (MHI_TRE_GET_DWORD(tre, 0)))
+#define MHI_TRE_GET_EV_LEN_MAX_TRB(max_trb, tre)    (GENMASK(__fls(max_trb), 0) & \
+						    (MHI_TRE_GET_DWORD(tre, 0)))
 #define MHI_TRE_GET_EV_CHID(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
 #define MHI_TRE_GET_EV_TYPE(tre)	FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 1)))
 #define MHI_TRE_GET_EV_STATE(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
@@ -188,6 +190,7 @@
 /* Transfer descriptor macros */
 #define MHI_TRE_DATA_PTR(ptr)		cpu_to_le64(ptr)
 #define MHI_TRE_DATA_DWORD0(len)	cpu_to_le32(FIELD_PREP(GENMASK(15, 0), len))
+#define MHI_TRE_DATA_DWORD0_MAX_TREB_CAP(max_len, len)	((GENMASK(__fls(max_len), 0)) & (len))
 #define MHI_TRE_TYPE_TRANSFER		2
 #define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
 								MHI_TRE_TYPE_TRANSFER) |    \
@@ -206,7 +209,11 @@
 #define MHI_RSCTRE_DATA_PTR(ptr, len)	cpu_to_le64(FIELD_PREP(GENMASK(64, 48), len) | ptr)
 #define MHI_RSCTRE_DATA_DWORD0(cookie)	cpu_to_le32(cookie)
 #define MHI_RSCTRE_DATA_DWORD1		cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
-							       MHI_PKT_TYPE_COALESCING))
+								MHI_PKT_TYPE_COALESCING))
+
+/* MHI Max TRB Length CAP ID */
+#define MAX_TRB_LEN_CAP_ID		0x5
+#define MAX_TRB_LEN_CFG			0x4
 
 enum mhi_capability_type {
 	MHI_CAP_ID_INTX = 0x1,
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index 50f96f2c823f..b0982cb24fb9 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -500,6 +500,25 @@ static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability,
 	return -ENXIO;
 }
 
+static int mhi_init_ext_trb_len(struct mhi_controller *mhi_cntrl)
+{
+	struct device *dev = &mhi_cntrl->mhi_dev->dev;
+	u32 trb_offset;
+	int ret;
+
+	ret = mhi_find_capability(mhi_cntrl, MAX_TRB_LEN_CAP_ID, &trb_offset);
+	if (ret)
+		return ret;
+
+	/* Get max TRB length */
+	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
+			   trb_offset + MAX_TRB_LEN_CFG, &mhi_cntrl->ext_trb_len);
+
+	dev_dbg(dev, "Max TRB length supported is : 0x%x\n", mhi_cntrl->ext_trb_len);
+
+	return 0;
+}
+
 int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
 {
 	u32 val;
@@ -637,6 +656,8 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
 		return ret;
 	}
 
+	ret = mhi_init_ext_trb_len(mhi_cntrl);
+
 	return 0;
 }
 
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index 6be15297829d..a11bddce2182 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -648,7 +648,12 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
 			buf_info = buf_ring->rp;
 			/* If it's the last TRE, get length from the event */
 			if (local_rp == ev_tre) {
-				xfer_len = MHI_TRE_GET_EV_LEN(event);
+				if (mhi_cntrl->ext_trb_len)
+					xfer_len = MHI_TRE_GET_EV_LEN_MAX_TRB(
+								mhi_cntrl->ext_trb_len,
+								event);
+				else
+					xfer_len = MHI_TRE_GET_EV_LEN(event);
 				send_cb = true;
 			} else {
 				xfer_len = buf_info->len;
@@ -664,7 +669,7 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
 
 			/* truncate to buf len if xfer_len is larger */
 			result.bytes_xferd =
-				min_t(u16, xfer_len, buf_info->len);
+				min_t(u32, xfer_len, buf_info->len);
 			mhi_del_ring_element(mhi_cntrl, buf_ring);
 			mhi_del_ring_element(mhi_cntrl, tre_ring);
 			local_rp = tre_ring->rp;
@@ -1288,7 +1293,13 @@ int __mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
 
 	mhi_tre = tre_ring->wp;
 	mhi_tre->ptr = MHI_TRE_DATA_PTR(buf_info->p_addr);
-	mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len);
+
+	if (mhi_cntrl->ext_trb_len)
+		mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0_MAX_TREB_CAP(mhi_cntrl->ext_trb_len,
+								     info->len);
+	else
+		mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len);
+
 	mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain);
 
 	if (mhi_chan->dir == DMA_TO_DEVICE)
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 013bc2d82196..0d78a95c2fa2 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -370,6 +370,7 @@ struct mhi_controller_config {
  * @wake_set: Device wakeup set flag
  * @irq_flags: irq flags passed to request_irq (optional)
  * @mru: the default MRU for the MHI device
+ * @ext_trb_len: Extended TRB length if device supports (optional)
  *
  * Fields marked as (required) need to be populated by the controller driver
  * before calling mhi_register_controller(). For the fields marked as (optional)
@@ -455,6 +456,7 @@ struct mhi_controller {
 	bool wake_set;
 	unsigned long irq_flags;
 	u32 mru;
+	u32 ext_trb_len;
 };
 
 /**

-- 
2.34.1
Re: [PATCH 10/11] drivers: bus: mhi: host: Add support for MHI MAX TRB capability
Posted by Manivannan Sadhasivam 4 weeks ago
On Thu, Dec 11, 2025 at 01:37:42PM +0530, Sivareddy Surasani wrote:
> From: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
> 
> Read the MHI capability for MAX TRB length if device is supporting.

Expand TRB.

> Use this information to send MHI data with a higher TRB length, as
> supported by the device.
> 

Add some context on what the device is going to do with it.

> Signed-off-by: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
> Signed-off-by: Sivareddy Surasani <sivareddy.surasani@oss.qualcomm.com>
> ---
>  drivers/bus/mhi/common.h    |  9 ++++++++-
>  drivers/bus/mhi/host/init.c | 21 +++++++++++++++++++++
>  drivers/bus/mhi/host/main.c | 17 ++++++++++++++---
>  include/linux/mhi.h         |  2 ++
>  4 files changed, 45 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
> index 3b3ecbc6169f..4962035f4693 100644
> --- a/drivers/bus/mhi/common.h
> +++ b/drivers/bus/mhi/common.h
> @@ -158,6 +158,8 @@
>  #define MHI_TRE_GET_EV_PTR(tre)		le64_to_cpu((tre)->ptr)
>  #define MHI_TRE_GET_EV_CODE(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
>  #define MHI_TRE_GET_EV_LEN(tre)		FIELD_GET(GENMASK(15, 0), (MHI_TRE_GET_DWORD(tre, 0)))
> +#define MHI_TRE_GET_EV_LEN_MAX_TRB(max_trb, tre)    (GENMASK(__fls(max_trb), 0) & \
> +						    (MHI_TRE_GET_DWORD(tre, 0)))
>  #define MHI_TRE_GET_EV_CHID(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
>  #define MHI_TRE_GET_EV_TYPE(tre)	FIELD_GET(GENMASK(23, 16), (MHI_TRE_GET_DWORD(tre, 1)))
>  #define MHI_TRE_GET_EV_STATE(tre)	FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 0)))
> @@ -188,6 +190,7 @@
>  /* Transfer descriptor macros */
>  #define MHI_TRE_DATA_PTR(ptr)		cpu_to_le64(ptr)
>  #define MHI_TRE_DATA_DWORD0(len)	cpu_to_le32(FIELD_PREP(GENMASK(15, 0), len))
> +#define MHI_TRE_DATA_DWORD0_MAX_TREB_CAP(max_len, len)	((GENMASK(__fls(max_len), 0)) & (len))
>  #define MHI_TRE_TYPE_TRANSFER		2
>  #define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
>  								MHI_TRE_TYPE_TRANSFER) |    \
> @@ -206,7 +209,11 @@
>  #define MHI_RSCTRE_DATA_PTR(ptr, len)	cpu_to_le64(FIELD_PREP(GENMASK(64, 48), len) | ptr)
>  #define MHI_RSCTRE_DATA_DWORD0(cookie)	cpu_to_le32(cookie)
>  #define MHI_RSCTRE_DATA_DWORD1		cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
> -							       MHI_PKT_TYPE_COALESCING))
> +								MHI_PKT_TYPE_COALESCING))
> +
> +/* MHI Max TRB Length CAP ID */
> +#define MAX_TRB_LEN_CAP_ID		0x5
> +#define MAX_TRB_LEN_CFG			0x4
>  
>  enum mhi_capability_type {
>  	MHI_CAP_ID_INTX = 0x1,
> diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
> index 50f96f2c823f..b0982cb24fb9 100644
> --- a/drivers/bus/mhi/host/init.c
> +++ b/drivers/bus/mhi/host/init.c
> @@ -500,6 +500,25 @@ static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability,
>  	return -ENXIO;
>  }
>  
> +static int mhi_init_ext_trb_len(struct mhi_controller *mhi_cntrl)

Why _ext_?

> +{
> +	struct device *dev = &mhi_cntrl->mhi_dev->dev;
> +	u32 trb_offset;
> +	int ret;
> +
> +	ret = mhi_find_capability(mhi_cntrl, MAX_TRB_LEN_CAP_ID, &trb_offset);
> +	if (ret)
> +		return ret;
> +
> +	/* Get max TRB length */
> +	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
> +			   trb_offset + MAX_TRB_LEN_CFG, &mhi_cntrl->ext_trb_len);
> +
> +	dev_dbg(dev, "Max TRB length supported is : 0x%x\n", mhi_cntrl->ext_trb_len);

"Max TRB length: 0x%x"

But it feels more natural to expose the value in decimal, than in hex.

- Mani

-- 
மணிவண்ணன் சதாசிவம்