summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2012-03-07 12:11:41 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2012-06-07 14:21:46 +0530
commitbdde5663f656349743b8f864f969c735be8b0b54 (patch)
tree5a9ab87b9251ab0d50a9deeea6c8aff3172c133d /drivers/i2c
parent2f09ba47a308dcba5b868c20e18179bf763c4d1d (diff)
i2c: tegra: Fix possible race condition.
on tegra3, the i2c communication start immediately after writing the tx fifo. And hence there is possibility to complete the transfer and generates done interrupt before actually sw updates their local pointers/count. This patch will make sure that pointers/count can get updated before data written into the fifo. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-on: http://git-master/r/89510 (cherry picked from commit 999c09f0ed32f271e767a319dd094947e63fdb8c) Change-Id: I8e974b83b5306ec3363d4ca31ce1b539a498ca08 Signed-off-by: Johnny Qiu <joqiu@nvidia.com> Reviewed-on: http://git-master/r/99997 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 13c9380ba7b3..31afae37a50c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -332,12 +332,19 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
{
u32 val;
int tx_fifo_avail;
- u8 *buf = i2c_dev->msg_buf;
- size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ u8 *buf;
+ size_t buf_remaining;
int words_to_transfer;
unsigned long flags;
spin_lock_irqsave(&i2c_dev->fifo_lock, flags);
+ if (!i2c_dev->msg_buf_remaining) {
+ spin_unlock_irqrestore(&i2c_dev->fifo_lock, flags);
+ return 0;
+ }
+
+ buf = i2c_dev->msg_buf;
+ buf_remaining = i2c_dev->msg_buf_remaining;
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
@@ -376,7 +383,12 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
* boundary and fault.
*/
if (tx_fifo_avail > 0 && buf_remaining > 0) {
- BUG_ON(buf_remaining > 3);
+ if (buf_remaining > 3) {
+ dev_err(i2c_dev->dev,
+ "Remaining buffer more than 3 %d\n",
+ buf_remaining);
+ BUG();
+ }
memcpy(&val, buf, buf_remaining);
/* Again update before writing to FIFO to make sure isr sees. */