From patchwork Thu Sep 16 10:21:20 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jon Povey X-Patchwork-Id: 185202 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8GANwOG016322 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 16 Sep 2010 10:24:34 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o8GALe2I004016 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 16 Sep 2010 05:21:40 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id o8GALdSI023017; Thu, 16 Sep 2010 05:21:40 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 4810180627; Thu, 16 Sep 2010 05:21:39 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id CA58780626 for ; Thu, 16 Sep 2010 05:21:37 -0500 (CDT) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with ESMTP id o8GALbU1002854 for ; Thu, 16 Sep 2010 05:21:37 -0500 (CDT) Received: from psmtp.com (na3sys009amx165.postini.com [74.125.149.91]) by medina.ext.ti.com (8.13.7/8.13.7) with SMTP id o8GALaFv023352 for ; Thu, 16 Sep 2010 05:21:36 -0500 Received: from source ([122.28.30.136]) by na3sys009amx165.postini.com ([74.125.148.10]) with SMTP; Thu, 16 Sep 2010 10:21:36 GMT Received: from localhost.localdomain (p4095-ipbf4103marunouchi.tokyo.ocn.ne.jp [123.224.193.95]) by smtp.sand.ocn.ne.jp (Postfix) with ESMTP id 3674423FA; Thu, 16 Sep 2010 19:21:34 +0900 (JST) From: Jon Povey To: linux-i2c@vger.kernel.org, davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH] i2c: davinci: Fix race when setting up for TX Date: Thu, 16 Sep 2010 19:21:20 +0900 Message-Id: <1284632480-24035-1-git-send-email-jon.povey@racelogic.co.uk> X-Mailer: git-send-email 1.6.3.3 X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.5000) s cv gt3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 16 Sep 2010 10:24:34 +0000 (UTC) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 2222c87..43aa55d 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -107,6 +107,7 @@ struct davinci_i2c_dev { u8 *buf; size_t buf_len; int irq; + spinlock_t lock; int stop; u8 terminate; struct i2c_adapter adapter; @@ -312,6 +313,8 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) u32 flag; u16 w; int r; + unsigned long flags; + int preload = 0; if (!pdata) pdata = &davinci_i2c_platform_data_default; @@ -347,6 +350,15 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) flag &= ~DAVINCI_I2C_MDR_STP; } + /* + * When transmitting, lock ISR out to avoid it racing on the buffer and + * DXR register before we are done + */ + if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) { + preload = 1; + spin_lock_irqsave(&dev->lock, flags); + } + /* Enable receive or transmit interrupts */ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG); if (msg->flags & I2C_M_RD) @@ -366,13 +378,15 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) * NACK-interrupt during sending of previous message and * ICDXR may have wrong data */ - if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) { + if (preload) { davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++); dev->buf_len--; + spin_unlock_irqrestore(&dev->lock, flags); } r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, dev->adapter.timeout); + if (r == 0) { dev_err(dev->dev, "controller timed out\n"); i2c_recover_bus(dev); @@ -490,6 +504,8 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) int count = 0; u16 w; + spin_lock(&dev->lock); + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); if (count++ == 100) { @@ -579,6 +595,8 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) } } + spin_unlock(&dev->lock); + return count ? IRQ_HANDLED : IRQ_NONE; } @@ -662,6 +680,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) goto err_release_region; } + spin_lock_init(&dev->lock); init_completion(&dev->cmd_complete); #ifdef CONFIG_CPU_FREQ init_completion(&dev->xfr_complete);