]> git.hungrycats.org Git - linux/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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Jun 2012 07:18:28 +0000 (15:18 +0800)
commit c889e91d2cc22123f20f40dde0c0a91856a20eea upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/i2c/busses/i2c-tegra.c

index 55e5ea62ccee3b69148c13ce337a1ff8531bc467..df19f3d588cde4dc95ba7b822b1b0e2397b8590a 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;
 }