diff options
author | Jean Delvare <jdelvare@suse.de> | 2014-11-12 10:20:40 +0100 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2014-11-12 16:06:38 +0100 |
commit | b3b8df97723d84c826d7419bf727a711a4efa068 (patch) | |
tree | 6764c08e2fe71343364fc916e287fdc3854277b6 /drivers/i2c | |
parent | i2c: rk3x: adjust the LOW divison based on characteristics of SCL (diff) | |
download | linux-b3b8df97723d84c826d7419bf727a711a4efa068.tar.xz linux-b3b8df97723d84c826d7419bf727a711a4efa068.zip |
i2c: i801: Use wait_event_timeout to wait for interrupts
Some systems have been reported to have trouble with interrupts. Use
wait_event_timeout() instead of wait_event() so we don't get stuck in
that case, and log the problem.
Signed-off-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 6ab4f1cb21f3..67661bbcbdd3 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -2,7 +2,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2007 - 2012 Jean Delvare <jdelvare@suse.de> + Copyright (C) 2007 - 2014 Jean Delvare <jdelvare@suse.de> Copyright (C) 2010 Intel Corporation, David Woodhouse <dwmw2@infradead.org> @@ -371,6 +371,7 @@ static int i801_transaction(struct i801_priv *priv, int xact) { int status; int result; + const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) @@ -379,7 +380,14 @@ static int i801_transaction(struct i801_priv *priv, int xact) if (priv->features & FEATURE_IRQ) { outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, SMBHSTCNT(priv)); - wait_event(priv->waitq, (status = priv->status)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } priv->status = 0; return i801_check_post(priv, status); } @@ -527,6 +535,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, int smbcmd; int status; int result; + const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) @@ -555,7 +564,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, priv->data = &data->block[1]; outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); - wait_event(priv->waitq, (status = priv->status)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } priv->status = 0; return i801_check_post(priv, status); } @@ -1212,6 +1228,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + /* Default timeout in interrupt mode: 200 ms */ + priv->adapter.timeout = HZ / 5; + if (priv->features & FEATURE_IRQ) { init_waitqueue_head(&priv->waitq); |