All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] Major code reorganization to make all i2c transfers working
@ 2018-02-03  7:58 Abhishek Sahu
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
                   ` (11 more replies)
  0 siblings, 12 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

The current driver is failing in following test case
1. Handling of failure cases is not working in long run for BAM
   mode. It generates error message “bam-dma-engine 7884000.dma: Cannot
   free busy channel” sometimes.
2. Following I2C transfers are failing
   a. Single transfer with multiple read messages
   b. Single transfer with multiple read/write message with maximum
      allowed length per message (65K) in BAM mode
   c. Single transfer with write greater than 32 bytes in QUP v1 and
      write greater than 64 bytes in QUP v2 for non-DMA mode.
3. No handling is present for Block/FIFO interrupts. Any non-error
   interrupts are being treated as the transfer completion and then
   polling is being done for available/free bytes in FIFO.

To fix all these issues, major code changes are required. This patch
series fixes all the above issues and makes the driver interrupt based
instead of polling based. After these changes, all the mentioned test
cases are working properly.

The code changes have been tested for QUP v1 (IPQ8064) and QUP
v2 (IPQ8074) with sample application written over i2c-dev.

Abhishek Sahu (12):
  i2c: qup: fixed releasing dma without flush operation completion
  i2c: qup: minor code reorganization for use_dma
  i2c: qup: remove redundant variables for BAM SG count
  i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags
  i2c: qup: proper error handling for i2c error in BAM mode
  i2c: qup: use the complete transfer length to choose DMA mode
  i2c: qup: change completion timeout according to transfer length
  i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  i2c: qup: send NACK for last read sub transfers
  i2c: qup: reorganization of driver code to remove polling for qup v1
  i2c: qup: reorganization of driver code to remove polling for qup v2

 drivers/i2c/busses/i2c-qup.c | 1538 +++++++++++++++++++++++++-----------------
 1 file changed, 924 insertions(+), 614 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-08 14:03   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 02/12] i2c: qup: minor code reorganization for use_dma Abhishek Sahu
                   ` (10 subsequent siblings)
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

The QUP BSLP BAM generates the following error sometimes if the
current I2C DMA transfer fails and the flush operation has been
scheduled

    “bam-dma-engine 7884000.dma: Cannot free busy channel”

If any I2C error comes during BAM DMA transfer, then the QUP I2C
interrupt will be generated and the flush operation will be
carried out to make i2c consume all scheduled DMA transfer.
Currently, the same completion structure is being used for BAM
transfer which has already completed without reinit. It will make
flush operation wait_for_completion_timeout completed immediately
and will proceed for freeing the DMA resources where the
descriptors are still in process.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 08f8e01..9faa26c41a 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (c) 2014, Sony Mobile Communications AB.
  *
  *
@@ -844,6 +844,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 	}
 
 	if (ret || qup->bus_err || qup->qup_err) {
+		reinit_completion(&qup->xfer);
+
 		if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
 			dev_err(qup->dev, "change to run state timed out");
 			goto desc_err;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 02/12] i2c: qup: minor code reorganization for use_dma
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-27 21:48   ` Christ, Austin
  2018-02-27 22:26   ` Andy Gross
  2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

1. Assigns use_dma in qup_dev structure itself which will
   help in subsequent patches to determine the mode in IRQ handler.
2. Does minor code reorganization for loops to reduce the
   unnecessary comparison and assignment.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 9faa26c41a..c68f433 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -190,6 +190,8 @@ struct qup_i2c_dev {
 
 	/* dma parameters */
 	bool			is_dma;
+	/* To check if the current transfer is using DMA */
+	bool			use_dma;
 	struct			dma_pool *dpool;
 	struct			qup_i2c_tag start_tag;
 	struct			qup_i2c_bam brx;
@@ -1297,7 +1299,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, len, idx = 0, use_dma = 0;
+	int ret, len, idx = 0;
 
 	qup->bus_err = 0;
 	qup->qup_err = 0;
@@ -1326,13 +1328,12 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			len = (msgs[idx].len > qup->out_fifo_sz) ||
 			      (msgs[idx].len > qup->in_fifo_sz);
 
-			if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
-				use_dma = 1;
-			 } else {
-				use_dma = 0;
+			if (is_vmalloc_addr(msgs[idx].buf) || !len)
 				break;
-			}
 		}
+
+		if (idx == num)
+			qup->use_dma = true;
 	}
 
 	idx = 0;
@@ -1356,15 +1357,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (use_dma) {
+		if (qup->use_dma) {
 			ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
+			qup->use_dma = false;
+			break;
 		} else {
 			if (msgs[idx].flags & I2C_M_RD)
 				ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
 			else
 				ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
 		}
-	} while ((idx++ < (num - 1)) && !use_dma && !ret);
+	} while ((idx++ < (num - 1)) && !ret);
 
 	if (!ret)
 		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
  2018-02-03  7:58 ` [PATCH 02/12] i2c: qup: minor code reorganization for use_dma Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-09  2:16   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer Abhishek Sahu
                   ` (8 subsequent siblings)
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
be used for total number of SG entries.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c68f433..bb83a2967 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -692,7 +692,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 	struct dma_async_tx_descriptor *txd, *rxd = NULL;
 	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
 	dma_cookie_t cookie_rx, cookie_tx;
-	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
+	u32 len, blocks, rem;
 	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
 	u8 *tags;
 
@@ -707,9 +707,6 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 		rem = msg->len - (blocks - 1) * limit;
 
 		if (msg->flags & I2C_M_RD) {
-			rx_nents += (blocks * 2) + 1;
-			tx_nents += 1;
-
 			while (qup->blk.pos < blocks) {
 				tlen = (i == (blocks - 1)) ? rem : limit;
 				tags = &qup->start_tag.start[off + len];
@@ -748,8 +745,6 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 			if (ret)
 				return ret;
 		} else {
-			tx_nents += (blocks * 2);
-
 			while (qup->blk.pos < blocks) {
 				tlen = (i == (blocks - 1)) ? rem : limit;
 				tags = &qup->start_tag.start[off + tx_len];
@@ -775,7 +770,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 
 			if (idx == (num - 1)) {
 				len = 1;
-				if (rx_nents) {
+				if (rx_buf) {
 					qup->btx.tag.start[0] =
 							QUP_BAM_INPUT_EOT;
 					len++;
@@ -787,14 +782,13 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 						     len, qup, DMA_TO_DEVICE);
 				if (ret)
 					return ret;
-				tx_nents += 1;
 			}
 		}
 		idx++;
 		msg++;
 	}
 
-	txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents,
+	txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_buf,
 				      DMA_MEM_TO_DEV,
 				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
 	if (!txd) {
@@ -803,7 +797,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 		goto desc_err;
 	}
 
-	if (!rx_nents) {
+	if (!rx_buf) {
 		txd->callback = qup_i2c_bam_cb;
 		txd->callback_param = qup;
 	}
@@ -816,9 +810,9 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 
 	dma_async_issue_pending(qup->btx.dma);
 
-	if (rx_nents) {
+	if (rx_buf) {
 		rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
-					      rx_nents, DMA_DEV_TO_MEM,
+					      rx_buf, DMA_DEV_TO_MEM,
 					      DMA_PREP_INTERRUPT);
 		if (!rxd) {
 			dev_err(qup->dev, "failed to get rx desc\n");
@@ -853,7 +847,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 			goto desc_err;
 		}
 
-		if (rx_nents)
+		if (rx_buf)
 			writel(QUP_BAM_INPUT_EOT,
 			       qup->base + QUP_OUT_FIFO_BASE);
 
@@ -871,10 +865,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 	}
 
 desc_err:
-	dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
+	dma_unmap_sg(qup->dev, qup->btx.sg, tx_buf, DMA_TO_DEVICE);
 
-	if (rx_nents)
-		dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
+	if (rx_buf)
+		dma_unmap_sg(qup->dev, qup->brx.sg, rx_buf,
 			     DMA_FROM_DEVICE);
 
 	return ret;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (2 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-15 14:31   ` Sricharan R
  2018-02-27 22:36   ` Andy Gross
  2018-02-03  7:58 ` [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags Abhishek Sahu
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

A single BAM transfer can have multiple read and write messages.
The EOT and FLUSH tags should be scheduled at the end of BAM HW
descriptors. Since the READ and WRITE can be present in any order
so for some of the cases, these tags are not being written
correctly.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 54 ++++++++++++++++++++------------------------
 1 file changed, 24 insertions(+), 30 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index bb83a2967..6357aff 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -560,7 +560,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
 }
 
 static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
-			    struct i2c_msg *msg,  int is_dma)
+			    struct i2c_msg *msg)
 {
 	u16 addr = i2c_8bit_addr_from_msg(msg);
 	int len = 0;
@@ -601,11 +601,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
 	else
 		tags[len++] = data_len;
 
-	if ((msg->flags & I2C_M_RD) && last && is_dma) {
-		tags[len++] = QUP_BAM_INPUT_EOT;
-		tags[len++] = QUP_BAM_FLUSH_STOP;
-	}
-
 	return len;
 }
 
@@ -614,7 +609,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	int data_len = 0, tag_len, index;
 	int ret;
 
-	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
+	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
 	index = msg->len - qup->blk.data_len;
 
 	/* only tags are written for read */
@@ -710,7 +705,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 			while (qup->blk.pos < blocks) {
 				tlen = (i == (blocks - 1)) ? rem : limit;
 				tags = &qup->start_tag.start[off + len];
-				len += qup_i2c_set_tags(tags, qup, msg, 1);
+				len += qup_i2c_set_tags(tags, qup, msg);
 				qup->blk.data_len -= tlen;
 
 				/* scratch buf to read the start and len tags */
@@ -738,17 +733,11 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 				return ret;
 
 			off += len;
-			/* scratch buf to read the BAM EOT and FLUSH tags */
-			ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
-					     &qup->brx.tag.start[0],
-					     2, qup, DMA_FROM_DEVICE);
-			if (ret)
-				return ret;
 		} else {
 			while (qup->blk.pos < blocks) {
 				tlen = (i == (blocks - 1)) ? rem : limit;
 				tags = &qup->start_tag.start[off + tx_len];
-				len = qup_i2c_set_tags(tags, qup, msg, 1);
+				len = qup_i2c_set_tags(tags, qup, msg);
 				qup->blk.data_len -= tlen;
 
 				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
@@ -768,26 +757,31 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 			}
 			off += tx_len;
 
-			if (idx == (num - 1)) {
-				len = 1;
-				if (rx_buf) {
-					qup->btx.tag.start[0] =
-							QUP_BAM_INPUT_EOT;
-					len++;
-				}
-				qup->btx.tag.start[len - 1] =
-							QUP_BAM_FLUSH_STOP;
-				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
-						     &qup->btx.tag.start[0],
-						     len, qup, DMA_TO_DEVICE);
-				if (ret)
-					return ret;
-			}
 		}
 		idx++;
 		msg++;
 	}
 
+	/* schedule the EOT and FLUSH I2C tags */
+	len = 1;
+	if (rx_buf) {
+		qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
+		len++;
+
+		/* scratch buf to read the BAM EOT and FLUSH tags */
+		ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
+				     &qup->brx.tag.start[0],
+				     2, qup, DMA_FROM_DEVICE);
+		if (ret)
+			return ret;
+	}
+
+	qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
+	ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->btx.tag.start[0],
+			     len, qup, DMA_TO_DEVICE);
+	if (ret)
+		return ret;
+
 	txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_buf,
 				      DMA_MEM_TO_DEV,
 				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (3 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-27 22:38   ` Andy Gross
  2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

In case of FLUSH operation, BAM copies INPUT EOT FLUSH (0x94)
instead of normal EOT (0x93) tag in input data stream when an
input EOT tag is received during flush operation. So only one tag
will be written instead of 2 separate tags.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 6357aff..094be6a 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -768,10 +768,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 		qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
 		len++;
 
-		/* scratch buf to read the BAM EOT and FLUSH tags */
+		/* scratch buf to read the BAM EOT FLUSH tags */
 		ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
 				     &qup->brx.tag.start[0],
-				     2, qup, DMA_FROM_DEVICE);
+				     1, qup, DMA_FROM_DEVICE);
 		if (ret)
 			return ret;
 	}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (4 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16  4:33   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
                   ` (5 subsequent siblings)
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

Currently the i2c error handling in BAM mode is not working
properly in stress condition.

1. After an error, the FIFO are being written with FLUSH and
   EOT tags which should not be required since already these tags
   have been written in BAM descriptor itself.

2. QUP state is being moved to RESET in IRQ handler in case
   of error. When QUP HW encounters an error in BAM mode then it
   moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH
   command needs to be executed while moving to RUN_STATE by writing
   to the QUP_STATE register with the I2C_FLUSH bit set to 1.

3. In Error case, sometimes, QUP generates more than one
   interrupt which will trigger the complete again. After an error,
   the flush operation will be scheduled after doing
   reinit_completion which should be triggered by BAM IRQ callback.
   If the second QUP IRQ comes during this time then it will call
   the complete and the transfer function will assume the all the
   BAM HW descriptors have been completed.

4. The release DMA is being called after each error which
   will free the DMA tx and rx channels. The error like NACK is very
   common in I2C transfer and every time this will be overhead. Now,
   since the error handling is proper so this release channel can be
   completely avoided.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 094be6a..6227a5c 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -228,9 +228,24 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 	if (bus_err)
 		writel(bus_err, qup->base + QUP_I2C_STATUS);
 
+	/*
+	 * Check for BAM mode and returns if already error has come for current
+	 * transfer. In Error case, sometimes, QUP generates more than one
+	 * interrupt.
+	 */
+	if (qup->use_dma && (qup->qup_err || qup->bus_err))
+		return IRQ_HANDLED;
+
 	/* Reset the QUP State in case of error */
 	if (qup_err || bus_err) {
-		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+		/*
+		 * Don’t reset the QUP state in case of BAM mode. The BAM
+		 * flush operation needs to be scheduled in transfer function
+		 * which will clear the remaining schedule descriptors in BAM
+		 * HW FIFO and generates the BAM interrupt.
+		 */
+		if (!qup->use_dma)
+			writel(QUP_RESET_STATE, qup->base + QUP_STATE);
 		goto done;
 	}
 
@@ -841,20 +856,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 			goto desc_err;
 		}
 
-		if (rx_buf)
-			writel(QUP_BAM_INPUT_EOT,
-			       qup->base + QUP_OUT_FIFO_BASE);
-
-		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
-
 		qup_i2c_flush(qup);
 
 		/* wait for remaining interrupts to occur */
 		if (!wait_for_completion_timeout(&qup->xfer, HZ))
 			dev_err(qup->dev, "flush timed out\n");
 
-		qup_i2c_rel_dma(qup);
-
 		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
 	}
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (5 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16  4:35   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 08/12] i2c: qup: change completion timeout according to transfer length Abhishek Sahu
                   ` (4 subsequent siblings)
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

Currently each message length in complete transfer is being
checked for determining DMA mode and if any of the message length
is less than FIFO length then non DMA mode is being used which
will increase overhead. DMA can be used for any length and it
should be determined with complete transfer length. Now, this
patch introduces DMA threshold length and the transfer will be
done in DMA mode if the total length is greater than this
threshold length.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 6227a5c..a91fc70 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -192,6 +192,8 @@ struct qup_i2c_dev {
 	bool			is_dma;
 	/* To check if the current transfer is using DMA */
 	bool			use_dma;
+	/* The threshold length above which DMA will be used */
+	unsigned int		dma_threshold;
 	struct			dma_pool *dpool;
 	struct			qup_i2c_tag start_tag;
 	struct			qup_i2c_bam brx;
@@ -1294,7 +1296,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, len, idx = 0;
+	int ret, idx = 0;
+	unsigned int total_len = 0;
 
 	qup->bus_err = 0;
 	qup->qup_err = 0;
@@ -1320,14 +1323,13 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 				goto out;
 			}
 
-			len = (msgs[idx].len > qup->out_fifo_sz) ||
-			      (msgs[idx].len > qup->in_fifo_sz);
-
-			if (is_vmalloc_addr(msgs[idx].buf) || !len)
+			if (is_vmalloc_addr(msgs[idx].buf))
 				break;
+
+			total_len += msgs[idx].len;
 		}
 
-		if (idx == num)
+		if (idx == num && total_len > qup->dma_threshold)
 			qup->use_dma = true;
 	}
 
@@ -1587,6 +1589,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	size = QUP_INPUT_FIFO_SIZE(io_mode);
 	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
+	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
 
 	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
 	hs_div = 3;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 08/12] i2c: qup: change completion timeout according to transfer length
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (6 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16  4:48   ` Sricharan R
  2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

Currently the completion timeout is being taken according to
maximum transfer length which is too high if SCL is operating in
high frequency. This patch calculates timeout on the basis of
one-byte transfer time and uses the same for completion timeout.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a91fc70..6df65ea 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -130,8 +130,8 @@
 #define MX_TX_RX_LEN			SZ_64K
 #define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
 
-/* Max timeout in ms for 32k bytes */
-#define TOUT_MAX			300
+/* Min timeout for i2c transfers */
+#define TOUT_MIN			2
 
 /* Default values. Use these if FW query fails */
 #define DEFAULT_CLK_FREQ 100000
@@ -172,6 +172,7 @@ struct qup_i2c_dev {
 	int			in_blk_sz;
 
 	unsigned long		one_byte_t;
+	unsigned long		xfer_timeout;
 	struct qup_i2c_block	blk;
 
 	struct i2c_msg		*msg;
@@ -845,7 +846,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 		dma_async_issue_pending(qup->brx.dma);
 	}
 
-	if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
+	if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
 		dev_err(qup->dev, "normal trans timed out\n");
 		ret = -ETIMEDOUT;
 	}
@@ -1601,6 +1602,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	 */
 	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
 	qup->one_byte_t = one_bit_t * 9;
+	qup->xfer_timeout = TOUT_MIN * HZ +
+			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
 
 	dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
 		qup->in_blk_sz, qup->in_fifo_sz,
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (7 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 08/12] i2c: qup: change completion timeout according to transfer length Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16  5:21   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
                   ` (2 subsequent siblings)
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

The BAM mode requires buffer for start tag data and tx, rx SG
list. Currently, this is being taken for maximum transfer length
(65K). But an I2C transfer can have multiple messages and each
message can be of this maximum length so the buffer overflow will
happen in this case. Since increasing buffer length won’t be
feasible since an I2C transfer can contain any number of messages
so this patch does following changes to make i2c transfers working
for multiple messages case.

1. Calculate the required buffers for 2 maximum length messages
   (65K * 2).
2. Split the descriptor formation and descriptor scheduling.
   The idea is to fit as many messages in one DMA transfers for 65K
   threshold value (max_xfer_sg_len). Whenever the sg_cnt is
   crossing this, then schedule the BAM transfer and subsequent
   transfer will again start from zero.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 199 +++++++++++++++++++++++++------------------
 1 file changed, 118 insertions(+), 81 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 6df65ea..ba717bb 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -155,6 +155,7 @@ struct qup_i2c_bam {
 	struct	qup_i2c_tag tag;
 	struct	dma_chan *dma;
 	struct	scatterlist *sg;
+	unsigned int sg_cnt;
 };
 
 struct qup_i2c_dev {
@@ -195,6 +196,8 @@ struct qup_i2c_dev {
 	bool			use_dma;
 	/* The threshold length above which DMA will be used */
 	unsigned int		dma_threshold;
+	unsigned int		max_xfer_sg_len;
+	unsigned int		tag_buf_pos;
 	struct			dma_pool *dpool;
 	struct			qup_i2c_tag start_tag;
 	struct			qup_i2c_bam brx;
@@ -699,86 +702,86 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
 	return 0;
 }
 
-static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
-			       int num)
+static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0, limit = QUP_READ_LIMIT;
+	u32 len = 0, blocks, rem;
+	u32 i = 0, tlen, tx_len = 0;
+	u8 *tags;
+
+	qup_i2c_set_blk_data(qup, msg);
+
+	blocks = qup->blk.count;
+	rem = msg->len - (blocks - 1) * limit;
+
+	if (msg->flags & I2C_M_RD) {
+		while (qup->blk.pos < blocks) {
+			tlen = (i == (blocks - 1)) ? rem : limit;
+			tags = &qup->start_tag.start[qup->tag_buf_pos + len];
+			len += qup_i2c_set_tags(tags, qup, msg);
+			qup->blk.data_len -= tlen;
+
+			/* scratch buf to read the start and len tags */
+			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
+					     &qup->brx.tag.start[0],
+					     2, qup, DMA_FROM_DEVICE);
+
+			if (ret)
+				return ret;
+
+			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
+					     &msg->buf[limit * i],
+					     tlen, qup,
+					     DMA_FROM_DEVICE);
+			if (ret)
+				return ret;
+
+			i++;
+			qup->blk.pos = i;
+		}
+		ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+				     &qup->start_tag.start[qup->tag_buf_pos],
+				     len, qup, DMA_TO_DEVICE);
+		if (ret)
+			return ret;
+
+		qup->tag_buf_pos += len;
+	} else {
+		while (qup->blk.pos < blocks) {
+			tlen = (i == (blocks - 1)) ? rem : limit;
+			tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len];
+			len = qup_i2c_set_tags(tags, qup, msg);
+			qup->blk.data_len -= tlen;
+
+			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+					     tags, len,
+					     qup, DMA_TO_DEVICE);
+			if (ret)
+				return ret;
+
+			tx_len += len;
+			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
+					     &msg->buf[limit * i],
+					     tlen, qup, DMA_TO_DEVICE);
+			if (ret)
+				return ret;
+			i++;
+			qup->blk.pos = i;
+		}
+
+		qup->tag_buf_pos += tx_len;
+	}
+
+	return 0;
+}
+
+static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
 {
 	struct dma_async_tx_descriptor *txd, *rxd = NULL;
-	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
+	int ret = 0;
 	dma_cookie_t cookie_rx, cookie_tx;
-	u32 len, blocks, rem;
-	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
-	u8 *tags;
-
-	while (idx < num) {
-		tx_len = 0, len = 0, i = 0;
-
-		qup->is_last = (idx == (num - 1));
-
-		qup_i2c_set_blk_data(qup, msg);
-
-		blocks = qup->blk.count;
-		rem = msg->len - (blocks - 1) * limit;
-
-		if (msg->flags & I2C_M_RD) {
-			while (qup->blk.pos < blocks) {
-				tlen = (i == (blocks - 1)) ? rem : limit;
-				tags = &qup->start_tag.start[off + len];
-				len += qup_i2c_set_tags(tags, qup, msg);
-				qup->blk.data_len -= tlen;
-
-				/* scratch buf to read the start and len tags */
-				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
-						     &qup->brx.tag.start[0],
-						     2, qup, DMA_FROM_DEVICE);
-
-				if (ret)
-					return ret;
-
-				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
-						     &msg->buf[limit * i],
-						     tlen, qup,
-						     DMA_FROM_DEVICE);
-				if (ret)
-					return ret;
-
-				i++;
-				qup->blk.pos = i;
-			}
-			ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
-					     &qup->start_tag.start[off],
-					     len, qup, DMA_TO_DEVICE);
-			if (ret)
-				return ret;
-
-			off += len;
-		} else {
-			while (qup->blk.pos < blocks) {
-				tlen = (i == (blocks - 1)) ? rem : limit;
-				tags = &qup->start_tag.start[off + tx_len];
-				len = qup_i2c_set_tags(tags, qup, msg);
-				qup->blk.data_len -= tlen;
-
-				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
-						     tags, len,
-						     qup, DMA_TO_DEVICE);
-				if (ret)
-					return ret;
-
-				tx_len += len;
-				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
-						     &msg->buf[limit * i],
-						     tlen, qup, DMA_TO_DEVICE);
-				if (ret)
-					return ret;
-				i++;
-				qup->blk.pos = i;
-			}
-			off += tx_len;
-
-		}
-		idx++;
-		msg++;
-	}
+	u32 len = 0;
+	u32 tx_buf = qup->btx.sg_cnt, rx_buf = qup->brx.sg_cnt;
 
 	/* schedule the EOT and FLUSH I2C tags */
 	len = 1;
@@ -878,11 +881,19 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
 	return ret;
 }
 
+static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
+{
+	qup->btx.sg_cnt = 0;
+	qup->brx.sg_cnt = 0;
+	qup->tag_buf_pos = 0;
+}
+
 static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
 			    int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret = 0;
+	int idx = 0;
 
 	enable_irq(qup->irq);
 	ret = qup_i2c_req_dma(qup);
@@ -905,9 +916,34 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
 		goto out;
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+	qup_i2c_bam_clear_tag_buffers(qup);
+
+	for (idx = 0; idx < num; idx++) {
+		qup->msg = msg + idx;
+		qup->is_last = idx == (num - 1);
+
+		ret = qup_i2c_bam_make_desc(qup, qup->msg);
+		if (ret)
+			break;
+
+		/*
+		 * Make DMA descriptor and schedule the BAM transfer if its
+		 * already crossed the maximum length. Since the memory for all
+		 * tags buffers have been taken for 2 maximum possible
+		 * transfers length so it will never cross the buffer actual
+		 * length.
+		 */
+		if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
+		    qup->brx.sg_cnt > qup->max_xfer_sg_len ||
+		    qup->is_last) {
+			ret = qup_i2c_bam_schedule_desc(qup);
+			if (ret)
+				break;
+
+			qup_i2c_bam_clear_tag_buffers(qup);
+		}
+	}
 
-	qup->msg = msg;
-	ret = qup_i2c_bam_do_xfer(qup, qup->msg, num);
 out:
 	disable_irq(qup->irq);
 
@@ -1459,7 +1495,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		else if (ret != 0)
 			goto nodma;
 
-		blocks = (MX_BLOCKS << 1) + 1;
+		qup->max_xfer_sg_len = (MX_BLOCKS << 1);
+		blocks = 2 * qup->max_xfer_sg_len + 1;
 		qup->btx.sg = devm_kzalloc(&pdev->dev,
 					   sizeof(*qup->btx.sg) * blocks,
 					   GFP_KERNEL);
@@ -1603,7 +1640,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
 	qup->one_byte_t = one_bit_t * 9;
 	qup->xfer_timeout = TOUT_MIN * HZ +
