diff options
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 9 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 6 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 105 | ||||
-rw-r--r-- | include/linux/ipmi.h | 10 |
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 | ||
2617 | void 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 | |||
2617 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | 2625 | int 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); | |||
4166 | EXPORT_SYMBOL(ipmi_get_version); | 4174 | EXPORT_SYMBOL(ipmi_get_version); |
4167 | EXPORT_SYMBOL(ipmi_request_settime); | 4175 | EXPORT_SYMBOL(ipmi_request_settime); |
4168 | EXPORT_SYMBOL(ipmi_request_supply_msgs); | 4176 | EXPORT_SYMBOL(ipmi_request_supply_msgs); |
4177 | EXPORT_SYMBOL(ipmi_poll_interface); | ||
4169 | EXPORT_SYMBOL(ipmi_register_smi); | 4178 | EXPORT_SYMBOL(ipmi_register_smi); |
4170 | EXPORT_SYMBOL(ipmi_unregister_smi); | 4179 | EXPORT_SYMBOL(ipmi_unregister_smi); |
4171 | EXPORT_SYMBOL(ipmi_register_for_cmd); | 4180 | EXPORT_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. */ | ||
679 | static enum si_sm_result smi_event_handler(struct smi_info *smi_info, | 680 | static 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) | |||
892 | static void poll(void *send_info) | 893 | static 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 | ||
904 | static void request_events(void *send_info) | 908 | static 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; | |||
314 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); | 314 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); |
315 | 315 | ||
316 | static int ipmi_heartbeat(void); | 316 | static int ipmi_heartbeat(void); |
317 | static 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 | ||
443 | static void dummy_smi_free(struct ipmi_smi_msg *msg) | 441 | static atomic_t panic_done_count = ATOMIC_INIT(0); |
442 | |||
443 | static void panic_smi_free(struct ipmi_smi_msg *msg) | ||
444 | { | 444 | { |
445 | atomic_dec(&panic_done_count); | ||
445 | } | 446 | } |
446 | static void dummy_recv_free(struct ipmi_recv_msg *msg) | 447 | static void panic_recv_free(struct ipmi_recv_msg *msg) |
448 | { | ||
449 | atomic_dec(&panic_done_count); | ||
450 | } | ||
451 | |||
452 | static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = | ||
453 | { | ||
454 | .done = panic_smi_free | ||
455 | }; | ||
456 | static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = | ||
447 | { | 457 | { |
458 | .done = panic_recv_free | ||
459 | }; | ||
460 | |||
461 | static 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 | |||
449 | static struct ipmi_smi_msg panic_halt_smi_msg = | 492 | static struct ipmi_smi_msg panic_halt_smi_msg = |
450 | { | 493 | { |
451 | .done = dummy_smi_free | 494 | .done = panic_smi_free |
452 | }; | 495 | }; |
453 | static struct ipmi_recv_msg panic_halt_recv_msg = | 496 | static 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 | ||
502 | static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = | ||
503 | { | ||
504 | .done = dummy_smi_free | ||
505 | }; | ||
506 | static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = | ||
507 | { | ||
508 | .done = dummy_recv_free | ||
509 | }; | ||
510 | |||
511 | static int ipmi_heartbeat(void) | 553 | static 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 | ||
583 | static 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 | |||
612 | static struct watchdog_info ident = | 625 | static 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 | */ | ||
375 | void 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 |