aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorChristian Ruppert <christian.ruppert@abilis.com>2013-06-07 04:51:23 -0400
committerWolfram Sang <wsa@the-dreams.de>2013-06-15 07:04:32 -0400
commit38d7fadef4973bb94e36897fcb6bb6a12fdd10c9 (patch)
tree3f42a138a920735fcdfad05862636903ff13c827 /drivers/i2c
parent8419c8debdc600b71fb89f0ffad80a6f436d80fe (diff)
i2c: designware: fix race between subsequent xfers
The designware block is not always properly disabled in the case of transfer errors. Interrupts from aborted transfers might be handled after the data structures for the following transfer are initialised but before the hardware is set up. This can corrupt the data structures to the point that the system is stuck in an infinite interrupt loop (where FIFOs are never emptied because dev->msg_read_idx == dev->msgs_num). This patch cleanly disables the designware-i2c hardware at the end of every transfer, be it successful or not. Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com> [wsa: extended the comment] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index db20a2841b75..3de549436992 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -583,11 +583,21 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
583 ret = wait_for_completion_timeout(&dev->cmd_complete, HZ); 583 ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
584 if (ret == 0) { 584 if (ret == 0) {
585 dev_err(dev->dev, "controller timed out\n"); 585 dev_err(dev->dev, "controller timed out\n");
586 /* i2c_dw_init implicitly disables the adapter */
586 i2c_dw_init(dev); 587 i2c_dw_init(dev);
587 ret = -ETIMEDOUT; 588 ret = -ETIMEDOUT;
588 goto done; 589 goto done;
589 } 590 }
590 591
592 /*
593 * We must disable the adapter before unlocking the &dev->lock mutex
594 * below. Otherwise the hardware might continue generating interrupts
595 * which in turn causes a race condition with the following transfer.
596 * Needs some more investigation if the additional interrupts are
597 * a hardware bug or this driver doesn't handle them correctly yet.
598 */
599 __i2c_dw_enable(dev, false);
600
591 if (dev->msg_err) { 601 if (dev->msg_err) {
592 ret = dev->msg_err; 602 ret = dev->msg_err;
593 goto done; 603 goto done;
@@ -595,8 +605,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
595 605
596 /* no error */ 606 /* no error */
597 if (likely(!dev->cmd_err)) { 607 if (likely(!dev->cmd_err)) {
598 /* Disable the adapter */
599 __i2c_dw_enable(dev, false);
600 ret = num; 608 ret = num;
601 goto done; 609 goto done;
602 } 610 }