From: Corey Minyard 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 Signed-off-by: Andrew Morton --- 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); } } _