aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhishek Sahu <absahu@codeaurora.org>2018-03-12 09:14:56 -0400
committerWolfram Sang <wsa@the-dreams.de>2018-03-24 08:19:59 -0400
commit3f450d3eea14799b14192231840c1753a660f150 (patch)
treeefabcf51373200f54bb48d46189eba4930d70431
parent7e6c35fe602df6821b3e7db5b1ba656162750fda (diff)
i2c: qup: proper error handling for i2c error in BAM mode
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> Reviewed-by: Sricharan R <sricharan@codeaurora.org> Reviewed-by: Austin Christ <austinwc@codeaurora.org> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-qup.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 73a288068632..d16361df1bfb 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -219,9 +219,24 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
219 if (bus_err) 219 if (bus_err)
220 writel(bus_err, qup->base + QUP_I2C_STATUS); 220 writel(bus_err, qup->base + QUP_I2C_STATUS);
221 221
222 /*
223 * Check for BAM mode and returns if already error has come for current
224 * transfer. In Error case, sometimes, QUP generates more than one
225 * interrupt.
226 */
227 if (qup->use_dma && (qup->qup_err || qup->bus_err))
228 return IRQ_HANDLED;
229
222 /* Reset the QUP State in case of error */ 230 /* Reset the QUP State in case of error */
223 if (qup_err || bus_err) { 231 if (qup_err || bus_err) {
224 writel(QUP_RESET_STATE, qup->base + QUP_STATE); 232 /*
233 * Don’t reset the QUP state in case of BAM mode. The BAM
234 * flush operation needs to be scheduled in transfer function
235 * which will clear the remaining schedule descriptors in BAM
236 * HW FIFO and generates the BAM interrupt.
237 */
238 if (!qup->use_dma)
239 writel(QUP_RESET_STATE, qup->base + QUP_STATE);
225 goto done; 240 goto done;
226 } 241 }
227 242
@@ -847,20 +862,12 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
847 goto desc_err; 862 goto desc_err;
848 } 863 }
849 864
850 if (rx_cnt)
851 writel(QUP_BAM_INPUT_EOT,
852 qup->base + QUP_OUT_FIFO_BASE);
853
854 writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
855
856 qup_i2c_flush(qup); 865 qup_i2c_flush(qup);
857 866
858 /* wait for remaining interrupts to occur */ 867 /* wait for remaining interrupts to occur */
859 if (!wait_for_completion_timeout(&qup->xfer, HZ)) 868 if (!wait_for_completion_timeout(&qup->xfer, HZ))
860 dev_err(qup->dev, "flush timed out\n"); 869 dev_err(qup->dev, "flush timed out\n");
861 870
862 qup_i2c_rel_dma(qup);
863
864 ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; 871 ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
865 } 872 }
866 873