Skip to content

Commit

Permalink
i2c-davinci: Fix race when setting up for TX
Browse files Browse the repository at this point in the history
When setting up to transmit, a race exists between the ISR and
i2c_davinci_xfer_msg() trying to load the first byte and adjust counters.
This is mostly visible for transmits > 1 byte long.

The hardware starts sending immediately that MDR is loaded. IMR trickery
doesn't work because if we start sending, finish the first byte and an
XRDY event occurs before we load IMR to unmask it, we never get an
interrupt, and we timeout.

Move the MDR load after DXR,IMR loads to avoid this race without locking.

Tested on DM355 connected to Techwell TW2836 and Wolfson WM8985

Signed-off-by: Jon Povey <jon.povey@racelogic.co.uk>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
  • Loading branch information
Jon Povey authored and Ben Dooks committed Sep 27, 2010
1 parent cc33e54 commit 4bba0fd
Showing 1 changed file with 3 additions and 3 deletions.
6 changes: 3 additions & 3 deletions drivers/i2c/busses/i2c-davinci.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)

dev->terminate = 0;

/* write the data into mode register */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);

/*
* First byte should be set here, not after interrupt,
* because transmit-data-ready interrupt can come before
Expand All @@ -371,6 +368,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
dev->buf_len--;
}

/* write the data into mode register; start transmitting */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);

r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
dev->adapter.timeout);
if (r == 0) {
Expand Down

0 comments on commit 4bba0fd

Please sign in to comment.