Patch "i2c: bcm2835: Fix hang for writing messages larger than 16 bytes" has been added to the 4.9-stable tree
Subsystems (4)
This is a note to let you know that I've just added the patch titled
i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
i2c-bcm2835-fix-hang-for-writing-messages-larger-than-16-bytes.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
e2474541032db65d02bf88b6a8c2f954654b443fMon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <[email protected]>
Date: Mon, 3 Oct 2016 22:06:08 +0200
Subject: i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Noralf Trønnes <[email protected]>
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.
--- drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
drivers/i2c/busses/i2c-bcm2835.c +14 -8
@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev {int irq;struct i2c_adapter adapter;struct completion completion; +struct i2c_msg *curr_msg;u32 msg_err;u8 *msg_buf;size_t msg_buf_remaining;
@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int treturn IRQ_HANDLED ; } -if (val &BCM2835_I2C_S_RXD ) { -bcm2835_drain_rxfifo (i2c_dev); -if (!(val &BCM2835_I2C_S_DONE )) -return IRQ_HANDLED ; - } -if (val &BCM2835_I2C_S_DONE ) { -if (i2c_dev->msg_buf_remaining) +if (i2c_dev->curr_msg->flags &I2C_M_RD ) { +bcm2835_drain_rxfifo (i2c_dev); + val =bcm2835_i2c_readl (i2c_dev,BCM2835_I2C_S ); + } + +if ((val &BCM2835_I2C_S_RXD ) || i2c_dev->msg_buf_remaining) i2c_dev->msg_err =BCM2835_I2C_S_LEN ;else i2c_dev->msg_err =0 ;
@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int treturn IRQ_HANDLED ; } -if (val &BCM2835_I2C_S_TXD ) { +if (val &BCM2835_I2C_S_TXW ) {bcm2835_fill_txfifo (i2c_dev);return IRQ_HANDLED ; } +if (val &BCM2835_I2C_S_RXR ) { +bcm2835_drain_rxfifo (i2c_dev); +return IRQ_HANDLED ; + } +return IRQ_NONE ; }
@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bu32 c;unsigned long time_left; + i2c_dev->curr_msg = msg; i2c_dev->msg_buf = msg->buf; i2c_dev->msg_buf_remaining = msg->len;reinit_completion (&i2c_dev->completion);
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/i2c-bcm2835-fix-hang-for-writing-messages-larger-than-16-bytes.patch