[PATCH 4.3 019/157] ipmi: Start the timer and thread on internal msgs

From: Greg Kroah-Hartman
Date: Wed Jan 27 2016 - 13:21:24 EST


4.3-stable review patch. If anyone has any objections, please let me know.

------------------

From: Corey Minyard <cminyard@xxxxxxxxxx>

commit 0cfec916e86d881e209de4b4ae9959a6271e6660 upstream.

The timer and thread were not being started for internal messages,
so in interrupt mode if something hung the timer would never go
off and clean things up. Factor out the internal message sending
and start the timer for those messages, too.

Signed-off-by: Corey Minyard <cminyard@xxxxxxxxxx>
Tested-by: Gouji, Masayuki <gouji.masayuki@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/char/ipmi/ipmi_si_intf.c | 73 +++++++++++++++++++++++----------------
1 file changed, 44 insertions(+), 29 deletions(-)

--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(
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
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(stru
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->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_inf
* 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
{
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_ha

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
/* 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_handl
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_handl
* 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)
@@ -3613,7 +3628,7 @@ static int try_smi_init(struct smi_info
* 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 +3923,7 @@ static void cleanup_one_si(struct smi_in
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);