diff options
author | Simon Lindgren <simon@aqwary.com> | 2014-08-26 21:13:24 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-10-05 14:54:07 -0700 |
commit | d5a6d0a4da8d97790df21cf96c1879856aedc651 (patch) | |
tree | 8953e287d201d43abd793778f02afcb627a27629 /drivers/i2c | |
parent | 6410b64defae58d7add75e0d2e5abf9e8b0b58ab (diff) | |
download | lwn-d5a6d0a4da8d97790df21cf96c1879856aedc651.tar.gz lwn-d5a6d0a4da8d97790df21cf96c1879856aedc651.zip |
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.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index c3e9b4714e52..b1240a250149 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -435,8 +435,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); |