summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 5459ffdde8dc..6eda61664aaa 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -809,6 +809,12 @@ restart:
*/
return_hosed_msg(smi_info, IPMI_BUS_ERR);
}
+ if (smi_info->waiting_msg != NULL) {
+ /* Also handle if there was a message waiting. */
+ smi_info->curr_msg = smi_info->waiting_msg;
+ smi_info->waiting_msg = NULL;
+ return_hosed_msg(smi_info, IPMI_BUS_ERR);
+ }
smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_HOSED);
goto out;
}
@@ -918,9 +924,14 @@ static int sender(void *send_info, struct ipmi_smi_msg *msg)
{
struct smi_info *smi_info = send_info;
unsigned long flags;
+ int rv = IPMI_CC_NO_ERROR;
debug_timestamp(smi_info, "Enqueue");
+ /*
+ * Check here for run to completion mode. A check under lock is
+ * later.
+ */
if (smi_info->si_state == SI_HOSED)
return IPMI_BUS_ERR;
@@ -934,18 +945,15 @@ static int sender(void *send_info, struct ipmi_smi_msg *msg)
}
spin_lock_irqsave(&smi_info->si_lock, flags);
- /*
- * The following two lines don't need to be under the lock for
- * the lock's sake, but they do need SMP memory barriers to
- * avoid getting things out of order. We are already claiming
- * the lock, anyway, so just do it under the lock to avoid the
- * ordering problem.
- */
- BUG_ON(smi_info->waiting_msg);
- smi_info->waiting_msg = msg;
- check_start_timer_thread(smi_info);
+ if (smi_info->si_state == SI_HOSED) {
+ rv = IPMI_BUS_ERR;
+ } else {
+ BUG_ON(smi_info->waiting_msg);
+ smi_info->waiting_msg = msg;
+ check_start_timer_thread(smi_info);
+ }
spin_unlock_irqrestore(&smi_info->si_lock, flags);
- return IPMI_CC_NO_ERROR;
+ return rv;
}
static void set_run_to_completion(void *send_info, bool i_run_to_completion)
@@ -1113,7 +1121,9 @@ static void smi_timeout(struct timer_list *t)
* SI_USEC_PER_JIFFY);
smi_result = smi_event_handler(smi_info, time_diff);
- if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
+ if (smi_info->si_state == SI_HOSED) {
+ timeout = jiffies + SI_TIMEOUT_HOSED;
+ } else if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
/* Running with interrupts, only do long timeouts. */
timeout = jiffies + SI_TIMEOUT_JIFFIES;
smi_inc_stat(smi_info, long_timeouts);
@@ -2226,7 +2236,8 @@ static void wait_msg_processed(struct smi_info *smi_info)
unsigned long jiffies_now;
long time_diff;
- while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
+ while (smi_info->si_state != SI_HOSED &&
+ (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL))) {
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
* SI_USEC_PER_JIFFY);