-			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
+		usecs_to_jiffies(2 * MX_TX_RX_LEN * qup->one_byte_t);
 
 	dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
 		qup->in_blk_sz, qup->in_fifo_sz,
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 10/12] i2c: qup: send NACK for last read sub transfers
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (8 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16  5:39   ` Sricharan R
                     ` (2 more replies)
  2018-02-03  7:58 ` [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 Abhishek Sahu
  2018-02-03  7:58 ` [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2 Abhishek Sahu
  11 siblings, 3 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

According to I2c specification, “If a master-receiver sends a
repeated START condition, it sends a not-acknowledge (A) just
before the repeated START condition”. QUP v2 supports sending
of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
same.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index ba717bb..edea3b9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -113,6 +113,7 @@
 #define QUP_TAG_V2_DATAWR              0x82
 #define QUP_TAG_V2_DATAWR_STOP         0x83
 #define QUP_TAG_V2_DATARD              0x85
+#define QUP_TAG_V2_DATARD_NACK         0x86
 #define QUP_TAG_V2_DATARD_STOP         0x87
 
 /* Status, Error flags */
@@ -609,7 +610,9 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
 			tags[len++] = QUP_TAG_V2_DATAWR_STOP;
 	} else {
 		if (msg->flags & I2C_M_RD)
-			tags[len++] = QUP_TAG_V2_DATARD;
+			tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
+				      QUP_TAG_V2_DATARD_NACK :
+				      QUP_TAG_V2_DATARD;
 		else
 			tags[len++] = QUP_TAG_V2_DATAWR;
 	}
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (9 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-05 23:03     ` kbuild test robot
  2018-02-16  7:44   ` Sricharan R
  2018-02-03  7:58 ` [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2 Abhishek Sahu
  11 siblings, 2 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

Following are the major issues in current driver code

1. The current driver simply assumes the transfer completion
   whenever its gets any non-error interrupts and then simply do the
   polling of available/free bytes in FIFO.
2. The block mode is not working properly since no handling in
   being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ.

Because of above, i2c v1 transfers of size greater than 32 are failing
with following error message

	i2c_qup 78b6000.i2c: timeout for fifo out full

To make block mode working properly and move to use the interrupts
instead of polling, major code reorganization is required. Following
are the major changes done in this patch

1. Remove the polling of TX FIFO free space and RX FIFO available
   bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
   QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
   interrupts to handle FIFO’s properly so check all these interrupts.
2. During write, For FIFO mode, TX FIFO can be directly written
   without checking for FIFO space. For block mode, the QUP will generate
   OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
   space.
3. During read, both TX and RX FIFO will be used. TX will be used
   for writing tags and RX will be used for receiving the data. In QUP,
   TX and RX can operate in separate mode so configure modes accordingly.
4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
   will be generated after all the bytes have been copied in RX FIFO. For
   read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
   whenever it has block size of available data.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 399 ++++++++++++++++++++++++++++---------------
 1 file changed, 257 insertions(+), 142 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index edea3b9..af6c21a 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -73,8 +73,11 @@
 #define QUP_IN_SVC_FLAG		BIT(9)
 #define QUP_MX_OUTPUT_DONE	BIT(10)
 #define QUP_MX_INPUT_DONE	BIT(11)
+#define OUT_BLOCK_WRITE_REQ	BIT(12)
+#define IN_BLOCK_READ_REQ	BIT(13)
 
 /* I2C mini core related values */
+#define QUP_NO_INPUT		BIT(7)
 #define QUP_CLOCK_AUTO_GATE	BIT(13)
 #define I2C_MINI_CORE		(2 << 8)
 #define I2C_N_VAL		15
@@ -138,13 +141,51 @@
 #define DEFAULT_CLK_FREQ 100000
 #define DEFAULT_SRC_CLK 20000000
 
+/* MAX_OUTPUT_DONE_FLAG has been received */
+#define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
+/* MAX_INPUT_DONE_FLAG has been received */
+#define QUP_BLK_EVENT_RX_IRQ_DONE		BIT(1)
+/* All the TX bytes have been written in TX FIFO */
+#define QUP_BLK_EVENT_TX_DATA_DONE		BIT(2)
+/* All the RX bytes have been read from RX FIFO */
+#define QUP_BLK_EVENT_RX_DATA_DONE		BIT(3)
+
+/* All the required events to mark a QUP I2C TX transfer completed */
+#define QUP_BLK_EVENT_TX_DONE		(QUP_BLK_EVENT_TX_IRQ_DONE | \
+					 QUP_BLK_EVENT_TX_DATA_DONE)
+/* All the required events to mark a QUP I2C RX transfer completed */
+#define QUP_BLK_EVENT_RX_DONE		(QUP_BLK_EVENT_TX_DONE | \
+					 QUP_BLK_EVENT_RX_IRQ_DONE | \
+					 QUP_BLK_EVENT_RX_DATA_DONE)
+
+/*
+ * count: no of blocks
+ * pos: current block number
+ * tx_tag_len: tx tag length for current block
+ * rx_tag_len: rx tag length for current block
+ * data_len: remaining data length for current message
+ * total_tx_len: total tx length including tag bytes for current QUP transfer
+ * total_rx_len: total rx length including tag bytes for current QUP transfer
+ * tx_fifo_free: number of free bytes in current QUP block write.
+ * fifo_available: number of available bytes in RX FIFO for current
+ *		   QUP block read
+ * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
+ * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
+ * tags: contains tx tag bytes for current QUP transfer
+ */
 struct qup_i2c_block {
-	int	count;
-	int	pos;
-	int	tx_tag_len;
-	int	rx_tag_len;
-	int	data_len;
-	u8	tags[6];
+	int		count;
+	int		pos;
+	int		tx_tag_len;
+	int		rx_tag_len;
+	int		data_len;
+	int		total_tx_len;
+	int		total_rx_len;
+	int		tx_fifo_free;
+	int		fifo_available;
+	bool		is_tx_blk_mode;
+	bool		is_rx_blk_mode;
+	u8		tags[6];
 };
 
 struct qup_i2c_tag {
@@ -187,6 +228,7 @@ struct qup_i2c_dev {
 
 	/* To check if this is the last msg */
 	bool			is_last;
+	bool			is_qup_v1;
 
 	/* To configure when bus is in run state */
 	int			config_run;
@@ -195,6 +237,10 @@ struct qup_i2c_dev {
 	bool			is_dma;
 	/* To check if the current transfer is using DMA */
 	bool			use_dma;
+	/* Required events to mark QUP transfer as completed */
+	u32			blk_events;
+	/* Already completed events in QUP transfer */
+	u32			cur_blk_events;
 	/* The threshold length above which DMA will be used */
 	unsigned int		dma_threshold;
 	unsigned int		max_xfer_sg_len;
@@ -205,11 +251,18 @@ struct qup_i2c_dev {
 	struct			qup_i2c_bam btx;
 
 	struct completion	xfer;
+	/* function to write data in tx fifo */
+	void (*write_tx_fifo)(struct qup_i2c_dev *qup);
+	/* function to read data from rx fifo */
+	void (*read_rx_fifo)(struct qup_i2c_dev *qup);
+	/* function to write tags in tx fifo for i2c read transfer */
+	void (*write_rx_tags)(struct qup_i2c_dev *qup);
 };
 
 static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 {
 	struct qup_i2c_dev *qup = dev;
+	struct qup_i2c_block *blk = &qup->blk;
 	u32 bus_err;
 	u32 qup_err;
 	u32 opflags;
@@ -256,12 +309,54 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 		goto done;
 	}
 
-	if (opflags & QUP_IN_SVC_FLAG)
-		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+	if (!qup->is_qup_v1)
+		goto done;
 
-	if (opflags & QUP_OUT_SVC_FLAG)
+	if (opflags & QUP_OUT_SVC_FLAG) {
 		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
 
+		/*
+		 * Ideally, would like to check QUP_MAX_OUTPUT_DONE_FLAG.
+		 * However, QUP_MAX_OUTPUT_DONE_FLAG is lagging behind
+		 * QUP_OUTPUT_SERVICE_FLAG. The only reason for
+		 * QUP_OUTPUT_SERVICE_FLAG to be set in FIFO mode is
+		 * QUP_MAX_OUTPUT_DONE_FLAG condition. The code checking
+		 * here QUP_OUTPUT_SERVICE_FLAG and assumes that
+		 * QUP_MAX_OUTPUT_DONE_FLAG.
+		 */
+		if (!blk->is_tx_blk_mode)
+			qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
+
+		if (opflags & OUT_BLOCK_WRITE_REQ) {
+			blk->tx_fifo_free += qup->out_blk_sz;
+			if (qup->msg->flags & I2C_M_RD)
+				qup->write_rx_tags(qup);
+			else
+				qup->write_tx_fifo(qup);
+		}
+	}
+
+	if (opflags & QUP_IN_SVC_FLAG) {
+		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+		if (!blk->is_rx_blk_mode) {
+			blk->fifo_available += qup->in_fifo_sz;
+			qup->read_rx_fifo(qup);
+		} else if (opflags & IN_BLOCK_READ_REQ) {
+			blk->fifo_available += qup->in_blk_sz;
+			qup->read_rx_fifo(qup);
+		}
+	}
+
+	if (opflags & QUP_MX_OUTPUT_DONE)
+		qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
+
+	if (opflags & QUP_MX_INPUT_DONE)
+		qup->cur_blk_events |= QUP_BLK_EVENT_RX_IRQ_DONE;
+
+	if (qup->cur_blk_events != qup->blk_events)
+		return IRQ_HANDLED;
+
 done:
 	qup->qup_err = qup_err;
 	qup->bus_err = bus_err;
@@ -327,6 +422,28 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
 	return 0;
 }
 
+/* Check if I2C bus returns to IDLE state */
+static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
+{
+	unsigned long timeout;
+	u32 status;
+	int ret = 0;
+
+	timeout = jiffies + len * 4;
+	for (;;) {
+		status = readl(qup->base + QUP_I2C_STATUS);
+		if (!(status & I2C_STATUS_BUS_ACTIVE))
+			break;
+
+		if (time_after(jiffies, timeout))
+			ret = -ETIMEDOUT;
+
+		usleep_range(len, len * 2);
+	}
+
+	return ret;
+}
+
 /**
  * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
  * @qup: The qup_i2c_dev device
@@ -397,23 +514,6 @@ static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
 	}
 }
 
-static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	/* Number of entries to shift out, including the start */
-	int total = msg->len + 1;
-
-	if (total < qup->out_fifo_sz) {
-		/* FIFO mode */
-		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_WRITE_CNT);
-	} else {
-		/* BLOCK mode (transfer data on chunks) */
-		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
-		       qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
-	}
-}
-
 static int check_for_fifo_space(struct qup_i2c_dev *qup)
 {
 	int ret;
@@ -446,28 +546,25 @@ static int check_for_fifo_space(struct qup_i2c_dev *qup)
 	return ret;
 }
 
-static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
 {
+	struct qup_i2c_block *blk = &qup->blk;
+	struct i2c_msg *msg = qup->msg;
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
 	int idx;
 	u32 val;
-	int ret = 0;
 
 	if (qup->pos == 0) {
 		val = QUP_TAG_START | addr;
 		idx = 1;
+		blk->tx_fifo_free--;
 	} else {
 		val = 0;
 		idx = 0;
 	}
 
-	while (qup->pos < msg->len) {
-		/* Check that there's space in the FIFO for our pair */
-		ret = check_for_fifo_space(qup);
-		if (ret)
-			return ret;
-
+	while (blk->tx_fifo_free && qup->pos < msg->len) {
 		if (qup->pos == msg->len - 1)
 			qup_tag = QUP_TAG_STOP;
 		else
@@ -484,11 +581,11 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 		qup->pos++;
 		idx++;
+		blk->tx_fifo_free--;
 	}
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-
-	return ret;
+	if (qup->pos == msg->len)
+		qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
 }
 
 static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
@@ -1009,64 +1106,6 @@ static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	int ret;
-
-	qup->msg = msg;
-	qup->pos = 0;
-
-	enable_irq(qup->irq);
-
-	qup_i2c_set_write_mode(qup, msg);
-
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
-
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
-
-	do {
-		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_issue_write(qup, msg);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_wait_for_complete(qup, msg);
-		if (ret)
-			goto err;
-	} while (qup->pos < msg->len);
-
-	/* Wait for the outstanding data in the fifo to drain */
-	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
-err:
-	disable_irq(qup->irq);
-	qup->msg = NULL;
-
-	return ret;
-}
-
-static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
-{
-	if (len < qup->in_fifo_sz) {
-		/* FIFO mode */
-		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_READ_CNT);
-	} else {
-		/* BLOCK mode (transfer data on chunks) */
-		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
-		       qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_INPUT_CNT);
-	}
-}
-
 static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
 {
 	int tx_len = qup->blk.tx_tag_len;
@@ -1089,44 +1128,27 @@ static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
 	}
 }
 
-static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	u32 addr, len, val;
-
-	addr = i2c_8bit_addr_from_msg(msg);
-
-	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
-	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
-
-	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
-	writel(val, qup->base + QUP_OUT_FIFO_BASE);
-}
-
-
-static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
 {
+	struct qup_i2c_block *blk = &qup->blk;
+	struct i2c_msg *msg = qup->msg;
 	u32 val = 0;
 	int idx;
-	int ret = 0;
 
-	for (idx = 0; qup->pos < msg->len; idx++) {
+	while (blk->fifo_available && qup->pos < msg->len) {
 		if ((idx & 1) == 0) {
-			/* Check that FIFO have data */
-			ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
-						 SET_BIT, 4 * ONE_BYTE);
-			if (ret)
-				return ret;
-
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
-
 			msg->buf[qup->pos++] = val & 0xFF;
 		} else {
 			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
 		}
+		idx++;
+		blk->fifo_available--;
 	}
 
-	return ret;
+	if (qup->pos == msg->len)
+		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
 }
 
 static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
@@ -1227,49 +1249,137 @@ static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool is_rx)
 {
+	qup->cur_blk_events = 0;
+	qup->blk_events = is_rx ? QUP_BLK_EVENT_RX_DONE : QUP_BLK_EVENT_TX_DONE;
+}
+
+static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup)
+{
+	struct i2c_msg *msg = qup->msg;
+	u32 addr, len, val;
+
+	addr = i2c_8bit_addr_from_msg(msg);
+
+	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
+	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
+
+	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+	writel(val, qup->base + QUP_OUT_FIFO_BASE);
+	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
+}
+
+static void qup_i2c_conf_v1(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL;
+	u32 io_mode = QUP_REPACK_EN;
+
+	blk->is_tx_blk_mode =
+		blk->total_tx_len > qup->out_fifo_sz ? true : false;
+	blk->is_rx_blk_mode =
+		blk->total_rx_len > qup->in_fifo_sz ? true : false;
+
+	if (blk->is_tx_blk_mode) {
+		io_mode |= QUP_OUTPUT_BLK_MODE;
+		writel(0, qup->base + QUP_MX_WRITE_CNT);
+		writel(blk->total_tx_len, qup->base + QUP_MX_OUTPUT_CNT);
+	} else {
+		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(blk->total_tx_len, qup->base + QUP_MX_WRITE_CNT);
+	}
+
+	if (blk->total_rx_len) {
+		if (blk->is_rx_blk_mode) {
+			io_mode |= QUP_INPUT_BLK_MODE;
+			writel(0, qup->base + QUP_MX_READ_CNT);
+			writel(blk->total_rx_len, qup->base + QUP_MX_INPUT_CNT);
+		} else {
+			writel(0, qup->base + QUP_MX_INPUT_CNT);
+			writel(blk->total_rx_len, qup->base + QUP_MX_READ_CNT);
+		}
+	} else {
+		qup_config |= QUP_NO_INPUT;
+	}
+
+	writel(qup_config, qup->base + QUP_CONFIG);
+	writel(io_mode, qup->base + QUP_IO_MODE);
+}
+
+static void qup_i2c_clear_blk_v1(struct qup_i2c_block *blk)
+{
+	blk->tx_fifo_free = 0;
+	blk->fifo_available = 0;
+}
+
+static int qup_i2c_conf_xfer_v1(struct qup_i2c_dev *qup, bool is_rx)
+{
+	struct qup_i2c_block *blk = &qup->blk;
 	int ret;
 
-	qup->msg = msg;
-	qup->pos  = 0;
-
-	enable_irq(qup->irq);
-	qup_i2c_set_read_mode(qup, msg->len);
-
+	qup_i2c_clear_blk_v1(blk);
+	qup_i2c_conf_v1(qup);
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
-		goto err;
+		return ret;
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
 	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
 	if (ret)
-		goto err;
+		return ret;
 
-	qup_i2c_issue_read(qup, msg);
+	qup_i2c_set_blk_event(qup, is_rx);
+	reinit_completion(&qup->xfer);
+	enable_irq(qup->irq);
+	if (!blk->is_tx_blk_mode) {
+		blk->tx_fifo_free = qup->out_fifo_sz;
+
+		if (is_rx)
+			qup_i2c_write_rx_tags_v1(qup);
+		else
+			qup_i2c_write_tx_fifo_v1(qup);
+	}
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
 		goto err;
 
-	do {
-		ret = qup_i2c_wait_for_complete(qup, msg);
-		if (ret)
-			goto err;
+	ret = qup_i2c_wait_for_complete(qup, qup->msg);
+	if (ret)
+		goto err;
 
-		ret = qup_i2c_read_fifo(qup, msg);
-		if (ret)
-			goto err;
-	} while (qup->pos < msg->len);
+	ret = qup_i2c_bus_active(qup, ONE_BYTE);
 
 err:
 	disable_irq(qup->irq);
-	qup->msg = NULL;
-
 	return ret;
 }
 
+static int qup_i2c_write_one(struct qup_i2c_dev *qup)
+{
+	struct i2c_msg *msg = qup->msg;
+	struct qup_i2c_block *blk = &qup->blk;
+
+	qup->pos = 0;
+	blk->total_tx_len = msg->len +  1;
+	blk->total_rx_len = 0;
+
+	return qup_i2c_conf_xfer_v1(qup, false);
+}
+
+static int qup_i2c_read_one(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+
+	qup->pos = 0;
+	blk->total_tx_len = 2;
+	blk->total_rx_len = qup->msg->len;
+
+	return qup_i2c_conf_xfer_v1(qup, true);
+}
+
 static int qup_i2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
@@ -1308,10 +1418,11 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			goto out;
 		}
 
+		qup->msg = &msgs[idx];
 		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
+			ret = qup_i2c_read_one(qup);
 		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+			ret = qup_i2c_write_one(qup);
 
 		if (ret)
 			break;
@@ -1489,6 +1600,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
 		qup->adap.algo = &qup_i2c_algo;
 		qup->adap.quirks = &qup_i2c_quirks;
+		qup->is_qup_v1 = true;
+		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
+		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
+		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
 	} else {
 		qup->adap.algo = &qup_i2c_algo_v2;
 		ret = qup_i2c_req_dma(qup);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2
  2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
                   ` (10 preceding siblings ...)
  2018-02-03  7:58 ` [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 Abhishek Sahu
@ 2018-02-03  7:58 ` Abhishek Sahu
  2018-02-16 11:23   ` Sricharan R
  2018-02-27 23:24   ` Christ, Austin
  11 siblings, 2 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-03  7:58 UTC (permalink / raw)
  To: Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel, Abhishek Sahu

Following are the major issues in current driver code

1. The current driver simply assumes the transfer completion
   whenever its gets any non-error interrupts and then simply do the
   polling of available/free bytes in FIFO.
2. The block mode is not working properly since no handling in
   being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_READ.
3. An i2c transfer can contain multiple message and QUP v2
   supports reconfiguration during run in which the mode should be same
   for all the sub transfer. Currently the mode is being programmed
   before every sub transfer which is functionally wrong. If one message
   is less than FIFO length and other message is greater than FIFO
   length, then transfers will fail.

Because of above, i2c v2 transfers of size greater than 64 are failing
with following error message

	i2c_qup 78b6000.i2c: timeout for fifo out full

To make block mode working properly and move to use the interrupts
instead of polling, major code reorganization is required. Following
are the major changes done in this patch

1. Remove the polling of TX FIFO free space and RX FIFO available
   bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
   QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
   interrupts to handle FIFO’s properly so check all these interrupts.
2. Determine the mode for transfer before starting by checking
   all the tx/rx data length in each message. The complete message can be
   transferred either in DMA mode or Programmed IO by FIFO/Block mode.
   in DMA mode, both tx and rx uses same mode but in PIO mode, the TX and
   RX can be in different mode.
3. During write, For FIFO mode, TX FIFO can be directly written
   without checking for FIFO space. For block mode, the QUP will generate
   OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
   space.
4. During read, both TX and RX FIFO will be used. TX will be used
   for writing tags and RX will be used for receiving the data. In QUP,
   TX and RX can operate in separate mode so configure modes accordingly.
5. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
   will be generated after all the bytes have been copied in RX FIFO. For
   read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
   whenever it has block size of available data.
6. Split the transfer in chunk of one QUP block size(256 bytes)
   and schedule each block separately. QUP v2 supports reconfiguration
   during run in which QUP can transfer multiple blocks without issuing a
   stop events.
7. Port the SMBus block read support for new code changes.

Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 917 +++++++++++++++++++++++++------------------
 1 file changed, 533 insertions(+), 384 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index af6c21a..46736a1 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -141,6 +141,15 @@
 #define DEFAULT_CLK_FREQ 100000
 #define DEFAULT_SRC_CLK 20000000
 
+/*
+ * Max tags length (start, stop and maximum 2 bytes address) for each QUP
+ * data transfer
+ */
+#define QUP_MAX_TAGS_LEN		4
+/* Max data length for each DATARD tags */
+#define RECV_MAX_DATA_LEN		254
+/* TAG length for DATA READ in RX FIFO  */
+#define READ_RX_TAGS_LEN		2
 /* MAX_OUTPUT_DONE_FLAG has been received */
 #define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
 /* MAX_INPUT_DONE_FLAG has been received */
@@ -164,11 +173,24 @@
  * tx_tag_len: tx tag length for current block
  * rx_tag_len: rx tag length for current block
  * data_len: remaining data length for current message
+ * cur_blk_len: data length for current block
  * total_tx_len: total tx length including tag bytes for current QUP transfer
  * total_rx_len: total rx length including tag bytes for current QUP transfer
+ * tx_fifo_data_pos: current byte number in TX FIFO word
  * tx_fifo_free: number of free bytes in current QUP block write.
+ * rx_fifo_data_pos: current byte number in RX FIFO word
  * fifo_available: number of available bytes in RX FIFO for current
  *		   QUP block read
+ * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write
+ *		 to TX FIFO will be appended in this data and will be written to
+ *		 TX FIFO when all the 4 bytes are available.
+ * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will
+ *		 contains the 4 bytes of RX data.
+ * cur_data: pointer to tell cur data position for current message
+ * cur_tx_tags: pointer to tell cur position in tags
+ * tx_tags_sent: all tx tag bytes have been written in FIFO word
+ * send_last_word: for tx FIFO, last word send is pending in current block
+ * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word
  * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
  * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
  * tags: contains tx tag bytes for current QUP transfer
@@ -179,10 +201,20 @@ struct qup_i2c_block {
 	int		tx_tag_len;
 	int		rx_tag_len;
 	int		data_len;
+	int		cur_blk_len;
 	int		total_tx_len;
 	int		total_rx_len;
+	int		tx_fifo_data_pos;
 	int		tx_fifo_free;
+	int		rx_fifo_data_pos;
 	int		fifo_available;
+	u32		tx_fifo_data;
+	u32		rx_fifo_data;
+	u8		*cur_data;
+	u8		*cur_tx_tags;
+	bool		tx_tags_sent;
+	bool		send_last_word;
+	bool		rx_tags_fetched;
 	bool		is_tx_blk_mode;
 	bool		is_rx_blk_mode;
 	u8		tags[6];
@@ -214,6 +246,7 @@ struct qup_i2c_dev {
 	int			out_blk_sz;
 	int			in_blk_sz;
 
+	int			blk_xfer_limit;
 	unsigned long		one_byte_t;
 	unsigned long		xfer_timeout;
 	struct qup_i2c_block	blk;
@@ -228,10 +261,10 @@ struct qup_i2c_dev {
 
 	/* To check if this is the last msg */
 	bool			is_last;
-	bool			is_qup_v1;
+	bool			is_smbus_read;
 
 	/* To configure when bus is in run state */
-	int			config_run;
+	u32			config_run;
 
 	/* dma parameters */
 	bool			is_dma;
@@ -245,6 +278,8 @@ struct qup_i2c_dev {
 	unsigned int		dma_threshold;
 	unsigned int		max_xfer_sg_len;
 	unsigned int		tag_buf_pos;
+	/* The threshold length above which block mode will be used */
+	unsigned int		blk_mode_threshold;
 	struct			dma_pool *dpool;
 	struct			qup_i2c_tag start_tag;
 	struct			qup_i2c_bam brx;
@@ -309,9 +344,6 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 		goto done;
 	}
 
-	if (!qup->is_qup_v1)
-		goto done;
-
 	if (opflags & QUP_OUT_SVC_FLAG) {
 		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
 
@@ -444,108 +476,6 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
 	return ret;
 }
 
-/**
- * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
- * @qup: The qup_i2c_dev device
- * @op: The bit/event to wait on
- * @val: value of the bit to wait on, 0 or 1
- * @len: The length the bytes to be transferred
- */
-static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
-			      int len)
-{
-	unsigned long timeout;
-	u32 opflags;
-	u32 status;
-	u32 shift = __ffs(op);
-	int ret = 0;
-
-	len *= qup->one_byte_t;
-	/* timeout after a wait of twice the max time */
-	timeout = jiffies + len * 4;
-
-	for (;;) {
-		opflags = readl(qup->base + QUP_OPERATIONAL);
-		status = readl(qup->base + QUP_I2C_STATUS);
-
-		if (((opflags & op) >> shift) == val) {
-			if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
-				if (!(status & I2C_STATUS_BUS_ACTIVE)) {
-					ret = 0;
-					goto done;
-				}
-			} else {
-				ret = 0;
-				goto done;
-			}
-		}
-
-		if (time_after(jiffies, timeout)) {
-			ret = -ETIMEDOUT;
-			goto done;
-		}
-		usleep_range(len, len * 2);
-	}
-
-done:
-	if (qup->bus_err || qup->qup_err)
-		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
-
-	return ret;
-}
-
-static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
-				      struct i2c_msg *msg)
-{
-	/* Number of entries to shift out, including the tags */
-	int total = msg->len + qup->blk.tx_tag_len;
-
-	total |= qup->config_run;
-
-	if (total < qup->out_fifo_sz) {
-		/* FIFO mode */
-		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_WRITE_CNT);
-	} else {
-		/* BLOCK mode (transfer data on chunks) */
-		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
-		       qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
-	}
-}
-
-static int check_for_fifo_space(struct qup_i2c_dev *qup)
-{
-	int ret;
-
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto out;
-
-	ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
-				 RESET_BIT, 4 * ONE_BYTE);
-	if (ret) {
-		/* Fifo is full. Drain out the fifo */
-		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-		if (ret)
-			goto out;
-
-		ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY,
-					 RESET_BIT, 256 * ONE_BYTE);
-		if (ret) {
-			dev_err(qup->dev, "timeout for fifo out full");
-			goto out;
-		}
-
-		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-		if (ret)
-			goto out;
-	}
-
-out:
-	return ret;
-}
-
 static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
 {
 	struct qup_i2c_block *blk = &qup->blk;
@@ -591,60 +521,17 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
 static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg)
 {
-	memset(&qup->blk, 0, sizeof(qup->blk));
-
+	qup->blk.pos = 0;
 	qup->blk.data_len = msg->len;
-	qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
-
-	/* 4 bytes for first block and 2 writes for rest */
-	qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
-
-	/* There are 2 tag bytes that are read in to fifo for every block */
-	if (msg->flags & I2C_M_RD)
-		qup->blk.rx_tag_len = qup->blk.count * 2;
-}
-
-static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
-			     int dlen, u8 *dbuf)
-{
-	u32 val = 0, idx = 0, pos = 0, i = 0, t;
-	int  len = tlen + dlen;
-	u8 *buf = tbuf;
-	int ret = 0;
-
-	while (len > 0) {
-		ret = check_for_fifo_space(qup);
-		if (ret)
-			return ret;
-
-		t = (len >= 4) ? 4 : len;
-
-		while (idx < t) {
-			if (!i && (pos >= tlen)) {
-				buf = dbuf;
-				pos = 0;
-				i = 1;
-			}
-			val |= buf[pos++] << (idx++ * 8);
-		}
-
-		writel(val, qup->base + QUP_OUT_FIFO_BASE);
-		idx  = 0;
-		val = 0;
-		len -= 4;
-	}
-
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-
-	return ret;
+	qup->blk.count = DIV_ROUND_UP(msg->len, qup->blk_xfer_limit);
 }
 
 static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
 {
 	int data_len;
 
-	if (qup->blk.data_len > QUP_READ_LIMIT)
-		data_len = QUP_READ_LIMIT;
+	if (qup->blk.data_len > qup->blk_xfer_limit)
+		data_len = qup->blk_xfer_limit;
 	else
 		data_len = qup->blk.data_len;
 
@@ -661,9 +548,9 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
 {
 	int len = 0;
 
-	if (msg->len > 1) {
+	if (qup->is_smbus_read) {
 		tags[len++] = QUP_TAG_V2_DATARD_STOP;
-		tags[len++] = qup_i2c_get_data_len(qup) - 1;
+		tags[len++] = qup_i2c_get_data_len(qup);
 	} else {
 		tags[len++] = QUP_TAG_V2_START;
 		tags[len++] = addr & 0xff;
@@ -725,24 +612,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
 	return len;
 }
 
-static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	int data_len = 0, tag_len, index;
-	int ret;
-
-	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
-	index = msg->len - qup->blk.data_len;
-
-	/* only tags are written for read */
-	if (!(msg->flags & I2C_M_RD))
-		data_len = qup_i2c_get_data_len(qup);
-
-	ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
-				data_len, &msg->buf[index]);
-	qup->blk.data_len -= data_len;
-
-	return ret;
-}
 
 static void qup_i2c_bam_cb(void *data)
 {
@@ -809,6 +678,7 @@ static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	u32 i = 0, tlen, tx_len = 0;
 	u8 *tags;
 
+	qup->blk_xfer_limit = QUP_READ_LIMIT;
 	qup_i2c_set_blk_data(qup, msg);
 
 	blocks = qup->blk.count;
@@ -1057,7 +927,7 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 	unsigned long left;
 	int ret = 0;
 
-	left = wait_for_completion_timeout(&qup->xfer, HZ);
+	left = wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout);
 	if (!left) {
 		writel(1, qup->base + QUP_SW_RESET);
 		ret = -ETIMEDOUT;
@@ -1069,65 +939,6 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 	return ret;
 }
 
-static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	int ret = 0;
-
-	qup->msg = msg;
-	qup->pos = 0;
-	enable_irq(qup->irq);
-	qup_i2c_set_blk_data(qup, msg);
-	qup_i2c_set_write_mode_v2(qup, msg);
-
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
-
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
-
-	do {
-		ret = qup_i2c_issue_xfer_v2(qup, msg);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_wait_for_complete(qup, msg);
-		if (ret)
-			goto err;
-
-		qup->blk.pos++;
-	} while (qup->blk.pos < qup->blk.count);
-
-	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
-
-err:
-	disable_irq(qup->irq);
-	qup->msg = NULL;
-
-	return ret;
-}
-
-static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
-{
-	int tx_len = qup->blk.tx_tag_len;
-
-	len += qup->blk.rx_tag_len;
-	len |= qup->config_run;
-	tx_len |= qup->config_run;
-
-	if (len < qup->in_fifo_sz) {
-		/* FIFO mode */
-		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
-		writel(len, qup->base + QUP_MX_READ_CNT);
-	} else {
-		/* BLOCK mode (transfer data on chunks) */
-		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
-		       qup->base + QUP_IO_MODE);
-		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
-		writel(len, qup->base + QUP_MX_INPUT_CNT);
-	}
-}
-
 static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
 {
 	struct qup_i2c_block *blk = &qup->blk;
@@ -1151,104 +962,6 @@ static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
 		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
 }
 
-static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
-				struct i2c_msg *msg)
-{
-	u32 val;
-	int idx, pos = 0, ret = 0, total, msg_offset = 0;
-
-	/*
-	 * If the message length is already read in
-	 * the first byte of the buffer, account for
-	 * that by setting the offset
-	 */
-	if (qup_i2c_check_msg_len(msg) && (msg->len > 1))
-		msg_offset = 1;
-	total = qup_i2c_get_data_len(qup);
-	total -= msg_offset;
-
-	/* 2 extra bytes for read tags */
-	while (pos < (total + 2)) {
-		/* Check that FIFO have data */
-		ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
-					 SET_BIT, 4 * ONE_BYTE);
-		if (ret) {
-			dev_err(qup->dev, "timeout for fifo not empty");
-			return ret;
-		}
-		val = readl(qup->base + QUP_IN_FIFO_BASE);
-
-		for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
-			/* first 2 bytes are tag bytes */
-			if (pos < 2)
-				continue;
-
-			if (pos >= (total + 2))
-				goto out;
-			msg->buf[qup->pos + msg_offset] = val & 0xff;
-			qup->pos++;
-		}
-	}
-
-out:
-	qup->blk.data_len -= total;
-
-	return ret;
-}
-
-static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
-{
-	int ret = 0;
-
-	qup->msg = msg;
-	qup->pos  = 0;
-	enable_irq(qup->irq);
-	qup_i2c_set_blk_data(qup, msg);
-	qup_i2c_set_read_mode_v2(qup, msg->len);
-
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
-
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
-
-	do {
-		ret = qup_i2c_issue_xfer_v2(qup, msg);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_wait_for_complete(qup, msg);
-		if (ret)
-			goto err;
-
-		ret = qup_i2c_read_fifo_v2(qup, msg);
-		if (ret)
-			goto err;
-
-		qup->blk.pos++;
-
-		/* Handle SMBus block read length */
-		if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) {
-			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) {
-				ret = -EPROTO;
-				goto err;
-			}
-			msg->len += msg->buf[0];
-			qup->pos = 0;
-			qup_i2c_set_blk_data(qup, msg);
-			/* set tag length for block read */
-			qup->blk.tx_tag_len = 2;
-			qup_i2c_set_read_mode_v2(qup, msg->buf[0]);
-		}
-	} while (qup->blk.pos < qup->blk.count);
-
-err:
-	disable_irq(qup->irq);
-	qup->msg = NULL;
-
-	return ret;
-}
-
 static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool is_rx)
 {
 	qup->cur_blk_events = 0;
@@ -1442,13 +1155,452 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 	return ret;
 }
 
+/*
+ * Function to configure registers related with reconfiguration during run
+ * and will be done before each I2C sub transfer.
+ */
+static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2;
+
+	if (blk->is_tx_blk_mode)
+		writel(qup->config_run | blk->total_tx_len,
+		       qup->base + QUP_MX_OUTPUT_CNT);
+	else
+		writel(qup->config_run | blk->total_tx_len,
+		       qup->base + QUP_MX_WRITE_CNT);
+
+	if (blk->total_rx_len) {
+		if (blk->is_rx_blk_mode)
+			writel(qup->config_run | blk->total_rx_len,
+			       qup->base + QUP_MX_INPUT_CNT);
+		else
+			writel(qup->config_run | blk->total_rx_len,
+			       qup->base + QUP_MX_READ_CNT);
+	} else {
+		qup_config |= QUP_NO_INPUT;
+	}
+
+	writel(qup_config, qup->base + QUP_CONFIG);
+}
+
+/*
+ * Function to configure registers related with transfer mode (FIFO/Block)
+ * before starting of i2c transfer and will be done only once in QUP RESET
+ * state.
+ */
+static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	u32 io_mode = QUP_REPACK_EN;
+
+	if (blk->is_tx_blk_mode) {
+		io_mode |= QUP_OUTPUT_BLK_MODE;
+		writel(0, qup->base + QUP_MX_WRITE_CNT);
+	} else {
+		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+	}
+
+	if (blk->is_rx_blk_mode) {
+		io_mode |= QUP_INPUT_BLK_MODE;
+		writel(0, qup->base + QUP_MX_READ_CNT);
+	} else {
+		writel(0, qup->base + QUP_MX_INPUT_CNT);
+	}
+
+	writel(io_mode, qup->base + QUP_IO_MODE);
+}
+
+/*
+ * Function to clear required variables before starting of any QUP v2
+ * sub transfer
+ */
+static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk)
+{
+	blk->send_last_word = false;
+	blk->tx_tags_sent = false;
+	blk->tx_fifo_data = 0;
+	blk->tx_fifo_data_pos = 0;
+	blk->tx_fifo_free = 0;
+
+	blk->rx_tags_fetched = false;
+	blk->rx_fifo_data = 0;
+	blk->rx_fifo_data_pos = 0;
+	blk->fifo_available = 0;
+}
+
+/*
+ * Function to receive data from RX FIFO for read message in QUP v2
+ * i2c transfer.
+ */
+static void qup_i2c_recv_data(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	int j;
+
+	for (j = blk->rx_fifo_data_pos;
+	     blk->cur_blk_len && blk->fifo_available;
+	     blk->cur_blk_len--, blk->fifo_available--) {
+		if (j == 0)
+			blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
+
+		*(blk->cur_data++) = blk->rx_fifo_data;
+		blk->rx_fifo_data >>= 8;
+
+		if (j == 3)
+			j = 0;
+		else
+			j++;
+	}
+
+	blk->rx_fifo_data_pos = j;
+}
+
+/* Function to receive tags for read message in QUP v2 i2c transfer. */
+static void qup_i2c_recv_tags(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+
+	blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
+	blk->rx_fifo_data >>= blk->rx_tag_len  * 8;
+	blk->rx_fifo_data_pos = blk->rx_tag_len;
+	blk->fifo_available -= blk->rx_tag_len;
+}
+
+/*
+ * This function reads the data and tags from RX FIFO. Since in read case, the
+ * tags will be preceded by received data bytes need to be written so
+ * 1. Check if rx_tags_fetched is false i.e. the start of QUP block so receive
+ *    all tag bytes and discard that.
+ * 2. Read the data from RX FIFO. When all the data bytes have been read then
+ *    mark the QUP_BLK_EVENT_RX_DATA_DONE in current block event and return.
+ */
+static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+
+	if (!blk->rx_tags_fetched) {
+		qup_i2c_recv_tags(qup);
+		blk->rx_tags_fetched = true;
+	}
+
+	qup_i2c_recv_data(qup);
+	if (!blk->cur_blk_len)
+		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
+}
+
+/*
+ * Function to write bytes in TX FIFO for write message in QUP v2 i2c
+ * transfer. QUP TX FIFO write works on word basis (4 bytes). New byte write to
+ * TX FIFO will be appended in this data tx_fifo_data and will be written to TX
+ * FIFO when all the 4 bytes are available.
+ */
+static void
+qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned int *len)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	unsigned int j;
+
+	for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free;
+	     (*len)--, blk->tx_fifo_free--) {
+		blk->tx_fifo_data |= *(*data)++ << (j * 8);
+		if (j == 3) {
+			writel(blk->tx_fifo_data,
+			       qup->base + QUP_OUT_FIFO_BASE);
+			blk->tx_fifo_data = 0x0;
+			j = 0;
+		} else {
+			j++;
+		}
+	}
+
+	blk->tx_fifo_data_pos = j;
+}
+
+/* Function to transfer tags for read message in QUP v2 i2c transfer. */
+static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+
+	qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len);
+	if (blk->tx_fifo_data_pos)
+		writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
+
+	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
+}
+
+/*
+ * This function writes the data and tags in TX FIFO. Since in write case, both
+ * tags and data need to be written and QUP write tags can have maximum 256 data
+ * length, so it follows simple internal state machine to manage it.
+ * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the
+ *    tags to TX FIFO.
+ * 2. Check if send_last_word is true. This will be set when last few data bytes
+ *    less than 4 bytes are reamining to be written in FIFO because of no FIFO
+ *    space. All this data bytes are available in tx_fifo_data so write this
+ *    in FIFO and mark the tx done.
+ * 3. Write the data to TX FIFO and check for cur_blk_len. If this is non zero
+ *    then more data is pending otherwise following 3 cases can be possible
+ *    a. if tx_fifo_data_pos is zero that means all the data bytes in this block
+ *       have been written in TX FIFO so mark the tx done.
+ *    b. tx_fifo_free is zero. In this case, last few bytes (less than 4
+ *       bytes) are copied to tx_fifo_data but couldn't be sent because of
+ *       FIFO full so make send_last_word true.
+ *    c. tx_fifo_free is non zero i.e tx FIFO is free so copy the remaining data
+ *       from tx_fifo_data to tx FIFO and mark the tx done. Since,
+ *       qup_i2c_write_blk_data do write in 4 bytes and FIFO space is in
+ *       multiple of 4 bytes so tx_fifo_free will be always greater than or
+ *       equal to 4 bytes.
+ */
+static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+
+	if (!blk->tx_tags_sent) {
+		qup_i2c_write_blk_data(qup, &blk->cur_tx_tags,
+				       &blk->tx_tag_len);
+		blk->tx_tags_sent = true;
+	}
+
+	if (blk->send_last_word)
+		goto send_last_word;
+
+	qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len);
+	if (!blk->cur_blk_len) {
+		if (!blk->tx_fifo_data_pos)
+			goto tx_data_done;
+
+		if (blk->tx_fifo_free)
+			goto send_last_word;
+
+		blk->send_last_word = true;
+	}
+
+	return;
+
+send_last_word:
+	writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
+tx_data_done:
+	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
+}
+
+/*
+ * Main transfer function which will be used for reading or writing i2c data.
+ * The QUP v2 supports reconfiguration during run in which multiple i2c sub
+ * transfers can be scheduled.
+ */
+static int
+qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool is_first,
+		     bool change_pause_state)
+{
+	struct qup_i2c_block *blk = &qup->blk;
+	struct i2c_msg *msg = qup->msg;
+	int ret;
+
+	/*
+	 * Check if its SMBus Block read for which the top level read will be
+	 * done into 2 QUP reads. One with message length 1 while other one is
+	 * with actual length.
+	 */
+	if (qup_i2c_check_msg_len(msg)) {
+		if (qup->is_smbus_read) {
+			/*
+			 * If the message length is already read in
+			 * the first byte of the buffer, account for
+			 * that by setting the offset
+			 */
+			blk->cur_data += 1;
+			is_first = false;
+		} else {
+			change_pause_state = false;
+		}
+	}
+
+	qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN;
+
+	qup_i2c_clear_blk_v2(blk);
+	qup_i2c_conf_count_v2(qup);
+
+	/* If it is first sub transfer, then configure i2c bus clocks */
+	if (is_first) {
+		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+		if (ret)
+			return ret;
+
+		writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+		if (ret)
+			return ret;
+	}
+
+	qup_i2c_set_blk_event(qup, is_rx);
+	reinit_completion(&qup->xfer);
+	enable_irq(qup->irq);
+	/*
+	 * In FIFO mode, tx FIFO can be written directly while in block mode the
+	 * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt
+	 */
+	if (!blk->is_tx_blk_mode) {
+		blk->tx_fifo_free = qup->out_fifo_sz;
+
+		if (is_rx)
+			qup_i2c_write_rx_tags_v2(qup);
+		else
+			qup_i2c_write_tx_fifo_v2(qup);
+	}
+
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto err;
+
+	ret = qup_i2c_wait_for_complete(qup, msg);
+	if (ret)
+		goto err;
+
+	/* Move to pause state for all the transfers, except last one */
+	if (change_pause_state) {
+		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+		if (ret)
+			goto err;
+	}
+
+err:
+	disable_irq(qup->irq);
+	return ret;
+}
+
+/*
+ * Function to transfer one read/write message in i2c transfer. It splits the
+ * message into multiple of blk_xfer_limit data length blocks and schedule each
+ * QUP block individually.
+ */
+static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, bool is_rx)
+{
+	int ret = 0;
+	unsigned int data_len, i;
+	struct i2c_msg *msg = qup->msg;
+	struct qup_i2c_block *blk = &qup->blk;
+	u8 *msg_buf = msg->buf;
+
+	qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT;
+	qup_i2c_set_blk_data(qup, msg);
+
+	for (i = 0; i < blk->count; i++) {
+		data_len =  qup_i2c_get_data_len(qup);
+		blk->pos = i;
+		blk->cur_tx_tags = blk->tags;
+		blk->cur_blk_len = data_len;
+		blk->tx_tag_len =
+			qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg);
+
+		blk->cur_data = msg_buf;
+
+		if (is_rx) {
+			blk->total_tx_len = blk->tx_tag_len;
+			blk->rx_tag_len = 2;
+			blk->total_rx_len = blk->rx_tag_len + data_len;
+		} else {
+			blk->total_tx_len = blk->tx_tag_len + data_len;
+			blk->total_rx_len = 0;
+		}
+
+		ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i,
+					   !qup->is_last || i < blk->count - 1);
+		if (ret)
+			return ret;
+
+		/* Handle SMBus block read length */
+		if (qup_i2c_check_msg_len(msg) && msg->len == 1 &&
+		    !qup->is_smbus_read) {
+			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX)
+				return -EPROTO;
+
+			msg->len = msg->buf[0];
+			qup->is_smbus_read = true;
+			ret = qup_i2c_xfer_v2_msg(qup, msg_id, true);
+			qup->is_smbus_read = false;
+			if (ret)
+				return ret;
+
+			msg->len += 1;
+		}
+
+		msg_buf += data_len;
+		blk->data_len -= qup->blk_xfer_limit;
+	}
+
+	return ret;
+}
+
+/*
+ * QUP v2 supports 3 modes
+ * Programmed IO using FIFO mode : Less than FIFO size
+ * Programmed IO using Block mode : Greater than FIFO size
+ * DMA using BAM : Appropriate for any transactio size but the address should be
+ *		   DMA applicable
+ *
+ * This function determines the mode which will be used for this transfer. An
+ * i2c transfer contains multiple message. Following are the rules to determine
+ * the mode used.
+ * 1. Determine the tx and rx length for each message and maximum tx and rx
+ *    length for complete transfer
+ * 2. If tx or rx length is greater than DMA threshold than use the DMA mode.
+ * 3. In FIFO or block mode, TX and RX can operate in different mode so check
+ *    for maximum tx and rx length to determine mode.
+ */
+static int
+qup_i2c_determine_mode(struct qup_i2c_dev *qup, struct i2c_msg msgs[], int num)
+{
+	int idx;
+	bool no_dma = false;
+	unsigned int max_tx_len = 0, max_rx_len = 0;
+	unsigned int cur_tx_len, cur_rx_len;
+	unsigned int total_rx_len = 0, total_tx_len = 0;
+
+	/* All i2c_msgs should be transferred using either dma or cpu */
+	for (idx = 0; idx < num; idx++) {
+		if (msgs[idx].len == 0)
+			return -EINVAL;
+
+		if (msgs[idx].flags & I2C_M_RD) {
+			cur_tx_len = 0;
+			cur_rx_len = msgs[idx].len;
+		} else {
+			cur_tx_len = msgs[idx].len;
+			cur_rx_len = 0;
+		}
+
+		if (is_vmalloc_addr(msgs[idx].buf))
+			no_dma = true;
+
+		max_tx_len = max(max_tx_len, cur_tx_len);
+		max_rx_len = max(max_rx_len, cur_rx_len);
+		total_rx_len += cur_rx_len;
+		total_tx_len += cur_tx_len;
+	}
+
+	if (!no_dma && qup->is_dma &&
+	    (total_tx_len > qup->dma_threshold ||
+	     total_rx_len > qup->dma_threshold)) {
+		qup->use_dma = true;
+	} else {
+		qup->blk.is_tx_blk_mode =
+			max_tx_len > qup->blk_mode_threshold ? true : false;
+		qup->blk.is_rx_blk_mode =
+			max_rx_len > qup->blk_mode_threshold ? true : false;
+	}
+
+	return 0;
+}
+
 static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   struct i2c_msg msgs[],
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx = 0;
-	unsigned int total_len = 0;
 
 	qup->bus_err = 0;
 	qup->qup_err = 0;
@@ -1457,6 +1609,10 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	if (ret < 0)
 		goto out;
 
+	ret = qup_i2c_determine_mode(qup, msgs, num);
+	if (ret)
+		goto out;
+
 	writel(1, qup->base + QUP_SW_RESET);
 	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
 	if (ret)
@@ -1466,59 +1622,35 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
 	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
 
