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 <[email protected]>
Cc: Wolfram Sang <[email protected]>
---
No change since v1.

 drivers/i2c/busses/i2c-i801.c |   25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

--- linux-3.18-rc4.orig/drivers/i2c/busses/i2c-i801.c   2014-11-10 
22:26:47.212135115 +0100
+++ linux-3.18-rc4/drivers/i2c/busses/i2c-i801.c        2014-11-10 
22:29:18.040417276 +0100
@@ -2,7 +2,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <[email protected]>,
     Philip Edelbrock <[email protected]>, and Mark D. Studebaker
     <[email protected]>
-    Copyright (C) 2007 - 2012  Jean Delvare <[email protected]>
+    Copyright (C) 2007 - 2014  Jean Delvare <[email protected]>
     Copyright (C) 2010         Intel Corporation,
                                David Woodhouse <[email protected]>
 
@@ -373,6 +373,7 @@ static int i801_transaction(struct i801_
 {
        int status;
        int result;
+       const struct i2c_adapter *adap = &priv->adapter;
 
        result = i801_check_pre(priv);
        if (result < 0)
@@ -381,7 +382,14 @@ static int i801_transaction(struct i801_
        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);
        }
@@ -529,6 +537,7 @@ static int i801_block_transaction_byte_b
        int smbcmd;
        int status;
        int result;
+       const struct i2c_adapter *adap = &priv->adapter;
 
        result = i801_check_pre(priv);
        if (result < 0)
@@ -557,7 +566,14 @@ static int i801_block_transaction_byte_b
                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);
        }
@@ -1215,6 +1231,9 @@ static int i801_probe(struct pci_dev *de
                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);
 

-- 
Jean Delvare
SUSE L3 Support
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to