a86f144caf72e03f965d06ceb7acbd6561fec70f
[oweals/openwrt.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