-	if ((qup->is_dma)) {
-		/* All i2c_msgs should be transferred using either dma or cpu */
+	if (qup_i2c_poll_state_i2c_master(qup)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (qup->use_dma) {
+		reinit_completion(&qup->xfer);
+		ret = qup_i2c_bam_xfer(adap, &msgs[0], num);
+		qup->use_dma = false;
+	} else {
+		qup_i2c_conf_mode_v2(qup);
+
 		for (idx = 0; idx < num; idx++) {
-			if (msgs[idx].len == 0) {
-				ret = -EINVAL;
-				goto out;
-			}
+			qup->msg = &msgs[idx];
+			qup->is_last = idx == (num - 1);
 
-			if (is_vmalloc_addr(msgs[idx].buf))
+			ret = qup_i2c_xfer_v2_msg(qup, idx,
+					!!(msgs[idx].flags & I2C_M_RD));
+			if (ret)
 				break;
-
-			total_len += msgs[idx].len;
 		}
-
-		if (idx == num && total_len > qup->dma_threshold)
-			qup->use_dma = true;
+		qup->msg = NULL;
 	}
 
-	idx = 0;
-
-	do {
-		if (msgs[idx].len == 0) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		if (qup_i2c_poll_state_i2c_master(qup)) {
-			ret = -EIO;
-			goto out;
-		}
-
-		qup->is_last = (idx == (num - 1));
-		if (idx)
-			qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
-		else
-			qup->config_run = 0;
-
-		reinit_completion(&qup->xfer);
-
-		if (qup->use_dma) {
-			ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
-			qup->use_dma = false;
-			break;
-		} else {
-			if (msgs[idx].flags & I2C_M_RD)
-				ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
-			else
-				ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
-		}
-	} while ((idx++ < (num - 1)) && !ret);
+	if (!ret)
+		ret = qup_i2c_bus_active(qup, ONE_BYTE);
 
 	if (!ret)
-		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+		qup_i2c_change_state(qup, QUP_RESET_STATE);
 
 	if (ret == 0)
 		ret = num;
@@ -1582,6 +1714,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	u32 src_clk_freq = DEFAULT_SRC_CLK;
 	u32 clk_freq = DEFAULT_CLK_FREQ;
 	int blocks;
+	bool is_qup_v1;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -1600,12 +1733,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
 		qup->adap.algo = &qup_i2c_algo;
 		qup->adap.quirks = &qup_i2c_quirks;
-		qup->is_qup_v1 = true;
-		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
-		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
-		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
+		is_qup_v1 = true;
 	} else {
 		qup->adap.algo = &qup_i2c_algo_v2;
+		is_qup_v1 = false;
 		ret = qup_i2c_req_dma(qup);
 
 		if (ret == -EPROBE_DEFER)
@@ -1731,14 +1862,31 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		ret = -EIO;
 		goto fail;
 	}
-	qup->out_blk_sz = blk_sizes[size] / 2;
+	qup->out_blk_sz = blk_sizes[size];
 
 	size = QUP_INPUT_BLOCK_SIZE(io_mode);
 	if (size >= ARRAY_SIZE(blk_sizes)) {
 		ret = -EIO;
 		goto fail;
 	}
-	qup->in_blk_sz = blk_sizes[size] / 2;
+	qup->in_blk_sz = blk_sizes[size];
+
+	if (is_qup_v1) {
+		/*
+		 * in QUP v1, QUP_CONFIG uses N as 15 i.e 16 bits constitutes a
+		 * single transfer but the block size is in bytes so divide the
+		 * in_blk_sz and out_blk_sz by 2
+		 */
+		qup->in_blk_sz /= 2;
+		qup->out_blk_sz /= 2;
+		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
+		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
+		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
+	} else {
+		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v2;
+		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v2;
+		qup->write_rx_tags = qup_i2c_write_rx_tags_v2;
+	}
 
 	size = QUP_OUTPUT_FIFO_SIZE(io_mode);
 	qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
@@ -1746,6 +1894,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	size = QUP_INPUT_FIFO_SIZE(io_mode);
 	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
 	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
+	qup->blk_mode_threshold = qup->dma_threshold - QUP_MAX_TAGS_LEN;
 
 	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
 	hs_div = 3;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
  2018-02-03  7:58 ` [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 Abhishek Sahu
@ 2018-02-05 23:03     ` kbuild test robot
  2018-02-16  7:44   ` Sricharan R
  1 sibling, 0 replies; 57+ messages in thread
From: kbuild test robot @ 2018-02-05 23:03 UTC (permalink / raw)
  Cc: kbuild-all, Andy Gross, Wolfram Sang, David Brown, Sricharan R,
	linux-arm-msm, linux-soc, linux-i2c, linux-kernel, Abhishek Sahu

[-- Attachment #1: Type: text/plain, Size: 3300 bytes --]

Hi Abhishek,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on wsa/i2c/for-next]
[also build test WARNING on v4.15 next-20180205]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Sahu/Major-code-reorganization-to-make-all-i2c-transfers-working/20180206-035527
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/i2c/busses/i2c-qup.c: In function 'qup_i2c_read_rx_fifo_v1':
>> drivers/i2c/busses/i2c-qup.c:1139:12: warning: 'idx' may be used uninitialized in this function [-Wmaybe-uninitialized]
      if ((idx & 1) == 0) {
          ~~~~~^~~~

vim +/idx +1139 drivers/i2c/busses/i2c-qup.c

191424bb Sricharan R     2016-01-19  1130  
3a487e36 Abhishek Sahu   2018-02-03  1131  static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
10c5a842 Bjorn Andersson 2014-03-13  1132  {
3a487e36 Abhishek Sahu   2018-02-03  1133  	struct qup_i2c_block *blk = &qup->blk;
3a487e36 Abhishek Sahu   2018-02-03  1134  	struct i2c_msg *msg = qup->msg;
10c5a842 Bjorn Andersson 2014-03-13  1135  	u32 val = 0;
10c5a842 Bjorn Andersson 2014-03-13  1136  	int idx;
10c5a842 Bjorn Andersson 2014-03-13  1137  
3a487e36 Abhishek Sahu   2018-02-03  1138  	while (blk->fifo_available && qup->pos < msg->len) {
10c5a842 Bjorn Andersson 2014-03-13 @1139  		if ((idx & 1) == 0) {
10c5a842 Bjorn Andersson 2014-03-13  1140  			/* Reading 2 words at time */
10c5a842 Bjorn Andersson 2014-03-13  1141  			val = readl(qup->base + QUP_IN_FIFO_BASE);
10c5a842 Bjorn Andersson 2014-03-13  1142  			msg->buf[qup->pos++] = val & 0xFF;
10c5a842 Bjorn Andersson 2014-03-13  1143  		} else {
10c5a842 Bjorn Andersson 2014-03-13  1144  			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
10c5a842 Bjorn Andersson 2014-03-13  1145  		}
3a487e36 Abhishek Sahu   2018-02-03  1146  		idx++;
3a487e36 Abhishek Sahu   2018-02-03  1147  		blk->fifo_available--;
10c5a842 Bjorn Andersson 2014-03-13  1148  	}
c4f0c5fb Sricharan R     2016-01-19  1149  
3a487e36 Abhishek Sahu   2018-02-03  1150  	if (qup->pos == msg->len)
3a487e36 Abhishek Sahu   2018-02-03  1151  		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
10c5a842 Bjorn Andersson 2014-03-13  1152  }
10c5a842 Bjorn Andersson 2014-03-13  1153  

:::::: The code at line 1139 was first introduced by commit
:::::: 10c5a8425968f8a43b7039ce6261367fc992289f i2c: qup: New bus driver for the Qualcomm QUP I2C controller

:::::: TO: Bjorn Andersson <bjorn.andersson@sonymobile.com>
:::::: CC: Wolfram Sang <wsa@the-dreams.de>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 37502 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
@ 2018-02-05 23:03     ` kbuild test robot
  0 siblings, 0 replies; 57+ messages in thread
From: kbuild test robot @ 2018-02-05 23:03 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: kbuild-all, Andy Gross, Wolfram Sang, David Brown, Sricharan R,
	linux-arm-msm, linux-soc, linux-i2c, linux-kernel, Abhishek Sahu

[-- Attachment #1: Type: text/plain, Size: 3300 bytes --]

Hi Abhishek,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on wsa/i2c/for-next]
[also build test WARNING on v4.15 next-20180205]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Abhishek-Sahu/Major-code-reorganization-to-make-all-i2c-transfers-working/20180206-035527
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/i2c/busses/i2c-qup.c: In function 'qup_i2c_read_rx_fifo_v1':
>> drivers/i2c/busses/i2c-qup.c:1139:12: warning: 'idx' may be used uninitialized in this function [-Wmaybe-uninitialized]
      if ((idx & 1) == 0) {
          ~~~~~^~~~

vim +/idx +1139 drivers/i2c/busses/i2c-qup.c

191424bb Sricharan R     2016-01-19  1130  
3a487e36 Abhishek Sahu   2018-02-03  1131  static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
10c5a842 Bjorn Andersson 2014-03-13  1132  {
3a487e36 Abhishek Sahu   2018-02-03  1133  	struct qup_i2c_block *blk = &qup->blk;
3a487e36 Abhishek Sahu   2018-02-03  1134  	struct i2c_msg *msg = qup->msg;
10c5a842 Bjorn Andersson 2014-03-13  1135  	u32 val = 0;
10c5a842 Bjorn Andersson 2014-03-13  1136  	int idx;
10c5a842 Bjorn Andersson 2014-03-13  1137  
3a487e36 Abhishek Sahu   2018-02-03  1138  	while (blk->fifo_available && qup->pos < msg->len) {
10c5a842 Bjorn Andersson 2014-03-13 @1139  		if ((idx & 1) == 0) {
10c5a842 Bjorn Andersson 2014-03-13  1140  			/* Reading 2 words at time */
10c5a842 Bjorn Andersson 2014-03-13  1141  			val = readl(qup->base + QUP_IN_FIFO_BASE);
10c5a842 Bjorn Andersson 2014-03-13  1142  			msg->buf[qup->pos++] = val & 0xFF;
10c5a842 Bjorn Andersson 2014-03-13  1143  		} else {
10c5a842 Bjorn Andersson 2014-03-13  1144  			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
10c5a842 Bjorn Andersson 2014-03-13  1145  		}
3a487e36 Abhishek Sahu   2018-02-03  1146  		idx++;
3a487e36 Abhishek Sahu   2018-02-03  1147  		blk->fifo_available--;
10c5a842 Bjorn Andersson 2014-03-13  1148  	}
c4f0c5fb Sricharan R     2016-01-19  1149  
3a487e36 Abhishek Sahu   2018-02-03  1150  	if (qup->pos == msg->len)
3a487e36 Abhishek Sahu   2018-02-03  1151  		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
10c5a842 Bjorn Andersson 2014-03-13  1152  }
10c5a842 Bjorn Andersson 2014-03-13  1153  

:::::: The code at line 1139 was first introduced by commit
:::::: 10c5a8425968f8a43b7039ce6261367fc992289f i2c: qup: New bus driver for the Qualcomm QUP I2C controller

:::::: TO: Bjorn Andersson <bjorn.andersson@sonymobile.com>
:::::: CC: Wolfram Sang <wsa@the-dreams.de>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 37502 bytes --]

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
@ 2018-02-08 14:03   ` Sricharan R
  2018-02-19 10:24     ` Abhishek Sahu
  2018-02-27 21:46   ` Christ, Austin
  2018-02-27 22:24   ` Andy Gross
  2 siblings, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-08 14:03 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> The QUP BSLP BAM generates the following error sometimes if the
> current I2C DMA transfer fails and the flush operation has been
> scheduled
> 
>     “bam-dma-engine 7884000.dma: Cannot free busy channel”
> 
> If any I2C error comes during BAM DMA transfer, then the QUP I2C
> interrupt will be generated and the flush operation will be
> carried out to make i2c consume all scheduled DMA transfer.
> Currently, the same completion structure is being used for BAM
> transfer which has already completed without reinit. It will make
> flush operation wait_for_completion_timeout completed immediately
> and will proceed for freeing the DMA resources where the
> descriptors are still in process.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 08f8e01..9faa26c41a 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.

Not sure, if this was an intended change. But given that you are fixing this,
you can change the header to the new SPDX one.

>   * Copyright (c) 2014, Sony Mobile Communications AB.
>   *
>   *
> @@ -844,6 +844,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  	}
>  
>  	if (ret || qup->bus_err || qup->qup_err) {
> +		reinit_completion(&qup->xfer);
> +
>  		if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
>  			dev_err(qup->dev, "change to run state timed out");
>  			goto desc_err;
> 

Except for the above nit,
  Acked-by: Sricharan R <sricharan@codeaurora.org>

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count
  2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
@ 2018-02-09  2:16   ` Sricharan R
  2018-02-19 10:26     ` Abhishek Sahu
  2018-02-27 21:51   ` Christ, Austin
  2018-02-27 22:28   ` Andy Gross
  2 siblings, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-09  2:16 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
> be used for total number of SG entries.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 26 ++++++++++----------------
>  1 file changed, 10 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index c68f433..bb83a2967 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -692,7 +692,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  	struct dma_async_tx_descriptor *txd, *rxd = NULL;
>  	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
>  	dma_cookie_t cookie_rx, cookie_tx;
> -	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> +	u32 len, blocks, rem;
>  	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
>  	u8 *tags;
>  

 This is correct. Just a nit, may be rx/tx_buf can be changed to
 rx/tx_count to make it more clear.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  2018-02-03  7:58 ` [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer Abhishek Sahu
@ 2018-02-15 14:31   ` Sricharan R
  2018-02-19 10:34     ` Abhishek Sahu
  2018-02-27 22:36   ` Andy Gross
  1 sibling, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-15 14:31 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> A single BAM transfer can have multiple read and write messages.
> The EOT and FLUSH tags should be scheduled at the end of BAM HW
> descriptors. Since the READ and WRITE can be present in any order
> so for some of the cases, these tags are not being written
> correctly.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 54 ++++++++++++++++++++------------------------
>  1 file changed, 24 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index bb83a2967..6357aff 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -560,7 +560,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
>  }
>  
>  static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
> -			    struct i2c_msg *msg,  int is_dma)
> +			    struct i2c_msg *msg)
>  {
>  	u16 addr = i2c_8bit_addr_from_msg(msg);
>  	int len = 0;
> @@ -601,11 +601,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>  	else
>  		tags[len++] = data_len;
>  
> -	if ((msg->flags & I2C_M_RD) && last && is_dma) {
> -		tags[len++] = QUP_BAM_INPUT_EOT;
> -		tags[len++] = QUP_BAM_FLUSH_STOP;
> -	}
> -
>  	return len;
>  }
>  
> @@ -614,7 +609,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  	int data_len = 0, tag_len, index;
>  	int ret;
>  
> -	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
> +	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
>  	index = msg->len - qup->blk.data_len;
>  
>  	/* only tags are written for read */
> @@ -710,7 +705,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  			while (qup->blk.pos < blocks) {
>  				tlen = (i == (blocks - 1)) ? rem : limit;
>  				tags = &qup->start_tag.start[off + len];
> -				len += qup_i2c_set_tags(tags, qup, msg, 1);
> +				len += qup_i2c_set_tags(tags, qup, msg);
>  				qup->blk.data_len -= tlen;
>  
>  				/* scratch buf to read the start and len tags */
> @@ -738,17 +733,11 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  				return ret;
>  
>  			off += len;
> -			/* scratch buf to read the BAM EOT and FLUSH tags */
> -			ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> -					     &qup->brx.tag.start[0],
> -					     2, qup, DMA_FROM_DEVICE);
> -			if (ret)
> -				return ret;
>  		} else {
>  			while (qup->blk.pos < blocks) {
>  				tlen = (i == (blocks - 1)) ? rem : limit;
>  				tags = &qup->start_tag.start[off + tx_len];
> -				len = qup_i2c_set_tags(tags, qup, msg, 1);
> +				len = qup_i2c_set_tags(tags, qup, msg);
>  				qup->blk.data_len -= tlen;
>  
>  				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> @@ -768,26 +757,31 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  			}
>  			off += tx_len;
>  
> -			if (idx == (num - 1)) {
> -				len = 1;
> -				if (rx_buf) {
> -					qup->btx.tag.start[0] =
> -							QUP_BAM_INPUT_EOT;
> -					len++;
> -				}
> -				qup->btx.tag.start[len - 1] =
> -							QUP_BAM_FLUSH_STOP;
> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -						     &qup->btx.tag.start[0],
> -						     len, qup, DMA_TO_DEVICE);
> -				if (ret)
> -					return ret;
> -			}
>  		}
>  		idx++;
>  		msg++;
>  	}

 While here, can you please split above the if, else in to two separate functions ?
 and probably one more function for handling the NACK case down below. The function
 size at the moment is too big.

>  
> +	/* schedule the EOT and FLUSH I2C tags */
> +	len = 1;
> +	if (rx_buf) {
> +		qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
> +		len++;
> +
> +		/* scratch buf to read the BAM EOT and FLUSH tags */
> +		ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> +				     &qup->brx.tag.start[0],
> +				     2, qup, DMA_FROM_DEVICE);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
> +	ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->btx.tag.start[0],
> +			     len, qup, DMA_TO_DEVICE);
> +	if (ret)
> +		return ret;
> +

  May be you can change the commit to make it explicit to say what is being
  fixed, like "current code is broken when there is sequence of wr,rd,wr" like that.
  Agree on this fix otherwise.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode
  2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
@ 2018-02-16  4:33   ` Sricharan R
  2018-02-27 22:00   ` Christ, Austin
  2018-02-27 22:58   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Sricharan R @ 2018-02-16  4:33 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel



On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> Currently the i2c error handling in BAM mode is not working
> properly in stress condition.
> 
> 1. After an error, the FIFO are being written with FLUSH and
>    EOT tags which should not be required since already these tags
>    have been written in BAM descriptor itself.
> 
> 2. QUP state is being moved to RESET in IRQ handler in case
>    of error. When QUP HW encounters an error in BAM mode then it
>    moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH
>    command needs to be executed while moving to RUN_STATE by writing
>    to the QUP_STATE register with the I2C_FLUSH bit set to 1.
> 
> 3. In Error case, sometimes, QUP generates more than one
>    interrupt which will trigger the complete again. After an error,
>    the flush operation will be scheduled after doing
>    reinit_completion which should be triggered by BAM IRQ callback.
>    If the second QUP IRQ comes during this time then it will call
>    the complete and the transfer function will assume the all the
>    BAM HW descriptors have been completed.
> 
> 4. The release DMA is being called after each error which
>    will free the DMA tx and rx channels. The error like NACK is very
>    common in I2C transfer and every time this will be overhead. Now,
>    since the error handling is proper so this release channel can be
>    completely avoided.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 094be6a..6227a5c 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -228,9 +228,24 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>  	if (bus_err)
>  		writel(bus_err, qup->base + QUP_I2C_STATUS);
>  
> +	/*
> +	 * Check for BAM mode and returns if already error has come for current
> +	 * transfer. In Error case, sometimes, QUP generates more than one
> +	 * interrupt.
> +	 */
> +	if (qup->use_dma && (qup->qup_err || qup->bus_err))
> +		return IRQ_HANDLED;
> +
>  	/* Reset the QUP State in case of error */
>  	if (qup_err || bus_err) {
> -		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
> +		/*
> +		 * Don’t reset the QUP state in case of BAM mode. The BAM
> +		 * flush operation needs to be scheduled in transfer function
> +		 * which will clear the remaining schedule descriptors in BAM
> +		 * HW FIFO and generates the BAM interrupt.
> +		 */
> +		if (!qup->use_dma)
> +			writel(QUP_RESET_STATE, qup->base + QUP_STATE);
>  		goto done;
>  	}
>  
> @@ -841,20 +856,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  			goto desc_err;
>  		}
>  
> -		if (rx_buf)
> -			writel(QUP_BAM_INPUT_EOT,
> -			       qup->base + QUP_OUT_FIFO_BASE);
> -
> -		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
> -
>  		qup_i2c_flush(qup);
>  
>  		/* wait for remaining interrupts to occur */
>  		if (!wait_for_completion_timeout(&qup->xfer, HZ))
>  			dev_err(qup->dev, "flush timed out\n");
>  
> -		qup_i2c_rel_dma(qup);
> -
>  		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
>  	}
>  
> 

 Reviewed-by: Sricharan R <sricharan@codeaurora.org>

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode
  2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
@ 2018-02-16  4:35   ` Sricharan R
  2018-02-19 10:49     ` Abhishek Sahu
  2018-02-27 22:01   ` Christ, Austin
  2018-02-27 22:59   ` Andy Gross
  2 siblings, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-16  4:35 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel



On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> Currently each message length in complete transfer is being
> checked for determining DMA mode and if any of the message length
> is less than FIFO length then non DMA mode is being used which
> will increase overhead. DMA can be used for any length and it
> should be determined with complete transfer length. Now, this
> patch introduces DMA threshold length and the transfer will be
> done in DMA mode if the total length is greater than this
> threshold length.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 6227a5c..a91fc70 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -192,6 +192,8 @@ struct qup_i2c_dev {
>  	bool			is_dma;
>  	/* To check if the current transfer is using DMA */
>  	bool			use_dma;
> +	/* The threshold length above which DMA will be used */
> +	unsigned int		dma_threshold;
>  	struct			dma_pool *dpool;
>  	struct			qup_i2c_tag start_tag;
>  	struct			qup_i2c_bam brx;
> @@ -1294,7 +1296,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>  			   int num)
>  {
>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> -	int ret, len, idx = 0;
> +	int ret, idx = 0;
> +	unsigned int total_len = 0;
>  
>  	qup->bus_err = 0;
>  	qup->qup_err = 0;
> @@ -1320,14 +1323,13 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>  				goto out;
>  			}
>  
> -			len = (msgs[idx].len > qup->out_fifo_sz) ||
> -			      (msgs[idx].len > qup->in_fifo_sz);
> -
> -			if (is_vmalloc_addr(msgs[idx].buf) || !len)
> +			if (is_vmalloc_addr(msgs[idx].buf))
>  				break;
> +
> +			total_len += msgs[idx].len;
>  		}
>  
> -		if (idx == num)
> +		if (idx == num && total_len > qup->dma_threshold)
>  			qup->use_dma = true;
>  	}
>  
> @@ -1587,6 +1589,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  
>  	size = QUP_INPUT_FIFO_SIZE(io_mode);
>  	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
> +	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);

  The patch is fine. small nit, you can avoid this global dma_threshold. Instead
  have it locally in qup_i2c_xfer_v2 itself.

Regards,
 Sricharan


