
From: Corey Minyard <minyard@acm.org>

The IPMI SMB driver, when running in run-to-completion mode (done during
panic time), would sometimes get locked up if a timeout occurred because
the timer would not get run properly.  This adds the timer handling to the
run-to-completion code.

Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/char/ipmi/ipmi_smb.c |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+)

diff -puN drivers/char/ipmi/ipmi_smb.c~fix-for-the-ipmi-smb-driver drivers/char/ipmi/ipmi_smb.c
--- 25/drivers/char/ipmi/ipmi_smb.c~fix-for-the-ipmi-smb-driver	Tue Feb 22 17:21:38 2005
+++ 25-akpm/drivers/char/ipmi/ipmi_smb.c	Tue Feb 22 17:21:38 2005
@@ -140,6 +140,10 @@ struct smb_info
 	   sure stuff goes out. */
 	int                 run_to_completion;
 
+	/* Used to perform timer operations when run-to-completion
+	   mode is on.  This is a countdown timer. */
+	int                 rtc_us_timer;
+
 	/* Used for sending/receiving data.  +1 for the length. */
 	unsigned char data[IPMI_MAX_MSG_LENGTH + 1];
 	unsigned int  data_len;
@@ -322,6 +326,8 @@ static void retry_timeout(unsigned long 
         struct smb_info     *smb_info = (void *) data;
         struct i2c_op_q_entry *i2ce;
 
+	smb_info->rtc_us_timer = 0;
+
         i2ce = &smb_info->i2c_q_entry;
         i2ce->xfer_type = I2C_OP_SMBUS;
         i2ce->handler = msg_done_handler;
@@ -380,6 +386,7 @@ static void msg_done_handler(struct i2c_
 			t->data = (unsigned long) smb_info;
 			t->function = retry_timeout;
 			add_timer(t);
+			smb_info->rtc_us_timer = 10000;
 			return;
 		}
 		if  (smb_info->smb_debug & SMB_DEBUG_MSG)
@@ -790,6 +797,13 @@ static void sender(void                *
 		i2c_poll(&smb_info->client, 0);
 		while (! SMB_IDLE(smb_info)) {
 			udelay(500);
+			if (smb_info->rtc_us_timer > 0) {
+				smb_info->rtc_us_timer -= 500;
+				if (smb_info->rtc_us_timer <= 0) {
+					retry_timeout((unsigned long) smb_info);
+					del_timer(&smb_info->retry_timer);
+				}
+			}
 			i2c_poll(&smb_info->client, 500);
 		}
 		return;
@@ -856,6 +870,13 @@ static void set_run_to_completion(void *
 		i2c_poll(&smb_info->client, 0);
 		while (! SMB_IDLE(smb_info)) {
 			udelay(500);
+			if (smb_info->rtc_us_timer > 0) {
+				smb_info->rtc_us_timer -= 500;
+				if (smb_info->rtc_us_timer <= 0) {
+					retry_timeout((unsigned long) smb_info);
+					del_timer(&smb_info->retry_timer);
+				}
+			}
 			i2c_poll(&smb_info->client, 500);
 		}
 	}
_
