]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
i2c: tegra: notify transfer-complete after clearing status.
authorLaxman Dewangan <ldewangan@nvidia.com>
Mon, 7 May 2012 06:46:19 +0000 (12:16 +0530)
committerWolfram Sang <w.sang@pengutronix.de>
Sat, 12 May 2012 14:10:12 +0000 (16:10 +0200)
The notification of the transfer complete by calling complete()
should be done after clearing all interrupt status.
This avoids the race condition of misconfigure the i2c controller
in multi-core environment.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: stable@kernel.org
drivers/i2c/busses/i2c-tegra.c

index 18067b3ee8c9f215feab9dfa17abd44ce980fe55..8b2e555a9563204476be25184d442d0422a49920 100644 (file)
@@ -401,8 +401,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
                        disable_irq_nosync(i2c_dev->irq);
                        i2c_dev->irq_disabled = 1;
                }
-
-               complete(&i2c_dev->msg_complete);
                goto err;
        }
 
@@ -411,7 +409,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
                        i2c_dev->msg_err |= I2C_ERR_NO_ACK;
                if (status & I2C_INT_ARBITRATION_LOST)
                        i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
-               complete(&i2c_dev->msg_complete);
                goto err;
        }
 
@@ -429,14 +426,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
                        tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
        }
 
+       i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+       if (i2c_dev->is_dvc)
+               dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
        if (status & I2C_INT_PACKET_XFER_COMPLETE) {
                BUG_ON(i2c_dev->msg_buf_remaining);
                complete(&i2c_dev->msg_complete);
        }
-
-       i2c_writel(i2c_dev, status, I2C_INT_STATUS);
-       if (i2c_dev->is_dvc)
-               dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
        return IRQ_HANDLED;
 err:
        /* An error occurred, mask all interrupts */
@@ -446,6 +443,8 @@ err:
        i2c_writel(i2c_dev, status, I2C_INT_STATUS);
        if (i2c_dev->is_dvc)
                dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+       complete(&i2c_dev->msg_complete);
        return IRQ_HANDLED;
 }