aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--include/linux/ipmi.h10
4 files changed, 83 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();
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 7a9db390c56a..c5bd28b69aec 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -365,6 +365,16 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
365 int priority); 365 int priority);
366 366
367/* 367/*
368 * Poll the IPMI interface for the user. This causes the IPMI code to
369 * do an immediate check for information from the driver and handle
370 * anything that is immediately pending. This will not block in any
371 * way. This is useful if you need to implement polling from the user
372 * for things like modifying the watchdog timeout when a panic occurs
373 * or disabling the watchdog timer on a reboot.
374 */
375void ipmi_poll_interface(ipmi_user_t user);
376
377/*
368 * When commands come in to the SMS, the user can register to receive 378 * When commands come in to the SMS, the user can register to receive
369 * them. Only one user can be listening on a specific netfn/cmd/chan tuple 379 * them. Only one user can be listening on a specific netfn/cmd/chan tuple
370 * at a time, you will get an EBUSY error if the command is already 380 * at a time, you will get an EBUSY error if the command is already