i2c: mxs_i2c: Squash endless loop

The endless waiting for a bit to be set can cause a hang, add a timeout
so we prevent such situation. A testcase for such a hang is below. The
testcase assumes a device to be present at address 0x50 and a device to
NOT be present at address 0x42 . Also note that the "sleep 1" induced
delays are imperative for this bug to manifest .

i2c read 0x42 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x50 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x42 0x0.2 0x10 0x42000000

The expected result of the above command is:

Error reading the chip.
Error reading the chip.

While without this patch, we observe a hang in the last read from 0x42
precisely when waiting for this bit to be set.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
master
Marek Vasut 11 years ago committed by Heiko Schocher
parent 2035d77d79
commit 124913556c
  1. 15
      drivers/i2c/mxs_i2c.c

@ -150,6 +150,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
uint32_t tmp = 0;
int timeout = MXS_I2C_MAX_TIMEOUT;
int ret;
int i;
@ -169,9 +170,17 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
for (i = 0; i < len; i++) {
if (!(i & 3)) {
while (readl(&i2c_regs->hw_i2c_queuestat) &
I2C_QUEUESTAT_RD_QUEUE_EMPTY)
;
while (--timeout) {
tmp = readl(&i2c_regs->hw_i2c_queuestat);
if (!(tmp & I2C_QUEUESTAT_RD_QUEUE_EMPTY))
break;
}
if (!timeout) {
debug("MXS I2C: Failed receiving data!\n");
return -ETIMEDOUT;
}
tmp = readl(&i2c_regs->hw_i2c_queuedata);
}
buffer[i] = tmp & 0xff;

Loading…
Cancel
Save