-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/12] i2c: qup: change completion timeout according to transfer length
  2018-02-03  7:58 ` [PATCH 08/12] i2c: qup: change completion timeout according to transfer length Abhishek Sahu
@ 2018-02-16  4:48   ` Sricharan R
  2018-02-19 10:56     ` Abhishek Sahu
  0 siblings, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-16  4:48 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel



On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> Currently the completion timeout is being taken according to
> maximum transfer length which is too high if SCL is operating in
> high frequency. This patch calculates timeout on the basis of
> one-byte transfer time and uses the same for completion timeout.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index a91fc70..6df65ea 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -130,8 +130,8 @@
>  #define MX_TX_RX_LEN			SZ_64K
>  #define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
>  
> -/* Max timeout in ms for 32k bytes */
> -#define TOUT_MAX			300
> +/* Min timeout for i2c transfers */
> +#define TOUT_MIN			2
>  

 may be you can mention, why is this 2 ?

Regards,
 Sricharan


>  /* Default values. Use these if FW query fails */
>  #define DEFAULT_CLK_FREQ 100000
> @@ -172,6 +172,7 @@ struct qup_i2c_dev {
>  	int			in_blk_sz;
>  
>  	unsigned long		one_byte_t;
> +	unsigned long		xfer_timeout;
>  	struct qup_i2c_block	blk;
>  
>  	struct i2c_msg		*msg;
> @@ -845,7 +846,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  		dma_async_issue_pending(qup->brx.dma);
>  	}
>  
> -	if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> +	if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) {
>  		dev_err(qup->dev, "normal trans timed out\n");
>  		ret = -ETIMEDOUT;
>  	}
> @@ -1601,6 +1602,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	 */
>  	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
>  	qup->one_byte_t = one_bit_t * 9;
> +	qup->xfer_timeout = TOUT_MIN * HZ +
> +			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
>  
>  	dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
>  		qup->in_blk_sz, qup->in_fifo_sz,
> 

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
@ 2018-02-16  5:21   ` Sricharan R
  2018-02-19 11:24     ` Abhishek Sahu
  2018-02-27 22:06   ` Christ, Austin
  2018-02-27 23:15   ` Andy Gross
  2 siblings, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-16  5:21 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> The BAM mode requires buffer for start tag data and tx, rx SG
> list. Currently, this is being taken for maximum transfer length
> (65K). But an I2C transfer can have multiple messages and each
> message can be of this maximum length so the buffer overflow will
> happen in this case. Since increasing buffer length won’t be
> feasible since an I2C transfer can contain any number of messages
> so this patch does following changes to make i2c transfers working
> for multiple messages case.
> 
> 1. Calculate the required buffers for 2 maximum length messages
>    (65K * 2).
> 2. Split the descriptor formation and descriptor scheduling.
>    The idea is to fit as many messages in one DMA transfers for 65K
>    threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>    crossing this, then schedule the BAM transfer and subsequent
>    transfer will again start from zero.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 199 +++++++++++++++++++++++++------------------
>  1 file changed, 118 insertions(+), 81 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 6df65ea..ba717bb 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -155,6 +155,7 @@ struct qup_i2c_bam {
>  	struct	qup_i2c_tag tag;
>  	struct	dma_chan *dma;
>  	struct	scatterlist *sg;
> +	unsigned int sg_cnt;
>  };
>  
>  struct qup_i2c_dev {
> @@ -195,6 +196,8 @@ struct qup_i2c_dev {
>  	bool			use_dma;
>  	/* The threshold length above which DMA will be used */
>  	unsigned int		dma_threshold;
> +	unsigned int		max_xfer_sg_len;
> +	unsigned int		tag_buf_pos;
>  	struct			dma_pool *dpool;
>  	struct			qup_i2c_tag start_tag;
>  	struct			qup_i2c_bam brx;
> @@ -699,86 +702,86 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
>  	return 0;
>  }
>  
> -static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
> -			       int num)
> +static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +{
> +	int ret = 0, limit = QUP_READ_LIMIT;
> +	u32 len = 0, blocks, rem;
> +	u32 i = 0, tlen, tx_len = 0;
> +	u8 *tags;
> +
> +	qup_i2c_set_blk_data(qup, msg);
> +
> +	blocks = qup->blk.count;
> +	rem = msg->len - (blocks - 1) * limit;
> +
> +	if (msg->flags & I2C_M_RD) {
> +		while (qup->blk.pos < blocks) {
> +			tlen = (i == (blocks - 1)) ? rem : limit;
> +			tags = &qup->start_tag.start[qup->tag_buf_pos + len];
> +			len += qup_i2c_set_tags(tags, qup, msg);
> +			qup->blk.data_len -= tlen;
> +
> +			/* scratch buf to read the start and len tags */
> +			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
> +					     &qup->brx.tag.start[0],
> +					     2, qup, DMA_FROM_DEVICE);
> +
> +			if (ret)
> +				return ret;
> +
> +			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
> +					     &msg->buf[limit * i],
> +					     tlen, qup,
> +					     DMA_FROM_DEVICE);
> +			if (ret)
> +				return ret;
> +
> +			i++;
> +			qup->blk.pos = i;
> +		}
> +		ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +				     &qup->start_tag.start[qup->tag_buf_pos],
> +				     len, qup, DMA_TO_DEVICE);
> +		if (ret)
> +			return ret;
> +
> +		qup->tag_buf_pos += len;
> +	} else {
> +		while (qup->blk.pos < blocks) {
> +			tlen = (i == (blocks - 1)) ? rem : limit;
> +			tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len];
> +			len = qup_i2c_set_tags(tags, qup, msg);
> +			qup->blk.data_len -= tlen;
> +
> +			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +					     tags, len,
> +					     qup, DMA_TO_DEVICE);
> +			if (ret)
> +				return ret;
> +
> +			tx_len += len;
> +			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +					     &msg->buf[limit * i],
> +					     tlen, qup, DMA_TO_DEVICE);
> +			if (ret)
> +				return ret;
> +			i++;
> +			qup->blk.pos = i;
> +		}
> +
> +		qup->tag_buf_pos += tx_len;
> +	}
> +
> +	return 0;
> +}
> +
> +static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
>  {
>  	struct dma_async_tx_descriptor *txd, *rxd = NULL;
> -	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
> +	int ret = 0;
>  	dma_cookie_t cookie_rx, cookie_tx;
> -	u32 len, blocks, rem;
> -	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> -	u8 *tags;
> -
> -	while (idx < num) {
> -		tx_len = 0, len = 0, i = 0;
> -
> -		qup->is_last = (idx == (num - 1));
> -
> -		qup_i2c_set_blk_data(qup, msg);
> -
> -		blocks = qup->blk.count;
> -		rem = msg->len - (blocks - 1) * limit;
> -
> -		if (msg->flags & I2C_M_RD) {
> -			while (qup->blk.pos < blocks) {
> -				tlen = (i == (blocks - 1)) ? rem : limit;
> -				tags = &qup->start_tag.start[off + len];
> -				len += qup_i2c_set_tags(tags, qup, msg);
> -				qup->blk.data_len -= tlen;
> -
> -				/* scratch buf to read the start and len tags */
> -				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> -						     &qup->brx.tag.start[0],
> -						     2, qup, DMA_FROM_DEVICE);
> -
> -				if (ret)
> -					return ret;
> -
> -				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> -						     &msg->buf[limit * i],
> -						     tlen, qup,
> -						     DMA_FROM_DEVICE);
> -				if (ret)
> -					return ret;
> -
> -				i++;
> -				qup->blk.pos = i;
> -			}
> -			ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -					     &qup->start_tag.start[off],
> -					     len, qup, DMA_TO_DEVICE);
> -			if (ret)
> -				return ret;
> -
> -			off += len;
> -		} else {
> -			while (qup->blk.pos < blocks) {
> -				tlen = (i == (blocks - 1)) ? rem : limit;
> -				tags = &qup->start_tag.start[off + tx_len];
> -				len = qup_i2c_set_tags(tags, qup, msg);
> -				qup->blk.data_len -= tlen;
> -
> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -						     tags, len,
> -						     qup, DMA_TO_DEVICE);
> -				if (ret)
> -					return ret;
> -
> -				tx_len += len;
> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -						     &msg->buf[limit * i],
> -						     tlen, qup, DMA_TO_DEVICE);
> -				if (ret)
> -					return ret;
> -				i++;
> -				qup->blk.pos = i;
> -			}
> -			off += tx_len;
> -
> -		}
> -		idx++;
> -		msg++;
> -	}
> +	u32 len = 0;
> +	u32 tx_buf = qup->btx.sg_cnt, rx_buf = qup->brx.sg_cnt;
>  
>  	/* schedule the EOT and FLUSH I2C tags */
>  	len = 1;
> @@ -878,11 +881,19 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  	return ret;
>  }
>  
> +static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
> +{
> +	qup->btx.sg_cnt = 0;
> +	qup->brx.sg_cnt = 0;
> +	qup->tag_buf_pos = 0;
> +}
> +
>  static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
>  			    int num)
>  {
>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>  	int ret = 0;
> +	int idx = 0;
>  
>  	enable_irq(qup->irq);
>  	ret = qup_i2c_req_dma(qup);
> @@ -905,9 +916,34 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
>  		goto out;
>  
>  	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> +	qup_i2c_bam_clear_tag_buffers(qup);
> +
> +	for (idx = 0; idx < num; idx++) {
> +		qup->msg = msg + idx;
> +		qup->is_last = idx == (num - 1);
> +
> +		ret = qup_i2c_bam_make_desc(qup, qup->msg);
> +		if (ret)
> +			break;
> +
> +		/*
> +		 * Make DMA descriptor and schedule the BAM transfer if its
> +		 * already crossed the maximum length. Since the memory for all
> +		 * tags buffers have been taken for 2 maximum possible
> +		 * transfers length so it will never cross the buffer actual
> +		 * length.
> +		 */
> +		if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
> +		    qup->brx.sg_cnt > qup->max_xfer_sg_len ||
> +		    qup->is_last) {
> +			ret = qup_i2c_bam_schedule_desc(qup);
> +			if (ret)
> +				break;
> +
> +			qup_i2c_bam_clear_tag_buffers(qup);
> +		}
> +	}
>  

  hmm, is this because of only stress tests or was there any device which
  was using i2c for multiple messages exceeding 64k bytes ?

  Infact we are trying to club two separate messages together across 64k
  boundaries. Not sure if its really correct. So either we club all messages
  fully or club only up to the length that would cover the whole message < 64K
  and send the remaining whole messages in next transfer.

Regards,
  Sricharan
 

> -	qup->msg = msg;
> -	ret = qup_i2c_bam_do_xfer(qup, qup->msg, num);
>  out:
>  	disable_irq(qup->irq);
>  
> @@ -1459,7 +1495,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  		else if (ret != 0)
>  			goto nodma;
>  
> -		blocks = (MX_BLOCKS << 1) + 1;
> +		qup->max_xfer_sg_len = (MX_BLOCKS << 1);
> +		blocks = 2 * qup->max_xfer_sg_len + 1;
>  		qup->btx.sg = devm_kzalloc(&pdev->dev,
>  					   sizeof(*qup->btx.sg) * blocks,
>  					   GFP_KERNEL);
> @@ -1603,7 +1640,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
>  	qup->one_byte_t = one_bit_t * 9;
>  	qup->xfer_timeout = TOUT_MIN * HZ +
> -			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
> +		usecs_to_jiffies(2 * MX_TX_RX_LEN * qup->one_byte_t);
>  
>  	dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
>  		qup->in_blk_sz, qup->in_fifo_sz,
> 

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 10/12] i2c: qup: send NACK for last read sub transfers
  2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
@ 2018-02-16  5:39   ` Sricharan R
  2018-02-27 22:07   ` Christ, Austin
  2018-02-27 23:17   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Sricharan R @ 2018-02-16  5:39 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> According to I2c specification, “If a master-receiver sends a
> repeated START condition, it sends a not-acknowledge (A) just
> before the repeated START condition”. QUP v2 supports sending
> of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
> same.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index ba717bb..edea3b9 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -113,6 +113,7 @@
>  #define QUP_TAG_V2_DATAWR              0x82
>  #define QUP_TAG_V2_DATAWR_STOP         0x83
>  #define QUP_TAG_V2_DATARD              0x85
> +#define QUP_TAG_V2_DATARD_NACK         0x86
>  #define QUP_TAG_V2_DATARD_STOP         0x87
>  
>  /* Status, Error flags */
> @@ -609,7 +610,9 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>  			tags[len++] = QUP_TAG_V2_DATAWR_STOP;
>  	} else {
>  		if (msg->flags & I2C_M_RD)
> -			tags[len++] = QUP_TAG_V2_DATARD;
> +			tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
> +				      QUP_TAG_V2_DATARD_NACK :
> +				      QUP_TAG_V2_DATARD;
>  		else
>  			tags[len++] = QUP_TAG_V2_DATAWR;

 good one. Thanks .

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
  2018-02-03  7:58 ` [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 Abhishek Sahu
  2018-02-05 23:03     ` kbuild test robot
@ 2018-02-16  7:44   ` Sricharan R
  2018-02-19 13:21     ` Abhishek Sahu
  1 sibling, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-16  7:44 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> Following are the major issues in current driver code
> 
> 1. The current driver simply assumes the transfer completion
>    whenever its gets any non-error interrupts and then simply do the
>    polling of available/free bytes in FIFO.
> 2. The block mode is not working properly since no handling in
>    being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ.
> 
> Because of above, i2c v1 transfers of size greater than 32 are failing
> with following error message
> 
> 	i2c_qup 78b6000.i2c: timeout for fifo out full
> 
> To make block mode working properly and move to use the interrupts
> instead of polling, major code reorganization is required. Following
> are the major changes done in this patch
> 
> 1. Remove the polling of TX FIFO free space and RX FIFO available
>    bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
>    QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
>    interrupts to handle FIFO’s properly so check all these interrupts.
> 2. During write, For FIFO mode, TX FIFO can be directly written
>    without checking for FIFO space. For block mode, the QUP will generate
>    OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
>    space.
> 3. During read, both TX and RX FIFO will be used. TX will be used
>    for writing tags and RX will be used for receiving the data. In QUP,
>    TX and RX can operate in separate mode so configure modes accordingly.
> 4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
>    will be generated after all the bytes have been copied in RX FIFO. For
>    read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
>    whenever it has block size of available data.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 399 ++++++++++++++++++++++++++++---------------
>  1 file changed, 257 insertions(+), 142 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index edea3b9..af6c21a 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -73,8 +73,11 @@
>  #define QUP_IN_SVC_FLAG		BIT(9)
>  #define QUP_MX_OUTPUT_DONE	BIT(10)
>  #define QUP_MX_INPUT_DONE	BIT(11)
> +#define OUT_BLOCK_WRITE_REQ	BIT(12)
> +#define IN_BLOCK_READ_REQ	BIT(13)
>  
>  /* I2C mini core related values */
> +#define QUP_NO_INPUT		BIT(7)
>  #define QUP_CLOCK_AUTO_GATE	BIT(13)
>  #define I2C_MINI_CORE		(2 << 8)
>  #define I2C_N_VAL		15
> @@ -138,13 +141,51 @@
>  #define DEFAULT_CLK_FREQ 100000
>  #define DEFAULT_SRC_CLK 20000000
>  
> +/* MAX_OUTPUT_DONE_FLAG has been received */
> +#define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
> +/* MAX_INPUT_DONE_FLAG has been received */
> +#define QUP_BLK_EVENT_RX_IRQ_DONE		BIT(1)
> +/* All the TX bytes have been written in TX FIFO */
> +#define QUP_BLK_EVENT_TX_DATA_DONE		BIT(2)
> +/* All the RX bytes have been read from RX FIFO */
> +#define QUP_BLK_EVENT_RX_DATA_DONE		BIT(3)
> +
> +/* All the required events to mark a QUP I2C TX transfer completed */
> +#define QUP_BLK_EVENT_TX_DONE		(QUP_BLK_EVENT_TX_IRQ_DONE | \
> +					 QUP_BLK_EVENT_TX_DATA_DONE)
> +/* All the required events to mark a QUP I2C RX transfer completed */
> +#define QUP_BLK_EVENT_RX_DONE		(QUP_BLK_EVENT_TX_DONE | \
> +					 QUP_BLK_EVENT_RX_IRQ_DONE | \
> +					 QUP_BLK_EVENT_RX_DATA_DONE)
> +
> +/*
> + * count: no of blocks
> + * pos: current block number
> + * tx_tag_len: tx tag length for current block
> + * rx_tag_len: rx tag length for current block
> + * data_len: remaining data length for current message
> + * total_tx_len: total tx length including tag bytes for current QUP transfer
> + * total_rx_len: total rx length including tag bytes for current QUP transfer
> + * tx_fifo_free: number of free bytes in current QUP block write.
> + * fifo_available: number of available bytes in RX FIFO for current
> + *		   QUP block read
> + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
> + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
> + * tags: contains tx tag bytes for current QUP transfer
> + */
>  struct qup_i2c_block {
> -	int	count;
> -	int	pos;
> -	int	tx_tag_len;
> -	int	rx_tag_len;
> -	int	data_len;
> -	u8	tags[6];
> +	int		count;
> +	int		pos;
> +	int		tx_tag_len;
> +	int		rx_tag_len;
> +	int		data_len;
> +	int		total_tx_len;
> +	int		total_rx_len;
> +	int		tx_fifo_free;
> +	int		fifo_available;
> +	bool		is_tx_blk_mode;
> +	bool		is_rx_blk_mode;
> +	u8		tags[6];
>  };
>  
>  struct qup_i2c_tag {
> @@ -187,6 +228,7 @@ struct qup_i2c_dev {
>  
>  	/* To check if this is the last msg */
>  	bool			is_last;
> +	bool			is_qup_v1;
>  
>  	/* To configure when bus is in run state */
>  	int			config_run;
> @@ -195,6 +237,10 @@ struct qup_i2c_dev {
>  	bool			is_dma;
>  	/* To check if the current transfer is using DMA */
>  	bool			use_dma;
> +	/* Required events to mark QUP transfer as completed */
> +	u32			blk_events;
> +	/* Already completed events in QUP transfer */
> +	u32			cur_blk_events;
>  	/* The threshold length above which DMA will be used */
>  	unsigned int		dma_threshold;
>  	unsigned int		max_xfer_sg_len;
> @@ -205,11 +251,18 @@ struct qup_i2c_dev {
>  	struct			qup_i2c_bam btx;
>  
>  	struct completion	xfer;
> +	/* function to write data in tx fifo */
> +	void (*write_tx_fifo)(struct qup_i2c_dev *qup);
> +	/* function to read data from rx fifo */
> +	void (*read_rx_fifo)(struct qup_i2c_dev *qup);
> +	/* function to write tags in tx fifo for i2c read transfer */
> +	void (*write_rx_tags)(struct qup_i2c_dev *qup);
>  };
>  
>  static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>  {
>  	struct qup_i2c_dev *qup = dev;
> +	struct qup_i2c_block *blk = &qup->blk;
>  	u32 bus_err;
>  	u32 qup_err;
>  	u32 opflags;
> @@ -256,12 +309,54 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>  		goto done;
>  	}
>  
> -	if (opflags & QUP_IN_SVC_FLAG)
> -		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> +	if (!qup->is_qup_v1)
> +		goto done;
>  
> -	if (opflags & QUP_OUT_SVC_FLAG)
> +	if (opflags & QUP_OUT_SVC_FLAG) {
>  		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>  
> +		/*
> +		 * Ideally, would like to check QUP_MAX_OUTPUT_DONE_FLAG.
> +		 * However, QUP_MAX_OUTPUT_DONE_FLAG is lagging behind
> +		 * QUP_OUTPUT_SERVICE_FLAG. The only reason for
> +		 * QUP_OUTPUT_SERVICE_FLAG to be set in FIFO mode is
> +		 * QUP_MAX_OUTPUT_DONE_FLAG condition. The code checking
> +		 * here QUP_OUTPUT_SERVICE_FLAG and assumes that
> +		 * QUP_MAX_OUTPUT_DONE_FLAG.
> +		 */
> +		if (!blk->is_tx_blk_mode)
> +			qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
> +
> +		if (opflags & OUT_BLOCK_WRITE_REQ) {
> +			blk->tx_fifo_free += qup->out_blk_sz;
> +			if (qup->msg->flags & I2C_M_RD)
> +				qup->write_rx_tags(qup);
> +			else
> +				qup->write_tx_fifo(qup);
> +		}
> +	}
> +
> +	if (opflags & QUP_IN_SVC_FLAG) {
> +		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
> +
> +		if (!blk->is_rx_blk_mode) {
> +			blk->fifo_available += qup->in_fifo_sz;
> +			qup->read_rx_fifo(qup);
> +		} else if (opflags & IN_BLOCK_READ_REQ) {
> +			blk->fifo_available += qup->in_blk_sz;
> +			qup->read_rx_fifo(qup);
> +		}
> +	}
> +
> +	if (opflags & QUP_MX_OUTPUT_DONE)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
> +
> +	if (opflags & QUP_MX_INPUT_DONE)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_IRQ_DONE;
> +
> +	if (qup->cur_blk_events != qup->blk_events)
> +		return IRQ_HANDLED;

  Is it correct that if we do a complete in above case, i mean
  for TX -> based on QUP_MX_OUTPUT_DONE and for RX -> based on
  QUP_MX_INPUT_DONE, would that simplify things by getting rid of
  QUP_BLK_EVENT_RX/TX_DONE and QUP_BLK_EVENT_RX/TX_IRQ_DONE
  altogether ?

Regards,
 Sricharan

  
> +
>  done:
>  	qup->qup_err = qup_err;
>  	qup->bus_err = bus_err;
> @@ -327,6 +422,28 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
>  	return 0;
>  }
>  
> +/* Check if I2C bus returns to IDLE state */
> +static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
> +{
> +	unsigned long timeout;
> +	u32 status;
> +	int ret = 0;
> +
> +	timeout = jiffies + len * 4;
> +	for (;;) {
> +		status = readl(qup->base + QUP_I2C_STATUS);
> +		if (!(status & I2C_STATUS_BUS_ACTIVE))
> +			break;
> +
> +		if (time_after(jiffies, timeout))
> +			ret = -ETIMEDOUT;
> +
> +		usleep_range(len, len * 2);
> +	}
> +
> +	return ret;
> +}
> +
>  /**
>   * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
>   * @qup: The qup_i2c_dev device
> @@ -397,23 +514,6 @@ static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
>  	}
>  }
>  
> -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	/* Number of entries to shift out, including the start */
> -	int total = msg->len + 1;
> -
> -	if (total < qup->out_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_WRITE_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
> -	}
> -}
> -
>  static int check_for_fifo_space(struct qup_i2c_dev *qup)
>  {
>  	int ret;
> @@ -446,28 +546,25 @@ static int check_for_fifo_space(struct qup_i2c_dev *qup)
>  	return ret;
>  }
>  
> -static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
>  {
> +	struct qup_i2c_block *blk = &qup->blk;
> +	struct i2c_msg *msg = qup->msg;
>  	u32 addr = msg->addr << 1;
>  	u32 qup_tag;
>  	int idx;
>  	u32 val;
> -	int ret = 0;
>  
>  	if (qup->pos == 0) {
>  		val = QUP_TAG_START | addr;
>  		idx = 1;
> +		blk->tx_fifo_free--;
>  	} else {
>  		val = 0;
>  		idx = 0;
>  	}
>  
> -	while (qup->pos < msg->len) {
> -		/* Check that there's space in the FIFO for our pair */
> -		ret = check_for_fifo_space(qup);
> -		if (ret)
> -			return ret;
> -
> +	while (blk->tx_fifo_free && qup->pos < msg->len) {
>  		if (qup->pos == msg->len - 1)
>  			qup_tag = QUP_TAG_STOP;
>  		else
> @@ -484,11 +581,11 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  
>  		qup->pos++;
>  		idx++;
> +		blk->tx_fifo_free--;
>  	}
>  
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -
> -	return ret;
> +	if (qup->pos == msg->len)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
>  }
>  
>  static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
> @@ -1009,64 +1106,6 @@ static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  	return ret;
>  }
>  
> -static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int ret;
> -
> -	qup->msg = msg;
> -	qup->pos = 0;
> -
> -	enable_irq(qup->irq);
> -
> -	qup_i2c_set_write_mode(qup, msg);
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -	if (ret)
> -		goto err;
> -
> -	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> -
> -	do {
> -		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_issue_write(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> -	} while (qup->pos < msg->len);
> -
> -	/* Wait for the outstanding data in the fifo to drain */
> -	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
> -err:
> -	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
> -	return ret;
> -}
> -
> -static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
> -{
> -	if (len < qup->in_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(len, qup->base + QUP_MX_READ_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(len, qup->base + QUP_MX_INPUT_CNT);
> -	}
> -}
> -
>  static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
>  {
>  	int tx_len = qup->blk.tx_tag_len;
> @@ -1089,44 +1128,27 @@ static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
>  	}
>  }
>  
> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	u32 addr, len, val;
> -
> -	addr = i2c_8bit_addr_from_msg(msg);
> -
> -	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
> -	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
> -
> -	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
> -	writel(val, qup->base + QUP_OUT_FIFO_BASE);
> -}
> -
> -
> -static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
>  {
> +	struct qup_i2c_block *blk = &qup->blk;
> +	struct i2c_msg *msg = qup->msg;
>  	u32 val = 0;
>  	int idx;
> -	int ret = 0;
>  
> -	for (idx = 0; qup->pos < msg->len; idx++) {
> +	while (blk->fifo_available && qup->pos < msg->len) {
>  		if ((idx & 1) == 0) {
> -			/* Check that FIFO have data */
> -			ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
> -						 SET_BIT, 4 * ONE_BYTE);
> -			if (ret)
> -				return ret;
> -
>  			/* Reading 2 words at time */
>  			val = readl(qup->base + QUP_IN_FIFO_BASE);
> -
>  			msg->buf[qup->pos++] = val & 0xFF;
>  		} else {
>  			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
>  		}
> +		idx++;
> +		blk->fifo_available--;
>  	}
>  
> -	return ret;
> +	if (qup->pos == msg->len)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
>  }
>  
>  static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
> @@ -1227,49 +1249,137 @@ static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  	return ret;
>  }
>  
> -static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool is_rx)
>  {
> +	qup->cur_blk_events = 0;
> +	qup->blk_events = is_rx ? QUP_BLK_EVENT_RX_DONE : QUP_BLK_EVENT_TX_DONE;
> +}
> +
> +static void qup_i2c_write_rx_tags_v1(struct qup_i2c_dev *qup)
> +{
> +	struct i2c_msg *msg = qup->msg;
> +	u32 addr, len, val;
> +
> +	addr = i2c_8bit_addr_from_msg(msg);
> +
> +	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
> +	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
> +
> +	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
> +	writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
> +}
> +
> +static void qup_i2c_conf_v1(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL;
> +	u32 io_mode = QUP_REPACK_EN;
> +
> +	blk->is_tx_blk_mode =
> +		blk->total_tx_len > qup->out_fifo_sz ? true : false;
> +	blk->is_rx_blk_mode =
> +		blk->total_rx_len > qup->in_fifo_sz ? true : false;
> +
> +	if (blk->is_tx_blk_mode) {
> +		io_mode |= QUP_OUTPUT_BLK_MODE;
> +		writel(0, qup->base + QUP_MX_WRITE_CNT);
> +		writel(blk->total_tx_len, qup->base + QUP_MX_OUTPUT_CNT);
> +	} else {
> +		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
> +		writel(blk->total_tx_len, qup->base + QUP_MX_WRITE_CNT);
> +	}
> +
> +	if (blk->total_rx_len) {
> +		if (blk->is_rx_blk_mode) {
> +			io_mode |= QUP_INPUT_BLK_MODE;
> +			writel(0, qup->base + QUP_MX_READ_CNT);
> +			writel(blk->total_rx_len, qup->base + QUP_MX_INPUT_CNT);
> +		} else {
> +			writel(0, qup->base + QUP_MX_INPUT_CNT);
> +			writel(blk->total_rx_len, qup->base + QUP_MX_READ_CNT);
> +		}
> +	} else {
> +		qup_config |= QUP_NO_INPUT;
> +	}
> +
> +	writel(qup_config, qup->base + QUP_CONFIG);
> +	writel(io_mode, qup->base + QUP_IO_MODE);
> +}
> +
> +static void qup_i2c_clear_blk_v1(struct qup_i2c_block *blk)
> +{
> +	blk->tx_fifo_free = 0;
> +	blk->fifo_available = 0;
> +}
> +
> +static int qup_i2c_conf_xfer_v1(struct qup_i2c_dev *qup, bool is_rx)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
>  	int ret;
>  
> -	qup->msg = msg;
> -	qup->pos  = 0;
> -
> -	enable_irq(qup->irq);
> -	qup_i2c_set_read_mode(qup, msg->len);
> -
> +	qup_i2c_clear_blk_v1(blk);
> +	qup_i2c_conf_v1(qup);
>  	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
>  	if (ret)
> -		goto err;
> +		return ret;
>  
>  	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
>  
>  	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
>  	if (ret)
> -		goto err;
> +		return ret;
>  
> -	qup_i2c_issue_read(qup, msg);
> +	qup_i2c_set_blk_event(qup, is_rx);
> +	reinit_completion(&qup->xfer);
> +	enable_irq(qup->irq);
> +	if (!blk->is_tx_blk_mode) {
> +		blk->tx_fifo_free = qup->out_fifo_sz;
> +
> +		if (is_rx)
> +			qup_i2c_write_rx_tags_v1(qup);
> +		else
> +			qup_i2c_write_tx_fifo_v1(qup);
> +	}
>  
>  	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
>  	if (ret)
>  		goto err;
>  
> -	do {
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> +	ret = qup_i2c_wait_for_complete(qup, qup->msg);
> +	if (ret)
> +		goto err;
>  
> -		ret = qup_i2c_read_fifo(qup, msg);
> -		if (ret)
> -			goto err;
> -	} while (qup->pos < msg->len);
> +	ret = qup_i2c_bus_active(qup, ONE_BYTE);
>  
>  err:
>  	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
>  	return ret;
>  }
>  
> +static int qup_i2c_write_one(struct qup_i2c_dev *qup)
> +{
> +	struct i2c_msg *msg = qup->msg;
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	qup->pos = 0;
> +	blk->total_tx_len = msg->len +  1;
> +	blk->total_rx_len = 0;
> +
> +	return qup_i2c_conf_xfer_v1(qup, false);
> +}
> +
> +static int qup_i2c_read_one(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	qup->pos = 0;
> +	blk->total_tx_len = 2;
> +	blk->total_rx_len = qup->msg->len;
> +
> +	return qup_i2c_conf_xfer_v1(qup, true);
> +}
> +
>  static int qup_i2c_xfer(struct i2c_adapter *adap,
>  			struct i2c_msg msgs[],
>  			int num)
> @@ -1308,10 +1418,11 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
>  			goto out;
>  		}
>  
> +		qup->msg = &msgs[idx];
>  		if (msgs[idx].flags & I2C_M_RD)
> -			ret = qup_i2c_read_one(qup, &msgs[idx]);
> +			ret = qup_i2c_read_one(qup);
>  		else
> -			ret = qup_i2c_write_one(qup, &msgs[idx]);
> +			ret = qup_i2c_write_one(qup);
>  
>  		if (ret)
>  			break;
> @@ -1489,6 +1600,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
>  		qup->adap.algo = &qup_i2c_algo;
>  		qup->adap.quirks = &qup_i2c_quirks;
> +		qup->is_qup_v1 = true;
> +		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
> +		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
> +		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
>  	} else {
>  		qup->adap.algo = &qup_i2c_algo_v2;
>  		ret = qup_i2c_req_dma(qup);
> 

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2
  2018-02-03  7:58 ` [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2 Abhishek Sahu
@ 2018-02-16 11:23   ` Sricharan R
  2018-02-19 14:08     ` Abhishek Sahu
  2018-02-27 23:24   ` Christ, Austin
  1 sibling, 1 reply; 57+ messages in thread
From: Sricharan R @ 2018-02-16 11:23 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, linux-arm-msm, linux-soc, linux-i2c, linux-kernel

Hi Abhishek,

On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> Following are the major issues in current driver code
> 
> 1. The current driver simply assumes the transfer completion
>    whenever its gets any non-error interrupts and then simply do the
>    polling of available/free bytes in FIFO.
> 2. The block mode is not working properly since no handling in
>    being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_READ.
> 3. An i2c transfer can contain multiple message and QUP v2
>    supports reconfiguration during run in which the mode should be same
>    for all the sub transfer. Currently the mode is being programmed
>    before every sub transfer which is functionally wrong. If one message
>    is less than FIFO length and other message is greater than FIFO length,
     then transfers will fail.
> 
> Because of above, i2c v2 transfers of size greater than 64 are failing
> with following error message
> 
> 	i2c_qup 78b6000.i2c: timeout for fifo out full
> 
> To make block mode working properly and move to use the interrupts
> instead of polling, major code reorganization is required. Following
> are the major changes done in this patch
> 
> 1. Remove the polling of TX FIFO free space and RX FIFO available
>    bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
>    QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
>    interrupts to handle FIFO’s properly so check all these interrupts.
> 2. Determine the mode for transfer before starting by checking
>    all the tx/rx data length in each message. The complete message can be
>    transferred either in DMA mode or Programmed IO by FIFO/Block mode.
>    in DMA mode, both tx and rx uses same mode but in PIO mode, the TX and
>    RX can be in different mode.
> 3. During write, For FIFO mode, TX FIFO can be directly written
>    without checking for FIFO space. For block mode, the QUP will generate
>    OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
>    space.
> 4. During read, both TX and RX FIFO will be used. TX will be used
>    for writing tags and RX will be used for receiving the data. In QUP,
>    TX and RX can operate in separate mode so configure modes accordingly.
> 5. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
>    will be generated after all the bytes have been copied in RX FIFO. For
>    read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
>    whenever it has block size of available data.
> 6. Split the transfer in chunk of one QUP block size(256 bytes)
>    and schedule each block separately. QUP v2 supports reconfiguration
>    during run in which QUP can transfer multiple blocks without issuing a
>    stop events.
> 7. Port the SMBus block read support for new code changes.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 917 +++++++++++++++++++++++++------------------
>  1 file changed, 533 insertions(+), 384 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index af6c21a..46736a1 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -141,6 +141,15 @@
>  #define DEFAULT_CLK_FREQ 100000
>  #define DEFAULT_SRC_CLK 20000000
>  
> +/*
> + * Max tags length (start, stop and maximum 2 bytes address) for each QUP
> + * data transfer
> + */
> +#define QUP_MAX_TAGS_LEN		4
> +/* Max data length for each DATARD tags */
> +#define RECV_MAX_DATA_LEN		254
> +/* TAG length for DATA READ in RX FIFO  */
> +#define READ_RX_TAGS_LEN		2
>  /* MAX_OUTPUT_DONE_FLAG has been received */
>  #define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
>  /* MAX_INPUT_DONE_FLAG has been received */
> @@ -164,11 +173,24 @@
>   * tx_tag_len: tx tag length for current block
>   * rx_tag_len: rx tag length for current block
>   * data_len: remaining data length for current message
> + * cur_blk_len: data length for current block
>   * total_tx_len: total tx length including tag bytes for current QUP transfer
>   * total_rx_len: total rx length including tag bytes for current QUP transfer
> + * tx_fifo_data_pos: current byte number in TX FIFO word
>   * tx_fifo_free: number of free bytes in current QUP block write.
> + * rx_fifo_data_pos: current byte number in RX FIFO word
>   * fifo_available: number of available bytes in RX FIFO for current
>   *		   QUP block read
> + * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write
> + *		 to TX FIFO will be appended in this data and will be written to
> + *		 TX FIFO when all the 4 bytes are available.
> + * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will
> + *		 contains the 4 bytes of RX data.
> + * cur_data: pointer to tell cur data position for current message
> + * cur_tx_tags: pointer to tell cur position in tags
> + * tx_tags_sent: all tx tag bytes have been written in FIFO word
> + * send_last_word: for tx FIFO, last word send is pending in current block
> + * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word
>   * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
>   * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
>   * tags: contains tx tag bytes for current QUP transfer
> @@ -179,10 +201,20 @@ struct qup_i2c_block {
>  	int		tx_tag_len;
>  	int		rx_tag_len;
>  	int		data_len;
> +	int		cur_blk_len;
>  	int		total_tx_len;
>  	int		total_rx_len;
> +	int		tx_fifo_data_pos;
>  	int		tx_fifo_free;
> +	int		rx_fifo_data_pos;
>  	int		fifo_available;
> +	u32		tx_fifo_data;
> +	u32		rx_fifo_data;
> +	u8		*cur_data;
> +	u8		*cur_tx_tags;
> +	bool		tx_tags_sent;
> +	bool		send_last_word;
> +	bool		rx_tags_fetched;
>  	bool		is_tx_blk_mode;
>  	bool		is_rx_blk_mode;
>  	u8		tags[6];
> @@ -214,6 +246,7 @@ struct qup_i2c_dev {
>  	int			out_blk_sz;
>  	int			in_blk_sz;
>  
> +	int			blk_xfer_limit;
>  	unsigned long		one_byte_t;
>  	unsigned long		xfer_timeout;
>  	struct qup_i2c_block	blk;
> @@ -228,10 +261,10 @@ struct qup_i2c_dev {
>  
>  	/* To check if this is the last msg */
>  	bool			is_last;
> -	bool			is_qup_v1;
> +	bool			is_smbus_read;
>  
>  	/* To configure when bus is in run state */
> -	int			config_run;
> +	u32			config_run;
>  
>  	/* dma parameters */
>  	bool			is_dma;
> @@ -245,6 +278,8 @@ struct qup_i2c_dev {
>  	unsigned int		dma_threshold;
>  	unsigned int		max_xfer_sg_len;
>  	unsigned int		tag_buf_pos;
> +	/* The threshold length above which block mode will be used */
> +	unsigned int		blk_mode_threshold;
>  	struct			dma_pool *dpool;
>  	struct			qup_i2c_tag start_tag;
>  	struct			qup_i2c_bam brx;
> @@ -309,9 +344,6 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>  		goto done;
>  	}
>  
> -	if (!qup->is_qup_v1)
> -		goto done;
> -
>  	if (opflags & QUP_OUT_SVC_FLAG) {
>  		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>  
> @@ -444,108 +476,6 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
>  	return ret;
>  }
>  
> -/**
> - * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
> - * @qup: The qup_i2c_dev device
> - * @op: The bit/event to wait on
> - * @val: value of the bit to wait on, 0 or 1
> - * @len: The length the bytes to be transferred
> - */
> -static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
> -			      int len)
> -{
> -	unsigned long timeout;
> -	u32 opflags;
> -	u32 status;
> -	u32 shift = __ffs(op);
> -	int ret = 0;
> -
> -	len *= qup->one_byte_t;
> -	/* timeout after a wait of twice the max time */
> -	timeout = jiffies + len * 4;
> -
> -	for (;;) {
> -		opflags = readl(qup->base + QUP_OPERATIONAL);
> -		status = readl(qup->base + QUP_I2C_STATUS);
> -
> -		if (((opflags & op) >> shift) == val) {
> -			if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
> -				if (!(status & I2C_STATUS_BUS_ACTIVE)) {
> -					ret = 0;
> -					goto done;
> -				}
> -			} else {
> -				ret = 0;
> -				goto done;
> -			}
> -		}
> -
> -		if (time_after(jiffies, timeout)) {
> -			ret = -ETIMEDOUT;
> -			goto done;
> -		}
> -		usleep_range(len, len * 2);
> -	}
> -
> -done:
> -	if (qup->bus_err || qup->qup_err)
> -		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
> -
> -	return ret;
> -}
> -
> -static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
> -				      struct i2c_msg *msg)
> -{
> -	/* Number of entries to shift out, including the tags */
> -	int total = msg->len + qup->blk.tx_tag_len;
> -
> -	total |= qup->config_run;
> -
> -	if (total < qup->out_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_WRITE_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
> -	}
> -}
> -
> -static int check_for_fifo_space(struct qup_i2c_dev *qup)
> -{
> -	int ret;
> -
> -	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> -	if (ret)
> -		goto out;
> -
> -	ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
> -				 RESET_BIT, 4 * ONE_BYTE);
> -	if (ret) {
> -		/* Fifo is full. Drain out the fifo */
> -		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -		if (ret)
> -			goto out;
> -
> -		ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY,
> -					 RESET_BIT, 256 * ONE_BYTE);
> -		if (ret) {
> -			dev_err(qup->dev, "timeout for fifo out full");
> -			goto out;
> -		}
> -
> -		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> -		if (ret)
> -			goto out;
> -	}
> -
> -out:
> -	return ret;
> -}
> -
>  static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
>  {
>  	struct qup_i2c_block *blk = &qup->blk;
> @@ -591,60 +521,17 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
>  static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
>  				 struct i2c_msg *msg)
>  {
> -	memset(&qup->blk, 0, sizeof(qup->blk));
> -
> +	qup->blk.pos = 0;
>  	qup->blk.data_len = msg->len;
> -	qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
> -
> -	/* 4 bytes for first block and 2 writes for rest */
> -	qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> -
> -	/* There are 2 tag bytes that are read in to fifo for every block */
> -	if (msg->flags & I2C_M_RD)
> -		qup->blk.rx_tag_len = qup->blk.count * 2;
> -}
> -
> -static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
> -			     int dlen, u8 *dbuf)
> -{
> -	u32 val = 0, idx = 0, pos = 0, i = 0, t;
> -	int  len = tlen + dlen;
> -	u8 *buf = tbuf;
> -	int ret = 0;
> -
> -	while (len > 0) {
> -		ret = check_for_fifo_space(qup);
> -		if (ret)
> -			return ret;
> -
> -		t = (len >= 4) ? 4 : len;
> -
> -		while (idx < t) {
> -			if (!i && (pos >= tlen)) {
> -				buf = dbuf;
> -				pos = 0;
> -				i = 1;
> -			}
> -			val |= buf[pos++] << (idx++ * 8);
> -		}
> -
> -		writel(val, qup->base + QUP_OUT_FIFO_BASE);
> -		idx  = 0;
> -		val = 0;
> -		len -= 4;
> -	}
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -
> -	return ret;
> +	qup->blk.count = DIV_ROUND_UP(msg->len, qup->blk_xfer_limit);
>  }
>  
>  static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
>  {
>  	int data_len;
>  
> -	if (qup->blk.data_len > QUP_READ_LIMIT)
> -		data_len = QUP_READ_LIMIT;
> +	if (qup->blk.data_len > qup->blk_xfer_limit)
> +		data_len = qup->blk_xfer_limit;
>  	else
>  		data_len = qup->blk.data_len;
>  
> @@ -661,9 +548,9 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
>  {
>  	int len = 0;
>  
> -	if (msg->len > 1) {
> +	if (qup->is_smbus_read) {
>  		tags[len++] = QUP_TAG_V2_DATARD_STOP;
> -		tags[len++] = qup_i2c_get_data_len(qup) - 1;
> +		tags[len++] = qup_i2c_get_data_len(qup);
>  	} else {
>  		tags[len++] = QUP_TAG_V2_START;
>  		tags[len++] = addr & 0xff;
> @@ -725,24 +612,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>  	return len;
>  }
>  
> -static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int data_len = 0, tag_len, index;
> -	int ret;
> -
> -	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
> -	index = msg->len - qup->blk.data_len;
> -
> -	/* only tags are written for read */
> -	if (!(msg->flags & I2C_M_RD))
> -		data_len = qup_i2c_get_data_len(qup);
> -
> -	ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
> -				data_len, &msg->buf[index]);
> -	qup->blk.data_len -= data_len;
> -
> -	return ret;
> -}
>  
>  static void qup_i2c_bam_cb(void *data)
>  {
> @@ -809,6 +678,7 @@ static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  	u32 i = 0, tlen, tx_len = 0;
>  	u8 *tags;
>  
> +	qup->blk_xfer_limit = QUP_READ_LIMIT;
>  	qup_i2c_set_blk_data(qup, msg);
>  
>  	blocks = qup->blk.count;
> @@ -1057,7 +927,7 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
>  	unsigned long left;
>  	int ret = 0;
>  
> -	left = wait_for_completion_timeout(&qup->xfer, HZ);
> +	left = wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout);
>  	if (!left) {
>  		writel(1, qup->base + QUP_SW_RESET);
>  		ret = -ETIMEDOUT;
> @@ -1069,65 +939,6 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
>  	return ret;
>  }
>  
> -static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int ret = 0;
> -
> -	qup->msg = msg;
> -	qup->pos = 0;
> -	enable_irq(qup->irq);
> -	qup_i2c_set_blk_data(qup, msg);
> -	qup_i2c_set_write_mode_v2(qup, msg);
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -	if (ret)
> -		goto err;
> -
> -	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> -
> -	do {
> -		ret = qup_i2c_issue_xfer_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		qup->blk.pos++;
> -	} while (qup->blk.pos < qup->blk.count);
> -
> -	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
> -
> -err:
> -	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
> -	return ret;
> -}
> -
> -static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
> -{
> -	int tx_len = qup->blk.tx_tag_len;
> -
> -	len += qup->blk.rx_tag_len;
> -	len |= qup->config_run;
> -	tx_len |= qup->config_run;
> -
> -	if (len < qup->in_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
> -		writel(len, qup->base + QUP_MX_READ_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
> -		writel(len, qup->base + QUP_MX_INPUT_CNT);
> -	}
> -}
> -
>  static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
>  {
>  	struct qup_i2c_block *blk = &qup->blk;
> @@ -1151,104 +962,6 @@ static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
>  		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
>  }
>  
> -static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
> -				struct i2c_msg *msg)
> -{
> -	u32 val;
> -	int idx, pos = 0, ret = 0, total, msg_offset = 0;
> -
> -	/*
> -	 * If the message length is already read in
> -	 * the first byte of the buffer, account for
> -	 * that by setting the offset
> -	 */
> -	if (qup_i2c_check_msg_len(msg) && (msg->len > 1))
> -		msg_offset = 1;
> -	total = qup_i2c_get_data_len(qup);
> -	total -= msg_offset;
> -
> -	/* 2 extra bytes for read tags */
> -	while (pos < (total + 2)) {
> -		/* Check that FIFO have data */
> -		ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
> -					 SET_BIT, 4 * ONE_BYTE);
> -		if (ret) {
> -			dev_err(qup->dev, "timeout for fifo not empty");
> -			return ret;
> -		}
> -		val = readl(qup->base + QUP_IN_FIFO_BASE);
> -
> -		for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
> -			/* first 2 bytes are tag bytes */
> -			if (pos < 2)
> -				continue;
> -
> -			if (pos >= (total + 2))
> -				goto out;
> -			msg->buf[qup->pos + msg_offset] = val & 0xff;
> -			qup->pos++;
> -		}
> -	}
> -
> -out:
> -	qup->blk.data_len -= total;
> -
> -	return ret;
> -}
> -
> -static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int ret = 0;
> -
> -	qup->msg = msg;
> -	qup->pos  = 0;
> -	enable_irq(qup->irq);
> -	qup_i2c_set_blk_data(qup, msg);
> -	qup_i2c_set_read_mode_v2(qup, msg->len);
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -	if (ret)
> -		goto err;
> -
> -	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> -
> -	do {
> -		ret = qup_i2c_issue_xfer_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_read_fifo_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		qup->blk.pos++;
> -
> -		/* Handle SMBus block read length */
> -		if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) {
> -			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) {
> -				ret = -EPROTO;
> -				goto err;
> -			}
> -			msg->len += msg->buf[0];
> -			qup->pos = 0;
> -			qup_i2c_set_blk_data(qup, msg);
> -			/* set tag length for block read */
> -			qup->blk.tx_tag_len = 2;
> -			qup_i2c_set_read_mode_v2(qup, msg->buf[0]);
> -		}
> -	} while (qup->blk.pos < qup->blk.count);
> -
> -err:
> -	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
> -	return ret;
> -}
> -
>  static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool is_rx)
>  {
>  	qup->cur_blk_events = 0;
> @@ -1442,13 +1155,452 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
>  	return ret;
>  }
>  
 
  Since this is used for both FIFO and BLK mode, might be good to call it
  qup_i2c_set_event. Same in rest of the places and macros as well.
  But if this is going to be removed altogether, then great.

> +/*
> + * Function to configure registers related with reconfiguration during run
> + * and will be done before each I2C sub transfer.
> + */
> +static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2;
> +
> +	if (blk->is_tx_blk_mode)
> +		writel(qup->config_run | blk->total_tx_len,
> +		       qup->base + QUP_MX_OUTPUT_CNT);
> +	else
> +		writel(qup->config_run | blk->total_tx_len,
> +		       qup->base + QUP_MX_WRITE_CNT);
> +
> +	if (blk->total_rx_len) {
> +		if (blk->is_rx_blk_mode)
> +			writel(qup->config_run | blk->total_rx_len,
> +			       qup->base + QUP_MX_INPUT_CNT);
> +		else
> +			writel(qup->config_run | blk->total_rx_len,
> +			       qup->base + QUP_MX_READ_CNT);
> +	} else {
> +		qup_config |= QUP_NO_INPUT;
> +	}
> +
> +	writel(qup_config, qup->base + QUP_CONFIG);
> +}
> +
> +/*
> + * Function to configure registers related with transfer mode (FIFO/Block)
> + * before starting of i2c transfer and will be done only once in QUP RESET
> + * state.
> + */
> +static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u32 io_mode = QUP_REPACK_EN;
> +
> +	if (blk->is_tx_blk_mode) {
> +		io_mode |= QUP_OUTPUT_BLK_MODE;
> +		writel(0, qup->base + QUP_MX_WRITE_CNT);
> +	} else {
> +		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
> +	}
> +
> +	if (blk->is_rx_blk_mode) {
> +		io_mode |= QUP_INPUT_BLK_MODE;
> +		writel(0, qup->base + QUP_MX_READ_CNT);
> +	} else {
> +		writel(0, qup->base + QUP_MX_INPUT_CNT);
> +	}
> +
> +	writel(io_mode, qup->base + QUP_IO_MODE);
> +}
> +
> +/*
> + * Function to clear required variables before starting of any QUP v2
> + * sub transfer
> + */
> +static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk)
> +{
> +	blk->send_last_word = false;
> +	blk->tx_tags_sent = false;
> +	blk->tx_fifo_data = 0;
> +	blk->tx_fifo_data_pos = 0;
> +	blk->tx_fifo_free = 0;
> +
> +	blk->rx_tags_fetched = false;
> +	blk->rx_fifo_data = 0;
> +	blk->rx_fifo_data_pos = 0;
> +	blk->fifo_available = 0;
> +}
> +
> +/*
> + * Function to receive data from RX FIFO for read message in QUP v2
> + * i2c transfer.
> + */
> +static void qup_i2c_recv_data(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	int j;
> +
> +	for (j = blk->rx_fifo_data_pos;
> +	     blk->cur_blk_len && blk->fifo_available;
> +	     blk->cur_blk_len--, blk->fifo_available--) {
> +		if (j == 0)
> +			blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
> +
> +		*(blk->cur_data++) = blk->rx_fifo_data;
> +		blk->rx_fifo_data >>= 8;
> +
> +		if (j == 3)
> +			j = 0;
> +		else
> +			j++;
> +	}
> +
> +	blk->rx_fifo_data_pos = j;
> +}
> +
> +/* Function to receive tags for read message in QUP v2 i2c transfer. */
> +static void qup_i2c_recv_tags(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
> +	blk->rx_fifo_data >>= blk->rx_tag_len  * 8;

  why cant it be simply ignored ?

> +	blk->rx_fifo_data_pos = blk->rx_tag_len;
> +	blk->fifo_available -= blk->rx_tag_len;
> +}
> +
> +/*
> + * This function reads the data and tags from RX FIFO. Since in read case, the
> + * tags will be preceded by received data bytes need to be written so
> + * 1. Check if rx_tags_fetched is false i.e. the start of QUP block so receive
> + *    all tag bytes and discard that.
> + * 2. Read the data from RX FIFO. When all the data bytes have been read then
> + *    mark the QUP_BLK_EVENT_RX_DATA_DONE in current block event and return.
> + */
> +static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	if (!blk->rx_tags_fetched) {
> +		qup_i2c_recv_tags(qup);
> +		blk->rx_tags_fetched = true;
> +	}
> +
> +	qup_i2c_recv_data(qup);
> +	if (!blk->cur_blk_len)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
> +}
> +
> +/*
> + * Function to write bytes in TX FIFO for write message in QUP v2 i2c
> + * transfer. QUP TX FIFO write works on word basis (4 bytes). New byte write to
> + * TX FIFO will be appended in this data tx_fifo_data and will be written to TX
> + * FIFO when all the 4 bytes are available.
> + */
> +static void
> +qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned int *len)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	unsigned int j;
> +
> +	for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free;
> +	     (*len)--, blk->tx_fifo_free--) {
> +		blk->tx_fifo_data |= *(*data)++ << (j * 8);
> +		if (j == 3) {
> +			writel(blk->tx_fifo_data,
> +			       qup->base + QUP_OUT_FIFO_BASE);
> +			blk->tx_fifo_data = 0x0;
> +			j = 0;
> +		} else {
> +			j++;
> +		}
> +	}
> +
> +	blk->tx_fifo_data_pos = j;
> +}
> +
> +/* Function to transfer tags for read message in QUP v2 i2c transfer. */
> +static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len);
> +	if (blk->tx_fifo_data_pos)
> +		writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
> +
> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
> +}
> +
> +/*
> + * This function writes the data and tags in TX FIFO. Since in write case, both
> + * tags and data need to be written and QUP write tags can have maximum 256 data
> + * length, so it follows simple internal state machine to manage it.
> + * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the
> + *    tags to TX FIFO.
> + * 2. Check if send_last_word is true. This will be set when last few data bytes
> + *    less than 4 bytes are reamining to be written in FIFO because of no FIFO
> + *    space. All this data bytes are available in tx_fifo_data so write this
> + *    in FIFO and mark the tx done.
> + * 3. Write the data to TX FIFO and check for cur_blk_len. If this is non zero
> + *    then more data is pending otherwise following 3 cases can be possible
> + *    a. if tx_fifo_data_pos is zero that means all the data bytes in this block
> + *       have been written in TX FIFO so mark the tx done.
> + *    b. tx_fifo_free is zero. In this case, last few bytes (less than 4
> + *       bytes) are copied to tx_fifo_data but couldn't be sent because of
> + *       FIFO full so make send_last_word true.
> + *    c. tx_fifo_free is non zero i.e tx FIFO is free so copy the remaining data
> + *       from tx_fifo_data to tx FIFO and mark the tx done. Since,
> + *       qup_i2c_write_blk_data do write in 4 bytes and FIFO space is in
> + *       multiple of 4 bytes so tx_fifo_free will be always greater than or
> + *       equal to 4 bytes.

       Comments b and c should be c and b as per the code below 

> + */
> +static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	if (!blk->tx_tags_sent) {
> +		qup_i2c_write_blk_data(qup, &blk->cur_tx_tags,
> +				       &blk->tx_tag_len);
> +		blk->tx_tags_sent = true;
> +	}
> +
> +	if (blk->send_last_word)
> +		goto send_last_word;
> +
> +	qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len);

 ok, do understand, why is cur_blk_len zero and we still have pending bytes to be written ?

> +	if (!blk->cur_blk_len) {
> +		if (!blk->tx_fifo_data_pos)
> +			goto tx_data_done;
> +
> +		if (blk->tx_fifo_free)
> +			goto send_last_word;
> +
> +		blk->send_last_word = true;
> +	}
> +
> +	return;
> +
> +send_last_word:
> +	writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
> +tx_data_done:
> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;

  Yes, as commented on the previous patch, if we can get rid of this 4 flags
  for completion in block/fifo mode, it would simply things a bit.

> +}
> +
> +/*
> + * Main transfer function which will be used for reading or writing i2c data.
> + * The QUP v2 supports reconfiguration during run in which multiple i2c sub
> + * transfers can be scheduled.
> + */
> +static int
> +qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool is_first,
> +		     bool change_pause_state)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	struct i2c_msg *msg = qup->msg;
> +	int ret;
> +
> +	/*
> +	 * Check if its SMBus Block read for which the top level read will be
> +	 * done into 2 QUP reads. One with message length 1 while other one is
> +	 * with actual length.
> +	 */
> +	if (qup_i2c_check_msg_len(msg)) {
> +		if (qup->is_smbus_read) {
> +			/*
> +			 * If the message length is already read in
> +			 * the first byte of the buffer, account for
> +			 * that by setting the offset
> +			 */
> +			blk->cur_data += 1;
> +			is_first = false;
> +		} else {
> +			change_pause_state = false;
> +		}
> +	}
> +
> +	qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN;
> +
> +	qup_i2c_clear_blk_v2(blk);
> +	qup_i2c_conf_count_v2(qup);
> +
> +	/* If it is first sub transfer, then configure i2c bus clocks */
> +	if (is_first) {
> +		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> +		if (ret)
> +			return ret;
> +
> +		writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> +
> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	qup_i2c_set_blk_event(qup, is_rx);

  hmm, if the completion is changed as per the just INPUT/OUTPUT done
  then this blk event tracking can be removed.

> +	reinit_completion(&qup->xfer);
> +	enable_irq(qup->irq);
> +	/*
> +	 * In FIFO mode, tx FIFO can be written directly while in block mode the
> +	 * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt
> +	 */
> +	if (!blk->is_tx_blk_mode) {
> +		blk->tx_fifo_free = qup->out_fifo_sz;
> +
> +		if (is_rx)
> +			qup_i2c_write_rx_tags_v2(qup);
> +		else
> +			qup_i2c_write_tx_fifo_v2(qup);
> +	}
> +
> +	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> +	if (ret)
> +		goto err;
> +
> +	ret = qup_i2c_wait_for_complete(qup, msg);
> +	if (ret)
> +		goto err;
> +
> +	/* Move to pause state for all the transfers, except last one */
> +	if (change_pause_state) {
> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> +		if (ret)
> +			goto err;
> +	}
> +
> +err:
> +	disable_irq(qup->irq);
> +	return ret;
> +}
> +
> +/*
> + * Function to transfer one read/write message in i2c transfer. It splits the
> + * message into multiple of blk_xfer_limit data length blocks and schedule each
> + * QUP block individually.
> + */
> +static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, bool is_rx)
> +{
> +	int ret = 0;
> +	unsigned int data_len, i;
> +	struct i2c_msg *msg = qup->msg;
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u8 *msg_buf = msg->buf;
> +
> +	qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT;
> +	qup_i2c_set_blk_data(qup, msg);
> +
> +	for (i = 0; i < blk->count; i++) {
> +		data_len =  qup_i2c_get_data_len(qup);
> +		blk->pos = i;
> +		blk->cur_tx_tags = blk->tags;
> +		blk->cur_blk_len = data_len;
> +		blk->tx_tag_len =
> +			qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg);
> +
> +		blk->cur_data = msg_buf;
> +
> +		if (is_rx) {
> +			blk->total_tx_len = blk->tx_tag_len;
> +			blk->rx_tag_len = 2;
> +			blk->total_rx_len = blk->rx_tag_len + data_len;
> +		} else {
> +			blk->total_tx_len = blk->tx_tag_len + data_len;
> +			blk->total_rx_len = 0;
> +		}
> +
> +		ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i,
> +					   !qup->is_last || i < blk->count - 1);
> +		if (ret)
> +			return ret;
> +
> +		/* Handle SMBus block read length */
> +		if (qup_i2c_check_msg_len(msg) && msg->len == 1 &&
> +		    !qup->is_smbus_read) {
> +			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX)
> +				return -EPROTO;
> +
> +			msg->len = msg->buf[0];
> +			qup->is_smbus_read = true;
> +			ret = qup_i2c_xfer_v2_msg(qup, msg_id, true);
> +			qup->is_smbus_read = false;
> +			if (ret)
> +				return ret;
> +
> +			msg->len += 1;
> +		}
> +
> +		msg_buf += data_len;
> +		blk->data_len -= qup->blk_xfer_limit;
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * QUP v2 supports 3 modes
> + * Programmed IO using FIFO mode : Less than FIFO size
> + * Programmed IO using Block mode : Greater than FIFO size
> + * DMA using BAM : Appropriate for any transactio size but the address should be
> + *		   DMA applicable
> + *

 s/transactio/transaction

> + * This function determines the mode which will be used for this transfer. An
> + * i2c transfer contains multiple message. Following are the rules to determine
> + * the mode used.
> + * 1. Determine the tx and rx length for each message and maximum tx and rx
> + *    length for complete transfer
> + * 2. If tx or rx length is greater than DMA threshold than use the DMA mode.
> + * 3. In FIFO or block mode, TX and RX can operate in different mode so check
> + *    for maximum tx and rx length to determine mode.
> + */
> +static int
> +qup_i2c_determine_mode(struct qup_i2c_dev *qup, struct i2c_msg msgs[], int num)
   
   qup_i2c_determine_mode_v2
 
> +{
> +	int idx;
> +	bool no_dma = false;
> +	unsigned int max_tx_len = 0, max_rx_len = 0;
> +	unsigned int cur_tx_len, cur_rx_len;
> +	unsigned int total_rx_len = 0, total_tx_len = 0;
> +
> +	/* All i2c_msgs should be transferred using either dma or cpu */
> +	for (idx = 0; idx < num; idx++) {
> +		if (msgs[idx].len == 0)
> +			return -EINVAL;
> +
> +		if (msgs[idx].flags & I2C_M_RD) {
> +			cur_tx_len = 0;
> +			cur_rx_len = msgs[idx].len;
> +		} else {
> +			cur_tx_len = msgs[idx].len;
> +			cur_rx_len = 0;
> +		}
> +
> +		if (is_vmalloc_addr(msgs[idx].buf))
> +			no_dma = true;
> +
> +		max_tx_len = max(max_tx_len, cur_tx_len);
> +		max_rx_len = max(max_rx_len, cur_rx_len);
> +		total_rx_len += cur_rx_len;
> +		total_tx_len += cur_tx_len;
> +	}

 why is tag length for each block not being considered here ?

> +
> +	if (!no_dma && qup->is_dma &&

  why do we need is_dma and use_dma ?
  Now that you have removed the need for is_dma in rest of places,
  better to get rid of that fully.

> +	    (total_tx_len > qup->dma_threshold ||
> +	     total_rx_len > qup->dma_threshold)) {
> +		qup->use_dma = true;
> +	} else {
> +		qup->blk.is_tx_blk_mode =
> +			max_tx_len > qup->blk_mode_threshold ? true : false;
> +		qup->blk.is_rx_blk_mode =
> +			max_rx_len > qup->blk_mode_threshold ? true : false;
> +	}
> +
> +	return 0;
> +}
> +
>  static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>  			   struct i2c_msg msgs[],
>  			   int num)
>  {
>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>  	int ret, idx = 0;
> -	unsigned int total_len = 0;
>  
>  	qup->bus_err = 0;
>  	qup->qup_err = 0;
> @@ -1457,6 +1609,10 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>  	if (ret < 0)
>  		goto out;
>  
> +	ret = qup_i2c_determine_mode(qup, msgs, num);
> +	if (ret)
> +		goto out;
> +
>  	writel(1, qup->base + QUP_SW_RESET);
>  	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
>  	if (ret)
> @@ -1466,59 +1622,35 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>  	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
>  	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
>  
> -	if ((qup->is_dma)) {
> -		/* All i2c_msgs should be transferred using either dma or cpu */
> +	if (qup_i2c_poll_state_i2c_master(qup)) {
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	if (qup->use_dma) {
> +		reinit_completion(&qup->xfer);
> +		ret = qup_i2c_bam_xfer(adap, &msgs[0], num);
> +		qup->use_dma = false;
> +	} else {
> +		qup_i2c_conf_mode_v2(qup);
> +
>  		for (idx = 0; idx < num; idx++) {
> -			if (msgs[idx].len == 0) {
> -				ret = -EINVAL;
> -				goto out;
> -			}
> +			qup->msg = &msgs[idx];
> +			qup->is_last = idx == (num - 1);
>  
> -			if (is_vmalloc_addr(msgs[idx].buf))
> +			ret = qup_i2c_xfer_v2_msg(qup, idx,
> +					!!(msgs[idx].flags & I2C_M_RD));

  why !!() is required here ?

> +			if (ret)
>  				break;
> -
> -			total_len += msgs[idx].len;
>  		}
> -
> -		if (idx == num && total_len > qup->dma_threshold)
> -			qup->use_dma = true;
> +		qup->msg = NULL;
>  	}
>  
> -	idx = 0;
> -
> -	do {
> -		if (msgs[idx].len == 0) {
> -			ret = -EINVAL;
> -			goto out;
> -		}
> -
> -		if (qup_i2c_poll_state_i2c_master(qup)) {
> -			ret = -EIO;
> -			goto out;
> -		}
> -
> -		qup->is_last = (idx == (num - 1));
> -		if (idx)
> -			qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
> -		else
> -			qup->config_run = 0;
> -
> -		reinit_completion(&qup->xfer);
> -
> -		if (qup->use_dma) {
> -			ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
> -			qup->use_dma = false;
> -			break;
> -		} else {
> -			if (msgs[idx].flags & I2C_M_RD)
> -				ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
> -			else
> -				ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
> -		}
> -	} while ((idx++ < (num - 1)) && !ret);
> +	if (!ret)
> +		ret = qup_i2c_bus_active(qup, ONE_BYTE);
>  
>  	if (!ret)
> -		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
> +		qup_i2c_change_state(qup, QUP_RESET_STATE);
>  
>  	if (ret == 0)
>  		ret = num;
> @@ -1582,6 +1714,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	u32 src_clk_freq = DEFAULT_SRC_CLK;
>  	u32 clk_freq = DEFAULT_CLK_FREQ;
>  	int blocks;
> +	bool is_qup_v1;
>  
>  	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>  	if (!qup)
> @@ -1600,12 +1733,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
>  		qup->adap.algo = &qup_i2c_algo;
>  		qup->adap.quirks = &qup_i2c_quirks;
> -		qup->is_qup_v1 = true;
> -		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
> -		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
> -		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
> +		is_qup_v1 = true;
>  	} else {
>  		qup->adap.algo = &qup_i2c_algo_v2;
> +		is_qup_v1 = false;
>  		ret = qup_i2c_req_dma(qup);
>  
>  		if (ret == -EPROBE_DEFER)
> @@ -1731,14 +1862,31 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  		ret = -EIO;
>  		goto fail;
>  	}
> -	qup->out_blk_sz = blk_sizes[size] / 2;
> +	qup->out_blk_sz = blk_sizes[size];
>  
>  	size = QUP_INPUT_BLOCK_SIZE(io_mode);
>  	if (size >= ARRAY_SIZE(blk_sizes)) {
>  		ret = -EIO;
>  		goto fail;
>  	}
> -	qup->in_blk_sz = blk_sizes[size] / 2;
> +	qup->in_blk_sz = blk_sizes[size];
> +
> +	if (is_qup_v1) {
> +		/*
> +		 * in QUP v1, QUP_CONFIG uses N as 15 i.e 16 bits constitutes a
> +		 * single transfer but the block size is in bytes so divide the
> +		 * in_blk_sz and out_blk_sz by 2
> +		 */
> +		qup->in_blk_sz /= 2;
> +		qup->out_blk_sz /= 2;
> +		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
> +		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
> +		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
> +	} else {
> +		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v2;
> +		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v2;
> +		qup->write_rx_tags = qup_i2c_write_rx_tags_v2;
> +	}
>  
>  	size = QUP_OUTPUT_FIFO_SIZE(io_mode);
>  	qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
> @@ -1746,6 +1894,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>  	size = QUP_INPUT_FIFO_SIZE(io_mode);
>  	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
>  	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
> +	qup->blk_mode_threshold = qup->dma_threshold - QUP_MAX_TAGS_LEN;
>  
>  	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
>  	hs_div = 3;
> 

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion
  2018-02-08 14:03   ` Sricharan R
@ 2018-02-19 10:24     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 10:24 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-08 19:33, Sricharan R wrote:
> Hi Abhishek,
> 
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> The QUP BSLP BAM generates the following error sometimes if the
>> current I2C DMA transfer fails and the flush operation has been
>> scheduled
>> 
>>     “bam-dma-engine 7884000.dma: Cannot free busy channel”
>> 
>> If any I2C error comes during BAM DMA transfer, then the QUP I2C
>> interrupt will be generated and the flush operation will be
>> carried out to make i2c consume all scheduled DMA transfer.
>> Currently, the same completion structure is being used for BAM
>> transfer which has already completed without reinit. It will make
>> flush operation wait_for_completion_timeout completed immediately
>> and will proceed for freeing the DMA resources where the
>> descriptors are still in process.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index 08f8e01..9faa26c41a 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -1,5 +1,5 @@
>>  /*
>> - * Copyright (c) 2009-2013, The Linux Foundation. All rights 
>> reserved.
>> + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All 
>> rights reserved.
> 
> Not sure, if this was an intended change. But given that you are fixing 
> this,

  Thanks Sricharan.
  Since this is the first patch, so I updated the year.

> you can change the header to the new SPDX one.
> 

  Yes that would be better.
  I will fix that also.

  Thanks,
  Abhishek

>>   * Copyright (c) 2014, Sony Mobile Communications AB.
>>   *
>>   *
>> @@ -844,6 +844,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev 
>> *qup, struct i2c_msg *msg,
>>  	}
>> 
>>  	if (ret || qup->bus_err || qup->qup_err) {
>> +		reinit_completion(&qup->xfer);
>> +
>>  		if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
>>  			dev_err(qup->dev, "change to run state timed out");
>>  			goto desc_err;
>> 
> 
> Except for the above nit,
>   Acked-by: Sricharan R <sricharan@codeaurora.org>
> 
> Regards,
>  Sricharan

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count
  2018-02-09  2:16   ` Sricharan R
@ 2018-02-19 10:26     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 10:26 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-09 07:46, Sricharan R wrote:
> Hi Abhishek,
> 
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
>> be used for total number of SG entries.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 26 ++++++++++----------------
>>  1 file changed, 10 insertions(+), 16 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index c68f433..bb83a2967 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -692,7 +692,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev 
>> *qup, struct i2c_msg *msg,
>>  	struct dma_async_tx_descriptor *txd, *rxd = NULL;
>>  	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
>>  	dma_cookie_t cookie_rx, cookie_tx;
>> -	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
>> +	u32 len, blocks, rem;
>>  	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
>>  	u8 *tags;
>> 
> 
>  This is correct. Just a nit, may be rx/tx_buf can be changed to
>  rx/tx_count to make it more clear.
> 

  Yes, rx/tx_count will be more meaningful. rx/tx_buf gives the
  impression that it is uchar buffer.  I will change that.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  2018-02-15 14:31   ` Sricharan R
@ 2018-02-19 10:34     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 10:34 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-15 20:01, Sricharan R wrote:
> Hi Abhishek,
> 
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> A single BAM transfer can have multiple read and write messages.
>> The EOT and FLUSH tags should be scheduled at the end of BAM HW
>> descriptors. Since the READ and WRITE can be present in any order
>> so for some of the cases, these tags are not being written
>> correctly.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 54 
>> ++++++++++++++++++++------------------------
>>  1 file changed, 24 insertions(+), 30 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index bb83a2967..6357aff 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -560,7 +560,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 
>> *tags, struct qup_i2c_dev *qup,
>>  }
>> 
>>  static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>> -			    struct i2c_msg *msg,  int is_dma)
>> +			    struct i2c_msg *msg)
>>  {
>>  	u16 addr = i2c_8bit_addr_from_msg(msg);
>>  	int len = 0;
>> @@ -601,11 +601,6 @@ static int qup_i2c_set_tags(u8 *tags, struct 
>> qup_i2c_dev *qup,
>>  	else
>>  		tags[len++] = data_len;
>> 
>> -	if ((msg->flags & I2C_M_RD) && last && is_dma) {
>> -		tags[len++] = QUP_BAM_INPUT_EOT;
>> -		tags[len++] = QUP_BAM_FLUSH_STOP;
>> -	}
>> -
>>  	return len;
>>  }
>> 
>> @@ -614,7 +609,7 @@ static int qup_i2c_issue_xfer_v2(struct 
>> qup_i2c_dev *qup, struct i2c_msg *msg)
>>  	int data_len = 0, tag_len, index;
>>  	int ret;
>> 
>> -	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg, 0);
>> +	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
>>  	index = msg->len - qup->blk.data_len;
>> 
>>  	/* only tags are written for read */
>> @@ -710,7 +705,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev 
>> *qup, struct i2c_msg *msg,
>>  			while (qup->blk.pos < blocks) {
>>  				tlen = (i == (blocks - 1)) ? rem : limit;
>>  				tags = &qup->start_tag.start[off + len];
>> -				len += qup_i2c_set_tags(tags, qup, msg, 1);
>> +				len += qup_i2c_set_tags(tags, qup, msg);
>>  				qup->blk.data_len -= tlen;
>> 
>>  				/* scratch buf to read the start and len tags */
>> @@ -738,17 +733,11 @@ static int qup_i2c_bam_do_xfer(struct 
>> qup_i2c_dev *qup, struct i2c_msg *msg,
>>  				return ret;
>> 
>>  			off += len;
>> -			/* scratch buf to read the BAM EOT and FLUSH tags */
>> -			ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
>> -					     &qup->brx.tag.start[0],
>> -					     2, qup, DMA_FROM_DEVICE);
>> -			if (ret)
>> -				return ret;
>>  		} else {
>>  			while (qup->blk.pos < blocks) {
>>  				tlen = (i == (blocks - 1)) ? rem : limit;
>>  				tags = &qup->start_tag.start[off + tx_len];
>> -				len = qup_i2c_set_tags(tags, qup, msg, 1);
>> +				len = qup_i2c_set_tags(tags, qup, msg);
>>  				qup->blk.data_len -= tlen;
>> 
>>  				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
>> @@ -768,26 +757,31 @@ static int qup_i2c_bam_do_xfer(struct 
>> qup_i2c_dev *qup, struct i2c_msg *msg,
>>  			}
>>  			off += tx_len;
>> 
>> -			if (idx == (num - 1)) {
>> -				len = 1;
>> -				if (rx_buf) {
>> -					qup->btx.tag.start[0] =
>> -							QUP_BAM_INPUT_EOT;
>> -					len++;
>> -				}
>> -				qup->btx.tag.start[len - 1] =
>> -							QUP_BAM_FLUSH_STOP;
>> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
>> -						     &qup->btx.tag.start[0],
>> -						     len, qup, DMA_TO_DEVICE);
>> -				if (ret)
>> -					return ret;
>> -			}
>>  		}
>>  		idx++;
>>  		msg++;
>>  	}
> 
>  While here, can you please split above the if, else in to two
> separate functions ?
>  and probably one more function for handling the NACK case down below.
> The function
>  size at the moment is too big.
> 

  Sure. Already I split this function into 2 functions in
  [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum 
xfer len
  which is making function size smaller. I will check if I can split in 
more
  functions.

>> 
>> +	/* schedule the EOT and FLUSH I2C tags */
>> +	len = 1;
>> +	if (rx_buf) {
>> +		qup->btx.tag.start[0] = QUP_BAM_INPUT_EOT;
>> +		len++;
>> +
>> +		/* scratch buf to read the BAM EOT and FLUSH tags */
>> +		ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
>> +				     &qup->brx.tag.start[0],
>> +				     2, qup, DMA_FROM_DEVICE);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	qup->btx.tag.start[len - 1] = QUP_BAM_FLUSH_STOP;
>> +	ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->btx.tag.start[0],
>> +			     len, qup, DMA_TO_DEVICE);
>> +	if (ret)
>> +		return ret;
>> +
> 
>   May be you can change the commit to make it explicit to say what is 
> being
>   fixed, like "current code is broken when there is sequence of
> wr,rd,wr" like that.
>   Agree on this fix otherwise.
> 

  Thanks. I will update the commit message to include the failure
  case which will give clear idea.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode
  2018-02-16  4:35   ` Sricharan R
@ 2018-02-19 10:49     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 10:49 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-16 10:05, Sricharan R wrote:
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> Currently each message length in complete transfer is being
>> checked for determining DMA mode and if any of the message length
>> is less than FIFO length then non DMA mode is being used which
>> will increase overhead. DMA can be used for any length and it
>> should be determined with complete transfer length. Now, this
>> patch introduces DMA threshold length and the transfer will be
>> done in DMA mode if the total length is greater than this
>> threshold length.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 15 +++++++++------
>>  1 file changed, 9 insertions(+), 6 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index 6227a5c..a91fc70 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -192,6 +192,8 @@ struct qup_i2c_dev {
>>  	bool			is_dma;
>>  	/* To check if the current transfer is using DMA */
>>  	bool			use_dma;
>> +	/* The threshold length above which DMA will be used */
>> +	unsigned int		dma_threshold;
>>  	struct			dma_pool *dpool;
>>  	struct			qup_i2c_tag start_tag;
>>  	struct			qup_i2c_bam brx;
>> @@ -1294,7 +1296,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter 
>> *adap,
>>  			   int num)
>>  {
>>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>> -	int ret, len, idx = 0;
>> +	int ret, idx = 0;
>> +	unsigned int total_len = 0;
>> 
>>  	qup->bus_err = 0;
>>  	qup->qup_err = 0;
>> @@ -1320,14 +1323,13 @@ static int qup_i2c_xfer_v2(struct i2c_adapter 
>> *adap,
>>  				goto out;
>>  			}
>> 
>> -			len = (msgs[idx].len > qup->out_fifo_sz) ||
>> -			      (msgs[idx].len > qup->in_fifo_sz);
>> -
>> -			if (is_vmalloc_addr(msgs[idx].buf) || !len)
>> +			if (is_vmalloc_addr(msgs[idx].buf))
>>  				break;
>> +
>> +			total_len += msgs[idx].len;
>>  		}
>> 
>> -		if (idx == num)
>> +		if (idx == num && total_len > qup->dma_threshold)
>>  			qup->use_dma = true;
>>  	}
>> 
>> @@ -1587,6 +1589,7 @@ static int qup_i2c_probe(struct platform_device 
>> *pdev)
>> 
>>  	size = QUP_INPUT_FIFO_SIZE(io_mode);
>>  	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
>> +	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
> 
>   The patch is fine. small nit, you can avoid this global 
> dma_threshold. Instead
>   have it locally in qup_i2c_xfer_v2 itself.

  Thanks Sricharan.

  The idea for introducing global dma_threshold was to give option
  for controlling the behavior from one place. If someone wants to
  change the length above which dma will be used, then It can be
  controlled from once place in the probe function itself.

  Also, min(qup->out_fifo_sz, qup->in_fifo_sz) requires comparison
  and adding in qup_i2c_xfer_v2 will make this happen everytime.

  Regards,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/12] i2c: qup: change completion timeout according to transfer length
  2018-02-16  4:48   ` Sricharan R
@ 2018-02-19 10:56     ` Abhishek Sahu
  2018-02-27 23:05       ` Andy Gross
  0 siblings, 1 reply; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 10:56 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-16 10:18, Sricharan R wrote:
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> Currently the completion timeout is being taken according to
>> maximum transfer length which is too high if SCL is operating in
>> high frequency. This patch calculates timeout on the basis of
>> one-byte transfer time and uses the same for completion timeout.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 9 ++++++---
>>  1 file changed, 6 insertions(+), 3 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index a91fc70..6df65ea 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -130,8 +130,8 @@
>>  #define MX_TX_RX_LEN			SZ_64K
>>  #define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
>> 
>> -/* Max timeout in ms for 32k bytes */
>> -#define TOUT_MAX			300
>> +/* Min timeout for i2c transfers */
>> +#define TOUT_MIN			2
>> 
> 
>  may be you can mention, why is this 2 ?
> 

  This 2 seconds is timeout which I am adding on the top of maximum
  xfer time calculated from bus speed to compensate the interrupt
  latency and other factors. It will make xfer timeout minimum as
  2 seconds.

  I will update the comment to explain it in more detail.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-16  5:21   ` Sricharan R
@ 2018-02-19 11:24     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 11:24 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-16 10:51, Sricharan R wrote:
> Hi Abhishek,
> 
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> The BAM mode requires buffer for start tag data and tx, rx SG
>> list. Currently, this is being taken for maximum transfer length
>> (65K). But an I2C transfer can have multiple messages and each
>> message can be of this maximum length so the buffer overflow will
>> happen in this case. Since increasing buffer length won’t be
>> feasible since an I2C transfer can contain any number of messages
>> so this patch does following changes to make i2c transfers working
>> for multiple messages case.
>> 
>> 1. Calculate the required buffers for 2 maximum length messages
>>    (65K * 2).
>> 2. Split the descriptor formation and descriptor scheduling.
>>    The idea is to fit as many messages in one DMA transfers for 65K
>>    threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>>    crossing this, then schedule the BAM transfer and subsequent
>>    transfer will again start from zero.

  <snip>

>> +static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
>> +{
>> +	qup->btx.sg_cnt = 0;
>> +	qup->brx.sg_cnt = 0;
>> +	qup->tag_buf_pos = 0;
>> +}
>> +
>>  static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg 
>> *msg,
>>  			    int num)
>>  {
>>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>>  	int ret = 0;
>> +	int idx = 0;
>> 
>>  	enable_irq(qup->irq);
>>  	ret = qup_i2c_req_dma(qup);
>> @@ -905,9 +916,34 @@ static int qup_i2c_bam_xfer(struct i2c_adapter 
>> *adap, struct i2c_msg *msg,
>>  		goto out;
>> 
>>  	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
>> +	qup_i2c_bam_clear_tag_buffers(qup);
>> +
>> +	for (idx = 0; idx < num; idx++) {
>> +		qup->msg = msg + idx;
>> +		qup->is_last = idx == (num - 1);
>> +
>> +		ret = qup_i2c_bam_make_desc(qup, qup->msg);
>> +		if (ret)
>> +			break;
>> +
>> +		/*
>> +		 * Make DMA descriptor and schedule the BAM transfer if its
>> +		 * already crossed the maximum length. Since the memory for all
>> +		 * tags buffers have been taken for 2 maximum possible
>> +		 * transfers length so it will never cross the buffer actual
>> +		 * length.
>> +		 */
>> +		if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
>> +		    qup->brx.sg_cnt > qup->max_xfer_sg_len ||
>> +		    qup->is_last) {
>> +			ret = qup_i2c_bam_schedule_desc(qup);
>> +			if (ret)
>> +				break;
>> +
>> +			qup_i2c_bam_clear_tag_buffers(qup);
>> +		}
>> +	}
>> 
> 
>   hmm, is this because of only stress tests or was there any device 
> which
>   was using i2c for multiple messages exceeding 64k bytes ?

  Its mainly part of stress test but we have test slave devices which
  supports the multiple messages exceeding 64k bytes. Also, in I2C EEPROM
  we can send the multiple messages exceeding 64k bytes. It will roll 
over
  to starting address after its capacity.

> 
>   Infact we are trying to club two separate messages together across 
> 64k
>   boundaries. Not sure if its really correct. So either we club all 
> messages
>   fully or club only up to the length that would cover the whole 
> message < 64K
>   and send the remaining whole messages in next transfer.
> 

  The QUP DMA can be used for any transfer length. It supports greater 
than
  64k also in one go. Only restriction is descriptors memory. clubing all
  messages won't be feasible since there is no restriction on the number 
of
  messages due to which we can't determine the required descriptors size.

  whole message < 64K will require more code changes since we need to 
calculate
  the number of required descriptors in advance. Again in descriptor 
formation,
  the number of required descriptors will be calculated and filled. To 
make the
  code less complicated, I have taken the memory for 128K xfer length 
which
  will make the current code working without any major code changes.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
  2018-02-16  7:44   ` Sricharan R
@ 2018-02-19 13:21     ` Abhishek Sahu
  2018-02-20  4:32       ` Sricharan R
  0 siblings, 1 reply; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 13:21 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-16 13:14, Sricharan R wrote:
> Hi Abhishek,
> 
> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>> Following are the major issues in current driver code
>> 
>> 1. The current driver simply assumes the transfer completion
>>    whenever its gets any non-error interrupts and then simply do the
>>    polling of available/free bytes in FIFO.
>> 2. The block mode is not working properly since no handling in
>>    being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ.
>> 
>> Because of above, i2c v1 transfers of size greater than 32 are failing
>> with following error message
>> 
>> 	i2c_qup 78b6000.i2c: timeout for fifo out full
>> 
>> To make block mode working properly and move to use the interrupts
>> instead of polling, major code reorganization is required. Following
>> are the major changes done in this patch
>> 
>> 1. Remove the polling of TX FIFO free space and RX FIFO available
>>    bytes and move to interrupts completely. QUP has 
>> QUP_MX_OUTPUT_DONE,
>>    QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
>>    interrupts to handle FIFO’s properly so check all these interrupts.
>> 2. During write, For FIFO mode, TX FIFO can be directly written
>>    without checking for FIFO space. For block mode, the QUP will 
>> generate
>>    OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of 
>> available
>>    space.
>> 3. During read, both TX and RX FIFO will be used. TX will be used
>>    for writing tags and RX will be used for receiving the data. In 
>> QUP,
>>    TX and RX can operate in separate mode so configure modes 
>> accordingly.
>> 4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
>>    will be generated after all the bytes have been copied in RX FIFO. 
>> For
>>    read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
>>    whenever it has block size of available data.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 399 
>> ++++++++++++++++++++++++++++---------------
>>  1 file changed, 257 insertions(+), 142 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index edea3b9..af6c21a 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -73,8 +73,11 @@
>>  #define QUP_IN_SVC_FLAG		BIT(9)
>>  #define QUP_MX_OUTPUT_DONE	BIT(10)
>>  #define QUP_MX_INPUT_DONE	BIT(11)
>> +#define OUT_BLOCK_WRITE_REQ	BIT(12)
>> +#define IN_BLOCK_READ_REQ	BIT(13)
>> 
>>  /* I2C mini core related values */
>> +#define QUP_NO_INPUT		BIT(7)
>>  #define QUP_CLOCK_AUTO_GATE	BIT(13)
>>  #define I2C_MINI_CORE		(2 << 8)
>>  #define I2C_N_VAL		15
>> @@ -138,13 +141,51 @@
>>  #define DEFAULT_CLK_FREQ 100000
>>  #define DEFAULT_SRC_CLK 20000000
>> 
>> +/* MAX_OUTPUT_DONE_FLAG has been received */
>> +#define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
>> +/* MAX_INPUT_DONE_FLAG has been received */
>> +#define QUP_BLK_EVENT_RX_IRQ_DONE		BIT(1)
>> +/* All the TX bytes have been written in TX FIFO */
>> +#define QUP_BLK_EVENT_TX_DATA_DONE		BIT(2)
>> +/* All the RX bytes have been read from RX FIFO */
>> +#define QUP_BLK_EVENT_RX_DATA_DONE		BIT(3)
>> +
>> +/* All the required events to mark a QUP I2C TX transfer completed */
>> +#define QUP_BLK_EVENT_TX_DONE		(QUP_BLK_EVENT_TX_IRQ_DONE | \
>> +					 QUP_BLK_EVENT_TX_DATA_DONE)
>> +/* All the required events to mark a QUP I2C RX transfer completed */
>> +#define QUP_BLK_EVENT_RX_DONE		(QUP_BLK_EVENT_TX_DONE | \
>> +					 QUP_BLK_EVENT_RX_IRQ_DONE | \
>> +					 QUP_BLK_EVENT_RX_DATA_DONE)
>> +
>> +/*
>> + * count: no of blocks
>> + * pos: current block number
>> + * tx_tag_len: tx tag length for current block
>> + * rx_tag_len: rx tag length for current block
>> + * data_len: remaining data length for current message
>> + * total_tx_len: total tx length including tag bytes for current QUP 
>> transfer
>> + * total_rx_len: total rx length including tag bytes for current QUP 
>> transfer
>> + * tx_fifo_free: number of free bytes in current QUP block write.
>> + * fifo_available: number of available bytes in RX FIFO for current
>> + *		   QUP block read
>> + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non 
>> BAM xfer.
>> + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non 
>> BAM xfer.
>> + * tags: contains tx tag bytes for current QUP transfer
>> + */
>>  struct qup_i2c_block {
>> -	int	count;
>> -	int	pos;
>> -	int	tx_tag_len;
>> -	int	rx_tag_len;
>> -	int	data_len;
>> -	u8	tags[6];
>> +	int		count;
>> +	int		pos;
>> +	int		tx_tag_len;
>> +	int		rx_tag_len;
>> +	int		data_len;
>> +	int		total_tx_len;
>> +	int		total_rx_len;
>> +	int		tx_fifo_free;
>> +	int		fifo_available;
>> +	bool		is_tx_blk_mode;
>> +	bool		is_rx_blk_mode;
>> +	u8		tags[6];
>>  };
>> 
>>  struct qup_i2c_tag {
>> @@ -187,6 +228,7 @@ struct qup_i2c_dev {
>> 
>>  	/* To check if this is the last msg */
>>  	bool			is_last;
>> +	bool			is_qup_v1;
>> 
>>  	/* To configure when bus is in run state */
>>  	int			config_run;
>> @@ -195,6 +237,10 @@ struct qup_i2c_dev {
>>  	bool			is_dma;
>>  	/* To check if the current transfer is using DMA */
>>  	bool			use_dma;
>> +	/* Required events to mark QUP transfer as completed */
>> +	u32			blk_events;
>> +	/* Already completed events in QUP transfer */
>> +	u32			cur_blk_events;
>>  	/* The threshold length above which DMA will be used */
>>  	unsigned int		dma_threshold;
>>  	unsigned int		max_xfer_sg_len;
>> @@ -205,11 +251,18 @@ struct qup_i2c_dev {
>>  	struct			qup_i2c_bam btx;
>> 
>>  	struct completion	xfer;
>> +	/* function to write data in tx fifo */
>> +	void (*write_tx_fifo)(struct qup_i2c_dev *qup);
>> +	/* function to read data from rx fifo */
>> +	void (*read_rx_fifo)(struct qup_i2c_dev *qup);
>> +	/* function to write tags in tx fifo for i2c read transfer */
>> +	void (*write_rx_tags)(struct qup_i2c_dev *qup);
>>  };
>> 
>>  static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>>  {
>>  	struct qup_i2c_dev *qup = dev;
>> +	struct qup_i2c_block *blk = &qup->blk;
>>  	u32 bus_err;
>>  	u32 qup_err;
>>  	u32 opflags;
>> @@ -256,12 +309,54 @@ static irqreturn_t qup_i2c_interrupt(int irq, 
>> void *dev)
>>  		goto done;
>>  	}
>> 
>> -	if (opflags & QUP_IN_SVC_FLAG)
>> -		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>> +	if (!qup->is_qup_v1)
>> +		goto done;
>> 
>> -	if (opflags & QUP_OUT_SVC_FLAG)
>> +	if (opflags & QUP_OUT_SVC_FLAG) {
>>  		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>> 
>> +		/*
>> +		 * Ideally, would like to check QUP_MAX_OUTPUT_DONE_FLAG.
>> +		 * However, QUP_MAX_OUTPUT_DONE_FLAG is lagging behind
>> +		 * QUP_OUTPUT_SERVICE_FLAG. The only reason for
>> +		 * QUP_OUTPUT_SERVICE_FLAG to be set in FIFO mode is
>> +		 * QUP_MAX_OUTPUT_DONE_FLAG condition. The code checking
>> +		 * here QUP_OUTPUT_SERVICE_FLAG and assumes that
>> +		 * QUP_MAX_OUTPUT_DONE_FLAG.
>> +		 */
>> +		if (!blk->is_tx_blk_mode)
>> +			qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
>> +
>> +		if (opflags & OUT_BLOCK_WRITE_REQ) {
>> +			blk->tx_fifo_free += qup->out_blk_sz;
>> +			if (qup->msg->flags & I2C_M_RD)
>> +				qup->write_rx_tags(qup);
>> +			else
>> +				qup->write_tx_fifo(qup);
>> +		}
>> +	}
>> +
>> +	if (opflags & QUP_IN_SVC_FLAG) {
>> +		writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>> +
>> +		if (!blk->is_rx_blk_mode) {
>> +			blk->fifo_available += qup->in_fifo_sz;
>> +			qup->read_rx_fifo(qup);
>> +		} else if (opflags & IN_BLOCK_READ_REQ) {
>> +			blk->fifo_available += qup->in_blk_sz;
>> +			qup->read_rx_fifo(qup);
>> +		}
>> +	}
>> +
>> +	if (opflags & QUP_MX_OUTPUT_DONE)
>> +		qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
>> +
>> +	if (opflags & QUP_MX_INPUT_DONE)
>> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_IRQ_DONE;
>> +
>> +	if (qup->cur_blk_events != qup->blk_events)
>> +		return IRQ_HANDLED;
> 
>   Is it correct that if we do a complete in above case, i mean
>   for TX -> based on QUP_MX_OUTPUT_DONE and for RX -> based on
>   QUP_MX_INPUT_DONE, would that simplify things by getting rid of
>   QUP_BLK_EVENT_RX/TX_DONE and QUP_BLK_EVENT_RX/TX_IRQ_DONE
>   altogether ?

  We can get rid of QUP_BLK_EVENT_TX_DONE.
  For RX, the QUP_MX_INPUT_DONE will be triggered when QUP copies all
  the data in FIFO from external i2c slave. So if 64 bytes read has been
  scheduled then  following is the behaviour

  IRQ with QUP_MX_INPUT_DONE and IN_BLOCK_READ_REQ -> read 16 bytes
  IRQ with IN_BLOCK_READ_REQ -> read next 16 bytes
  IRQ with IN_BLOCK_READ_REQ  -> read next 16 bytes
  IRQ with IN_BLOCK_READ_REQ -> read last 16 bytes

  So for RX, we can't trigger complete by checking QUP_BLK_EVENT_RX_DONE 
alone.
  We need to track the number of bytes read from FIFO. Instead of putting
  this check, I am taking one extra event bit QUP_BLK_EVENT_RX_DONE which
  will be set when all the bytes has been read.

  I am not sure if checking QUP_MX_INPUT_DONE will always work since
  there may be some case, when for small transfers the QUP_MX_INPUT_DONE
  will come before QUP_MX_OUTPUT_DONE so checking for both will work
  always.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2
  2018-02-16 11:23   ` Sricharan R
@ 2018-02-19 14:08     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-02-19 14:08 UTC (permalink / raw)
  To: Sricharan R
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

<snip>

>>  static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool 
>> is_rx)
>>  {
>>  	qup->cur_blk_events = 0;
>> @@ -1442,13 +1155,452 @@ static int qup_i2c_xfer(struct i2c_adapter 
>> *adap,
>>  	return ret;
>>  }
>> 
> 
>   Since this is used for both FIFO and BLK mode, might be good to call 
> it
>   qup_i2c_set_event. Same in rest of the places and macros as well.
>   But if this is going to be removed altogether, then great.
> 

   Sure. I will rename this and others.
   I will check for removing but as replied in Patch 11. We need to track 
for
   3 things in RX case. For TX case, OUTPUT_DONE should be sufficient.

>> +/*
>> + * Function to configure registers related with reconfiguration 
>> during run
>> + * and will be done before each I2C sub transfer.
>> + */
>> +static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2;
>> +
>> +	if (blk->is_tx_blk_mode)
>> +		writel(qup->config_run | blk->total_tx_len,
>> +		       qup->base + QUP_MX_OUTPUT_CNT);
>> +	else
>> +		writel(qup->config_run | blk->total_tx_len,
>> +		       qup->base + QUP_MX_WRITE_CNT);
>> +
>> +	if (blk->total_rx_len) {
>> +		if (blk->is_rx_blk_mode)
>> +			writel(qup->config_run | blk->total_rx_len,
>> +			       qup->base + QUP_MX_INPUT_CNT);
>> +		else
>> +			writel(qup->config_run | blk->total_rx_len,
>> +			       qup->base + QUP_MX_READ_CNT);
>> +	} else {
>> +		qup_config |= QUP_NO_INPUT;
>> +	}
>> +
>> +	writel(qup_config, qup->base + QUP_CONFIG);
>> +}
>> +
>> +/*
>> + * Function to configure registers related with transfer mode 
>> (FIFO/Block)
>> + * before starting of i2c transfer and will be done only once in QUP 
>> RESET
>> + * state.
>> + */
>> +static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	u32 io_mode = QUP_REPACK_EN;
>> +
>> +	if (blk->is_tx_blk_mode) {
>> +		io_mode |= QUP_OUTPUT_BLK_MODE;
>> +		writel(0, qup->base + QUP_MX_WRITE_CNT);
>> +	} else {
>> +		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
>> +	}
>> +
>> +	if (blk->is_rx_blk_mode) {
>> +		io_mode |= QUP_INPUT_BLK_MODE;
>> +		writel(0, qup->base + QUP_MX_READ_CNT);
>> +	} else {
>> +		writel(0, qup->base + QUP_MX_INPUT_CNT);
>> +	}
>> +
>> +	writel(io_mode, qup->base + QUP_IO_MODE);
>> +}
>> +
>> +/*
>> + * Function to clear required variables before starting of any QUP v2
>> + * sub transfer
>> + */
>> +static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk)
>> +{
>> +	blk->send_last_word = false;
>> +	blk->tx_tags_sent = false;
>> +	blk->tx_fifo_data = 0;
>> +	blk->tx_fifo_data_pos = 0;
>> +	blk->tx_fifo_free = 0;
>> +
>> +	blk->rx_tags_fetched = false;
>> +	blk->rx_fifo_data = 0;
>> +	blk->rx_fifo_data_pos = 0;
>> +	blk->fifo_available = 0;
>> +}
>> +
>> +/*
>> + * Function to receive data from RX FIFO for read message in QUP v2
>> + * i2c transfer.
>> + */
>> +static void qup_i2c_recv_data(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	int j;
>> +
>> +	for (j = blk->rx_fifo_data_pos;
>> +	     blk->cur_blk_len && blk->fifo_available;
>> +	     blk->cur_blk_len--, blk->fifo_available--) {
>> +		if (j == 0)
>> +			blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
>> +
>> +		*(blk->cur_data++) = blk->rx_fifo_data;
>> +		blk->rx_fifo_data >>= 8;
>> +
>> +		if (j == 3)
>> +			j = 0;
>> +		else
>> +			j++;
>> +	}
>> +
>> +	blk->rx_fifo_data_pos = j;
>> +}
>> +
>> +/* Function to receive tags for read message in QUP v2 i2c transfer. 
>> */
>> +static void qup_i2c_recv_tags(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +
>> +	blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
>> +	blk->rx_fifo_data >>= blk->rx_tag_len  * 8;
> 
>   why cant it be simply ignored ?
> 

   We need to read the data from FIFO and increment the rx_fifo_data_pos
   and decrement the fifo_available. The tag bytes are being ignored.

>> +	blk->rx_fifo_data_pos = blk->rx_tag_len;
>> +	blk->fifo_available -= blk->rx_tag_len;
>> +}
>> +
>> +/*
>> + * This function reads the data and tags from RX FIFO. Since in read 
>> case, the
>> + * tags will be preceded by received data bytes need to be written so
>> + * 1. Check if rx_tags_fetched is false i.e. the start of QUP block 
>> so receive
>> + *    all tag bytes and discard that.
>> + * 2. Read the data from RX FIFO. When all the data bytes have been 
>> read then
>> + *    mark the QUP_BLK_EVENT_RX_DATA_DONE in current block event and 
>> return.
>> + */
>> +static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +
>> +	if (!blk->rx_tags_fetched) {
>> +		qup_i2c_recv_tags(qup);
>> +		blk->rx_tags_fetched = true;
>> +	}
>> +
>> +	qup_i2c_recv_data(qup);
>> +	if (!blk->cur_blk_len)
>> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
>> +}
>> +
>> +/*
>> + * Function to write bytes in TX FIFO for write message in QUP v2 i2c
>> + * transfer. QUP TX FIFO write works on word basis (4 bytes). New 
>> byte write to
>> + * TX FIFO will be appended in this data tx_fifo_data and will be 
>> written to TX
>> + * FIFO when all the 4 bytes are available.
>> + */
>> +static void
>> +qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned 
>> int *len)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	unsigned int j;
>> +
>> +	for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free;
>> +	     (*len)--, blk->tx_fifo_free--) {
>> +		blk->tx_fifo_data |= *(*data)++ << (j * 8);
>> +		if (j == 3) {
>> +			writel(blk->tx_fifo_data,
>> +			       qup->base + QUP_OUT_FIFO_BASE);
>> +			blk->tx_fifo_data = 0x0;
>> +			j = 0;
>> +		} else {
>> +			j++;
>> +		}
>> +	}
>> +
>> +	blk->tx_fifo_data_pos = j;
>> +}
>> +
>> +/* Function to transfer tags for read message in QUP v2 i2c transfer. 
>> */
>> +static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +
>> +	qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len);
>> +	if (blk->tx_fifo_data_pos)
>> +		writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
>> +
>> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
>> +}
>> +
>> +/*
>> + * This function writes the data and tags in TX FIFO. Since in write 
>> case, both
>> + * tags and data need to be written and QUP write tags can have 
>> maximum 256 data
>> + * length, so it follows simple internal state machine to manage it.
>> + * 1. Check if tx_tags_sent is false i.e. the start of QUP block so 
>> write the
>> + *    tags to TX FIFO.
>> + * 2. Check if send_last_word is true. This will be set when last few 
>> data bytes
>> + *    less than 4 bytes are reamining to be written in FIFO because 
>> of no FIFO
>> + *    space. All this data bytes are available in tx_fifo_data so 
>> write this
>> + *    in FIFO and mark the tx done.
>> + * 3. Write the data to TX FIFO and check for cur_blk_len. If this is 
>> non zero
>> + *    then more data is pending otherwise following 3 cases can be 
>> possible
>> + *    a. if tx_fifo_data_pos is zero that means all the data bytes in 
>> this block
>> + *       have been written in TX FIFO so mark the tx done.
>> + *    b. tx_fifo_free is zero. In this case, last few bytes (less 
>> than 4
>> + *       bytes) are copied to tx_fifo_data but couldn't be sent 
>> because of
>> + *       FIFO full so make send_last_word true.
>> + *    c. tx_fifo_free is non zero i.e tx FIFO is free so copy the 
>> remaining data
>> + *       from tx_fifo_data to tx FIFO and mark the tx done. Since,
>> + *       qup_i2c_write_blk_data do write in 4 bytes and FIFO space is 
>> in
>> + *       multiple of 4 bytes so tx_fifo_free will be always greater 
>> than or
>> + *       equal to 4 bytes.
> 
>        Comments b and c should be c and b as per the code below
> 

  I Will fix that.

>> + */
>> +static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +
>> +	if (!blk->tx_tags_sent) {
>> +		qup_i2c_write_blk_data(qup, &blk->cur_tx_tags,
>> +				       &blk->tx_tag_len);
>> +		blk->tx_tags_sent = true;
>> +	}
>> +
>> +	if (blk->send_last_word)
>> +		goto send_last_word;
>> +
>> +	qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len);
> 
>  ok, do understand, why is cur_blk_len zero and we still have pending
> bytes to be written ?
> 

  qup_i2c_write_blk_data will return if we don't have space
  in TX FIFO or these are last remaining bytes (less than 4).
  qup_i2c_write_blk_data will write to TX FIFO when the tx_fifo_data_pos
  is 3 i.e all 4 bytes.

  The following check is taking care of this case.
  If we have space available in TX FIFO then copy the data from 
tx_fifo_data
  otherwise mark send_last_word true so that when space will be
  available then this function will just sent those remaining bytes.


>> +	if (!blk->cur_blk_len) {
>> +		if (!blk->tx_fifo_data_pos)
>> +			goto tx_data_done;
>> +
>> +		if (blk->tx_fifo_free)
>> +			goto send_last_word;
>> +
>> +		blk->send_last_word = true;
>> +	}
>> +
>> +	return;
>> +
>> +send_last_word:
>> +	writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
>> +tx_data_done:
>> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
> 
>   Yes, as commented on the previous patch, if we can get rid of this 4 
> flags
>   for completion in block/fifo mode, it would simply things a bit.
> 

  It seems QUP_BLK_EVENT_TX_DATA_DONE can be removed.

>> +}
>> +
>> +/*
>> + * Main transfer function which will be used for reading or writing 
>> i2c data.
>> + * The QUP v2 supports reconfiguration during run in which multiple 
>> i2c sub
>> + * transfers can be scheduled.
>> + */
>> +static int
>> +qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool 
>> is_first,
>> +		     bool change_pause_state)
>> +{
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	struct i2c_msg *msg = qup->msg;
>> +	int ret;
>> +
>> +	/*
>> +	 * Check if its SMBus Block read for which the top level read will 
>> be
>> +	 * done into 2 QUP reads. One with message length 1 while other one 
>> is
>> +	 * with actual length.
>> +	 */
>> +	if (qup_i2c_check_msg_len(msg)) {
>> +		if (qup->is_smbus_read) {
>> +			/*
>> +			 * If the message length is already read in
>> +			 * the first byte of the buffer, account for
>> +			 * that by setting the offset
>> +			 */
>> +			blk->cur_data += 1;
>> +			is_first = false;
>> +		} else {
>> +			change_pause_state = false;
>> +		}
>> +	}
>> +
>> +	qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN;
>> +
>> +	qup_i2c_clear_blk_v2(blk);
>> +	qup_i2c_conf_count_v2(qup);
>> +
>> +	/* If it is first sub transfer, then configure i2c bus clocks */
>> +	if (is_first) {
>> +		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
>> +		if (ret)
>> +			return ret;
>> +
>> +		writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
>> +
>> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	qup_i2c_set_blk_event(qup, is_rx);
> 
>   hmm, if the completion is changed as per the just INPUT/OUTPUT done
>   then this blk event tracking can be removed.
> 

  I will check for RX case. If adding condition for I2C_M_RD and 
remaining
  bytes to be read is zero makes code more readable then I will change
  and remove this function.

>> +	reinit_completion(&qup->xfer);
>> +	enable_irq(qup->irq);
>> +	/*
>> +	 * In FIFO mode, tx FIFO can be written directly while in block mode 
>> the
>> +	 * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt
>> +	 */
>> +	if (!blk->is_tx_blk_mode) {
>> +		blk->tx_fifo_free = qup->out_fifo_sz;
>> +
>> +		if (is_rx)
>> +			qup_i2c_write_rx_tags_v2(qup);
>> +		else
>> +			qup_i2c_write_tx_fifo_v2(qup);
>> +	}
>> +
>> +	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
>> +	if (ret)
>> +		goto err;
>> +
>> +	ret = qup_i2c_wait_for_complete(qup, msg);
>> +	if (ret)
>> +		goto err;
>> +
>> +	/* Move to pause state for all the transfers, except last one */
>> +	if (change_pause_state) {
>> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
>> +		if (ret)
>> +			goto err;
>> +	}
>> +
>> +err:
>> +	disable_irq(qup->irq);
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Function to transfer one read/write message in i2c transfer. It 
>> splits the
>> + * message into multiple of blk_xfer_limit data length blocks and 
>> schedule each
>> + * QUP block individually.
>> + */
>> +static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, 
>> bool is_rx)
>> +{
>> +	int ret = 0;
>> +	unsigned int data_len, i;
>> +	struct i2c_msg *msg = qup->msg;
>> +	struct qup_i2c_block *blk = &qup->blk;
>> +	u8 *msg_buf = msg->buf;
>> +
>> +	qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT;
>> +	qup_i2c_set_blk_data(qup, msg);
>> +
>> +	for (i = 0; i < blk->count; i++) {
>> +		data_len =  qup_i2c_get_data_len(qup);
>> +		blk->pos = i;
>> +		blk->cur_tx_tags = blk->tags;
>> +		blk->cur_blk_len = data_len;
>> +		blk->tx_tag_len =
>> +			qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg);
>> +
>> +		blk->cur_data = msg_buf;
>> +
>> +		if (is_rx) {
>> +			blk->total_tx_len = blk->tx_tag_len;
>> +			blk->rx_tag_len = 2;
>> +			blk->total_rx_len = blk->rx_tag_len + data_len;
>> +		} else {
>> +			blk->total_tx_len = blk->tx_tag_len + data_len;
>> +			blk->total_rx_len = 0;
>> +		}
>> +
>> +		ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i,
>> +					   !qup->is_last || i < blk->count - 1);
>> +		if (ret)
>> +			return ret;
>> +
>> +		/* Handle SMBus block read length */
>> +		if (qup_i2c_check_msg_len(msg) && msg->len == 1 &&
>> +		    !qup->is_smbus_read) {
>> +			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX)
>> +				return -EPROTO;
>> +
>> +			msg->len = msg->buf[0];
>> +			qup->is_smbus_read = true;
>> +			ret = qup_i2c_xfer_v2_msg(qup, msg_id, true);
>> +			qup->is_smbus_read = false;
>> +			if (ret)
>> +				return ret;
>> +
>> +			msg->len += 1;
>> +		}
>> +
>> +		msg_buf += data_len;
>> +		blk->data_len -= qup->blk_xfer_limit;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +/*
>> + * QUP v2 supports 3 modes
>> + * Programmed IO using FIFO mode : Less than FIFO size
>> + * Programmed IO using Block mode : Greater than FIFO size
>> + * DMA using BAM : Appropriate for any transactio size but the 
>> address should be
>> + *		   DMA applicable
>> + *
> 
>  s/transactio/transaction
> 

  I Will fix this and qup_i2c_determine_mode.

>> + * This function determines the mode which will be used for this 
>> transfer. An
>> + * i2c transfer contains multiple message. Following are the rules to 
>> determine
>> + * the mode used.
>> + * 1. Determine the tx and rx length for each message and maximum tx 
>> and rx
>> + *    length for complete transfer
>> + * 2. If tx or rx length is greater than DMA threshold than use the 
>> DMA mode.
>> + * 3. In FIFO or block mode, TX and RX can operate in different mode 
>> so check
>> + *    for maximum tx and rx length to determine mode.
>> + */
>> +static int
>> +qup_i2c_determine_mode(struct qup_i2c_dev *qup, struct i2c_msg 
>> msgs[], int num)
> 
>    qup_i2c_determine_mode_v2
> 
>> +{
>> +	int idx;
>> +	bool no_dma = false;
>> +	unsigned int max_tx_len = 0, max_rx_len = 0;
>> +	unsigned int cur_tx_len, cur_rx_len;
>> +	unsigned int total_rx_len = 0, total_tx_len = 0;
>> +
>> +	/* All i2c_msgs should be transferred using either dma or cpu */
>> +	for (idx = 0; idx < num; idx++) {
>> +		if (msgs[idx].len == 0)
>> +			return -EINVAL;
>> +
>> +		if (msgs[idx].flags & I2C_M_RD) {
>> +			cur_tx_len = 0;
>> +			cur_rx_len = msgs[idx].len;
>> +		} else {
>> +			cur_tx_len = msgs[idx].len;
>> +			cur_rx_len = 0;
>> +		}
>> +
>> +		if (is_vmalloc_addr(msgs[idx].buf))
>> +			no_dma = true;
>> +
>> +		max_tx_len = max(max_tx_len, cur_tx_len);
>> +		max_rx_len = max(max_rx_len, cur_rx_len);
>> +		total_rx_len += cur_rx_len;
>> +		total_tx_len += cur_tx_len;
>> +	}
> 
>  why is tag length for each block not being considered here ?

  That is to avoid unnecessary calculation.
  The role of this function is to just determine mode.
  DMA and block mode will work for any xfer length.
  but FIFO won't work for > 64.

  The max tag length already we have considered in blk_mode_threshold.
  in None of the case, it will give FIFO mode for xfer greater than
  64 bytes.

> 
>> +
>> +	if (!no_dma && qup->is_dma &&
> 
>   why do we need is_dma and use_dma ?
>   Now that you have removed the need for is_dma in rest of places,
>   better to get rid of that fully.
> 

  Both are doing separate things.
  use_dma will be false if any msgs[idx].buf is vmalloc address.
  qup->is_dma will be false if the dma channels are not defined
  in dtsi or in case of some DMA channel allocation failure.


>> +	    (total_tx_len > qup->dma_threshold ||
>> +	     total_rx_len > qup->dma_threshold)) {
>> +		qup->use_dma = true;
>> +	} else {
>> +		qup->blk.is_tx_blk_mode =
>> +			max_tx_len > qup->blk_mode_threshold ? true : false;
>> +		qup->blk.is_rx_blk_mode =
>> +			max_rx_len > qup->blk_mode_threshold ? true : false;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>  static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>>  			   struct i2c_msg msgs[],
>>  			   int num)
>>  {
>>  	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>>  	int ret, idx = 0;
>> -	unsigned int total_len = 0;
>> 
>>  	qup->bus_err = 0;
>>  	qup->qup_err = 0;
>> @@ -1457,6 +1609,10 @@ static int qup_i2c_xfer_v2(struct i2c_adapter 
>> *adap,
>>  	if (ret < 0)
>>  		goto out;
>> 
>> +	ret = qup_i2c_determine_mode(qup, msgs, num);
>> +	if (ret)
>> +		goto out;
>> +
>>  	writel(1, qup->base + QUP_SW_RESET);
>>  	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
>>  	if (ret)
>> @@ -1466,59 +1622,35 @@ static int qup_i2c_xfer_v2(struct i2c_adapter 
>> *adap,
>>  	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
>>  	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
>> 
>> -	if ((qup->is_dma)) {
>> -		/* All i2c_msgs should be transferred using either dma or cpu */
>> +	if (qup_i2c_poll_state_i2c_master(qup)) {
>> +		ret = -EIO;
>> +		goto out;
>> +	}
>> +
>> +	if (qup->use_dma) {
>> +		reinit_completion(&qup->xfer);
>> +		ret = qup_i2c_bam_xfer(adap, &msgs[0], num);
>> +		qup->use_dma = false;
>> +	} else {
>> +		qup_i2c_conf_mode_v2(qup);
>> +
>>  		for (idx = 0; idx < num; idx++) {
>> -			if (msgs[idx].len == 0) {
>> -				ret = -EINVAL;
>> -				goto out;
>> -			}
>> +			qup->msg = &msgs[idx];
>> +			qup->is_last = idx == (num - 1);
>> 
>> -			if (is_vmalloc_addr(msgs[idx].buf))
>> +			ret = qup_i2c_xfer_v2_msg(qup, idx,
>> +					!!(msgs[idx].flags & I2C_M_RD));
> 
>   why !!() is required here ?
> 

  I made it to change for boolean.
  Same thing, we are doing in other places inside i2c base driver.

  Regards,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1
  2018-02-19 13:21     ` Abhishek Sahu
@ 2018-02-20  4:32       ` Sricharan R
  0 siblings, 0 replies; 57+ messages in thread
From: Sricharan R @ 2018-02-20  4:32 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Andy Gross, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

Hi Abhishek,

On 2/19/2018 6:51 PM, Abhishek Sahu wrote:
> On 2018-02-16 13:14, Sricharan R wrote:
>> Hi Abhishek,
>>
>> On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
>>> Following are the major issues in current driver code
>>>
>>> 1. The current driver simply assumes the transfer completion
>>>    whenever its gets any non-error interrupts and then simply do the
>>>    polling of available/free bytes in FIFO.
>>> 2. The block mode is not working properly since no handling in
>>>    being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ.
>>>
>>> Because of above, i2c v1 transfers of size greater than 32 are failing
>>> with following error message
>>>
>>>     i2c_qup 78b6000.i2c: timeout for fifo out full
>>>
>>> To make block mode working properly and move to use the interrupts
>>> instead of polling, major code reorganization is required. Following
>>> are the major changes done in this patch
>>>
>>> 1. Remove the polling of TX FIFO free space and RX FIFO available
>>>    bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
>>>    QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
>>>    interrupts to handle FIFO’s properly so check all these interrupts.
>>> 2. During write, For FIFO mode, TX FIFO can be directly written
>>>    without checking for FIFO space. For block mode, the QUP will generate
>>>    OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
>>>    space.
>>> 3. During read, both TX and RX FIFO will be used. TX will be used
>>>    for writing tags and RX will be used for receiving the data. In QUP,
>>>    TX and RX can operate in separate mode so configure modes accordingly.
>>> 4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
>>>    will be generated after all the bytes have been copied in RX FIFO. For
>>>    read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
>>>    whenever it has block size of available data.
>>>
>>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>>> ---
>>>  drivers/i2c/busses/i2c-qup.c | 399 ++++++++++++++++++++++++++++---------------
>>>  1 file changed, 257 insertions(+), 142 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
>>> index edea3b9..af6c21a 100644
>>> --- a/drivers/i2c/busses/i2c-qup.c
>>> +++ b/drivers/i2c/busses/i2c-qup.c
>>> @@ -73,8 +73,11 @@
>>>  #define QUP_IN_SVC_FLAG        BIT(9)
>>>  #define QUP_MX_OUTPUT_DONE    BIT(10)
>>>  #define QUP_MX_INPUT_DONE    BIT(11)
>>> +#define OUT_BLOCK_WRITE_REQ    BIT(12)
>>> +#define IN_BLOCK_READ_REQ    BIT(13)
>>>
>>>  /* I2C mini core related values */
>>> +#define QUP_NO_INPUT        BIT(7)
>>>  #define QUP_CLOCK_AUTO_GATE    BIT(13)
>>>  #define I2C_MINI_CORE        (2 << 8)
>>>  #define I2C_N_VAL        15
>>> @@ -138,13 +141,51 @@
>>>  #define DEFAULT_CLK_FREQ 100000
>>>  #define DEFAULT_SRC_CLK 20000000
>>>
>>> +/* MAX_OUTPUT_DONE_FLAG has been received */
>>> +#define QUP_BLK_EVENT_TX_IRQ_DONE        BIT(0)
>>> +/* MAX_INPUT_DONE_FLAG has been received */
>>> +#define QUP_BLK_EVENT_RX_IRQ_DONE        BIT(1)
>>> +/* All the TX bytes have been written in TX FIFO */
>>> +#define QUP_BLK_EVENT_TX_DATA_DONE        BIT(2)
>>> +/* All the RX bytes have been read from RX FIFO */
>>> +#define QUP_BLK_EVENT_RX_DATA_DONE        BIT(3)
>>> +
>>> +/* All the required events to mark a QUP I2C TX transfer completed */
>>> +#define QUP_BLK_EVENT_TX_DONE        (QUP_BLK_EVENT_TX_IRQ_DONE | \
>>> +                     QUP_BLK_EVENT_TX_DATA_DONE)
>>> +/* All the required events to mark a QUP I2C RX transfer completed */
>>> +#define QUP_BLK_EVENT_RX_DONE        (QUP_BLK_EVENT_TX_DONE | \
>>> +                     QUP_BLK_EVENT_RX_IRQ_DONE | \
>>> +                     QUP_BLK_EVENT_RX_DATA_DONE)
>>> +
>>> +/*
>>> + * count: no of blocks
>>> + * pos: current block number
>>> + * tx_tag_len: tx tag length for current block
>>> + * rx_tag_len: rx tag length for current block
>>> + * data_len: remaining data length for current message
>>> + * total_tx_len: total tx length including tag bytes for current QUP transfer
>>> + * total_rx_len: total rx length including tag bytes for current QUP transfer
>>> + * tx_fifo_free: number of free bytes in current QUP block write.
>>> + * fifo_available: number of available bytes in RX FIFO for current
>>> + *           QUP block read
>>> + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
>>> + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
>>> + * tags: contains tx tag bytes for current QUP transfer
>>> + */
>>>  struct qup_i2c_block {
>>> -    int    count;
>>> -    int    pos;
>>> -    int    tx_tag_len;
>>> -    int    rx_tag_len;
>>> -    int    data_len;
>>> -    u8    tags[6];
>>> +    int        count;
>>> +    int        pos;
>>> +    int        tx_tag_len;
>>> +    int        rx_tag_len;
>>> +    int        data_len;
>>> +    int        total_tx_len;
>>> +    int        total_rx_len;
>>> +    int        tx_fifo_free;
>>> +    int        fifo_available;
>>> +    bool        is_tx_blk_mode;
>>> +    bool        is_rx_blk_mode;
>>> +    u8        tags[6];
>>>  };
>>>
>>>  struct qup_i2c_tag {
>>> @@ -187,6 +228,7 @@ struct qup_i2c_dev {
>>>
>>>      /* To check if this is the last msg */
>>>      bool            is_last;
>>> +    bool            is_qup_v1;
>>>
>>>      /* To configure when bus is in run state */
>>>      int            config_run;
>>> @@ -195,6 +237,10 @@ struct qup_i2c_dev {
>>>      bool            is_dma;
>>>      /* To check if the current transfer is using DMA */
>>>      bool            use_dma;
>>> +    /* Required events to mark QUP transfer as completed */
>>> +    u32            blk_events;
>>> +    /* Already completed events in QUP transfer */
>>> +    u32            cur_blk_events;
>>>      /* The threshold length above which DMA will be used */
>>>      unsigned int        dma_threshold;
>>>      unsigned int        max_xfer_sg_len;
>>> @@ -205,11 +251,18 @@ struct qup_i2c_dev {
>>>      struct            qup_i2c_bam btx;
>>>
>>>      struct completion    xfer;
>>> +    /* function to write data in tx fifo */
>>> +    void (*write_tx_fifo)(struct qup_i2c_dev *qup);
>>> +    /* function to read data from rx fifo */
>>> +    void (*read_rx_fifo)(struct qup_i2c_dev *qup);
>>> +    /* function to write tags in tx fifo for i2c read transfer */
>>> +    void (*write_rx_tags)(struct qup_i2c_dev *qup);
>>>  };
>>>
>>>  static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>>>  {
>>>      struct qup_i2c_dev *qup = dev;
>>> +    struct qup_i2c_block *blk = &qup->blk;
>>>      u32 bus_err;
>>>      u32 qup_err;
>>>      u32 opflags;
>>> @@ -256,12 +309,54 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>>>          goto done;
>>>      }
>>>
>>> -    if (opflags & QUP_IN_SVC_FLAG)
>>> -        writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>>> +    if (!qup->is_qup_v1)
>>> +        goto done;
>>>
>>> -    if (opflags & QUP_OUT_SVC_FLAG)
>>> +    if (opflags & QUP_OUT_SVC_FLAG) {
>>>          writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>>>
>>> +        /*
>>> +         * Ideally, would like to check QUP_MAX_OUTPUT_DONE_FLAG.
>>> +         * However, QUP_MAX_OUTPUT_DONE_FLAG is lagging behind
>>> +         * QUP_OUTPUT_SERVICE_FLAG. The only reason for
>>> +         * QUP_OUTPUT_SERVICE_FLAG to be set in FIFO mode is
>>> +         * QUP_MAX_OUTPUT_DONE_FLAG condition. The code checking
>>> +         * here QUP_OUTPUT_SERVICE_FLAG and assumes that
>>> +         * QUP_MAX_OUTPUT_DONE_FLAG.
>>> +         */
>>> +        if (!blk->is_tx_blk_mode)
>>> +            qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
>>> +
>>> +        if (opflags & OUT_BLOCK_WRITE_REQ) {
>>> +            blk->tx_fifo_free += qup->out_blk_sz;
>>> +            if (qup->msg->flags & I2C_M_RD)
>>> +                qup->write_rx_tags(qup);
>>> +            else
>>> +                qup->write_tx_fifo(qup);
>>> +        }
>>> +    }
>>> +
>>> +    if (opflags & QUP_IN_SVC_FLAG) {
>>> +        writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>>> +
>>> +        if (!blk->is_rx_blk_mode) {
>>> +            blk->fifo_available += qup->in_fifo_sz;
>>> +            qup->read_rx_fifo(qup);
>>> +        } else if (opflags & IN_BLOCK_READ_REQ) {
>>> +            blk->fifo_available += qup->in_blk_sz;
>>> +            qup->read_rx_fifo(qup);
>>> +        }
>>> +    }
>>> +
>>> +    if (opflags & QUP_MX_OUTPUT_DONE)
>>> +        qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE;
>>> +
>>> +    if (opflags & QUP_MX_INPUT_DONE)
>>> +        qup->cur_blk_events |= QUP_BLK_EVENT_RX_IRQ_DONE;
>>> +
>>> +    if (qup->cur_blk_events != qup->blk_events)
>>> +        return IRQ_HANDLED;
>>
>>   Is it correct that if we do a complete in above case, i mean
>>   for TX -> based on QUP_MX_OUTPUT_DONE and for RX -> based on
>>   QUP_MX_INPUT_DONE, would that simplify things by getting rid of
>>   QUP_BLK_EVENT_RX/TX_DONE and QUP_BLK_EVENT_RX/TX_IRQ_DONE
>>   altogether ?
> 
>  We can get rid of QUP_BLK_EVENT_TX_DONE.
>  For RX, the QUP_MX_INPUT_DONE will be triggered when QUP copies all
>  the data in FIFO from external i2c slave. So if 64 bytes read has been
>  scheduled then  following is the behaviour
> 
>  IRQ with QUP_MX_INPUT_DONE and IN_BLOCK_READ_REQ -> read 16 bytes
>  IRQ with IN_BLOCK_READ_REQ -> read next 16 bytes
>  IRQ with IN_BLOCK_READ_REQ  -> read next 16 bytes
>  IRQ with IN_BLOCK_READ_REQ -> read last 16 bytes
> 
>  So for RX, we can't trigger complete by checking QUP_BLK_EVENT_RX_DONE alone.
>  We need to track the number of bytes read from FIFO. Instead of putting
>  this check, I am taking one extra event bit QUP_BLK_EVENT_RX_DONE which
>  will be set when all the bytes has been read.
> 
>  I am not sure if checking QUP_MX_INPUT_DONE will always work since
>  there may be some case, when for small transfers the QUP_MX_INPUT_DONE
>  will come before QUP_MX_OUTPUT_DONE so checking for both will work
>  always.

Looking in to the code and the above case,
  RX -> complete when the required len bytes are read from FIFO in to the msg buffer.
  TX -> complete just when QUP_MX_OUTPUT_DONE is set.

Tf this helps of getting rid of 3 of the above 4 flags tracking and all your stress/testing
continues to work then fine.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
  2018-02-08 14:03   ` Sricharan R
@ 2018-02-27 21:46   ` Christ, Austin
  2018-02-27 22:24   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 21:46 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> The QUP BSLP BAM generates the following error sometimes if the
> current I2C DMA transfer fails and the flush operation has been
> scheduled
> 
>      “bam-dma-engine 7884000.dma: Cannot free busy channel”
> 
> If any I2C error comes during BAM DMA transfer, then the QUP I2C
> interrupt will be generated and the flush operation will be
> carried out to make i2c consume all scheduled DMA transfer.
> Currently, the same completion structure is being used for BAM
> transfer which has already completed without reinit. It will make
> flush operation wait_for_completion_timeout completed immediately
> and will proceed for freeing the DMA resources where the
> descriptors are still in process.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 08f8e01..9faa26c41a 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -1,5 +1,5 @@
>   /*
> - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved.
>    * Copyright (c) 2014, Sony Mobile Communications AB.
>    *
>    *
> @@ -844,6 +844,8 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   	}
>   
>   	if (ret || qup->bus_err || qup->qup_err) {
> +		reinit_completion(&qup->xfer);
> +
>   		if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
>   			dev_err(qup->dev, "change to run state timed out");
>   			goto desc_err;
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/12] i2c: qup: minor code reorganization for use_dma
  2018-02-03  7:58 ` [PATCH 02/12] i2c: qup: minor code reorganization for use_dma Abhishek Sahu
@ 2018-02-27 21:48   ` Christ, Austin
  2018-02-27 22:26   ` Andy Gross
  1 sibling, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 21:48 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> 1. Assigns use_dma in qup_dev structure itself which will
>     help in subsequent patches to determine the mode in IRQ handler.
> 2. Does minor code reorganization for loops to reduce the
>     unnecessary comparison and assignment.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 19 +++++++++++--------
>   1 file changed, 11 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 9faa26c41a..c68f433 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -190,6 +190,8 @@ struct qup_i2c_dev {
>   
>   	/* dma parameters */
>   	bool			is_dma;
> +	/* To check if the current transfer is using DMA */
> +	bool			use_dma;
>   	struct			dma_pool *dpool;
>   	struct			qup_i2c_tag start_tag;
>   	struct			qup_i2c_bam brx;
> @@ -1297,7 +1299,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   			   int num)
>   {
>   	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> -	int ret, len, idx = 0, use_dma = 0;
> +	int ret, len, idx = 0;
>   
>   	qup->bus_err = 0;
>   	qup->qup_err = 0;
> @@ -1326,13 +1328,12 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   			len = (msgs[idx].len > qup->out_fifo_sz) ||
>   			      (msgs[idx].len > qup->in_fifo_sz);
>   
> -			if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
> -				use_dma = 1;
> -			 } else {
> -				use_dma = 0;
> +			if (is_vmalloc_addr(msgs[idx].buf) || !len)
>   				break;
> -			}
>   		}
> +
> +		if (idx == num)
> +			qup->use_dma = true;
>   	}
>   
>   	idx = 0;
> @@ -1356,15 +1357,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   
>   		reinit_completion(&qup->xfer);
>   
> -		if (use_dma) {
> +		if (qup->use_dma) {
>   			ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
> +			qup->use_dma = false;
> +			break;
>   		} else {
>   			if (msgs[idx].flags & I2C_M_RD)
>   				ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
>   			else
>   				ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
>   		}
> -	} while ((idx++ < (num - 1)) && !use_dma && !ret);
> +	} while ((idx++ < (num - 1)) && !ret);
>   
>   	if (!ret)
>   		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count
  2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
  2018-02-09  2:16   ` Sricharan R
@ 2018-02-27 21:51   ` Christ, Austin
  2018-02-27 22:28   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 21:51 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

