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

Sivareddy Surasani <[email protected]>
Newsgroups dev.linux.lists.mhi,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Vivek Pernamitta <[email protected]>

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 <[email protected]>
Signed-off-by: Sivareddy Surasani <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.