summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Povišer <povik+lin@cutebit.org>2022-03-29 20:38:17 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-04-20 09:08:33 +0200
commitbdbbb9ceb986a846cd59454128e1d1f2b73358d4 (patch)
tree7c5654b4a119534b83ddaf19c697e05a42df94e8
parent0f088623b6db0d533fe7fa787d0283b58a275b18 (diff)
downloadlinux-stable-bdbbb9ceb986a846cd59454128e1d1f2b73358d4.tar.gz
linux-stable-bdbbb9ceb986a846cd59454128e1d1f2b73358d4.tar.bz2
linux-stable-bdbbb9ceb986a846cd59454128e1d1f2b73358d4.zip
i2c: pasemi: Wait for write xfers to finish
commit bd8963e602c77adc76dbbbfc3417c3cf14fed76b upstream. Wait for completion of write transfers before returning from the driver. At first sight it may seem advantageous to leave write transfers queued for the controller to carry out on its own time, but there's a couple of issues with it: * Driver doesn't check for FIFO space. * The queued writes can complete while the driver is in its I2C read transfer path which means it will get confused by the raising of XEN (the 'transaction ended' signal). This can cause a spurious ENODATA error due to premature reading of the MRXFIFO register. Adding the wait fixes some unreliability issues with the driver. There's some efficiency cost to it (especially with pasemi_smb_waitready doing its polling), but that will be alleviated once the driver receives interrupt support. Fixes: beb58aa39e6e ("i2c: PA Semi SMBus driver") Signed-off-by: Martin Povišer <povik+lin@cutebit.org> Reviewed-by: Sven Peter <sven@svenpeter.dev> Signed-off-by: Wolfram Sang <wsa@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index df1dbc92a024..25c877654c32 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -145,6 +145,12 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
TXFIFO_WR(smbus, msg->buf[msg->len-1] |
(stop ? MTXFIFO_STOP : 0));
+
+ if (stop) {
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+ }
}
return 0;