I agree with Sricharan's comments about naming, otherwise looks good.

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
> be used for total number of SG entries.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 26 ++++++++++----------------
>   1 file changed, 10 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index c68f433..bb83a2967 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -692,7 +692,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   	struct dma_async_tx_descriptor *txd, *rxd = NULL;
>   	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
>   	dma_cookie_t cookie_rx, cookie_tx;
> -	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> +	u32 len, blocks, rem;
>   	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
>   	u8 *tags;
>   
> @@ -707,9 +707,6 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   		rem = msg->len - (blocks - 1) * limit;
>   
>   		if (msg->flags & I2C_M_RD) {
> -			rx_nents += (blocks * 2) + 1;
> -			tx_nents += 1;
> -
>   			while (qup->blk.pos < blocks) {
>   				tlen = (i == (blocks - 1)) ? rem : limit;
>   				tags = &qup->start_tag.start[off + len];
> @@ -748,8 +745,6 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   			if (ret)
>   				return ret;
>   		} else {
> -			tx_nents += (blocks * 2);
> -
>   			while (qup->blk.pos < blocks) {
>   				tlen = (i == (blocks - 1)) ? rem : limit;
>   				tags = &qup->start_tag.start[off + tx_len];
> @@ -775,7 +770,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   
>   			if (idx == (num - 1)) {
>   				len = 1;
> -				if (rx_nents) {
> +				if (rx_buf) {
>   					qup->btx.tag.start[0] =
>   							QUP_BAM_INPUT_EOT;
>   					len++;
> @@ -787,14 +782,13 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   						     len, qup, DMA_TO_DEVICE);
>   				if (ret)
>   					return ret;
> -				tx_nents += 1;
>   			}
>   		}
>   		idx++;
>   		msg++;
>   	}
>   
> -	txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_nents,
> +	txd = dmaengine_prep_slave_sg(qup->btx.dma, qup->btx.sg, tx_buf,
>   				      DMA_MEM_TO_DEV,
>   				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
>   	if (!txd) {
> @@ -803,7 +797,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   		goto desc_err;
>   	}
>   
> -	if (!rx_nents) {
> +	if (!rx_buf) {
>   		txd->callback = qup_i2c_bam_cb;
>   		txd->callback_param = qup;
>   	}
> @@ -816,9 +810,9 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   
>   	dma_async_issue_pending(qup->btx.dma);
>   
> -	if (rx_nents) {
> +	if (rx_buf) {
>   		rxd = dmaengine_prep_slave_sg(qup->brx.dma, qup->brx.sg,
> -					      rx_nents, DMA_DEV_TO_MEM,
> +					      rx_buf, DMA_DEV_TO_MEM,
>   					      DMA_PREP_INTERRUPT);
>   		if (!rxd) {
>   			dev_err(qup->dev, "failed to get rx desc\n");
> @@ -853,7 +847,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   			goto desc_err;
>   		}
>   
> -		if (rx_nents)
> +		if (rx_buf)
>   			writel(QUP_BAM_INPUT_EOT,
>   			       qup->base + QUP_OUT_FIFO_BASE);
>   
> @@ -871,10 +865,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   	}
>   
>   desc_err:
> -	dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
> +	dma_unmap_sg(qup->dev, qup->btx.sg, tx_buf, DMA_TO_DEVICE);
>   
> -	if (rx_nents)
> -		dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
> +	if (rx_buf)
> +		dma_unmap_sg(qup->dev, qup->brx.sg, rx_buf,
>   			     DMA_FROM_DEVICE);
>   
>   	return ret;
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode
  2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
  2018-02-16  4:33   ` Sricharan R
@ 2018-02-27 22:00   ` Christ, Austin
  2018-02-27 22:58   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 22:00 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> Currently the i2c error handling in BAM mode is not working
> properly in stress condition.
> 
> 1. After an error, the FIFO are being written with FLUSH and
>     EOT tags which should not be required since already these tags
>     have been written in BAM descriptor itself.
> 
> 2. QUP state is being moved to RESET in IRQ handler in case
>     of error. When QUP HW encounters an error in BAM mode then it
>     moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH
>     command needs to be executed while moving to RUN_STATE by writing
>     to the QUP_STATE register with the I2C_FLUSH bit set to 1.
> 
> 3. In Error case, sometimes, QUP generates more than one
>     interrupt which will trigger the complete again. After an error,
>     the flush operation will be scheduled after doing
>     reinit_completion which should be triggered by BAM IRQ callback.
>     If the second QUP IRQ comes during this time then it will call
>     the complete and the transfer function will assume the all the
>     BAM HW descriptors have been completed.
> 
> 4. The release DMA is being called after each error which
>     will free the DMA tx and rx channels. The error like NACK is very
>     common in I2C transfer and every time this will be overhead. Now,
>     since the error handling is proper so this release channel can be
>     completely avoided.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++---------
>   1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 094be6a..6227a5c 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -228,9 +228,24 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>   	if (bus_err)
>   		writel(bus_err, qup->base + QUP_I2C_STATUS);
>   
> +	/*
> +	 * Check for BAM mode and returns if already error has come for current
> +	 * transfer. In Error case, sometimes, QUP generates more than one
> +	 * interrupt.
> +	 */
> +	if (qup->use_dma && (qup->qup_err || qup->bus_err))
> +		return IRQ_HANDLED;
> +
>   	/* Reset the QUP State in case of error */
>   	if (qup_err || bus_err) {
> -		writel(QUP_RESET_STATE, qup->base + QUP_STATE);
> +		/*
> +		 * Don’t reset the QUP state in case of BAM mode. The BAM
> +		 * flush operation needs to be scheduled in transfer function
> +		 * which will clear the remaining schedule descriptors in BAM
> +		 * HW FIFO and generates the BAM interrupt.
> +		 */
> +		if (!qup->use_dma)
> +			writel(QUP_RESET_STATE, qup->base + QUP_STATE);
>   		goto done;
>   	}
>   
> @@ -841,20 +856,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   			goto desc_err;
>   		}
>   
> -		if (rx_buf)
> -			writel(QUP_BAM_INPUT_EOT,
> -			       qup->base + QUP_OUT_FIFO_BASE);
> -
> -		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
> -
>   		qup_i2c_flush(qup);
>   
>   		/* wait for remaining interrupts to occur */
>   		if (!wait_for_completion_timeout(&qup->xfer, HZ))
>   			dev_err(qup->dev, "flush timed out\n");
>   
> -		qup_i2c_rel_dma(qup);
> -
>   		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
>   	}
>   
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode
  2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
  2018-02-16  4:35   ` Sricharan R
@ 2018-02-27 22:01   ` Christ, Austin
  2018-02-27 22:59   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 22:01 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> Currently each message length in complete transfer is being
> checked for determining DMA mode and if any of the message length
> is less than FIFO length then non DMA mode is being used which
> will increase overhead. DMA can be used for any length and it
> should be determined with complete transfer length. Now, this
> patch introduces DMA threshold length and the transfer will be
> done in DMA mode if the total length is greater than this
> threshold length.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 15 +++++++++------
>   1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 6227a5c..a91fc70 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -192,6 +192,8 @@ struct qup_i2c_dev {
>   	bool			is_dma;
>   	/* To check if the current transfer is using DMA */
>   	bool			use_dma;
> +	/* The threshold length above which DMA will be used */
> +	unsigned int		dma_threshold;
>   	struct			dma_pool *dpool;
>   	struct			qup_i2c_tag start_tag;
>   	struct			qup_i2c_bam brx;
> @@ -1294,7 +1296,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   			   int num)
>   {
>   	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> -	int ret, len, idx = 0;
> +	int ret, idx = 0;
> +	unsigned int total_len = 0;
>   
>   	qup->bus_err = 0;
>   	qup->qup_err = 0;
> @@ -1320,14 +1323,13 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   				goto out;
>   			}
>   
> -			len = (msgs[idx].len > qup->out_fifo_sz) ||
> -			      (msgs[idx].len > qup->in_fifo_sz);
> -
> -			if (is_vmalloc_addr(msgs[idx].buf) || !len)
> +			if (is_vmalloc_addr(msgs[idx].buf))
>   				break;
> +
> +			total_len += msgs[idx].len;
>   		}
>   
> -		if (idx == num)
> +		if (idx == num && total_len > qup->dma_threshold)
>   			qup->use_dma = true;
>   	}
>   
> @@ -1587,6 +1589,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   
>   	size = QUP_INPUT_FIFO_SIZE(io_mode);
>   	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
> +	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
>   
>   	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
>   	hs_div = 3;
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
  2018-02-16  5:21   ` Sricharan R
@ 2018-02-27 22:06   ` Christ, Austin
  2018-03-12 13:55     ` Abhishek Sahu
  2018-02-27 23:15   ` Andy Gross
  2 siblings, 1 reply; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 22:06 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Hey Abhishek,


On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> The BAM mode requires buffer for start tag data and tx, rx SG
> list. Currently, this is being taken for maximum transfer length
> (65K). But an I2C transfer can have multiple messages and each
> message can be of this maximum length so the buffer overflow will
> happen in this case. Since increasing buffer length won’t be
> feasible since an I2C transfer can contain any number of messages
> so this patch does following changes to make i2c transfers working
> for multiple messages case.
> 
> 1. Calculate the required buffers for 2 maximum length messages
>     (65K * 2).
> 2. Split the descriptor formation and descriptor scheduling.
>     The idea is to fit as many messages in one DMA transfers for 65K
>     threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>     crossing this, then schedule the BAM transfer and subsequent
>     transfer will again start from zero.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 199 +++++++++++++++++++++++++------------------
>   1 file changed, 118 insertions(+), 81 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index 6df65ea..ba717bb 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -155,6 +155,7 @@ struct qup_i2c_bam {
>   	struct	qup_i2c_tag tag;
>   	struct	dma_chan *dma;
>   	struct	scatterlist *sg;
> +	unsigned int sg_cnt;
>   };
>   
>   struct qup_i2c_dev {
> @@ -195,6 +196,8 @@ struct qup_i2c_dev {
>   	bool			use_dma;
>   	/* The threshold length above which DMA will be used */
>   	unsigned int		dma_threshold;
> +	unsigned int		max_xfer_sg_len;
> +	unsigned int		tag_buf_pos;
>   	struct			dma_pool *dpool;
>   	struct			qup_i2c_tag start_tag;
>   	struct			qup_i2c_bam brx;
> @@ -699,86 +702,86 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
>   	return 0;
>   }
>   
> -static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
> -			       int num)
> +static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +{
> +	int ret = 0, limit = QUP_READ_LIMIT;
> +	u32 len = 0, blocks, rem;
> +	u32 i = 0, tlen, tx_len = 0;
> +	u8 *tags;
> +
> +	qup_i2c_set_blk_data(qup, msg);
> +
> +	blocks = qup->blk.count;
> +	rem = msg->len - (blocks - 1) * limit;
> +
> +	if (msg->flags & I2C_M_RD) {
> +		while (qup->blk.pos < blocks) {
> +			tlen = (i == (blocks - 1)) ? rem : limit;
> +			tags = &qup->start_tag.start[qup->tag_buf_pos + len];
> +			len += qup_i2c_set_tags(tags, qup, msg);
> +			qup->blk.data_len -= tlen;
> +
> +			/* scratch buf to read the start and len tags */
> +			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
> +					     &qup->brx.tag.start[0],
> +					     2, qup, DMA_FROM_DEVICE);
> +
> +			if (ret)
> +				return ret;
> +
> +			ret = qup_sg_set_buf(&qup->brx.sg[qup->brx.sg_cnt++],
> +					     &msg->buf[limit * i],
> +					     tlen, qup,
> +					     DMA_FROM_DEVICE);
> +			if (ret)
> +				return ret;
> +
> +			i++;
> +			qup->blk.pos = i;
> +		}
> +		ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +				     &qup->start_tag.start[qup->tag_buf_pos],
> +				     len, qup, DMA_TO_DEVICE);
> +		if (ret)
> +			return ret;
> +
> +		qup->tag_buf_pos += len;
> +	} else {
> +		while (qup->blk.pos < blocks) {
> +			tlen = (i == (blocks - 1)) ? rem : limit;
> +			tags = &qup->start_tag.start[qup->tag_buf_pos + tx_len];
> +			len = qup_i2c_set_tags(tags, qup, msg);
> +			qup->blk.data_len -= tlen;
> +
> +			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +					     tags, len,
> +					     qup, DMA_TO_DEVICE);
> +			if (ret)
> +				return ret;
> +
> +			tx_len += len;
> +			ret = qup_sg_set_buf(&qup->btx.sg[qup->btx.sg_cnt++],
> +					     &msg->buf[limit * i],
> +					     tlen, qup, DMA_TO_DEVICE);
> +			if (ret)
> +				return ret;
> +			i++;
> +			qup->blk.pos = i;
> +		}
> +
> +		qup->tag_buf_pos += tx_len;
> +	}
> +
> +	return 0;
> +}
> +
> +static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
>   {
>   	struct dma_async_tx_descriptor *txd, *rxd = NULL;
> -	int ret = 0, idx = 0, limit = QUP_READ_LIMIT;
> +	int ret = 0;
>   	dma_cookie_t cookie_rx, cookie_tx;
> -	u32 len, blocks, rem;
> -	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> -	u8 *tags;
> -
> -	while (idx < num) {
> -		tx_len = 0, len = 0, i = 0;
> -
> -		qup->is_last = (idx == (num - 1));
> -
> -		qup_i2c_set_blk_data(qup, msg);
> -
> -		blocks = qup->blk.count;
> -		rem = msg->len - (blocks - 1) * limit;
> -
> -		if (msg->flags & I2C_M_RD) {
> -			while (qup->blk.pos < blocks) {
> -				tlen = (i == (blocks - 1)) ? rem : limit;
> -				tags = &qup->start_tag.start[off + len];
> -				len += qup_i2c_set_tags(tags, qup, msg);
> -				qup->blk.data_len -= tlen;
> -
> -				/* scratch buf to read the start and len tags */
> -				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> -						     &qup->brx.tag.start[0],
> -						     2, qup, DMA_FROM_DEVICE);
> -
> -				if (ret)
> -					return ret;
> -
> -				ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
> -						     &msg->buf[limit * i],
> -						     tlen, qup,
> -						     DMA_FROM_DEVICE);
> -				if (ret)
> -					return ret;
> -
> -				i++;
> -				qup->blk.pos = i;
> -			}
> -			ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -					     &qup->start_tag.start[off],
> -					     len, qup, DMA_TO_DEVICE);
> -			if (ret)
> -				return ret;
> -
> -			off += len;
> -		} else {
> -			while (qup->blk.pos < blocks) {
> -				tlen = (i == (blocks - 1)) ? rem : limit;
> -				tags = &qup->start_tag.start[off + tx_len];
> -				len = qup_i2c_set_tags(tags, qup, msg);
> -				qup->blk.data_len -= tlen;
> -
> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -						     tags, len,
> -						     qup, DMA_TO_DEVICE);
> -				if (ret)
> -					return ret;
> -
> -				tx_len += len;
> -				ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
> -						     &msg->buf[limit * i],
> -						     tlen, qup, DMA_TO_DEVICE);
> -				if (ret)
> -					return ret;
> -				i++;
> -				qup->blk.pos = i;
> -			}
> -			off += tx_len;
> -
> -		}
> -		idx++;
> -		msg++;
> -	}
> +	u32 len = 0;
> +	u32 tx_buf = qup->btx.sg_cnt, rx_buf = qup->brx.sg_cnt;
>   
>   	/* schedule the EOT and FLUSH I2C tags */
>   	len = 1;
> @@ -878,11 +881,19 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>   	return ret;
>   }
>   
> +static void qup_i2c_bam_clear_tag_buffers(struct qup_i2c_dev *qup)
> +{
> +	qup->btx.sg_cnt = 0;
> +	qup->brx.sg_cnt = 0;
> +	qup->tag_buf_pos = 0;
> +}
> +
>   static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
>   			    int num)
>   {
>   	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>   	int ret = 0;
> +	int idx = 0;
>   
>   	enable_irq(qup->irq);
>   	ret = qup_i2c_req_dma(qup);
> @@ -905,9 +916,34 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
>   		goto out;
>   
>   	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> +	qup_i2c_bam_clear_tag_buffers(qup);
> +
> +	for (idx = 0; idx < num; idx++) {
> +		qup->msg = msg + idx;
> +		qup->is_last = idx == (num - 1);
> +
> +		ret = qup_i2c_bam_make_desc(qup, qup->msg);
> +		if (ret)
> +			break;
> +
> +		/*
> +		 * Make DMA descriptor and schedule the BAM transfer if its
> +		 * already crossed the maximum length. Since the memory for all
> +		 * tags buffers have been taken for 2 maximum possible
> +		 * transfers length so it will never cross the buffer actual
> +		 * length.
> +		 */
> +		if (qup->btx.sg_cnt > qup->max_xfer_sg_len ||
> +		    qup->brx.sg_cnt > qup->max_xfer_sg_len ||
> +		    qup->is_last) {
> +			ret = qup_i2c_bam_schedule_desc(qup);
> +			if (ret)
> +				break;
> +
> +			qup_i2c_bam_clear_tag_buffers(qup);
> +		}
> +	}
>   
> -	qup->msg = msg;
> -	ret = qup_i2c_bam_do_xfer(qup, qup->msg, num);
>   out:
>   	disable_irq(qup->irq);
>   
> @@ -1459,7 +1495,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   		else if (ret != 0)
>   			goto nodma;
>   
> -		blocks = (MX_BLOCKS << 1) + 1;
> +		qup->max_xfer_sg_len = (MX_BLOCKS << 1);
> +		blocks = 2 * qup->max_xfer_sg_len + 1;
>   		qup->btx.sg = devm_kzalloc(&pdev->dev,
>   					   sizeof(*qup->btx.sg) * blocks,
>   					   GFP_KERNEL);
> @@ -1603,7 +1640,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
>   	qup->one_byte_t = one_bit_t * 9;
>   	qup->xfer_timeout = TOUT_MIN * HZ +
> -			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
> +		usecs_to_jiffies(2 * MX_TX_RX_LEN * qup->one_byte_t);

Maybe it would make sense to add a comment here explaining why the magic 
number 2 has been added.
>   
>   	dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
>   		qup->in_blk_sz, qup->in_fifo_sz,
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 10/12] i2c: qup: send NACK for last read sub transfers
  2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
  2018-02-16  5:39   ` Sricharan R
@ 2018-02-27 22:07   ` Christ, Austin
  2018-02-27 23:17   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 22:07 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel

