aboutsummaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorVille Syrjala <syrjala@sci.fi>2012-03-15 18:11:05 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-19 08:57:59 -0700
commit35f68010b4311eacf6340473b062418715d68a39 (patch)
treecb482f2b882598f145a2643bbee9e9e20ddfbbcd /drivers/i2c
parent90b7d65c8cba8830ede8307a21a76c8757eefa3a (diff)
i2c-algo-bit: Fix spurious SCL timeouts under heavy load
commit 8ee161ce5e0cfc689eb677f227a6248191165fac upstream. When the system is under heavy load, there can be a significant delay between the getscl() and time_after() calls inside sclhi(). That delay may cause the time_after() check to trigger after SCL has gone high, causing sclhi() to return -ETIMEDOUT. To fix the problem, double check that SCL is still low after the timeout has been reached, before deciding to return -ETIMEDOUT. Signed-off-by: Ville Syrjala <syrjala@sci.fi> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index eca3bcc4599..f2ce8c36816 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -103,8 +103,14 @@ static int sclhi(struct i2c_algo_bit_data *adap)
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
- if (time_after(jiffies, start + adap->timeout))
+ if (time_after(jiffies, start + adap->timeout)) {
+ /* Test one last time, as we may have been preempted
+ * between last check and timeout test.
+ */
+ if (getscl(adap))
+ break;
return -ETIMEDOUT;
+ }
cond_resched();
}
#ifdef DEBUG