Skip to content

Commit 8ade08a

Browse files
robhancocksedgregkh
authored andcommitted
i2c: xiic: Wait for TX empty to avoid missed TX NAKs
commit 521da1e upstream. Frequently an I2C write will be followed by a read, such as a register address write followed by a read of the register value. In this driver, when the TX FIFO half empty interrupt was raised and it was determined that there was enough space in the TX FIFO to send the following read command, it would do so without waiting for the TX FIFO to actually empty. Unfortunately it appears that in some cases this can result in a NAK that was raised by the target device on the write, such as due to an unsupported register address, being ignored and the subsequent read being done anyway. This can potentially put the I2C bus into an invalid state and/or result in invalid read data being processed. To avoid this, once a message has been fully written to the TX FIFO, wait for the TX FIFO empty interrupt before moving on to the next message, to ensure NAKs are handled properly. Fixes: e1d5b65 ("i2c: Add support for Xilinx XPS IIC Bus Interface") Signed-off-by: Robert Hancock <[email protected]> Cc: <[email protected]> # v2.6.34+ Reviewed-by: Manikanta Guntupalli <[email protected]> Acked-by: Michal Simek <[email protected]> Signed-off-by: Andi Shyti <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1e03cff commit 8ade08a

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

drivers/i2c/busses/i2c-xiic.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -772,14 +772,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
772772
goto out;
773773
}
774774

775-
xiic_fill_tx_fifo(i2c);
776-
777-
/* current message sent and there is space in the fifo */
778-
if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
775+
if (xiic_tx_space(i2c)) {
776+
xiic_fill_tx_fifo(i2c);
777+
} else {
778+
/* current message fully written */
779779
dev_dbg(i2c->adap.dev.parent,
780780
"%s end of message sent, nmsgs: %d\n",
781781
__func__, i2c->nmsgs);
782-
if (i2c->nmsgs > 1) {
782+
/* Don't move onto the next message until the TX FIFO empties,
783+
* to ensure that a NAK is not missed.
784+
*/
785+
if (i2c->nmsgs > 1 && (pend & XIIC_INTR_TX_EMPTY_MASK)) {
783786
i2c->nmsgs--;
784787
i2c->tx_msg++;
785788
xfer_more = 1;
@@ -790,11 +793,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
790793
"%s Got TX IRQ but no more to do...\n",
791794
__func__);
792795
}
793-
} else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
794-
/* current frame is sent and is last,
795-
* make sure to disable tx half
796-
*/
797-
xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
796+
}
798797
}
799798

800799
if (pend & XIIC_INTR_BNB_MASK) {

0 commit comments

Comments
 (0)