Tested on Centriq 2400

Reviewed-by: Austin Christ <austinwc@codeaurora.org>

On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> According to I2c specification, “If a master-receiver sends a
> repeated START condition, it sends a not-acknowledge (A) just
> before the repeated START condition”. QUP v2 supports sending
> of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
> same.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index ba717bb..edea3b9 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -113,6 +113,7 @@
>   #define QUP_TAG_V2_DATAWR              0x82
>   #define QUP_TAG_V2_DATAWR_STOP         0x83
>   #define QUP_TAG_V2_DATARD              0x85
> +#define QUP_TAG_V2_DATARD_NACK         0x86
>   #define QUP_TAG_V2_DATARD_STOP         0x87
>   
>   /* Status, Error flags */
> @@ -609,7 +610,9 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>   			tags[len++] = QUP_TAG_V2_DATAWR_STOP;
>   	} else {
>   		if (msg->flags & I2C_M_RD)
> -			tags[len++] = QUP_TAG_V2_DATARD;
> +			tags[len++] = qup->blk.pos == (qup->blk.count - 1) ?
> +				      QUP_TAG_V2_DATARD_NACK :
> +				      QUP_TAG_V2_DATARD;
>   		else
>   			tags[len++] = QUP_TAG_V2_DATAWR;
>   	}
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion
  2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
  2018-02-08 14:03   ` Sricharan R
  2018-02-27 21:46   ` Christ, Austin
