a86f144caf72e03f965d06ceb7acbd6561fec70f
[openwrt/staging/mkresin.git] /
1 From 3f450d3eea14799b14192231840c1753a660f150 Mon Sep 17 00:00:00 2001
2 From: Abhishek Sahu <absahu@codeaurora.org>
3 Date: Mon, 12 Mar 2018 18:44:56 +0530
4 Subject: [PATCH 07/13] i2c: qup: proper error handling for i2c error in BAM
5 mode
6
7 Currently the i2c error handling in BAM mode is not working
8 properly in stress condition.
9
10 1. After an error, the FIFO are being written with FLUSH and
11 EOT tags which should not be required since already these tags
12 have been written in BAM descriptor itself.
13
14 2. QUP state is being moved to RESET in IRQ handler in case
15 of error. When QUP HW encounters an error in BAM mode then it
16 moves the QUP STATE to PAUSE state. In this case, I2C_FLUSH
17 command needs to be executed while moving to RUN_STATE by writing
18 to the QUP_STATE register with the I2C_FLUSH bit set to 1.
19
20 3. In Error case, sometimes, QUP generates more than one
21 interrupt which will trigger the complete again. After an error,
22 the flush operation will be scheduled after doing
23 reinit_completion which should be triggered by BAM IRQ callback.
24 If the second QUP IRQ comes during this time then it will call
25 the complete and the transfer function will assume the all the
26 BAM HW descriptors have been completed.
27
28 4. The release DMA is being called after each error which
29 will free the DMA tx and rx channels. The error like NACK is very
30 common in I2C transfer and every time this will be overhead. Now,
31 since the error handling is proper so this release channel can be
32 completely avoided.
33
34 Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
35 Reviewed-by: Sricharan R <sricharan@codeaurora.org>
36 Reviewed-by: Austin Christ <austinwc@codeaurora.org>
37 Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
38 ---
39 drivers/i2c/busses/i2c-qup.c | 25 ++++++++++++++++---------
40 1 file changed, 16 insertions(+), 9 deletions(-)
41
42 --- a/drivers/i2c/busses/i2c-qup.c
43 +++ b/drivers/i2c/busses/i2c-qup.c
44 @@ -219,9 +219,24 @@ static irqreturn_t qup_i2c_interrupt(int
45 if (bus_err)
46 writel(bus_err, qup->base + QUP_I2C_STATUS);
47
48 + /*
49 + * Check for BAM mode and returns if already error has come for current
50 + * transfer. In Error case, sometimes, QUP generates more than one
51 + * interrupt.
52 + */
53 + if (qup->use_dma && (qup->qup_err || qup->bus_err))
54 + return IRQ_HANDLED;
55 +
56 /* Reset the QUP State in case of error */
57 if (qup_err || bus_err) {
58 - writel(QUP_RESET_STATE, qup->base + QUP_STATE);
59 + /*
60 + * Don’t reset the QUP state in case of BAM mode. The BAM
61 + * flush operation needs to be scheduled in transfer function
62 + * which will clear the remaining schedule descriptors in BAM
63 + * HW FIFO and generates the BAM interrupt.
64 + */
65 + if (!qup->use_dma)
66 + writel(QUP_RESET_STATE, qup->base + QUP_STATE);
67 goto done;
68 }
69
70 @@ -847,20 +862,12 @@ static int qup_i2c_bam_do_xfer(struct qu
71 goto desc_err;
72 }
73
74 - if (rx_cnt)
75 - writel(QUP_BAM_INPUT_EOT,
76 - qup->base + QUP_OUT_FIFO_BASE);
77 -
78 - writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
79 -
80 qup_i2c_flush(qup);
81
82 /* wait for remaining interrupts to occur */
83 if (!wait_for_completion_timeout(&qup->xfer, HZ))
84 dev_err(qup->dev, "flush timed out\n");
85
86 - qup_i2c_rel_dma(qup);
87 -
88 ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
89 }
90