diff options
| author | Noralf Trønnes <noralf@tronnes.org> | 2016-10-03 16:06:08 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-18 01:11:47 -0400 |
| commit | 938f8e856064c0a7890ab998ec66abf1d093fd18 (patch) | |
| tree | 137ecd6501a24594e65999487f1825d520cb834a /drivers/i2c | |
| parent | f7513c9165bfe9671d83b940780602980e4ac913 (diff) | |
i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
commit e2474541032db65d02bf88b6a8c2f954654b443f upstream.
Writing messages larger than the FIFO size results in a hang, rendering
the machine unusable. This is because the RXD status flag is set on the
first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
from the buffer. The controller continues to trigger interrupts waiting
for the missing bytes, but bcm2835_fill_txfifo() has none to give.
In this situation wait_for_completion_timeout() apparently is unable to
stop the madness.
The BCM2835 ARM Peripherals datasheet has this to say about the flags:
TXD: is set when the FIFO has space for at least one byte of data.
RXD: is set when the FIFO contains at least one byte of data.
TXW: is set during a write transfer and the FIFO is less than full.
RXR: is set during a read transfer and the FIFO is or more full.
Implementing the logic from the downstream i2c-bcm2708 driver solved
the hang problem.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/i2c-bcm2835.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d4f3239b5686..f283b714aa79 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c | |||
| @@ -64,6 +64,7 @@ struct bcm2835_i2c_dev { | |||
| 64 | int irq; | 64 | int irq; |
| 65 | struct i2c_adapter adapter; | 65 | struct i2c_adapter adapter; |
| 66 | struct completion completion; | 66 | struct completion completion; |
| 67 | struct i2c_msg *curr_msg; | ||
| 67 | u32 msg_err; | 68 | u32 msg_err; |
| 68 | u8 *msg_buf; | 69 | u8 *msg_buf; |
| 69 | size_t msg_buf_remaining; | 70 | size_t msg_buf_remaining; |
| @@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) | |||
| 126 | return IRQ_HANDLED; | 127 | return IRQ_HANDLED; |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | if (val & BCM2835_I2C_S_RXD) { | ||
| 130 | bcm2835_drain_rxfifo(i2c_dev); | ||
| 131 | if (!(val & BCM2835_I2C_S_DONE)) | ||
| 132 | return IRQ_HANDLED; | ||
| 133 | } | ||
| 134 | |||
| 135 | if (val & BCM2835_I2C_S_DONE) { | 130 | if (val & BCM2835_I2C_S_DONE) { |
| 136 | if (i2c_dev->msg_buf_remaining) | 131 | if (i2c_dev->curr_msg->flags & I2C_M_RD) { |
| 132 | bcm2835_drain_rxfifo(i2c_dev); | ||
| 133 | val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); | ||
| 134 | } | ||
| 135 | |||
| 136 | if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining) | ||
| 137 | i2c_dev->msg_err = BCM2835_I2C_S_LEN; | 137 | i2c_dev->msg_err = BCM2835_I2C_S_LEN; |
| 138 | else | 138 | else |
| 139 | i2c_dev->msg_err = 0; | 139 | i2c_dev->msg_err = 0; |
| @@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) | |||
| 141 | return IRQ_HANDLED; | 141 | return IRQ_HANDLED; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | if (val & BCM2835_I2C_S_TXD) { | 144 | if (val & BCM2835_I2C_S_TXW) { |
| 145 | bcm2835_fill_txfifo(i2c_dev); | 145 | bcm2835_fill_txfifo(i2c_dev); |
| 146 | return IRQ_HANDLED; | 146 | return IRQ_HANDLED; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | if (val & BCM2835_I2C_S_RXR) { | ||
| 150 | bcm2835_drain_rxfifo(i2c_dev); | ||
| 151 | return IRQ_HANDLED; | ||
| 152 | } | ||
| 153 | |||
| 149 | return IRQ_NONE; | 154 | return IRQ_NONE; |
| 150 | } | 155 | } |
| 151 | 156 | ||
| @@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, | |||
| 155 | u32 c; | 160 | u32 c; |
| 156 | unsigned long time_left; | 161 | unsigned long time_left; |
| 157 | 162 | ||
| 163 | i2c_dev->curr_msg = msg; | ||
| 158 | i2c_dev->msg_buf = msg->buf; | 164 | i2c_dev->msg_buf = msg->buf; |
| 159 | i2c_dev->msg_buf_remaining = msg->len; | 165 | i2c_dev->msg_buf_remaining = msg->len; |
| 160 | reinit_completion(&i2c_dev->completion); | 166 | reinit_completion(&i2c_dev->completion); |
