i2c: i801: Use wait_event_timeout to wait for interrupts
authorJean Delvare <jdelvare@suse.de>
Wed, 12 Nov 2014 09:20:40 +0000 (10:20 +0100)
committerWolfram Sang <wsa@the-dreams.de>
Wed, 12 Nov 2014 15:06:38 +0000 (16:06 +0100)
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>
drivers/i2c/busses/i2c-i801.c

index 6ab4f1cb21f3fae717dfdfbf3b07e721d6e7254e..67661bbcbdd37d5334d22541c3df3b84fdf37a9e 100644 (file)
@@ -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);