|
@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
|
|
|
return rv;
|
|
|
}
|
|
|
|
|
|
-static void start_check_enables(struct smi_info *smi_info)
|
|
|
+static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
|
|
+{
|
|
|
+ smi_info->last_timeout_jiffies = jiffies;
|
|
|
+ mod_timer(&smi_info->si_timer, new_val);
|
|
|
+ smi_info->timer_running = true;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Start a new message and (re)start the timer and thread.
|
|
|
+ */
|
|
|
+static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
|
|
|
+ unsigned int size)
|
|
|
+{
|
|
|
+ smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
|
|
|
+
|
|
|
+ if (smi_info->thread)
|
|
|
+ wake_up_process(smi_info->thread);
|
|
|
+
|
|
|
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
|
|
|
+}
|
|
|
+
|
|
|
+static void start_check_enables(struct smi_info *smi_info, bool start_timer)
|
|
|
{
|
|
|
unsigned char msg[2];
|
|
|
|
|
|
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
|
|
|
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
|
|
|
|
|
|
- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
|
|
|
+ if (start_timer)
|
|
|
+ start_new_msg(smi_info, msg, 2);
|
|
|
+ else
|
|
|
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
|
|
|
smi_info->si_state = SI_CHECKING_ENABLES;
|
|
|
}
|
|
|
|
|
|
-static void start_clear_flags(struct smi_info *smi_info)
|
|
|
+static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
|
|
|
{
|
|
|
unsigned char msg[3];
|
|
|
|
|
@@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info)
|
|
|
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
|
|
|
msg[2] = WDT_PRE_TIMEOUT_INT;
|
|
|
|
|
|
- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
|
|
|
+ if (start_timer)
|
|
|
+ start_new_msg(smi_info, msg, 3);
|
|
|
+ else
|
|
|
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
|
|
|
smi_info->si_state = SI_CLEARING_FLAGS;
|
|
|
}
|
|
|
|
|
@@ -442,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
|
|
|
smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
|
|
|
smi_info->curr_msg->data_size = 2;
|
|
|
|
|
|
- smi_info->handlers->start_transaction(
|
|
|
- smi_info->si_sm,
|
|
|
- smi_info->curr_msg->data,
|
|
|
- smi_info->curr_msg->data_size);
|
|
|
+ start_new_msg(smi_info, smi_info->curr_msg->data,
|
|
|
+ smi_info->curr_msg->data_size);
|
|
|
smi_info->si_state = SI_GETTING_MESSAGES;
|
|
|
}
|
|
|
|
|
@@ -455,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info)
|
|
|
smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
|
|
|
smi_info->curr_msg->data_size = 2;
|
|
|
|
|
|
- smi_info->handlers->start_transaction(
|
|
|
- smi_info->si_sm,
|
|
|
- smi_info->curr_msg->data,
|
|
|
- smi_info->curr_msg->data_size);
|
|
|
+ start_new_msg(smi_info, smi_info->curr_msg->data,
|
|
|
+ smi_info->curr_msg->data_size);
|
|
|
smi_info->si_state = SI_GETTING_EVENTS;
|
|
|
}
|
|
|
|
|
|
-static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
|
|
-{
|
|
|
- smi_info->last_timeout_jiffies = jiffies;
|
|
|
- mod_timer(&smi_info->si_timer, new_val);
|
|
|
- smi_info->timer_running = true;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* When we have a situtaion where we run out of memory and cannot
|
|
|
* allocate messages, we just leave them in the BMC and run the system
|
|
@@ -478,11 +494,11 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
|
|
* Note that we cannot just use disable_irq(), since the interrupt may
|
|
|
* be shared.
|
|
|
*/
|
|
|
-static inline bool disable_si_irq(struct smi_info *smi_info)
|
|
|
+static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer)
|
|
|
{
|
|
|
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
|
|
|
smi_info->interrupt_disabled = true;
|
|
|
- start_check_enables(smi_info);
|
|
|
+ start_check_enables(smi_info, start_timer);
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
@@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
|
|
|
{
|
|
|
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
|
|
|
smi_info->interrupt_disabled = false;
|
|
|
- start_check_enables(smi_info);
|
|
|
+ start_check_enables(smi_info, true);
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
@@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
|
|
|
|
|
|
msg = ipmi_alloc_smi_msg();
|
|
|
if (!msg) {
|
|
|
- if (!disable_si_irq(smi_info))
|
|
|
+ if (!disable_si_irq(smi_info, true))
|
|
|
smi_info->si_state = SI_NORMAL;
|
|
|
} else if (enable_si_irq(smi_info)) {
|
|
|
ipmi_free_smi_msg(msg);
|
|
@@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info)
|
|
|
/* Watchdog pre-timeout */
|
|
|
smi_inc_stat(smi_info, watchdog_pretimeouts);
|
|
|
|
|
|
- start_clear_flags(smi_info);
|
|
|
+ start_clear_flags(smi_info, true);
|
|
|
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
|
|
|
if (smi_info->intf)
|
|
|
ipmi_smi_watchdog_pretimeout(smi_info->intf);
|
|
@@ -879,8 +895,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
|
|
|
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
|
|
|
msg[1] = IPMI_GET_MSG_FLAGS_CMD;
|
|
|
|
|
|
- smi_info->handlers->start_transaction(
|
|
|
- smi_info->si_sm, msg, 2);
|
|
|
+ start_new_msg(smi_info, msg, 2);
|
|
|
smi_info->si_state = SI_GETTING_FLAGS;
|
|
|
goto restart;
|
|
|
}
|
|
@@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
|
|
|
* disable and messages disabled.
|
|
|
*/
|
|
|
if (smi_info->supports_event_msg_buff || smi_info->irq) {
|
|
|
- start_check_enables(smi_info);
|
|
|
+ start_check_enables(smi_info, true);
|
|
|
} else {
|
|
|
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
|
|
|
if (!smi_info->curr_msg)
|
|
@@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
|
|
|
}
|
|
|
goto restart;
|
|
|
}
|
|
|
+
|
|
|
+ if (si_sm_result == SI_SM_IDLE && smi_info->timer_running) {
|
|
|
+ /* Ok it if fails, the timer will just go off. */
|
|
|
+ if (del_timer(&smi_info->si_timer))
|
|
|
+ smi_info->timer_running = false;
|
|
|
+ }
|
|
|
+
|
|
|
out:
|
|
|
return si_sm_result;
|
|
|
}
|
|
@@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = {
|
|
|
.data = (void *)(unsigned long) SI_BT },
|
|
|
{},
|
|
|
};
|
|
|
+MODULE_DEVICE_TABLE(of, of_ipmi_match);
|
|
|
|
|
|
static int of_ipmi_probe(struct platform_device *dev)
|
|
|
{
|
|
@@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev)
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
-MODULE_DEVICE_TABLE(of, of_ipmi_match);
|
|
|
#else
|
|
|
#define of_ipmi_match NULL
|
|
|
static int of_ipmi_probe(struct platform_device *dev)
|
|
@@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
|
|
* Start clearing the flags before we enable interrupts or the
|
|
|
* timer to avoid racing with the timer.
|
|
|
*/
|
|
|
- start_clear_flags(new_smi);
|
|
|
+ start_clear_flags(new_smi, false);
|
|
|
|
|
|
/*
|
|
|
* IRQ is defined to be set when non-zero. req_events will
|
|
@@ -3908,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
|
|
|
poll(to_clean);
|
|
|
schedule_timeout_uninterruptible(1);
|
|
|
}
|
|
|
- disable_si_irq(to_clean);
|
|
|
+ disable_si_irq(to_clean, false);
|
|
|
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
|
|
|
poll(to_clean);
|
|
|
schedule_timeout_uninterruptible(1);
|