@ 2018-02-27 22:24   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:24 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:06PM +0530, Abhishek Sahu wrote:
> The QUP BSLP BAM generates the following error sometimes if the
> current I2C DMA transfer fails and the flush operation has been
> scheduled
> 
>     “bam-dma-engine 7884000.dma: Cannot free busy channel”
> 
> If any I2C error comes during BAM DMA transfer, then the QUP I2C
> interrupt will be generated and the flush operation will be
> carried out to make i2c consume all scheduled DMA transfer.
> Currently, the same completion structure is being used for BAM
> transfer which has already completed without reinit. It will make
> flush operation wait_for_completion_timeout completed immediately
> and will proceed for freeing the DMA resources where the
> descriptors are still in process.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 02/12] i2c: qup: minor code reorganization for use_dma
  2018-02-03  7:58 ` [PATCH 02/12] i2c: qup: minor code reorganization for use_dma Abhishek Sahu
  2018-02-27 21:48   ` Christ, Austin
@ 2018-02-27 22:26   ` Andy Gross
  1 sibling, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:26 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:07PM +0530, Abhishek Sahu wrote:
> 1. Assigns use_dma in qup_dev structure itself which will
>    help in subsequent patches to determine the mode in IRQ handler.
> 2. Does minor code reorganization for loops to reduce the
>    unnecessary comparison and assignment.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count
  2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
  2018-02-09  2:16   ` Sricharan R
  2018-02-27 21:51   ` Christ, Austin
@ 2018-02-27 22:28   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:28 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:08PM +0530, Abhishek Sahu wrote:
> The rx_nents and tx_nents are redundant. rx_buf and tx_buf can
> be used for total number of SG entries.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---

Naming conventions aside,

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  2018-02-03  7:58 ` [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer Abhishek Sahu
  2018-02-15 14:31   ` Sricharan R
@ 2018-02-27 22:36   ` Andy Gross
  2018-03-08 13:40     ` Abhishek Sahu
  1 sibling, 1 reply; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:36 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:09PM +0530, Abhishek Sahu wrote:
> A single BAM transfer can have multiple read and write messages.
> The EOT and FLUSH tags should be scheduled at the end of BAM HW
> descriptors. Since the READ and WRITE can be present in any order
> so for some of the cases, these tags are not being written
> correctly.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 54 ++++++++++++++++++++------------------------
>  1 file changed, 24 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index bb83a2967..6357aff 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -560,7 +560,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
>  }
>  
>  static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
> -			    struct i2c_msg *msg,  int is_dma)
> +			    struct i2c_msg *msg)
>  {
>  	u16 addr = i2c_8bit_addr_from_msg(msg);
>  	int len = 0;
> @@ -601,11 +601,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>  	else
>  		tags[len++] = data_len;
>  
> -	if ((msg->flags & I2C_M_RD) && last && is_dma) {
> -		tags[len++] = QUP_BAM_INPUT_EOT;
> -		tags[len++] = QUP_BAM_FLUSH_STOP;
> -	}
> -

So lets say you have multiple read and 1 write message.  These changes will send
a EOT/FLUSH for all reads.  I think the intent here was that the last read
message (not the last message) would have the EOT+FLUSH.  Can there be an issue
with sending EOT/FLUSH for all reads?  And how does this mesh up with the BAM
signaling?


Regards,

Andy

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags
  2018-02-03  7:58 ` [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags Abhishek Sahu
@ 2018-02-27 22:38   ` Andy Gross
  0 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:38 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:10PM +0530, Abhishek Sahu wrote:
> In case of FLUSH operation, BAM copies INPUT EOT FLUSH (0x94)
> instead of normal EOT (0x93) tag in input data stream when an
> input EOT tag is received during flush operation. So only one tag
> will be written instead of 2 separate tags.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode
  2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
  2018-02-16  4:33   ` Sricharan R
  2018-02-27 22:00   ` Christ, Austin
@ 2018-02-27 22:58   ` Andy Gross
  2018-03-12 12:34     ` Abhishek Sahu
  2 siblings, 1 reply; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:58 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:11PM +0530, Abhishek Sahu wrote:

<snip>

> @@ -841,20 +856,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
>  			goto desc_err;
>  		}
>  
> -		if (rx_buf)
> -			writel(QUP_BAM_INPUT_EOT,
> -			       qup->base + QUP_OUT_FIFO_BASE);
> -
> -		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
> -
>  		qup_i2c_flush(qup);
>  
>  		/* wait for remaining interrupts to occur */
>  		if (!wait_for_completion_timeout(&qup->xfer, HZ))
>  			dev_err(qup->dev, "flush timed out\n");
>  
> -		qup_i2c_rel_dma(qup);
> -

So this really only works due to the previous patch that adds the flush/eot tags
to all of the read messages.  If the answer to the previous question is that
only the last read message gets the eot/flush, then this code needs to remain in
place.  Otherwise, it's fine.


Andy

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode
  2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
  2018-02-16  4:35   ` Sricharan R
  2018-02-27 22:01   ` Christ, Austin
@ 2018-02-27 22:59   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 22:59 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:12PM +0530, Abhishek Sahu wrote:
> Currently each message length in complete transfer is being
> checked for determining DMA mode and if any of the message length
> is less than FIFO length then non DMA mode is being used which
> will increase overhead. DMA can be used for any length and it
> should be determined with complete transfer length. Now, this
> patch introduces DMA threshold length and the transfer will be
> done in DMA mode if the total length is greater than this
> threshold length.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---

I agree with Sricharan's nit.

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 08/12] i2c: qup: change completion timeout according to transfer length
  2018-02-19 10:56     ` Abhishek Sahu
@ 2018-02-27 23:05       ` Andy Gross
  0 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 23:05 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Sricharan R, Wolfram Sang, David Brown, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Mon, Feb 19, 2018 at 04:26:18PM +0530, Abhishek Sahu wrote:
> On 2018-02-16 10:18, Sricharan R wrote:
> >On 2/3/2018 1:28 PM, Abhishek Sahu wrote:
> >>Currently the completion timeout is being taken according to
> >>maximum transfer length which is too high if SCL is operating in
> >>high frequency. This patch calculates timeout on the basis of
> >>one-byte transfer time and uses the same for completion timeout.
> >>
> >>Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> >>---
> >> drivers/i2c/busses/i2c-qup.c | 9 ++++++---
> >> 1 file changed, 6 insertions(+), 3 deletions(-)
> >>
> >>diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> >>index a91fc70..6df65ea 100644
> >>--- a/drivers/i2c/busses/i2c-qup.c
> >>+++ b/drivers/i2c/busses/i2c-qup.c
> >>@@ -130,8 +130,8 @@
> >> #define MX_TX_RX_LEN			SZ_64K
> >> #define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
> >>
> >>-/* Max timeout in ms for 32k bytes */
> >>-#define TOUT_MAX			300
> >>+/* Min timeout for i2c transfers */
> >>+#define TOUT_MIN			2
> >>
> >
> > may be you can mention, why is this 2 ?
> >
> 
>  This 2 seconds is timeout which I am adding on the top of maximum
>  xfer time calculated from bus speed to compensate the interrupt
>  latency and other factors. It will make xfer timeout minimum as
>  2 seconds.
> 
>  I will update the comment to explain it in more detail.

Once you do that add:

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
  2018-02-16  5:21   ` Sricharan R
  2018-02-27 22:06   ` Christ, Austin
@ 2018-02-27 23:15   ` Andy Gross
  2018-03-12 12:28     ` Abhishek Sahu
  2 siblings, 1 reply; 57+ messages in thread
From: Andy Gross @ 2018-02-27 23:15 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:14PM +0530, Abhishek Sahu wrote:
> The BAM mode requires buffer for start tag data and tx, rx SG
> list. Currently, this is being taken for maximum transfer length
> (65K). But an I2C transfer can have multiple messages and each
> message can be of this maximum length so the buffer overflow will
> happen in this case. Since increasing buffer length won’t be
> feasible since an I2C transfer can contain any number of messages
> so this patch does following changes to make i2c transfers working
> for multiple messages case.
> 
> 1. Calculate the required buffers for 2 maximum length messages
>    (65K * 2).
> 2. Split the descriptor formation and descriptor scheduling.
>    The idea is to fit as many messages in one DMA transfers for 65K
>    threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>    crossing this, then schedule the BAM transfer and subsequent
>    transfer will again start from zero.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

I'm ok with this patch.  I find the idea of a > 64k size message to be something
that usually wouldn't be encountered, but... with some eeproms and maybe TPMs
perhaps this could happen?

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 10/12] i2c: qup: send NACK for last read sub transfers
  2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
  2018-02-16  5:39   ` Sricharan R
  2018-02-27 22:07   ` Christ, Austin
@ 2018-02-27 23:17   ` Andy Gross
  2 siblings, 0 replies; 57+ messages in thread
From: Andy Gross @ 2018-02-27 23:17 UTC (permalink / raw)
  To: Abhishek Sahu
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On Sat, Feb 03, 2018 at 01:28:15PM +0530, Abhishek Sahu wrote:
> According to I2c specification, “If a master-receiver sends a
> repeated START condition, it sends a not-acknowledge (A) just
> before the repeated START condition”. QUP v2 supports sending
> of NACK without stop with QUP_TAG_V2_DATARD_NACK so added the
> same.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>

Reviewed-by: Andy Gross <andy.gross@linaro.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2
  2018-02-03  7:58 ` [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2 Abhishek Sahu
  2018-02-16 11:23   ` Sricharan R
@ 2018-02-27 23:24   ` Christ, Austin
  2018-03-12 13:58     ` Abhishek Sahu
  1 sibling, 1 reply; 57+ messages in thread
From: Christ, Austin @ 2018-02-27 23:24 UTC (permalink / raw)
  To: Abhishek Sahu, Andy Gross, Wolfram Sang
  Cc: David Brown, Sricharan R, linux-arm-msm, linux-soc, linux-i2c,
	linux-kernel



On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
> Following are the major issues in current driver code
> 
> 1. The current driver simply assumes the transfer completion
>     whenever its gets any non-error interrupts and then simply do the
>     polling of available/free bytes in FIFO.
> 2. The block mode is not working properly since no handling in
>     being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_READ.
> 3. An i2c transfer can contain multiple message and QUP v2
>     supports reconfiguration during run in which the mode should be same
>     for all the sub transfer. Currently the mode is being programmed
>     before every sub transfer which is functionally wrong. If one message
>     is less than FIFO length and other message is greater than FIFO
>     length, then transfers will fail.
> 
> Because of above, i2c v2 transfers of size greater than 64 are failing
> with following error message
> 
> 	i2c_qup 78b6000.i2c: timeout for fifo out full
> 
> To make block mode working properly and move to use the interrupts
> instead of polling, major code reorganization is required. Following
> are the major changes done in this patch
> 
> 1. Remove the polling of TX FIFO free space and RX FIFO available
>     bytes and move to interrupts completely. QUP has QUP_MX_OUTPUT_DONE,
>     QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ
>     interrupts to handle FIFO’s properly so check all these interrupts.
> 2. Determine the mode for transfer before starting by checking
>     all the tx/rx data length in each message. The complete message can be
>     transferred either in DMA mode or Programmed IO by FIFO/Block mode.
>     in DMA mode, both tx and rx uses same mode but in PIO mode, the TX and
>     RX can be in different mode.
> 3. During write, For FIFO mode, TX FIFO can be directly written
>     without checking for FIFO space. For block mode, the QUP will generate
>     OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of available
>     space.
> 4. During read, both TX and RX FIFO will be used. TX will be used
>     for writing tags and RX will be used for receiving the data. In QUP,
>     TX and RX can operate in separate mode so configure modes accordingly.
> 5. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which
>     will be generated after all the bytes have been copied in RX FIFO. For
>     read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts
>     whenever it has block size of available data.
> 6. Split the transfer in chunk of one QUP block size(256 bytes)
>     and schedule each block separately. QUP v2 supports reconfiguration
>     during run in which QUP can transfer multiple blocks without issuing a
>     stop events.
> 7. Port the SMBus block read support for new code changes.
> 
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
>   drivers/i2c/busses/i2c-qup.c | 917 +++++++++++++++++++++++++------------------
>   1 file changed, 533 insertions(+), 384 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index af6c21a..46736a1 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -141,6 +141,15 @@
>   #define DEFAULT_CLK_FREQ 100000
>   #define DEFAULT_SRC_CLK 20000000
>   
> +/*
> + * Max tags length (start, stop and maximum 2 bytes address) for each QUP
> + * data transfer
> + */
> +#define QUP_MAX_TAGS_LEN		4
> +/* Max data length for each DATARD tags */
> +#define RECV_MAX_DATA_LEN		254
> +/* TAG length for DATA READ in RX FIFO  */
> +#define READ_RX_TAGS_LEN		2
>   /* MAX_OUTPUT_DONE_FLAG has been received */
>   #define QUP_BLK_EVENT_TX_IRQ_DONE		BIT(0)
>   /* MAX_INPUT_DONE_FLAG has been received */
> @@ -164,11 +173,24 @@
>    * tx_tag_len: tx tag length for current block
>    * rx_tag_len: rx tag length for current block
>    * data_len: remaining data length for current message
> + * cur_blk_len: data length for current block
>    * total_tx_len: total tx length including tag bytes for current QUP transfer
>    * total_rx_len: total rx length including tag bytes for current QUP transfer
> + * tx_fifo_data_pos: current byte number in TX FIFO word
>    * tx_fifo_free: number of free bytes in current QUP block write.
> + * rx_fifo_data_pos: current byte number in RX FIFO word
>    * fifo_available: number of available bytes in RX FIFO for current
>    *		   QUP block read
> + * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write
> + *		 to TX FIFO will be appended in this data and will be written to
> + *		 TX FIFO when all the 4 bytes are available.
> + * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will
> + *		 contains the 4 bytes of RX data.
> + * cur_data: pointer to tell cur data position for current message
> + * cur_tx_tags: pointer to tell cur position in tags
> + * tx_tags_sent: all tx tag bytes have been written in FIFO word
> + * send_last_word: for tx FIFO, last word send is pending in current block
> + * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word
>    * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer.
>    * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer.
>    * tags: contains tx tag bytes for current QUP transfer
> @@ -179,10 +201,20 @@ struct qup_i2c_block {
>   	int		tx_tag_len;
>   	int		rx_tag_len;
>   	int		data_len;
> +	int		cur_blk_len;
>   	int		total_tx_len;
>   	int		total_rx_len;
> +	int		tx_fifo_data_pos;
>   	int		tx_fifo_free;
> +	int		rx_fifo_data_pos;
>   	int		fifo_available;
> +	u32		tx_fifo_data;
> +	u32		rx_fifo_data;
> +	u8		*cur_data;
> +	u8		*cur_tx_tags;
> +	bool		tx_tags_sent;
> +	bool		send_last_word;
> +	bool		rx_tags_fetched;
>   	bool		is_tx_blk_mode;
>   	bool		is_rx_blk_mode;
>   	u8		tags[6];
> @@ -214,6 +246,7 @@ struct qup_i2c_dev {
>   	int			out_blk_sz;
>   	int			in_blk_sz;
>   
> +	int			blk_xfer_limit;
>   	unsigned long		one_byte_t;
>   	unsigned long		xfer_timeout;
>   	struct qup_i2c_block	blk;
> @@ -228,10 +261,10 @@ struct qup_i2c_dev {
>   
>   	/* To check if this is the last msg */
>   	bool			is_last;
> -	bool			is_qup_v1;
> +	bool			is_smbus_read;
>   
>   	/* To configure when bus is in run state */
> -	int			config_run;
> +	u32			config_run;
>   
>   	/* dma parameters */
>   	bool			is_dma;
> @@ -245,6 +278,8 @@ struct qup_i2c_dev {
>   	unsigned int		dma_threshold;
>   	unsigned int		max_xfer_sg_len;
>   	unsigned int		tag_buf_pos;
> +	/* The threshold length above which block mode will be used */
> +	unsigned int		blk_mode_threshold;
>   	struct			dma_pool *dpool;
>   	struct			qup_i2c_tag start_tag;
>   	struct			qup_i2c_bam brx;
> @@ -309,9 +344,6 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
>   		goto done;
>   	}
>   
> -	if (!qup->is_qup_v1)
> -		goto done;
> -
>   	if (opflags & QUP_OUT_SVC_FLAG) {
>   		writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
>   
> @@ -444,108 +476,6 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
>   	return ret;
>   }
>   
> -/**
> - * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
> - * @qup: The qup_i2c_dev device
> - * @op: The bit/event to wait on
> - * @val: value of the bit to wait on, 0 or 1
> - * @len: The length the bytes to be transferred
> - */
> -static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
> -			      int len)
> -{
> -	unsigned long timeout;
> -	u32 opflags;
> -	u32 status;
> -	u32 shift = __ffs(op);
> -	int ret = 0;
> -
> -	len *= qup->one_byte_t;
> -	/* timeout after a wait of twice the max time */
> -	timeout = jiffies + len * 4;
> -
> -	for (;;) {
> -		opflags = readl(qup->base + QUP_OPERATIONAL);
> -		status = readl(qup->base + QUP_I2C_STATUS);
> -
> -		if (((opflags & op) >> shift) == val) {
> -			if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
> -				if (!(status & I2C_STATUS_BUS_ACTIVE)) {
> -					ret = 0;
> -					goto done;
> -				}
> -			} else {
> -				ret = 0;
> -				goto done;
> -			}
> -		}
> -
> -		if (time_after(jiffies, timeout)) {
> -			ret = -ETIMEDOUT;
> -			goto done;
> -		}
> -		usleep_range(len, len * 2);
> -	}
> -
> -done:
> -	if (qup->bus_err || qup->qup_err)
> -		ret =  (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
> -
> -	return ret;
> -}
> -
> -static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
> -				      struct i2c_msg *msg)
> -{
> -	/* Number of entries to shift out, including the tags */
> -	int total = msg->len + qup->blk.tx_tag_len;
> -
> -	total |= qup->config_run;
> -
> -	if (total < qup->out_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_WRITE_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
> -	}
> -}
> -
> -static int check_for_fifo_space(struct qup_i2c_dev *qup)
> -{
> -	int ret;
> -
> -	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> -	if (ret)
> -		goto out;
> -
> -	ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
> -				 RESET_BIT, 4 * ONE_BYTE);
> -	if (ret) {
> -		/* Fifo is full. Drain out the fifo */
> -		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -		if (ret)
> -			goto out;
> -
> -		ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY,
> -					 RESET_BIT, 256 * ONE_BYTE);
> -		if (ret) {
> -			dev_err(qup->dev, "timeout for fifo out full");
> -			goto out;
> -		}
> -
> -		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> -		if (ret)
> -			goto out;
> -	}
> -
> -out:
> -	return ret;
> -}
> -
>   static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
>   {
>   	struct qup_i2c_block *blk = &qup->blk;
> @@ -591,60 +521,17 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
>   static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup,
>   				 struct i2c_msg *msg)
>   {
> -	memset(&qup->blk, 0, sizeof(qup->blk));
> -
> +	qup->blk.pos = 0;
>   	qup->blk.data_len = msg->len;
> -	qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
> -
> -	/* 4 bytes for first block and 2 writes for rest */
> -	qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> -
> -	/* There are 2 tag bytes that are read in to fifo for every block */
> -	if (msg->flags & I2C_M_RD)
> -		qup->blk.rx_tag_len = qup->blk.count * 2;
> -}
> -
> -static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
> -			     int dlen, u8 *dbuf)
> -{
> -	u32 val = 0, idx = 0, pos = 0, i = 0, t;
> -	int  len = tlen + dlen;
> -	u8 *buf = tbuf;
> -	int ret = 0;
> -
> -	while (len > 0) {
> -		ret = check_for_fifo_space(qup);
> -		if (ret)
> -			return ret;
> -
> -		t = (len >= 4) ? 4 : len;
> -
> -		while (idx < t) {
> -			if (!i && (pos >= tlen)) {
> -				buf = dbuf;
> -				pos = 0;
> -				i = 1;
> -			}
> -			val |= buf[pos++] << (idx++ * 8);
> -		}
> -
> -		writel(val, qup->base + QUP_OUT_FIFO_BASE);
> -		idx  = 0;
> -		val = 0;
> -		len -= 4;
> -	}
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -
> -	return ret;
> +	qup->blk.count = DIV_ROUND_UP(msg->len, qup->blk_xfer_limit);
>   }
>   
>   static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
>   {
>   	int data_len;
>   
> -	if (qup->blk.data_len > QUP_READ_LIMIT)
> -		data_len = QUP_READ_LIMIT;
> +	if (qup->blk.data_len > qup->blk_xfer_limit)
> +		data_len = qup->blk_xfer_limit;
>   	else
>   		data_len = qup->blk.data_len;
>   
> @@ -661,9 +548,9 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
>   {
>   	int len = 0;
>   
> -	if (msg->len > 1) {
> +	if (qup->is_smbus_read) {
>   		tags[len++] = QUP_TAG_V2_DATARD_STOP;
> -		tags[len++] = qup_i2c_get_data_len(qup) - 1;
> +		tags[len++] = qup_i2c_get_data_len(qup);
>   	} else {
>   		tags[len++] = QUP_TAG_V2_START;
>   		tags[len++] = addr & 0xff;
> @@ -725,24 +612,6 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>   	return len;
>   }
>   
> -static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int data_len = 0, tag_len, index;
> -	int ret;
> -
> -	tag_len = qup_i2c_set_tags(qup->blk.tags, qup, msg);
> -	index = msg->len - qup->blk.data_len;
> -
> -	/* only tags are written for read */
> -	if (!(msg->flags & I2C_M_RD))
> -		data_len = qup_i2c_get_data_len(qup);
> -
> -	ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
> -				data_len, &msg->buf[index]);
> -	qup->blk.data_len -= data_len;
> -
> -	return ret;
> -}
>   
>   static void qup_i2c_bam_cb(void *data)
>   {
> @@ -809,6 +678,7 @@ static int qup_i2c_bam_make_desc(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>   	u32 i = 0, tlen, tx_len = 0;
>   	u8 *tags;
>   
> +	qup->blk_xfer_limit = QUP_READ_LIMIT;
>   	qup_i2c_set_blk_data(qup, msg);
>   
>   	blocks = qup->blk.count;
> @@ -1057,7 +927,7 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
>   	unsigned long left;
>   	int ret = 0;
>   
> -	left = wait_for_completion_timeout(&qup->xfer, HZ);
> +	left = wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout);
>   	if (!left) {
>   		writel(1, qup->base + QUP_SW_RESET);
>   		ret = -ETIMEDOUT;
> @@ -1069,65 +939,6 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
>   	return ret;
>   }
>   
> -static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int ret = 0;
> -
> -	qup->msg = msg;
> -	qup->pos = 0;
> -	enable_irq(qup->irq);
> -	qup_i2c_set_blk_data(qup, msg);
> -	qup_i2c_set_write_mode_v2(qup, msg);
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -	if (ret)
> -		goto err;
> -
> -	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> -
> -	do {
> -		ret = qup_i2c_issue_xfer_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		qup->blk.pos++;
> -	} while (qup->blk.pos < qup->blk.count);
> -
> -	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
> -
> -err:
> -	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
> -	return ret;
> -}
> -
> -static void qup_i2c_set_read_mode_v2(struct qup_i2c_dev *qup, int len)
> -{
> -	int tx_len = qup->blk.tx_tag_len;
> -
> -	len += qup->blk.rx_tag_len;
> -	len |= qup->config_run;
> -	tx_len |= qup->config_run;
> -
> -	if (len < qup->in_fifo_sz) {
> -		/* FIFO mode */
> -		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
> -		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
> -		writel(len, qup->base + QUP_MX_READ_CNT);
> -	} else {
> -		/* BLOCK mode (transfer data on chunks) */
> -		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
> -		       qup->base + QUP_IO_MODE);
> -		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
> -		writel(len, qup->base + QUP_MX_INPUT_CNT);
> -	}
> -}
> -
>   static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
>   {
>   	struct qup_i2c_block *blk = &qup->blk;
> @@ -1151,104 +962,6 @@ static void qup_i2c_read_rx_fifo_v1(struct qup_i2c_dev *qup)
>   		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
>   }
>   
> -static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
> -				struct i2c_msg *msg)
> -{
> -	u32 val;
> -	int idx, pos = 0, ret = 0, total, msg_offset = 0;
> -
> -	/*
> -	 * If the message length is already read in
> -	 * the first byte of the buffer, account for
> -	 * that by setting the offset
> -	 */
> -	if (qup_i2c_check_msg_len(msg) && (msg->len > 1))
> -		msg_offset = 1;
> -	total = qup_i2c_get_data_len(qup);
> -	total -= msg_offset;
> -
> -	/* 2 extra bytes for read tags */
> -	while (pos < (total + 2)) {
> -		/* Check that FIFO have data */
> -		ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
> -					 SET_BIT, 4 * ONE_BYTE);
> -		if (ret) {
> -			dev_err(qup->dev, "timeout for fifo not empty");
> -			return ret;
> -		}
> -		val = readl(qup->base + QUP_IN_FIFO_BASE);
> -
> -		for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
> -			/* first 2 bytes are tag bytes */
> -			if (pos < 2)
> -				continue;
> -
> -			if (pos >= (total + 2))
> -				goto out;
> -			msg->buf[qup->pos + msg_offset] = val & 0xff;
> -			qup->pos++;
> -		}
> -	}
> -
> -out:
> -	qup->blk.data_len -= total;
> -
> -	return ret;
> -}
> -
> -static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> -{
> -	int ret = 0;
> -
> -	qup->msg = msg;
> -	qup->pos  = 0;
> -	enable_irq(qup->irq);
> -	qup_i2c_set_blk_data(qup, msg);
> -	qup_i2c_set_read_mode_v2(qup, msg->len);
> -
> -	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> -	if (ret)
> -		goto err;
> -
> -	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> -
> -	do {
> -		ret = qup_i2c_issue_xfer_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_wait_for_complete(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		ret = qup_i2c_read_fifo_v2(qup, msg);
> -		if (ret)
> -			goto err;
> -
> -		qup->blk.pos++;
> -
> -		/* Handle SMBus block read length */
> -		if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) {
> -			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) {
> -				ret = -EPROTO;
> -				goto err;
> -			}
> -			msg->len += msg->buf[0];
> -			qup->pos = 0;
> -			qup_i2c_set_blk_data(qup, msg);
> -			/* set tag length for block read */
> -			qup->blk.tx_tag_len = 2;
> -			qup_i2c_set_read_mode_v2(qup, msg->buf[0]);
> -		}
> -	} while (qup->blk.pos < qup->blk.count);
> -
> -err:
> -	disable_irq(qup->irq);
> -	qup->msg = NULL;
> -
> -	return ret;
> -}
> -
>   static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool is_rx)
>   {
>   	qup->cur_blk_events = 0;
> @@ -1442,13 +1155,452 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
>   	return ret;
>   }
>   
> +/*
> + * Function to configure registers related with reconfiguration during run
> + * and will be done before each I2C sub transfer.
> + */
Consider changing comment style to remove the word "Function" and state 
the operation in simple present tense.

