summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorSimon Lindgren <simon@aqwary.com>2014-08-26 21:13:24 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-10-05 14:52:11 -0700
commitf486b8ed93220f0ddaae8780cdaed6316d7dccc0 (patch)
tree8fa6b12dce4d1dbc6190b0ba563e42b0b0fc45ed /drivers/i2c
parent383e2104c699ea08738da2770c9383bdfaee58ac (diff)
i2c: at91: Fix a race condition during signal handling in at91_do_twi_xfer.
commit 6721f28a26efd6368497abbdef5dcfc59608d899 upstream. There is a race condition in at91_do_twi_xfer when signals arrive. If a signal is recieved while waiting for a transfer to complete wait_for_completion_interruptible_timeout() will return -ERESTARTSYS. This is not handled correctly resulting in interrupts still being enabled and a transfer being in flight when we return. Symptoms include a range of oopses and bus lockups. Oopses can happen when the transfer completes because the interrupt handler will corrupt the stack. If a new transfer is started before the interrupt fires the controller will start a new transfer in the middle of the old one, resulting in confused slaves and a locked bus. To avoid this, use wait_for_completion_io_timeout instead so that we don't have to deal with gracefully shutting down the transfer and disabling the interrupts. Signed-off-by: Simon Lindgren <simon@aqwary.com> Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-at91.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 374fdc410ba7..11e9c7f9bf9b 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -434,8 +434,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
}
}
- ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
- dev->adapter.timeout);
+ ret = wait_for_completion_io_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
if (ret == 0) {
dev_err(dev->dev, "controller timed out\n");
at91_init_twi_bus(dev);