Skip to content

Commit

Permalink
ipmi: Start the timer and thread on internal msgs
Browse files Browse the repository at this point in the history
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>
Cc: stable@vger.kernel.org
  • Loading branch information
cminyard committed Nov 16, 2015
1 parent 8005c49 commit 0cfec91
Showing 1 changed file with 44 additions and 29 deletions.
73 changes: 44 additions & 29 deletions drivers/char/ipmi/ipmi_si_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -3613,7 +3628,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
Expand Down Expand Up @@ -3908,7 +3923,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);
Expand Down

0 comments on commit 0cfec91

Please sign in to comment.