Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Corey Minyard and committed by
Linus Torvalds
fcfa4724 650dd0c7

+83 -47
+9
drivers/char/ipmi/ipmi_msghandler.c
··· 2614 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 2625 int ipmi_register_smi(struct ipmi_smi_handlers *handlers, 2618 2626 void *send_info, 2619 2627 struct ipmi_device_id *device_id, ··· 4174 4166 EXPORT_SYMBOL(ipmi_get_version); 4175 4167 EXPORT_SYMBOL(ipmi_request_settime); 4176 4168 EXPORT_SYMBOL(ipmi_request_supply_msgs); 4169 + EXPORT_SYMBOL(ipmi_poll_interface); 4177 4170 EXPORT_SYMBOL(ipmi_register_smi); 4178 4171 EXPORT_SYMBOL(ipmi_unregister_smi); 4179 4172 EXPORT_SYMBOL(ipmi_register_for_cmd);
+5 -1
drivers/char/ipmi/ipmi_si_intf.c
··· 675 675 } 676 676 677 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 680 static enum si_sm_result smi_event_handler(struct smi_info *smi_info, 680 681 int time) 681 682 { ··· 893 892 static void poll(void *send_info) 894 893 { 895 894 struct smi_info *smi_info = send_info; 895 + unsigned long flags; 896 896 897 897 /* 898 898 * Make sure there is some delay in the poll loop so we can 899 899 * drive time forward and timeout things. 900 900 */ 901 901 udelay(10); 902 + spin_lock_irqsave(&smi_info->si_lock, flags); 902 903 smi_event_handler(smi_info, 10); 904 + spin_unlock_irqrestore(&smi_info->si_lock, flags); 903 905 } 904 906 905 907 static void request_events(void *send_info)
+59 -46
drivers/char/ipmi/ipmi_watchdog.c
··· 314 314 static atomic_t preop_panic_excl = ATOMIC_INIT(-1); 315 315 316 316 static int ipmi_heartbeat(void); 317 - static void panic_halt_ipmi_heartbeat(void); 318 - 319 317 320 318 /* We use a mutex to make sure that only one thing can send a set 321 319 timeout at one time, because we only have one copy of the data. ··· 438 440 return rv; 439 441 } 440 442 441 - static void dummy_smi_free(struct ipmi_smi_msg *msg) 443 + static atomic_t panic_done_count = ATOMIC_INIT(0); 444 + 445 + static void panic_smi_free(struct ipmi_smi_msg *msg) 442 446 { 447 + atomic_dec(&panic_done_count); 443 448 } 444 - static void dummy_recv_free(struct ipmi_recv_msg *msg) 449 + static void panic_recv_free(struct ipmi_recv_msg *msg) 445 450 { 451 + atomic_dec(&panic_done_count); 446 452 } 453 + 454 + static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = 455 + { 456 + .done = panic_smi_free 457 + }; 458 + static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = 459 + { 460 + .done = panic_recv_free 461 + }; 462 + 463 + static void panic_halt_ipmi_heartbeat(void) 464 + { 465 + struct kernel_ipmi_msg msg; 466 + struct ipmi_system_interface_addr addr; 467 + int rv; 468 + 469 + /* Don't reset the timer if we have the timer turned off, that 470 + re-enables the watchdog. */ 471 + if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) 472 + return; 473 + 474 + addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; 475 + addr.channel = IPMI_BMC_CHANNEL; 476 + addr.lun = 0; 477 + 478 + msg.netfn = 0x06; 479 + msg.cmd = IPMI_WDOG_RESET_TIMER; 480 + msg.data = NULL; 481 + msg.data_len = 0; 482 + rv = ipmi_request_supply_msgs(watchdog_user, 483 + (struct ipmi_addr *) &addr, 484 + 0, 485 + &msg, 486 + NULL, 487 + &panic_halt_heartbeat_smi_msg, 488 + &panic_halt_heartbeat_recv_msg, 489 + 1); 490 + if (!rv) 491 + atomic_add(2, &panic_done_count); 492 + } 493 + 447 494 static struct ipmi_smi_msg panic_halt_smi_msg = 448 495 { 449 - .done = dummy_smi_free 496 + .done = panic_smi_free 450 497 }; 451 498 static struct ipmi_recv_msg panic_halt_recv_msg = 452 499 { 453 - .done = dummy_recv_free 500 + .done = panic_recv_free 454 501 }; 455 502 456 503 /* Special call, doesn't claim any locks. This is only to be called ··· 507 464 int send_heartbeat_now; 508 465 int rv; 509 466 467 + /* Wait for the messages to be free. */ 468 + while (atomic_read(&panic_done_count) != 0) 469 + ipmi_poll_interface(watchdog_user); 510 470 rv = i_ipmi_set_timeout(&panic_halt_smi_msg, 511 471 &panic_halt_recv_msg, 512 472 &send_heartbeat_now); 513 473 if (!rv) { 474 + atomic_add(2, &panic_done_count); 514 475 if (send_heartbeat_now) 515 476 panic_halt_ipmi_heartbeat(); 516 - } 477 + } else 478 + printk(KERN_WARNING PFX 479 + "Unable to extend the watchdog timeout."); 480 + while (atomic_read(&panic_done_count) != 0) 481 + ipmi_poll_interface(watchdog_user); 517 482 } 518 483 519 484 /* We use a semaphore to make sure that only one thing can send a ··· 548 497 static struct ipmi_recv_msg heartbeat_recv_msg = 549 498 { 550 499 .done = heartbeat_free_recv 551 - }; 552 - 553 - static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = 554 - { 555 - .done = dummy_smi_free 556 - }; 557 - static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = 558 - { 559 - .done = dummy_recv_free 560 500 }; 561 501 562 502 static int ipmi_heartbeat(void) ··· 620 578 mutex_unlock(&heartbeat_lock); 621 579 622 580 return rv; 623 - } 624 - 625 - static void panic_halt_ipmi_heartbeat(void) 626 - { 627 - struct kernel_ipmi_msg msg; 628 - struct ipmi_system_interface_addr addr; 629 - 630 - 631 - /* Don't reset the timer if we have the timer turned off, that 632 - re-enables the watchdog. */ 633 - if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) 634 - return; 635 - 636 - addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; 637 - addr.channel = IPMI_BMC_CHANNEL; 638 - addr.lun = 0; 639 - 640 - msg.netfn = 0x06; 641 - msg.cmd = IPMI_WDOG_RESET_TIMER; 642 - msg.data = NULL; 643 - msg.data_len = 0; 644 - ipmi_request_supply_msgs(watchdog_user, 645 - (struct ipmi_addr *) &addr, 646 - 0, 647 - &msg, 648 - NULL, 649 - &panic_halt_heartbeat_smi_msg, 650 - &panic_halt_heartbeat_recv_msg, 651 - 1); 652 581 } 653 582 654 583 static struct watchdog_info ident = ··· 1011 998 /* Make sure we only do this once. */ 1012 999 reboot_event_handled = 1; 1013 1000 1014 - if (code == SYS_DOWN || code == SYS_HALT) { 1001 + if (code == SYS_POWER_OFF || code == SYS_HALT) { 1015 1002 /* Disable the WDT if we are shutting down. */ 1016 1003 ipmi_watchdog_state = WDOG_TIMEOUT_NONE; 1017 1004 panic_halt_ipmi_set_timeout();
+10
include/linux/ipmi.h
··· 365 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 378 * When commands come in to the SMS, the user can register to receive 369 379 * them. Only one user can be listening on a specific netfn/cmd/chan tuple 370 380 * at a time, you will get an EBUSY error if the command is already