aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2007-10-18 06:07:09 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:32 -0400
commitfcfa4724116589d6a5fac92af410b6f12d41b5bb (patch)
treee709e6e51e8475836f56478a4645bbeeb8daf134 /drivers/char/ipmi
parent650dd0c7faf8126aaa261833dc9171a070deeaf3 (diff)
IPMI: add polled interface
Currently the IPMI watchdog timer sets the watchdog timeout on a panic, but it doesn't actually poll the interface to make sure the message goes out. Add an interface for polling the IPMI driver, and add code to the IPMI watchdog timer to poll the interface when the timer is set from a panic. Signed-off-by: Corey Minyard <cminyard@mvista.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c9
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c6
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c105
3 files changed, 73 insertions, 47 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 8435fba73daf..46d14ac16212 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2614,6 +2614,14 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2614 return; 2614 return;
2615} 2615}
2616 2616
2617void ipmi_poll_interface(ipmi_user_t user)
2618{
2619 ipmi_smi_t intf = user->intf;
2620
2621 if (intf->handlers->poll)
2622 intf->handlers->poll(intf->send_info);
2623}
2624
2617int ipmi_register_smi(struct ipmi_smi_handlers *handlers, 2625int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
2618 void *send_info, 2626 void *send_info,
2619 struct ipmi_device_id *device_id, 2627 struct ipmi_device_id *device_id,
@@ -4166,6 +4174,7 @@ EXPORT_SYMBOL(ipmi_destroy_user);
4166EXPORT_SYMBOL(ipmi_get_version); 4174EXPORT_SYMBOL(ipmi_get_version);
4167EXPORT_SYMBOL(ipmi_request_settime); 4175EXPORT_SYMBOL(ipmi_request_settime);
4168EXPORT_SYMBOL(ipmi_request_supply_msgs); 4176EXPORT_SYMBOL(ipmi_request_supply_msgs);
4177EXPORT_SYMBOL(ipmi_poll_interface);
4169EXPORT_SYMBOL(ipmi_register_smi); 4178EXPORT_SYMBOL(ipmi_register_smi);
4170EXPORT_SYMBOL(ipmi_unregister_smi); 4179EXPORT_SYMBOL(ipmi_unregister_smi);
4171EXPORT_SYMBOL(ipmi_register_for_cmd); 4180EXPORT_SYMBOL(ipmi_register_for_cmd);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e018932af795..da09eb0ef788 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -675,7 +675,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
675} 675}
676 676
677/* Called on timeouts and events. Timeouts should pass the elapsed 677/* Called on timeouts and events. Timeouts should pass the elapsed
678 time, interrupts should pass in zero. */ 678 time, interrupts should pass in zero. Must be called with
679 si_lock held and interrupts disabled. */
679static enum si_sm_result smi_event_handler(struct smi_info *smi_info, 680static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
680 int time) 681 int time)
681{ 682{
@@ -892,13 +893,16 @@ static int ipmi_thread(void *data)
892static void poll(void *send_info) 893static void poll(void *send_info)
893{ 894{
894 struct smi_info *smi_info = send_info; 895 struct smi_info *smi_info = send_info;
896 unsigned long flags;
895 897
896 /* 898 /*
897 * Make sure there is some delay in the poll loop so we can 899 * Make sure there is some delay in the poll loop so we can
898 * drive time forward and timeout things. 900 * drive time forward and timeout things.
899 */ 901 */
900 udelay(10); 902 udelay(10);
903 spin_lock_irqsave(&smi_info->si_lock, flags);
901 smi_event_handler(smi_info, 10); 904 smi_event_handler(smi_info, 10);
905 spin_unlock_irqrestore(&smi_info->si_lock, flags);
902} 906}
903 907
904static void request_events(void *send_info) 908static void request_events(void *send_info)
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 806106b8c980..19a8683bd25d 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -314,8 +314,6 @@ static unsigned char ipmi_version_minor;
314static atomic_t preop_panic_excl = ATOMIC_INIT(-1); 314static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
315 315
316static int ipmi_heartbeat(void); 316static int ipmi_heartbeat(void);
317static void panic_halt_ipmi_heartbeat(void);
318
319 317
320/* We use a mutex to make sure that only one thing can send a set 318/* We use a mutex to make sure that only one thing can send a set
321 timeout at one time, because we only have one copy of the data. 319 timeout at one time, because we only have one copy of the data.
@@ -440,19 +438,64 @@ out:
440 return rv; 438 return rv;
441} 439}
442 440
443static void dummy_smi_free(struct ipmi_smi_msg *msg) 441static atomic_t panic_done_count = ATOMIC_INIT(0);
442
443static void panic_smi_free(struct ipmi_smi_msg *msg)
444{ 444{
445 atomic_dec(&panic_done_count);
445} 446}
446static void dummy_recv_free(struct ipmi_recv_msg *msg) 447static void panic_recv_free(struct ipmi_recv_msg *msg)
448{
449 atomic_dec(&panic_done_count);
450}
451
452static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
453{
454 .done = panic_smi_free
455};
456static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
447{ 457{
458 .done = panic_recv_free
459};
460
461static void panic_halt_ipmi_heartbeat(void)
462{
463 struct kernel_ipmi_msg msg;
464 struct ipmi_system_interface_addr addr;
465 int rv;
466
467 /* Don't reset the timer if we have the timer turned off, that
468 re-enables the watchdog. */
469 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
470 return;
471
472 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
473 addr.channel = IPMI_BMC_CHANNEL;
474 addr.lun = 0;
475
476 msg.netfn = 0x06;
477 msg.cmd = IPMI_WDOG_RESET_TIMER;
478 msg.data = NULL;
479 msg.data_len = 0;
480 rv = ipmi_request_supply_msgs(watchdog_user,
481 (struct ipmi_addr *) &addr,
482 0,
483 &msg,
484 NULL,
485 &panic_halt_heartbeat_smi_msg,
486 &panic_halt_heartbeat_recv_msg,
487 1);
488 if (!rv)
489 atomic_add(2, &panic_done_count);
448} 490}
491
449static struct ipmi_smi_msg panic_halt_smi_msg = 492static struct ipmi_smi_msg panic_halt_smi_msg =
450{ 493{
451 .done = dummy_smi_free 494 .done = panic_smi_free
452}; 495};
453static struct ipmi_recv_msg panic_halt_recv_msg = 496static struct ipmi_recv_msg panic_halt_recv_msg =
454{ 497{
455 .done = dummy_recv_free 498 .done = panic_recv_free
456}; 499};
457 500
458/* Special call, doesn't claim any locks. This is only to be called 501/* Special call, doesn't claim any locks. This is only to be called
@@ -464,13 +507,21 @@ static void panic_halt_ipmi_set_timeout(void)
464 int send_heartbeat_now; 507 int send_heartbeat_now;
465 int rv; 508 int rv;
466 509
510 /* Wait for the messages to be free. */
511 while (atomic_read(&panic_done_count) != 0)
512 ipmi_poll_interface(watchdog_user);
467 rv = i_ipmi_set_timeout(&panic_halt_smi_msg, 513 rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
468 &panic_halt_recv_msg, 514 &panic_halt_recv_msg,
469 &send_heartbeat_now); 515 &send_heartbeat_now);
470 if (!rv) { 516 if (!rv) {
517 atomic_add(2, &panic_done_count);
471 if (send_heartbeat_now) 518 if (send_heartbeat_now)
472 panic_halt_ipmi_heartbeat(); 519 panic_halt_ipmi_heartbeat();
473 } 520 } else
521 printk(KERN_WARNING PFX
522 "Unable to extend the watchdog timeout.");
523 while (atomic_read(&panic_done_count) != 0)
524 ipmi_poll_interface(watchdog_user);
474} 525}
475 526
476/* We use a semaphore to make sure that only one thing can send a 527/* We use a semaphore to make sure that only one thing can send a
@@ -499,15 +550,6 @@ static struct ipmi_recv_msg heartbeat_recv_msg =
499 .done = heartbeat_free_recv 550 .done = heartbeat_free_recv
500}; 551};
501 552
502static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
503{
504 .done = dummy_smi_free
505};
506static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
507{
508 .done = dummy_recv_free
509};
510
511static int ipmi_heartbeat(void) 553static int ipmi_heartbeat(void)
512{ 554{
513 struct kernel_ipmi_msg msg; 555 struct kernel_ipmi_msg msg;
@@ -580,35 +622,6 @@ static int ipmi_heartbeat(void)
580 return rv; 622 return rv;
581} 623}
582 624
583static void panic_halt_ipmi_heartbeat(void)
584{
585 struct kernel_ipmi_msg msg;
586 struct ipmi_system_interface_addr addr;
587
588
589 /* Don't reset the timer if we have the timer turned off, that
590 re-enables the watchdog. */
591 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
592 return;
593
594 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
595 addr.channel = IPMI_BMC_CHANNEL;
596 addr.lun = 0;
597
598 msg.netfn = 0x06;
599 msg.cmd = IPMI_WDOG_RESET_TIMER;
600 msg.data = NULL;
601 msg.data_len = 0;
602 ipmi_request_supply_msgs(watchdog_user,
603 (struct ipmi_addr *) &addr,
604 0,
605 &msg,
606 NULL,
607 &panic_halt_heartbeat_smi_msg,
608 &panic_halt_heartbeat_recv_msg,
609 1);
610}
611
612static struct watchdog_info ident = 625static struct watchdog_info ident =
613{ 626{
614 .options = 0, /* WDIOF_SETTIMEOUT, */ 627 .options = 0, /* WDIOF_SETTIMEOUT, */
@@ -998,7 +1011,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
998 /* Make sure we only do this once. */ 1011 /* Make sure we only do this once. */
999 reboot_event_handled = 1; 1012 reboot_event_handled = 1;
1000 1013
1001 if (code == SYS_DOWN || code == SYS_HALT) { 1014 if (code == SYS_POWER_OFF || code == SYS_HALT) {
1002 /* Disable the WDT if we are shutting down. */ 1015 /* Disable the WDT if we are shutting down. */
1003 ipmi_watchdog_state = WDOG_TIMEOUT_NONE; 1016 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
1004 panic_halt_ipmi_set_timeout(); 1017 panic_halt_ipmi_set_timeout();