"Function to configure ..." would be "Configure ..."

Same comment for all comments of this style below.

> +static void qup_i2c_conf_count_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u32 qup_config = I2C_MINI_CORE | I2C_N_VAL_V2;
> +
> +	if (blk->is_tx_blk_mode)
> +		writel(qup->config_run | blk->total_tx_len,
> +		       qup->base + QUP_MX_OUTPUT_CNT);
> +	else
> +		writel(qup->config_run | blk->total_tx_len,
> +		       qup->base + QUP_MX_WRITE_CNT);
> +
> +	if (blk->total_rx_len) {
> +		if (blk->is_rx_blk_mode)
> +			writel(qup->config_run | blk->total_rx_len,
> +			       qup->base + QUP_MX_INPUT_CNT);
> +		else
> +			writel(qup->config_run | blk->total_rx_len,
> +			       qup->base + QUP_MX_READ_CNT);
> +	} else {
> +		qup_config |= QUP_NO_INPUT;
> +	}
> +
> +	writel(qup_config, qup->base + QUP_CONFIG);
> +}
> +
> +/*
> + * Function to configure registers related with transfer mode (FIFO/Block)
> + * before starting of i2c transfer and will be done only once in QUP RESET
> + * state.
> + */
> +static void qup_i2c_conf_mode_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u32 io_mode = QUP_REPACK_EN;
> +
> +	if (blk->is_tx_blk_mode) {
> +		io_mode |= QUP_OUTPUT_BLK_MODE;
> +		writel(0, qup->base + QUP_MX_WRITE_CNT);
> +	} else {
> +		writel(0, qup->base + QUP_MX_OUTPUT_CNT);
> +	}
> +
> +	if (blk->is_rx_blk_mode) {
> +		io_mode |= QUP_INPUT_BLK_MODE;
> +		writel(0, qup->base + QUP_MX_READ_CNT);
> +	} else {
> +		writel(0, qup->base + QUP_MX_INPUT_CNT);
> +	}
> +
> +	writel(io_mode, qup->base + QUP_IO_MODE);
> +}
> +
> +/*
> + * Function to clear required variables before starting of any QUP v2
> + * sub transfer
> + */
> +static void qup_i2c_clear_blk_v2(struct qup_i2c_block *blk)
> +{
> +	blk->send_last_word = false;
> +	blk->tx_tags_sent = false;
> +	blk->tx_fifo_data = 0;
> +	blk->tx_fifo_data_pos = 0;
> +	blk->tx_fifo_free = 0;
> +
> +	blk->rx_tags_fetched = false;
> +	blk->rx_fifo_data = 0;
> +	blk->rx_fifo_data_pos = 0;
> +	blk->fifo_available = 0;
> +}
> +
> +/*
> + * Function to receive data from RX FIFO for read message in QUP v2
> + * i2c transfer.
> + */
> +static void qup_i2c_recv_data(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	int j;
> +
> +	for (j = blk->rx_fifo_data_pos;
> +	     blk->cur_blk_len && blk->fifo_available;
> +	     blk->cur_blk_len--, blk->fifo_available--) {
> +		if (j == 0)
> +			blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
> +
> +		*(blk->cur_data++) = blk->rx_fifo_data;
> +		blk->rx_fifo_data >>= 8;
> +
> +		if (j == 3)
> +			j = 0;
> +		else
> +			j++;
> +	}
> +
> +	blk->rx_fifo_data_pos = j;
> +}
> +
> +/* Function to receive tags for read message in QUP v2 i2c transfer. */
> +static void qup_i2c_recv_tags(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	blk->rx_fifo_data = readl(qup->base + QUP_IN_FIFO_BASE);
> +	blk->rx_fifo_data >>= blk->rx_tag_len  * 8;
> +	blk->rx_fifo_data_pos = blk->rx_tag_len;
> +	blk->fifo_available -= blk->rx_tag_len;
> +}
> +
> +/*
> + * This function reads the data and tags from RX FIFO. Since in read case, the
> + * tags will be preceded by received data bytes need to be written so
> + * 1. Check if rx_tags_fetched is false i.e. the start of QUP block so receive
> + *    all tag bytes and discard that.
put i.e. statement into () to make the comment more readable
> + * 2. Read the data from RX FIFO. When all the data bytes have been read then
> + *    mark the QUP_BLK_EVENT_RX_DATA_DONE in current block event and return.
> + */
> +static void qup_i2c_read_rx_fifo_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	if (!blk->rx_tags_fetched) {
> +		qup_i2c_recv_tags(qup);
> +		blk->rx_tags_fetched = true;
> +	}
> +
> +	qup_i2c_recv_data(qup);
> +	if (!blk->cur_blk_len)
> +		qup->cur_blk_events |= QUP_BLK_EVENT_RX_DATA_DONE;
> +}
> +
> +/*
> + * Function to write bytes in TX FIFO for write message in QUP v2 i2c
> + * transfer. QUP TX FIFO write works on word basis (4 bytes). New byte write to
> + * TX FIFO will be appended in this data tx_fifo_data and will be written to TX
> + * FIFO when all the 4 bytes are available.
> + */
> +static void
> +qup_i2c_write_blk_data(struct qup_i2c_dev *qup, u8 **data, unsigned int *len)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	unsigned int j;
> +
> +	for (j = blk->tx_fifo_data_pos; *len && blk->tx_fifo_free;
> +	     (*len)--, blk->tx_fifo_free--) {
> +		blk->tx_fifo_data |= *(*data)++ << (j * 8);
> +		if (j == 3) {
> +			writel(blk->tx_fifo_data,
> +			       qup->base + QUP_OUT_FIFO_BASE);
> +			blk->tx_fifo_data = 0x0;
> +			j = 0;
> +		} else {
> +			j++;
> +		}
> +	}
> +
> +	blk->tx_fifo_data_pos = j;
> +}
> +
> +/* Function to transfer tags for read message in QUP v2 i2c transfer. */
> +static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	qup_i2c_write_blk_data(qup, &blk->cur_tx_tags, &blk->tx_tag_len);
> +	if (blk->tx_fifo_data_pos)
> +		writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
> +
> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
> +}
> +
> +/*
> + * This function writes the data and tags in TX FIFO. Since in write case, both
> + * tags and data need to be written and QUP write tags can have maximum 256 data
> + * length, so it follows simple internal state machine to manage it.
> + * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the
> + *    tags to TX FIFO.
put i.e. the start of QUP block in () for clarity
> + * 2. Check if send_last_word is true. This will be set when last few data bytes
> + *    less than 4 bytes are reamining to be written in FIFO because of no FIFO
> + *    space. All this data bytes are available in tx_fifo_data so write this
> + *    in FIFO and mark the tx done.
> + * 3. Write the data to TX FIFO and check for cur_blk_len. If this is non zero
> + *    then more data is pending otherwise following 3 cases can be possible
> + *    a. if tx_fifo_data_pos is zero that means all the data bytes in this block
> + *       have been written in TX FIFO so mark the tx done.
> + *    b. tx_fifo_free is zero. In this case, last few bytes (less than 4
> + *       bytes) are copied to tx_fifo_data but couldn't be sent because of
> + *       FIFO full so make send_last_word true.
> + *    c. tx_fifo_free is non zero i.e tx FIFO is free so copy the remaining data
> + *       from tx_fifo_data to tx FIFO and mark the tx done. Since,
> + *       qup_i2c_write_blk_data do write in 4 bytes and FIFO space is in
> + *       multiple of 4 bytes so tx_fifo_free will be always greater than or
> + *       equal to 4 bytes.
> + */
> +static void qup_i2c_write_tx_fifo_v2(struct qup_i2c_dev *qup)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +
> +	if (!blk->tx_tags_sent) {
> +		qup_i2c_write_blk_data(qup, &blk->cur_tx_tags,
> +				       &blk->tx_tag_len);
> +		blk->tx_tags_sent = true;
> +	}
> +
> +	if (blk->send_last_word)
> +		goto send_last_word;
> +
> +	qup_i2c_write_blk_data(qup, &blk->cur_data, &blk->cur_blk_len);
> +	if (!blk->cur_blk_len) {
> +		if (!blk->tx_fifo_data_pos)
> +			goto tx_data_done;
> +
> +		if (blk->tx_fifo_free)
> +			goto send_last_word;
> +
> +		blk->send_last_word = true;
> +	}
> +
> +	return;
> +
> +send_last_word:
> +	writel(blk->tx_fifo_data, qup->base + QUP_OUT_FIFO_BASE);
> +tx_data_done:
> +	qup->cur_blk_events |= QUP_BLK_EVENT_TX_DATA_DONE;
> +}
> +
> +/*
> + * Main transfer function which will be used for reading or writing i2c data.
> + * The QUP v2 supports reconfiguration during run in which multiple i2c sub
> + * transfers can be scheduled.
> + */
> +static int
> +qup_i2c_conf_xfer_v2(struct qup_i2c_dev *qup, bool is_rx, bool is_first,
> +		     bool change_pause_state)
> +{
> +	struct qup_i2c_block *blk = &qup->blk;
> +	struct i2c_msg *msg = qup->msg;
> +	int ret;
> +
> +	/*
> +	 * Check if its SMBus Block read for which the top level read will be
> +	 * done into 2 QUP reads. One with message length 1 while other one is
> +	 * with actual length.
> +	 */
> +	if (qup_i2c_check_msg_len(msg)) {
> +		if (qup->is_smbus_read) {
> +			/*
> +			 * If the message length is already read in
> +			 * the first byte of the buffer, account for
> +			 * that by setting the offset
> +			 */
> +			blk->cur_data += 1;
> +			is_first = false;
> +		} else {
> +			change_pause_state = false;
> +		}
> +	}
> +
> +	qup->config_run = is_first ? 0 : QUP_I2C_MX_CONFIG_DURING_RUN;
> +
> +	qup_i2c_clear_blk_v2(blk);
> +	qup_i2c_conf_count_v2(qup);
> +
> +	/* If it is first sub transfer, then configure i2c bus clocks */
> +	if (is_first) {
> +		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> +		if (ret)
> +			return ret;
> +
> +		writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
> +
> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	qup_i2c_set_blk_event(qup, is_rx);
> +	reinit_completion(&qup->xfer);
> +	enable_irq(qup->irq);
> +	/*
> +	 * In FIFO mode, tx FIFO can be written directly while in block mode the
> +	 * it will be written after getting OUT_BLOCK_WRITE_REQ interrupt
> +	 */
> +	if (!blk->is_tx_blk_mode) {
> +		blk->tx_fifo_free = qup->out_fifo_sz;
> +
> +		if (is_rx)
> +			qup_i2c_write_rx_tags_v2(qup);
> +		else
> +			qup_i2c_write_tx_fifo_v2(qup);
> +	}
> +
> +	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
> +	if (ret)
> +		goto err;
> +
> +	ret = qup_i2c_wait_for_complete(qup, msg);
> +	if (ret)
> +		goto err;
> +
> +	/* Move to pause state for all the transfers, except last one */
> +	if (change_pause_state) {
> +		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
> +		if (ret)
> +			goto err;
> +	}
> +
> +err:
> +	disable_irq(qup->irq);
> +	return ret;
> +}
> +
> +/*
> + * Function to transfer one read/write message in i2c transfer. It splits the
> + * message into multiple of blk_xfer_limit data length blocks and schedule each
> + * QUP block individually.
> + */
> +static int qup_i2c_xfer_v2_msg(struct qup_i2c_dev *qup, int msg_id, bool is_rx)
> +{
> +	int ret = 0;
> +	unsigned int data_len, i;
> +	struct i2c_msg *msg = qup->msg;
> +	struct qup_i2c_block *blk = &qup->blk;
> +	u8 *msg_buf = msg->buf;
> +
> +	qup->blk_xfer_limit = is_rx ? RECV_MAX_DATA_LEN : QUP_READ_LIMIT;
> +	qup_i2c_set_blk_data(qup, msg);
> +
> +	for (i = 0; i < blk->count; i++) {
> +		data_len =  qup_i2c_get_data_len(qup);
> +		blk->pos = i;
> +		blk->cur_tx_tags = blk->tags;
> +		blk->cur_blk_len = data_len;
> +		blk->tx_tag_len =
> +			qup_i2c_set_tags(blk->cur_tx_tags, qup, qup->msg);
> +
> +		blk->cur_data = msg_buf;
> +
> +		if (is_rx) {
> +			blk->total_tx_len = blk->tx_tag_len;
> +			blk->rx_tag_len = 2;
> +			blk->total_rx_len = blk->rx_tag_len + data_len;
> +		} else {
> +			blk->total_tx_len = blk->tx_tag_len + data_len;
> +			blk->total_rx_len = 0;
> +		}
> +
> +		ret = qup_i2c_conf_xfer_v2(qup, is_rx, !msg_id && !i,
> +					   !qup->is_last || i < blk->count - 1);
> +		if (ret)
> +			return ret;
> +
> +		/* Handle SMBus block read length */
> +		if (qup_i2c_check_msg_len(msg) && msg->len == 1 &&
> +		    !qup->is_smbus_read) {
> +			if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX)
> +				return -EPROTO;
> +
> +			msg->len = msg->buf[0];
> +			qup->is_smbus_read = true;
> +			ret = qup_i2c_xfer_v2_msg(qup, msg_id, true);
> +			qup->is_smbus_read = false;
> +			if (ret)
> +				return ret;
> +
> +			msg->len += 1;
> +		}
> +
> +		msg_buf += data_len;
> +		blk->data_len -= qup->blk_xfer_limit;
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * QUP v2 supports 3 modes
> + * Programmed IO using FIFO mode : Less than FIFO size
> + * Programmed IO using Block mode : Greater than FIFO size
> + * DMA using BAM : Appropriate for any transactio size but the address should be
> + *		   DMA applicable
> + *
> + * This function determines the mode which will be used for this transfer. An
> + * i2c transfer contains multiple message. Following are the rules to determine
> + * the mode used.
> + * 1. Determine the tx and rx length for each message and maximum tx and rx
> + *    length for complete transfer
> + * 2. If tx or rx length is greater than DMA threshold than use the DMA mode.
> + * 3. In FIFO or block mode, TX and RX can operate in different mode so check
> + *    for maximum tx and rx length to determine mode.
> + */
> +static int
> +qup_i2c_determine_mode(struct qup_i2c_dev *qup, struct i2c_msg msgs[], int num)
> +{
> +	int idx;
> +	bool no_dma = false;
> +	unsigned int max_tx_len = 0, max_rx_len = 0;
> +	unsigned int cur_tx_len, cur_rx_len;
> +	unsigned int total_rx_len = 0, total_tx_len = 0;
> +
> +	/* All i2c_msgs should be transferred using either dma or cpu */
> +	for (idx = 0; idx < num; idx++) {
> +		if (msgs[idx].len == 0)
> +			return -EINVAL;
> +
> +		if (msgs[idx].flags & I2C_M_RD) {
> +			cur_tx_len = 0;
> +			cur_rx_len = msgs[idx].len;
> +		} else {
> +			cur_tx_len = msgs[idx].len;
> +			cur_rx_len = 0;
> +		}
> +
> +		if (is_vmalloc_addr(msgs[idx].buf))
> +			no_dma = true;
> +
> +		max_tx_len = max(max_tx_len, cur_tx_len);
> +		max_rx_len = max(max_rx_len, cur_rx_len);
> +		total_rx_len += cur_rx_len;
> +		total_tx_len += cur_tx_len;
> +	}
> +
> +	if (!no_dma && qup->is_dma &&
> +	    (total_tx_len > qup->dma_threshold ||
> +	     total_rx_len > qup->dma_threshold)) {
> +		qup->use_dma = true;
> +	} else {
> +		qup->blk.is_tx_blk_mode =
> +			max_tx_len > qup->blk_mode_threshold ? true : false;
> +		qup->blk.is_rx_blk_mode =
> +			max_rx_len > qup->blk_mode_threshold ? true : false;
> +	}
> +
> +	return 0;
> +}
> +
>   static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   			   struct i2c_msg msgs[],
>   			   int num)
>   {
>   	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
>   	int ret, idx = 0;
> -	unsigned int total_len = 0;
>   
>   	qup->bus_err = 0;
>   	qup->qup_err = 0;
> @@ -1457,6 +1609,10 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   	if (ret < 0)
>   		goto out;
>   
> +	ret = qup_i2c_determine_mode(qup, msgs, num);
> +	if (ret)
> +		goto out;
> +
>   	writel(1, qup->base + QUP_SW_RESET);
>   	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
>   	if (ret)
> @@ -1466,59 +1622,35 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>   	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
>   	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
>   
> -	if ((qup->is_dma)) {
> -		/* All i2c_msgs should be transferred using either dma or cpu */
> +	if (qup_i2c_poll_state_i2c_master(qup)) {
> +		ret = -EIO;
> +		goto out;
> +	}
> +
> +	if (qup->use_dma) {
> +		reinit_completion(&qup->xfer);
> +		ret = qup_i2c_bam_xfer(adap, &msgs[0], num);
> +		qup->use_dma = false;
> +	} else {
> +		qup_i2c_conf_mode_v2(qup);
> +
>   		for (idx = 0; idx < num; idx++) {
> -			if (msgs[idx].len == 0) {
> -				ret = -EINVAL;
> -				goto out;
> -			}
> +			qup->msg = &msgs[idx];
> +			qup->is_last = idx == (num - 1);
>   
> -			if (is_vmalloc_addr(msgs[idx].buf))
> +			ret = qup_i2c_xfer_v2_msg(qup, idx,
> +					!!(msgs[idx].flags & I2C_M_RD));
> +			if (ret)
>   				break;
> -
> -			total_len += msgs[idx].len;
>   		}
> -
> -		if (idx == num && total_len > qup->dma_threshold)
> -			qup->use_dma = true;
> +		qup->msg = NULL;
>   	}
>   
> -	idx = 0;
> -
> -	do {
> -		if (msgs[idx].len == 0) {
> -			ret = -EINVAL;
> -			goto out;
> -		}
> -
> -		if (qup_i2c_poll_state_i2c_master(qup)) {
> -			ret = -EIO;
> -			goto out;
> -		}
> -
> -		qup->is_last = (idx == (num - 1));
> -		if (idx)
> -			qup->config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
> -		else
> -			qup->config_run = 0;
> -
> -		reinit_completion(&qup->xfer);
> -
> -		if (qup->use_dma) {
> -			ret = qup_i2c_bam_xfer(adap, &msgs[idx], num);
> -			qup->use_dma = false;
> -			break;
> -		} else {
> -			if (msgs[idx].flags & I2C_M_RD)
> -				ret = qup_i2c_read_one_v2(qup, &msgs[idx]);
> -			else
> -				ret = qup_i2c_write_one_v2(qup, &msgs[idx]);
> -		}
> -	} while ((idx++ < (num - 1)) && !ret);
> +	if (!ret)
> +		ret = qup_i2c_bus_active(qup, ONE_BYTE);
>   
>   	if (!ret)
> -		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
> +		qup_i2c_change_state(qup, QUP_RESET_STATE);
>   
>   	if (ret == 0)
>   		ret = num;
> @@ -1582,6 +1714,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   	u32 src_clk_freq = DEFAULT_SRC_CLK;
>   	u32 clk_freq = DEFAULT_CLK_FREQ;
>   	int blocks;
> +	bool is_qup_v1;
>   
>   	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>   	if (!qup)
> @@ -1600,12 +1733,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
>   		qup->adap.algo = &qup_i2c_algo;
>   		qup->adap.quirks = &qup_i2c_quirks;
> -		qup->is_qup_v1 = true;
> -		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
> -		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
> -		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
> +		is_qup_v1 = true;
>   	} else {
>   		qup->adap.algo = &qup_i2c_algo_v2;
> +		is_qup_v1 = false;
>   		ret = qup_i2c_req_dma(qup);
>   
>   		if (ret == -EPROBE_DEFER)
> @@ -1731,14 +1862,31 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   		ret = -EIO;
>   		goto fail;
>   	}
> -	qup->out_blk_sz = blk_sizes[size] / 2;
> +	qup->out_blk_sz = blk_sizes[size];
>   
>   	size = QUP_INPUT_BLOCK_SIZE(io_mode);
>   	if (size >= ARRAY_SIZE(blk_sizes)) {
>   		ret = -EIO;
>   		goto fail;
>   	}
> -	qup->in_blk_sz = blk_sizes[size] / 2;
> +	qup->in_blk_sz = blk_sizes[size];
> +
> +	if (is_qup_v1) {
> +		/*
> +		 * in QUP v1, QUP_CONFIG uses N as 15 i.e 16 bits constitutes a
> +		 * single transfer but the block size is in bytes so divide the
> +		 * in_blk_sz and out_blk_sz by 2
> +		 */
> +		qup->in_blk_sz /= 2;
> +		qup->out_blk_sz /= 2;
> +		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v1;
> +		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v1;
> +		qup->write_rx_tags = qup_i2c_write_rx_tags_v1;
> +	} else {
> +		qup->write_tx_fifo = qup_i2c_write_tx_fifo_v2;
> +		qup->read_rx_fifo = qup_i2c_read_rx_fifo_v2;
> +		qup->write_rx_tags = qup_i2c_write_rx_tags_v2;
> +	}
>   
>   	size = QUP_OUTPUT_FIFO_SIZE(io_mode);
>   	qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
> @@ -1746,6 +1894,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>   	size = QUP_INPUT_FIFO_SIZE(io_mode);
>   	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
>   	qup->dma_threshold = min(qup->out_fifo_sz, qup->in_fifo_sz);
> +	qup->blk_mode_threshold = qup->dma_threshold - QUP_MAX_TAGS_LEN;
>   
>   	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
>   	hs_div = 3;
> 

-- 
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer
  2018-02-27 22:36   ` Andy Gross
@ 2018-03-08 13:40     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-03-08 13:40 UTC (permalink / raw)
  To: Andy Gross
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-28 04:06, Andy Gross wrote:
> On Sat, Feb 03, 2018 at 01:28:09PM +0530, Abhishek Sahu wrote:
>> A single BAM transfer can have multiple read and write messages.
>> The EOT and FLUSH tags should be scheduled at the end of BAM HW
>> descriptors. Since the READ and WRITE can be present in any order
>> so for some of the cases, these tags are not being written
>> correctly.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
>> ---
>>  drivers/i2c/busses/i2c-qup.c | 54 
>> ++++++++++++++++++++------------------------
>>  1 file changed, 24 insertions(+), 30 deletions(-)
>> 
>> diff --git a/drivers/i2c/busses/i2c-qup.c 
>> b/drivers/i2c/busses/i2c-qup.c
>> index bb83a2967..6357aff 100644
>> --- a/drivers/i2c/busses/i2c-qup.c
>> +++ b/drivers/i2c/busses/i2c-qup.c
>> @@ -560,7 +560,7 @@ static int qup_i2c_set_tags_smb(u16 addr, u8 
>> *tags, struct qup_i2c_dev *qup,
>>  }
>> 
>>  static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
>> -			    struct i2c_msg *msg,  int is_dma)
>> +			    struct i2c_msg *msg)
>>  {
>>  	u16 addr = i2c_8bit_addr_from_msg(msg);
>>  	int len = 0;
>> @@ -601,11 +601,6 @@ static int qup_i2c_set_tags(u8 *tags, struct 
>> qup_i2c_dev *qup,
>>  	else
>>  		tags[len++] = data_len;
>> 
>> -	if ((msg->flags & I2C_M_RD) && last && is_dma) {
>> -		tags[len++] = QUP_BAM_INPUT_EOT;
>> -		tags[len++] = QUP_BAM_FLUSH_STOP;
>> -	}
>> -
> 
> So lets say you have multiple read and 1 write message.  These changes 
> will send
> a EOT/FLUSH for all reads.  I think the intent here was that the last 
> read
> message (not the last message) would have the EOT+FLUSH.  Can there be 
> an issue
> with sending EOT/FLUSH for all reads?  And how does this mesh up with 
> the BAM
> signaling?
> 

  Thanks Andy and Austin for reviewing these patches.

  The role of FLUSH and EOT tag is to flush already scheduled descriptors
  in HW. EOT is required only when descriptors are scheduled in RX FIFO.
  If all the messages are WRITE, then only FLUSH tag will be used.

  Let’s take following example

  READ, READ, READ, READ

  Currently EOT and FLUSH tags are being written after each READ. If we
  get the NACK for first READ itself, then flush will be triggered. It
  will look for first FLUSH tag in TX FIFO and will stop there so only
  descriptors for first READ will be flushed. We need to clear all
  scheduled descriptors to generate the completion.

  Now this patch is scheduling FLUSH and EOT only once after all the
  descriptors. So, flush will clear all the scheduled descriptors and
  BAM will generate the completion interrupt. For multiple READ and
  single WRITE also, this will work fine.

  I tested with
  - single xfer with multiple read messages
  - single xfer with multiple write messages
  - single xfer with multiple alternate read and write messages

  for non-connected address in forceful DMA mode which will generate
  the NACK for first byte itself.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-27 23:15   ` Andy Gross
@ 2018-03-12 12:28     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-03-12 12:28 UTC (permalink / raw)
  To: Andy Gross
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-28 04:45, Andy Gross wrote:
> On Sat, Feb 03, 2018 at 01:28:14PM +0530, Abhishek Sahu wrote:
>> The BAM mode requires buffer for start tag data and tx, rx SG
>> list. Currently, this is being taken for maximum transfer length
>> (65K). But an I2C transfer can have multiple messages and each
>> message can be of this maximum length so the buffer overflow will
>> happen in this case. Since increasing buffer length won’t be
>> feasible since an I2C transfer can contain any number of messages
>> so this patch does following changes to make i2c transfers working
>> for multiple messages case.
>> 
>> 1. Calculate the required buffers for 2 maximum length messages
>>    (65K * 2).
>> 2. Split the descriptor formation and descriptor scheduling.
>>    The idea is to fit as many messages in one DMA transfers for 65K
>>    threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>>    crossing this, then schedule the BAM transfer and subsequent
>>    transfer will again start from zero.
>> 
>> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> 
> I'm ok with this patch.  I find the idea of a > 64k size message to be 
> something
> that usually wouldn't be encountered, but... with some eeproms and 
> maybe TPMs
> perhaps this could happen?
> 
> Reviewed-by: Andy Gross <andy.gross@linaro.org>

  Thanks Andy for reviewing this patch.

  There are EEPROM available with 1MB size like AT24CM01 in which we can 
read
  complete flash (128 KB) in single go by one transfer with 2 read 
messages of
  64KB.

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode
  2018-02-27 22:58   ` Andy Gross
@ 2018-03-12 12:34     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-03-12 12:34 UTC (permalink / raw)
  To: Andy Gross
  Cc: Wolfram Sang, David Brown, Sricharan R, linux-arm-msm, linux-soc,
	linux-i2c, linux-kernel

On 2018-02-28 04:28, Andy Gross wrote:
> On Sat, Feb 03, 2018 at 01:28:11PM +0530, Abhishek Sahu wrote:
> 
> <snip>
> 
>> @@ -841,20 +856,12 @@ static int qup_i2c_bam_do_xfer(struct 
>> qup_i2c_dev *qup, struct i2c_msg *msg,
>>  			goto desc_err;
>>  		}
>> 
>> -		if (rx_buf)
>> -			writel(QUP_BAM_INPUT_EOT,
>> -			       qup->base + QUP_OUT_FIFO_BASE);
>> -
>> -		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
>> -
>>  		qup_i2c_flush(qup);
>> 
>>  		/* wait for remaining interrupts to occur */
>>  		if (!wait_for_completion_timeout(&qup->xfer, HZ))
>>  			dev_err(qup->dev, "flush timed out\n");
>> 
>> -		qup_i2c_rel_dma(qup);
>> -
> 
> So this really only works due to the previous patch that adds the 
> flush/eot tags
> to all of the read messages.  If the answer to the previous question is 
> that
> only the last read message gets the eot/flush, then this code needs to 
> remain in
> place.  Otherwise, it's fine.
> 
> 
> Andy

   Thanks Andy,

   We need to schedule EOT/FLUSH after last message.
   For following transfer

   READ, READ, WRITE (FLUSH + EOT tags after that)

   In this case, FLUSH will clear all the descriptors till WRITE and 
trigger TX
   completion. EOT will be copied in RX FIFO and trigger RX completion.

   Thanks,
   Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len
  2018-02-27 22:06   ` Christ, Austin
@ 2018-03-12 13:55     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-03-12 13:55 UTC (permalink / raw)
  To: Christ, Austin
  Cc: Andy Gross, Wolfram Sang, David Brown, Sricharan R,
	linux-arm-msm, linux-soc, linux-i2c, linux-kernel

On 2018-02-28 03:36, Christ, Austin wrote:
> Hey Abhishek,
> 
> 
> On 2/3/2018 12:58 AM, Abhishek Sahu wrote:
>> The BAM mode requires buffer for start tag data and tx, rx SG
>> list. Currently, this is being taken for maximum transfer length
>> (65K). But an I2C transfer can have multiple messages and each
>> message can be of this maximum length so the buffer overflow will
>> happen in this case. Since increasing buffer length won’t be
>> feasible since an I2C transfer can contain any number of messages
>> so this patch does following changes to make i2c transfers working
>> for multiple messages case.
>> 
>> 1. Calculate the required buffers for 2 maximum length messages
>>     (65K * 2).
>> 2. Split the descriptor formation and descriptor scheduling.
>>     The idea is to fit as many messages in one DMA transfers for 65K
>>     threshold value (max_xfer_sg_len). Whenever the sg_cnt is
>>     crossing this, then schedule the BAM transfer and subsequent
>>     transfer will again start from zero.
>> 

<snip>

>> @@ -1603,7 +1640,7 @@ static int qup_i2c_probe(struct platform_device 
>> *pdev)
>>   	one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
>>   	qup->one_byte_t = one_bit_t * 9;
>>   	qup->xfer_timeout = TOUT_MIN * HZ +
>> -			    usecs_to_jiffies(MX_TX_RX_LEN * qup->one_byte_t);
>> +		usecs_to_jiffies(2 * MX_TX_RX_LEN * qup->one_byte_t);
> 
> Maybe it would make sense to add a comment here explaining why the
> magic number 2 has been added.

  Thanks Austin for reviewing the patches.

  Now in v2, I have used the new macro MX_DMA_TX_RX_LEN  which will make
  this multiplication by 2 more clear. This 2 is for allocating memory
  by taking 2 maximum length messages.

  https://lkml.org/lkml/2018/3/12/423

  Thanks,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2
  2018-02-27 23:24   ` Christ, Austin
@ 2018-03-12 13:58     ` Abhishek Sahu
  0 siblings, 0 replies; 57+ messages in thread
From: Abhishek Sahu @ 2018-03-12 13:58 UTC (permalink / raw)
  To: Christ, Austin
  Cc: Andy Gross, Wolfram Sang, David Brown, Sricharan R,
	linux-arm-msm, linux-soc, linux-i2c, linux-kernel

<snip>

>>   static void qup_i2c_set_blk_event(struct qup_i2c_dev *qup, bool 
>> is_rx)
>>   {
>>   	qup->cur_blk_events = 0;
>> @@ -1442,13 +1155,452 @@ static int qup_i2c_xfer(struct i2c_adapter 
>> *adap,
>>   	return ret;
>>   }
>>   +/*
>> + * Function to configure registers related with reconfiguration 
>> during run
>> + * and will be done before each I2C sub transfer.
>> + */
> Consider changing comment style to remove the word "Function" and
> state the operation in simple present tense.
> 
> "Function to configure ..." would be "Configure ..."
> 
> Same comment for all comments of this style below.
> 


  Thanks Austin.

  I have done the changes for comments styles in v2

  https://lkml.org/lkml/2018/3/12/421

  Regards,
  Abhishek

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2018-03-12 13:58 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-03  7:58 [PATCH 00/12] Major code reorganization to make all i2c transfers working Abhishek Sahu
2018-02-03  7:58 ` [PATCH 01/12] i2c: qup: fixed releasing dma without flush operation completion Abhishek Sahu
2018-02-08 14:03   ` Sricharan R
2018-02-19 10:24     ` Abhishek Sahu
2018-02-27 21:46   ` Christ, Austin
2018-02-27 22:24   ` Andy Gross
2018-02-03  7:58 ` [PATCH 02/12] i2c: qup: minor code reorganization for use_dma Abhishek Sahu
2018-02-27 21:48   ` Christ, Austin
2018-02-27 22:26   ` Andy Gross
2018-02-03  7:58 ` [PATCH 03/12] i2c: qup: remove redundant variables for BAM SG count Abhishek Sahu
2018-02-09  2:16   ` Sricharan R
2018-02-19 10:26     ` Abhishek Sahu
2018-02-27 21:51   ` Christ, Austin
2018-02-27 22:28   ` Andy Gross
2018-02-03  7:58 ` [PATCH 04/12] i2c: qup: schedule EOT and FLUSH tags at the end of transfer Abhishek Sahu
2018-02-15 14:31   ` Sricharan R
2018-02-19 10:34     ` Abhishek Sahu
2018-02-27 22:36   ` Andy Gross
2018-03-08 13:40     ` Abhishek Sahu
2018-02-03  7:58 ` [PATCH 05/12] i2c: qup: fix the transfer length for BAM rx EOT FLUSH tags Abhishek Sahu
2018-02-27 22:38   ` Andy Gross
2018-02-03  7:58 ` [PATCH 06/12] i2c: qup: proper error handling for i2c error in BAM mode Abhishek Sahu
2018-02-16  4:33   ` Sricharan R
2018-02-27 22:00   ` Christ, Austin
2018-02-27 22:58   ` Andy Gross
2018-03-12 12:34     ` Abhishek Sahu
2018-02-03  7:58 ` [PATCH 07/12] i2c: qup: use the complete transfer length to choose DMA mode Abhishek Sahu
2018-02-16  4:35   ` Sricharan R
2018-02-19 10:49     ` Abhishek Sahu
2018-02-27 22:01   ` Christ, Austin
2018-02-27 22:59   ` Andy Gross
2018-02-03  7:58 ` [PATCH 08/12] i2c: qup: change completion timeout according to transfer length Abhishek Sahu
2018-02-16  4:48   ` Sricharan R
2018-02-19 10:56     ` Abhishek Sahu
2018-02-27 23:05       ` Andy Gross
2018-02-03  7:58 ` [PATCH 09/12] i2c: qup: fix buffer overflow for multiple msg of maximum xfer len Abhishek Sahu
2018-02-16  5:21   ` Sricharan R
2018-02-19 11:24     ` Abhishek Sahu
2018-02-27 22:06   ` Christ, Austin
2018-03-12 13:55     ` Abhishek Sahu
2018-02-27 23:15   ` Andy Gross
2018-03-12 12:28     ` Abhishek Sahu
2018-02-03  7:58 ` [PATCH 10/12] i2c: qup: send NACK for last read sub transfers Abhishek Sahu
2018-02-16  5:39   ` Sricharan R
2018-02-27 22:07   ` Christ, Austin
2018-02-27 23:17   ` Andy Gross
2018-02-03  7:58 ` [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 Abhishek Sahu
2018-02-05 23:03   ` kbuild test robot
2018-02-05 23:03     ` kbuild test robot
2018-02-16  7:44   ` Sricharan R
2018-02-19 13:21     ` Abhishek Sahu
2018-02-20  4:32       ` Sricharan R
2018-02-03  7:58 ` [PATCH 12/12] i2c: qup: reorganization of driver code to remove polling for qup v2 Abhishek Sahu
2018-02-16 11:23   ` Sricharan R
2018-02-19 14:08     ` Abhishek Sahu
2018-02-27 23:24   ` Christ, Austin
2018-03-12 13:58     ` Abhishek Sahu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.