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 <[EMAIL PROTECTED]>

Index: linux-2.6.11-rc4/drivers/char/ipmi/ipmi_smb.c
===================================================================
--- linux-2.6.11-rc4.orig/drivers/char/ipmi/ipmi_smb.c
+++ linux-2.6.11-rc4/drivers/char/ipmi/ipmi_smb.c
@@ -140,6 +140,10 @@
           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 @@
         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 @@
                        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 @@
                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 @@
                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);
                }
        }

Reply via email to