Patch for orabug 12394831 This patch merged 3 upstream patches: commit ea4078ca1a7a3a198e519c2a7a2ed6126e40b130 Author: Matthew Garrett Date: Wed May 26 14:43:48 2010 -0700 ipmi: reduce polling when interrupts are available If we're not currently in the middle of a transaction, and if we have interrupts, there's no real reason to poll the controller more frequently than the core IPMI code does. Set the interrupt_disabled flag appropriately as the interrupt state changes, and make the timeout code reset itself only if the transaction is incomplete or we have no interrupts. commit 3326f4f2276791561af1fd5f2020be0186459813 Author: Matthew Garrett Date: Wed May 26 14:43:49 2010 -0700 ipmi: reduce polling We can reasonably alter the poll rate depending on whether we're performing a transaction or merely waiting for an event. commit 4c418ba9695a24917a1fcfa48f7db3fd76337eb7 Author: Doe, YiCheng Date: Thu Mar 10 14:00:21 2011 -0600 ipmi: Fix IPMI errors due to timing problems This patch fixes an issue in OpenIPMI module where sometimes an ABORT command is sent after sending an IPMI request to BMC causing the IPMI request to fail. diff -up linux-2.6.18.i686/drivers/char/ipmi/ipmi_si_intf.c.orig linux-2.6.18.i686/drivers/char/ipmi/ipmi_si_intf.c --- linux-2.6.18.i686/drivers/char/ipmi/ipmi_si_intf.c.orig 2011-06-14 12:45:25.000000000 +0800 +++ linux-2.6.18.i686/drivers/char/ipmi/ipmi_si_intf.c 2011-06-14 13:07:48.000000000 +0800 @@ -380,6 +380,9 @@ static inline void disable_si_irq(struct if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { start_disable_irq(smi_info); smi_info->interrupt_disabled = 1; + if (!atomic_read(&smi_info->stop_operation)) + mod_timer(&smi_info->si_timer, + jiffies + SI_TIMEOUT_JIFFIES); } } @@ -628,6 +631,8 @@ static void handle_transaction_done(stru printk(KERN_WARNING "ipmi_si: Could not enable interrupts" ", failed set, using polled mode.\n"); + } else { + smi_info->interrupt_disabled = 0; } smi_info->si_state = SI_NORMAL; break; @@ -810,6 +815,19 @@ static void sender(void * printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif + /* + * last_timeout_jiffies is updated here to avoid + * smi_timeout() handler passing very large time_diff + * value to smi_event_handler() that causes + * the send command to abort. + */ + smi_info->last_timeout_jiffies = jiffies; + + mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES); + + if (smi_info->thread) + wake_up_process(smi_info->thread); + if (smi_info->run_to_completion) { /* If we are running to completion, then throw it in the list and run transactions until everything is @@ -884,6 +902,8 @@ static int ipmi_thread(void *data) } else if (smi_result == SI_SM_CALL_WITH_DELAY) schedule(); + else if (smi_result == SI_SM_IDLE) + schedule_timeout_interruptible(100); else schedule_timeout_interruptible(1); } @@ -922,6 +942,7 @@ static void smi_timeout(unsigned long da unsigned long flags; unsigned long jiffies_now; long time_diff; + long timeout; #ifdef DEBUG_TIMING struct timeval t; #endif @@ -942,11 +963,11 @@ static void smi_timeout(unsigned long da if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { /* Running with interrupts, only do long timeouts. */ - smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; + timeout = jiffies + SI_TIMEOUT_JIFFIES; spin_lock_irqsave(&smi_info->count_lock, flags); smi_info->long_timeouts++; spin_unlock_irqrestore(&smi_info->count_lock, flags); - goto do_add_timer; + goto do_mod_timer; } /* If the state machine asks for a short delay, then shorten @@ -955,16 +976,17 @@ static void smi_timeout(unsigned long da spin_lock_irqsave(&smi_info->count_lock, flags); smi_info->short_timeouts++; spin_unlock_irqrestore(&smi_info->count_lock, flags); - smi_info->si_timer.expires = jiffies + 1; + timeout = jiffies + 1; } else { spin_lock_irqsave(&smi_info->count_lock, flags); smi_info->long_timeouts++; spin_unlock_irqrestore(&smi_info->count_lock, flags); - smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; + timeout = jiffies + SI_TIMEOUT_JIFFIES; } - do_add_timer: - add_timer(&(smi_info->si_timer)); + do_mod_timer: + if (smi_result != SI_SM_IDLE) + mod_timer(&(smi_info->si_timer), timeout); } static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) @@ -2776,7 +2798,7 @@ static int try_smi_init(struct smi_info atomic_set(&new_smi->req_events, 0); new_smi->run_to_completion = 0; - new_smi->interrupt_disabled = 0; + new_smi->interrupt_disabled = 1; atomic_set(&new_smi->stop_operation, 0); new_smi->intf_num = smi_num; smi_num++;