i2c: tegra: Fix to avoid possible race condition
Chaitanya Bandi [Fri, 16 Mar 2012 12:17:35 +0000 (17:17 +0530)]
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>

drivers/i2c/busses/i2c-tegra.c

index 9560100..46fe536 100644 (file)
@@ -152,6 +152,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;
@@ -321,6 +322,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) >>
@@ -370,6 +374,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;
 }
 
@@ -886,6 +892,7 @@ static int __devinit 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);
 
        if (pdev->dev.of_node)
                i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,