diff options
author | Chaitanya Bandi <bandik@nvidia.com> | 2012-03-16 17:47:35 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-04-03 09:27:00 -0700 |
commit | 8ddb969ed5b866ddbba5c55043848b8b9ab3dda4 (patch) | |
tree | f9a5d66fcf79a53adfd0c1ea41b71851f56ed00e /drivers/i2c | |
parent | d1bafe42b06e728e4502b9cbaba39c34d3d58913 (diff) |
i2c: tegra: Fix to avoid possible race condition
Because of race condition between isr and tx fifo fill,
duplicate data is being written. So added locking to make
Tx fifo fill as atomic.
Change-Id: Ia99466adadfb6d86a6f238ec4cd0aa13bd36e434
Signed-off-by: Chaitanya Bandi <bandik@nvidia.com>
Reviewed-on: http://git-master/r/90870
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.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index ad12f75bbdbf..bde4a6dd8e33 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -151,6 +151,7 @@ struct tegra_i2c_dev { struct clk *fast_clk; struct resource *iomem; struct rt_mutex dev_lock; + spinlock_t fifo_lock; void __iomem *base; int cont_id; int irq; @@ -320,6 +321,9 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) u8 *buf = i2c_dev->msg_buf; size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; + unsigned long flags; + + spin_lock_irqsave(&i2c_dev->fifo_lock, flags); val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> @@ -369,6 +373,8 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, val, I2C_TX_FIFO); } + spin_unlock_irqrestore(&i2c_dev->fifo_lock, flags); + return 0; } @@ -885,6 +891,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->msgs = NULL; i2c_dev->msgs_num = 0; rt_mutex_init(&i2c_dev->dev_lock); + spin_lock_init(&i2c_dev->fifo_lock); i2c_dev->slave_addr = plat->slave_addr; i2c_dev->hs_master_code = plat->hs_master_code; |