| From 0cfec916e86d881e209de4b4ae9959a6271e6660 Mon Sep 17 00:00:00 2001 |
| From: Corey Minyard <cminyard@mvista.com> |
| Date: Sat, 5 Sep 2015 17:44:13 -0500 |
| Subject: ipmi: Start the timer and thread on internal msgs |
| |
| From: Corey Minyard <cminyard@mvista.com> |
| |
| 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@mvista.com> |
| Tested-by: Gouji, Masayuki <gouji.masayuki@jp.fujitsu.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| 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); |