From b3b8df97723d84c826d7419bf727a711a4efa068 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Nov 2014 10:20:40 +0100 Subject: [PATCH] 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 Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 25 ++++++++++++++++++++++--- 1 file 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 , Philip Edelbrock , and Mark D. Studebaker - Copyright (C) 2007 - 2012 Jean Delvare + Copyright (C) 2007 - 2014 Jean Delvare Copyright (C) 2010 Intel Corporation, David Woodhouse @@ -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); -- 2.20.1