Commit cd6caf55 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-4.4' of git://git.code.sf.net/p/openipmi/linux-ipmi

Pull IPMI updates from Corey Minyard:
 "Some fixes for small IPMI problems.

  The most significant is that the driver wasn't starting the timer for
  some messages, which would result in problems if that message failed
  for some reason.

  The others are small optimizations or making things a little neater"

* tag 'for-linus-4.4' of git://git.code.sf.net/p/openipmi/linux-ipmi:
  ipmi watchdog : add panic_wdt_timeout parameter
  char: ipmi: Move MODULE_DEVICE_TABLE() to follow struct
  ipmi: Stop the timer immediately if idle
  ipmi: Start the timer and thread on internal msgs
parents 8bdddfae c7f42c63
...@@ -587,7 +587,7 @@ used to control it: ...@@ -587,7 +587,7 @@ used to control it:
modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type> modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
preaction=<preaction type> preop=<preop type> start_now=x preaction=<preaction type> preop=<preop type> start_now=x
nowayout=x ifnum_to_use=n nowayout=x ifnum_to_use=n panic_wdt_timeout=<t>
ifnum_to_use specifies which interface the watchdog timer should use. ifnum_to_use specifies which interface the watchdog timer should use.
The default is -1, which means to pick the first one registered. The default is -1, which means to pick the first one registered.
...@@ -597,7 +597,9 @@ is the amount of seconds before the reset that the pre-timeout panic will ...@@ -597,7 +597,9 @@ is the amount of seconds before the reset that the pre-timeout panic will
occur (if pretimeout is zero, then pretimeout will not be enabled). Note occur (if pretimeout is zero, then pretimeout will not be enabled). Note
that the pretimeout is the time before the final timeout. So if the that the pretimeout is the time before the final timeout. So if the
timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout
will occur in 40 second (10 seconds before the timeout). will occur in 40 second (10 seconds before the timeout). The panic_wdt_timeout
is the value of timeout which is set on kernel panic, in order to let actions
such as kdump to occur during panic.
The action may be "reset", "power_cycle", or "power_off", and The action may be "reset", "power_cycle", or "power_off", and
specifies what to do when the timer times out, and defaults to specifies what to do when the timer times out, and defaults to
...@@ -634,6 +636,7 @@ for configuring the watchdog: ...@@ -634,6 +636,7 @@ for configuring the watchdog:
ipmi_watchdog.preop=<preop type> ipmi_watchdog.preop=<preop type>
ipmi_watchdog.start_now=x ipmi_watchdog.start_now=x
ipmi_watchdog.nowayout=x ipmi_watchdog.nowayout=x
ipmi_watchdog.panic_wdt_timeout=<t>
The options are the same as the module parameter options. The options are the same as the module parameter options.
......
...@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) ...@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
return rv; 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]; unsigned char msg[2];
msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; 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; 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]; unsigned char msg[3];
...@@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info) ...@@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info)
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
msg[2] = WDT_PRE_TIMEOUT_INT; 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; smi_info->si_state = SI_CLEARING_FLAGS;
} }
...@@ -442,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info) ...@@ -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[1] = IPMI_GET_MSG_CMD;
smi_info->curr_msg->data_size = 2; smi_info->curr_msg->data_size = 2;
smi_info->handlers->start_transaction( start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->si_sm, smi_info->curr_msg->data_size);
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_MESSAGES; smi_info->si_state = SI_GETTING_MESSAGES;
} }
...@@ -455,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info) ...@@ -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[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
smi_info->curr_msg->data_size = 2; smi_info->curr_msg->data_size = 2;
smi_info->handlers->start_transaction( start_new_msg(smi_info, smi_info->curr_msg->data,
smi_info->si_sm, smi_info->curr_msg->data_size);
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS; 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 * 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 * 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) ...@@ -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 * Note that we cannot just use disable_irq(), since the interrupt may
* be shared. * 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)) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
smi_info->interrupt_disabled = true; smi_info->interrupt_disabled = true;
start_check_enables(smi_info); start_check_enables(smi_info, start_timer);
return true; return true;
} }
return false; return false;
...@@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) ...@@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
{ {
if ((smi_info->irq) && (smi_info->interrupt_disabled)) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
smi_info->interrupt_disabled = false; smi_info->interrupt_disabled = false;
start_check_enables(smi_info); start_check_enables(smi_info, true);
return true; return true;
} }
return false; return false;
...@@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) ...@@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
msg = ipmi_alloc_smi_msg(); msg = ipmi_alloc_smi_msg();
if (!msg) { if (!msg) {
if (!disable_si_irq(smi_info)) if (!disable_si_irq(smi_info, true))
smi_info->si_state = SI_NORMAL; smi_info->si_state = SI_NORMAL;
} else if (enable_si_irq(smi_info)) { } else if (enable_si_irq(smi_info)) {
ipmi_free_smi_msg(msg); ipmi_free_smi_msg(msg);
...@@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info) ...@@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info)
/* Watchdog pre-timeout */ /* Watchdog pre-timeout */
smi_inc_stat(smi_info, watchdog_pretimeouts); 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; smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
if (smi_info->intf) if (smi_info->intf)
ipmi_smi_watchdog_pretimeout(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, ...@@ -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[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_MSG_FLAGS_CMD; msg[1] = IPMI_GET_MSG_FLAGS_CMD;
smi_info->handlers->start_transaction( start_new_msg(smi_info, msg, 2);
smi_info->si_sm, msg, 2);
smi_info->si_state = SI_GETTING_FLAGS; smi_info->si_state = SI_GETTING_FLAGS;
goto restart; goto restart;
} }
...@@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, ...@@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
* disable and messages disabled. * disable and messages disabled.
*/ */
if (smi_info->supports_event_msg_buff || smi_info->irq) { if (smi_info->supports_event_msg_buff || smi_info->irq) {
start_check_enables(smi_info); start_check_enables(smi_info, true);
} else { } else {
smi_info->curr_msg = alloc_msg_handle_irq(smi_info); smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
if (!smi_info->curr_msg) if (!smi_info->curr_msg)
...@@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, ...@@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
} }
goto restart; 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: out:
return si_sm_result; return si_sm_result;
} }
...@@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = { ...@@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = {
.data = (void *)(unsigned long) SI_BT }, .data = (void *)(unsigned long) SI_BT },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, of_ipmi_match);
static int of_ipmi_probe(struct platform_device *dev) static int of_ipmi_probe(struct platform_device *dev)
{ {
...@@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev) ...@@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev)
} }
return 0; return 0;
} }
MODULE_DEVICE_TABLE(of, of_ipmi_match);
#else #else
#define of_ipmi_match NULL #define of_ipmi_match NULL
static int of_ipmi_probe(struct platform_device *dev) static int of_ipmi_probe(struct platform_device *dev)
...@@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi)
* Start clearing the flags before we enable interrupts or the * Start clearing the flags before we enable interrupts or the
* timer to avoid racing with the timer. * 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 * 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) ...@@ -3908,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
poll(to_clean); poll(to_clean);
schedule_timeout_uninterruptible(1); 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)) { while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean); poll(to_clean);
schedule_timeout_uninterruptible(1); schedule_timeout_uninterruptible(1);
......
...@@ -153,6 +153,9 @@ static int timeout = 10; ...@@ -153,6 +153,9 @@ static int timeout = 10;
/* The pre-timeout is disabled by default. */ /* The pre-timeout is disabled by default. */
static int pretimeout; static int pretimeout;
/* Default timeout to set on panic */
static int panic_wdt_timeout = 255;
/* Default action is to reset the board on a timeout. */ /* Default action is to reset the board on a timeout. */
static unsigned char action_val = WDOG_TIMEOUT_RESET; static unsigned char action_val = WDOG_TIMEOUT_RESET;
...@@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds."); ...@@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
module_param(pretimeout, timeout, 0644); module_param(pretimeout, timeout, 0644);
MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
module_param(panic_wdt_timeout, timeout, 0644);
MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds.");
module_param_cb(action, &param_ops_str, action_op, 0644); module_param_cb(action, &param_ops_str, action_op, 0644);
MODULE_PARM_DESC(action, "Timeout action. One of: " MODULE_PARM_DESC(action, "Timeout action. One of: "
"reset, none, power_cycle, power_off."); "reset, none, power_cycle, power_off.");
...@@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this, ...@@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this,
/* Make sure we do this only once. */ /* Make sure we do this only once. */
panic_event_handled = 1; panic_event_handled = 1;
timeout = 255; timeout = panic_wdt_timeout;
pretimeout = 0; pretimeout = 0;
panic_halt_ipmi_set_timeout(); panic_halt_ipmi_set_timeout();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment