Commit f313b43b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c fix from Wolfram Sang:
 "A single driver bugfix for I2C.

  The bug was found by systematically stress testing the driver, so I am
  confident to merge it that late in the cycle although it is probably
  unusually large"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: xlp9xx: Fix case where SSIF read transaction completes early
parents 112cbae2 5eb173f5
...@@ -191,28 +191,43 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) ...@@ -191,28 +191,43 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
if (priv->len_recv) { if (priv->len_recv) {
/* read length byte */ /* read length byte */
rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
/*
* We expect at least 2 interrupts for I2C_M_RECV_LEN
* transactions. The length is updated during the first
* interrupt, and the buffer contents are only copied
* during subsequent interrupts. If in case the interrupts
* get merged we would complete the transaction without
* copying out the bytes from RX fifo. To avoid this now we
* drain the fifo as and when data is available.
* We drained the rlen byte already, decrement total length
* by one.
*/
len--;
if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) { if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) {
rlen = 0; /*abort transfer */ rlen = 0; /*abort transfer */
priv->msg_buf_remaining = 0; priv->msg_buf_remaining = 0;
priv->msg_len = 0; priv->msg_len = 0;
} else { xlp9xx_i2c_update_rlen(priv);
*buf++ = rlen; return;
if (priv->client_pec)
++rlen; /* account for error check byte */
/* update remaining bytes and message length */
priv->msg_buf_remaining = rlen;
priv->msg_len = rlen + 1;
} }
*buf++ = rlen;
if (priv->client_pec)
++rlen; /* account for error check byte */
/* update remaining bytes and message length */
priv->msg_buf_remaining = rlen;
priv->msg_len = rlen + 1;
xlp9xx_i2c_update_rlen(priv); xlp9xx_i2c_update_rlen(priv);
priv->len_recv = false; priv->len_recv = false;
} else {
len = min(priv->msg_buf_remaining, len);
for (i = 0; i < len; i++, buf++)
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
priv->msg_buf_remaining -= len;
} }
len = min(priv->msg_buf_remaining, len);
for (i = 0; i < len; i++, buf++)
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
priv->msg_buf_remaining -= len;
priv->msg_buf = buf; priv->msg_buf = buf;
if (priv->msg_buf_remaining) if (priv->msg_buf_remaining)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment