diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_watchdog.c')
| -rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 268 |
1 files changed, 167 insertions, 101 deletions
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 41f78e2c158..e686fc92516 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
| @@ -50,10 +50,19 @@ | |||
| 50 | #include <linux/poll.h> | 50 | #include <linux/poll.h> |
| 51 | #include <linux/string.h> | 51 | #include <linux/string.h> |
| 52 | #include <linux/ctype.h> | 52 | #include <linux/ctype.h> |
| 53 | #include <linux/delay.h> | ||
| 53 | #include <asm/atomic.h> | 54 | #include <asm/atomic.h> |
| 54 | 55 | ||
| 55 | #ifdef CONFIG_X86_LOCAL_APIC | 56 | #ifdef CONFIG_X86 |
| 56 | #include <asm/apic.h> | 57 | /* This is ugly, but I've determined that x86 is the only architecture |
| 58 | that can reasonably support the IPMI NMI watchdog timeout at this | ||
| 59 | time. If another architecture adds this capability somehow, it | ||
| 60 | will have to be a somewhat different mechanism and I have no idea | ||
| 61 | how it will work. So in the unlikely event that another | ||
| 62 | architecture supports this, we can figure out a good generic | ||
| 63 | mechanism for it at that time. */ | ||
| 64 | #include <asm/kdebug.h> | ||
| 65 | #define HAVE_DIE_NMI | ||
| 57 | #endif | 66 | #endif |
| 58 | 67 | ||
| 59 | #define PFX "IPMI Watchdog: " | 68 | #define PFX "IPMI Watchdog: " |
| @@ -166,8 +175,6 @@ static char expect_close; | |||
| 166 | 175 | ||
| 167 | static int ifnum_to_use = -1; | 176 | static int ifnum_to_use = -1; |
| 168 | 177 | ||
| 169 | static DECLARE_RWSEM(register_sem); | ||
| 170 | |||
| 171 | /* Parameters to ipmi_set_timeout */ | 178 | /* Parameters to ipmi_set_timeout */ |
| 172 | #define IPMI_SET_TIMEOUT_NO_HB 0 | 179 | #define IPMI_SET_TIMEOUT_NO_HB 0 |
| 173 | #define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1 | 180 | #define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1 |
| @@ -193,11 +200,9 @@ static int set_param_int(const char *val, struct kernel_param *kp) | |||
| 193 | if (endp == val) | 200 | if (endp == val) |
| 194 | return -EINVAL; | 201 | return -EINVAL; |
| 195 | 202 | ||
| 196 | down_read(®ister_sem); | ||
| 197 | *((int *)kp->arg) = l; | 203 | *((int *)kp->arg) = l; |
| 198 | if (watchdog_user) | 204 | if (watchdog_user) |
| 199 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | 205 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); |
| 200 | up_read(®ister_sem); | ||
| 201 | 206 | ||
| 202 | return rv; | 207 | return rv; |
| 203 | } | 208 | } |
| @@ -226,17 +231,15 @@ static int set_param_str(const char *val, struct kernel_param *kp) | |||
| 226 | 231 | ||
| 227 | s = strstrip(valcp); | 232 | s = strstrip(valcp); |
| 228 | 233 | ||
| 229 | down_read(®ister_sem); | ||
| 230 | rv = fn(s, NULL); | 234 | rv = fn(s, NULL); |
| 231 | if (rv) | 235 | if (rv) |
| 232 | goto out_unlock; | 236 | goto out; |
| 233 | 237 | ||
| 234 | check_parms(); | 238 | check_parms(); |
| 235 | if (watchdog_user) | 239 | if (watchdog_user) |
| 236 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | 240 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); |
| 237 | 241 | ||
| 238 | out_unlock: | 242 | out: |
| 239 | up_read(®ister_sem); | ||
| 240 | return rv; | 243 | return rv; |
| 241 | } | 244 | } |
| 242 | 245 | ||
| @@ -319,9 +322,12 @@ static unsigned char ipmi_version_minor; | |||
| 319 | /* If a pretimeout occurs, this is used to allow only one panic to happen. */ | 322 | /* If a pretimeout occurs, this is used to allow only one panic to happen. */ |
| 320 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); | 323 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); |
| 321 | 324 | ||
| 322 | static int ipmi_heartbeat(void); | 325 | #ifdef HAVE_DIE_NMI |
| 323 | static void panic_halt_ipmi_heartbeat(void); | 326 | static int testing_nmi; |
| 327 | static int nmi_handler_registered; | ||
| 328 | #endif | ||
| 324 | 329 | ||
| 330 | static int ipmi_heartbeat(void); | ||
| 325 | 331 | ||
| 326 | /* We use a mutex to make sure that only one thing can send a set | 332 | /* We use a mutex to make sure that only one thing can send a set |
| 327 | timeout at one time, because we only have one copy of the data. | 333 | timeout at one time, because we only have one copy of the data. |
| @@ -360,6 +366,9 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, | |||
| 360 | int hbnow = 0; | 366 | int hbnow = 0; |
| 361 | 367 | ||
| 362 | 368 | ||
| 369 | /* These can be cleared as we are setting the timeout. */ | ||
| 370 | pretimeout_since_last_heartbeat = 0; | ||
| 371 | |||
| 363 | data[0] = 0; | 372 | data[0] = 0; |
| 364 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); | 373 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); |
| 365 | 374 | ||
| @@ -434,31 +443,75 @@ static int ipmi_set_timeout(int do_heartbeat) | |||
| 434 | 443 | ||
| 435 | wait_for_completion(&set_timeout_wait); | 444 | wait_for_completion(&set_timeout_wait); |
| 436 | 445 | ||
| 446 | mutex_unlock(&set_timeout_lock); | ||
| 447 | |||
| 437 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) | 448 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) |
| 438 | || ((send_heartbeat_now) | 449 | || ((send_heartbeat_now) |
| 439 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) | 450 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) |
| 440 | { | ||
| 441 | rv = ipmi_heartbeat(); | 451 | rv = ipmi_heartbeat(); |
| 442 | } | ||
| 443 | mutex_unlock(&set_timeout_lock); | ||
| 444 | 452 | ||
| 445 | out: | 453 | out: |
| 446 | return rv; | 454 | return rv; |
| 447 | } | 455 | } |
| 448 | 456 | ||
| 449 | static void dummy_smi_free(struct ipmi_smi_msg *msg) | 457 | static atomic_t panic_done_count = ATOMIC_INIT(0); |
| 458 | |||
| 459 | static void panic_smi_free(struct ipmi_smi_msg *msg) | ||
| 450 | { | 460 | { |
| 461 | atomic_dec(&panic_done_count); | ||
| 451 | } | 462 | } |
| 452 | static void dummy_recv_free(struct ipmi_recv_msg *msg) | 463 | static void panic_recv_free(struct ipmi_recv_msg *msg) |
| 453 | { | 464 | { |
| 465 | atomic_dec(&panic_done_count); | ||
| 466 | } | ||
| 467 | |||
| 468 | static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = | ||
| 469 | { | ||
| 470 | .done = panic_smi_free | ||
| 471 | }; | ||
| 472 | static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = | ||
| 473 | { | ||
| 474 | .done = panic_recv_free | ||
| 475 | }; | ||
| 476 | |||
| 477 | static void panic_halt_ipmi_heartbeat(void) | ||
| 478 | { | ||
| 479 | struct kernel_ipmi_msg msg; | ||
| 480 | struct ipmi_system_interface_addr addr; | ||
| 481 | int rv; | ||
| 482 | |||
| 483 | /* Don't reset the timer if we have the timer turned off, that | ||
| 484 | re-enables the watchdog. */ | ||
| 485 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | ||
| 486 | return; | ||
| 487 | |||
| 488 | addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
| 489 | addr.channel = IPMI_BMC_CHANNEL; | ||
| 490 | addr.lun = 0; | ||
| 491 | |||
| 492 | msg.netfn = 0x06; | ||
| 493 | msg.cmd = IPMI_WDOG_RESET_TIMER; | ||
| 494 | msg.data = NULL; | ||
| 495 | msg.data_len = 0; | ||
| 496 | rv = ipmi_request_supply_msgs(watchdog_user, | ||
| 497 | (struct ipmi_addr *) &addr, | ||
| 498 | 0, | ||
| 499 | &msg, | ||
| 500 | NULL, | ||
| 501 | &panic_halt_heartbeat_smi_msg, | ||
| 502 | &panic_halt_heartbeat_recv_msg, | ||
| 503 | 1); | ||
| 504 | if (!rv) | ||
| 505 | atomic_add(2, &panic_done_count); | ||
| 454 | } | 506 | } |
| 507 | |||
| 455 | static struct ipmi_smi_msg panic_halt_smi_msg = | 508 | static struct ipmi_smi_msg panic_halt_smi_msg = |
| 456 | { | 509 | { |
| 457 | .done = dummy_smi_free | 510 | .done = panic_smi_free |
| 458 | }; | 511 | }; |
| 459 | static struct ipmi_recv_msg panic_halt_recv_msg = | 512 | static struct ipmi_recv_msg panic_halt_recv_msg = |
| 460 | { | 513 | { |
| 461 | .done = dummy_recv_free | 514 | .done = panic_recv_free |
| 462 | }; | 515 | }; |
| 463 | 516 | ||
| 464 | /* Special call, doesn't claim any locks. This is only to be called | 517 | /* Special call, doesn't claim any locks. This is only to be called |
| @@ -470,13 +523,21 @@ static void panic_halt_ipmi_set_timeout(void) | |||
| 470 | int send_heartbeat_now; | 523 | int send_heartbeat_now; |
| 471 | int rv; | 524 | int rv; |
| 472 | 525 | ||
| 526 | /* Wait for the messages to be free. */ | ||
| 527 | while (atomic_read(&panic_done_count) != 0) | ||
| 528 | ipmi_poll_interface(watchdog_user); | ||
| 473 | rv = i_ipmi_set_timeout(&panic_halt_smi_msg, | 529 | rv = i_ipmi_set_timeout(&panic_halt_smi_msg, |
| 474 | &panic_halt_recv_msg, | 530 | &panic_halt_recv_msg, |
| 475 | &send_heartbeat_now); | 531 | &send_heartbeat_now); |
| 476 | if (!rv) { | 532 | if (!rv) { |
| 533 | atomic_add(2, &panic_done_count); | ||
| 477 | if (send_heartbeat_now) | 534 | if (send_heartbeat_now) |
| 478 | panic_halt_ipmi_heartbeat(); | 535 | panic_halt_ipmi_heartbeat(); |
| 479 | } | 536 | } else |
| 537 | printk(KERN_WARNING PFX | ||
| 538 | "Unable to extend the watchdog timeout."); | ||
| 539 | while (atomic_read(&panic_done_count) != 0) | ||
| 540 | ipmi_poll_interface(watchdog_user); | ||
| 480 | } | 541 | } |
| 481 | 542 | ||
| 482 | /* We use a semaphore to make sure that only one thing can send a | 543 | /* We use a semaphore to make sure that only one thing can send a |
| @@ -505,24 +566,14 @@ static struct ipmi_recv_msg heartbeat_recv_msg = | |||
| 505 | .done = heartbeat_free_recv | 566 | .done = heartbeat_free_recv |
| 506 | }; | 567 | }; |
| 507 | 568 | ||
| 508 | static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = | ||
| 509 | { | ||
| 510 | .done = dummy_smi_free | ||
| 511 | }; | ||
| 512 | static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = | ||
| 513 | { | ||
| 514 | .done = dummy_recv_free | ||
| 515 | }; | ||
| 516 | |||
| 517 | static int ipmi_heartbeat(void) | 569 | static int ipmi_heartbeat(void) |
| 518 | { | 570 | { |
| 519 | struct kernel_ipmi_msg msg; | 571 | struct kernel_ipmi_msg msg; |
| 520 | int rv; | 572 | int rv; |
| 521 | struct ipmi_system_interface_addr addr; | 573 | struct ipmi_system_interface_addr addr; |
| 522 | 574 | ||
| 523 | if (ipmi_ignore_heartbeat) { | 575 | if (ipmi_ignore_heartbeat) |
| 524 | return 0; | 576 | return 0; |
| 525 | } | ||
| 526 | 577 | ||
| 527 | if (ipmi_start_timer_on_heartbeat) { | 578 | if (ipmi_start_timer_on_heartbeat) { |
| 528 | ipmi_start_timer_on_heartbeat = 0; | 579 | ipmi_start_timer_on_heartbeat = 0; |
| @@ -533,7 +584,6 @@ static int ipmi_heartbeat(void) | |||
| 533 | We don't want to set the action, though, we want to | 584 | We don't want to set the action, though, we want to |
| 534 | leave that alone (thus it can't be combined with the | 585 | leave that alone (thus it can't be combined with the |
| 535 | above operation. */ | 586 | above operation. */ |
| 536 | pretimeout_since_last_heartbeat = 0; | ||
| 537 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | 587 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); |
| 538 | } | 588 | } |
| 539 | 589 | ||
| @@ -586,35 +636,6 @@ static int ipmi_heartbeat(void) | |||
| 586 | return rv; | 636 | return rv; |
| 587 | } | 637 | } |
| 588 | 638 | ||
| 589 | static void panic_halt_ipmi_heartbeat(void) | ||
| 590 | { | ||
| 591 | struct kernel_ipmi_msg msg; | ||
| 592 | struct ipmi_system_interface_addr addr; | ||
| 593 | |||
| 594 | |||
| 595 | /* Don't reset the timer if we have the timer turned off, that | ||
| 596 | re-enables the watchdog. */ | ||
| 597 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | ||
| 598 | return; | ||
| 599 | |||
| 600 | addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
| 601 | addr.channel = IPMI_BMC_CHANNEL; | ||
| 602 | addr.lun = 0; | ||
| 603 | |||
| 604 | msg.netfn = 0x06; | ||
| 605 | msg.cmd = IPMI_WDOG_RESET_TIMER; | ||
| 606 | msg.data = NULL; | ||
| 607 | msg.data_len = 0; | ||
| 608 | ipmi_request_supply_msgs(watchdog_user, | ||
| 609 | (struct ipmi_addr *) &addr, | ||
| 610 | 0, | ||
| 611 | &msg, | ||
| 612 | NULL, | ||
| 613 | &panic_halt_heartbeat_smi_msg, | ||
| 614 | &panic_halt_heartbeat_recv_msg, | ||
| 615 | 1); | ||
| 616 | } | ||
| 617 | |||
| 618 | static struct watchdog_info ident = | 639 | static struct watchdog_info ident = |
| 619 | { | 640 | { |
| 620 | .options = 0, /* WDIOF_SETTIMEOUT, */ | 641 | .options = 0, /* WDIOF_SETTIMEOUT, */ |
| @@ -895,7 +916,6 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
| 895 | { | 916 | { |
| 896 | int rv = -EBUSY; | 917 | int rv = -EBUSY; |
| 897 | 918 | ||
| 898 | down_write(®ister_sem); | ||
| 899 | if (watchdog_user) | 919 | if (watchdog_user) |
| 900 | goto out; | 920 | goto out; |
| 901 | 921 | ||
| @@ -921,15 +941,56 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
| 921 | printk(KERN_CRIT PFX "Unable to register misc device\n"); | 941 | printk(KERN_CRIT PFX "Unable to register misc device\n"); |
| 922 | } | 942 | } |
| 923 | 943 | ||
| 924 | out: | 944 | #ifdef HAVE_DIE_NMI |
| 925 | up_write(®ister_sem); | 945 | if (nmi_handler_registered) { |
| 946 | int old_pretimeout = pretimeout; | ||
| 947 | int old_timeout = timeout; | ||
| 948 | int old_preop_val = preop_val; | ||
| 949 | |||
| 950 | /* Set the pretimeout to go off in a second and give | ||
| 951 | ourselves plenty of time to stop the timer. */ | ||
| 952 | ipmi_watchdog_state = WDOG_TIMEOUT_RESET; | ||
| 953 | preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ | ||
| 954 | pretimeout = 99; | ||
| 955 | timeout = 100; | ||
| 956 | |||
| 957 | testing_nmi = 1; | ||
| 958 | |||
| 959 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | ||
| 960 | if (rv) { | ||
| 961 | printk(KERN_WARNING PFX "Error starting timer to" | ||
| 962 | " test NMI: 0x%x. The NMI pretimeout will" | ||
| 963 | " likely not work\n", rv); | ||
| 964 | rv = 0; | ||
| 965 | goto out_restore; | ||
| 966 | } | ||
| 967 | |||
| 968 | msleep(1500); | ||
| 926 | 969 | ||
| 970 | if (testing_nmi != 2) { | ||
| 971 | printk(KERN_WARNING PFX "IPMI NMI didn't seem to" | ||
| 972 | " occur. The NMI pretimeout will" | ||
| 973 | " likely not work\n"); | ||
| 974 | } | ||
| 975 | out_restore: | ||
| 976 | testing_nmi = 0; | ||
| 977 | preop_val = old_preop_val; | ||
| 978 | pretimeout = old_pretimeout; | ||
| 979 | timeout = old_timeout; | ||
| 980 | } | ||
| 981 | #endif | ||
| 982 | |||
| 983 | out: | ||
| 927 | if ((start_now) && (rv == 0)) { | 984 | if ((start_now) && (rv == 0)) { |
| 928 | /* Run from startup, so start the timer now. */ | 985 | /* Run from startup, so start the timer now. */ |
| 929 | start_now = 0; /* Disable this function after first startup. */ | 986 | start_now = 0; /* Disable this function after first startup. */ |
| 930 | ipmi_watchdog_state = action_val; | 987 | ipmi_watchdog_state = action_val; |
| 931 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | 988 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); |
| 932 | printk(KERN_INFO PFX "Starting now!\n"); | 989 | printk(KERN_INFO PFX "Starting now!\n"); |
| 990 | } else { | ||
| 991 | /* Stop the timer now. */ | ||
| 992 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
| 993 | ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); | ||
| 933 | } | 994 | } |
| 934 | } | 995 | } |
| 935 | 996 | ||
| @@ -937,8 +998,6 @@ static void ipmi_unregister_watchdog(int ipmi_intf) | |||
| 937 | { | 998 | { |
| 938 | int rv; | 999 | int rv; |
| 939 | 1000 | ||
| 940 | down_write(®ister_sem); | ||
| 941 | |||
| 942 | if (!watchdog_user) | 1001 | if (!watchdog_user) |
| 943 | goto out; | 1002 | goto out; |
| 944 | 1003 | ||
| @@ -963,20 +1022,44 @@ static void ipmi_unregister_watchdog(int ipmi_intf) | |||
| 963 | watchdog_user = NULL; | 1022 | watchdog_user = NULL; |
| 964 | 1023 | ||
| 965 | out: | 1024 | out: |
| 966 | up_write(®ister_sem); | 1025 | return; |
| 967 | } | 1026 | } |
| 968 | 1027 | ||
| 969 | #ifdef HAVE_NMI_HANDLER | 1028 | #ifdef HAVE_DIE_NMI |
| 970 | static int | 1029 | static int |
| 971 | ipmi_nmi(void *dev_id, int cpu, int handled) | 1030 | ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) |
| 972 | { | 1031 | { |
| 1032 | struct die_args *args = data; | ||
| 1033 | |||
| 1034 | if (val != DIE_NMI) | ||
| 1035 | return NOTIFY_OK; | ||
| 1036 | |||
| 1037 | /* Hack, if it's a memory or I/O error, ignore it. */ | ||
| 1038 | if (args->err & 0xc0) | ||
| 1039 | return NOTIFY_OK; | ||
| 1040 | |||
| 1041 | /* | ||
| 1042 | * If we get here, it's an NMI that's not a memory or I/O | ||
| 1043 | * error. We can't truly tell if it's from IPMI or not | ||
| 1044 | * without sending a message, and sending a message is almost | ||
| 1045 | * impossible because of locking. | ||
| 1046 | */ | ||
| 1047 | |||
| 1048 | if (testing_nmi) { | ||
| 1049 | testing_nmi = 2; | ||
| 1050 | return NOTIFY_STOP; | ||
| 1051 | } | ||
| 1052 | |||
| 973 | /* If we are not expecting a timeout, ignore it. */ | 1053 | /* If we are not expecting a timeout, ignore it. */ |
| 974 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | 1054 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) |
| 975 | return NOTIFY_DONE; | 1055 | return NOTIFY_OK; |
| 1056 | |||
| 1057 | if (preaction_val != WDOG_PRETIMEOUT_NMI) | ||
| 1058 | return NOTIFY_OK; | ||
| 976 | 1059 | ||
| 977 | /* If no one else handled the NMI, we assume it was the IPMI | 1060 | /* If no one else handled the NMI, we assume it was the IPMI |
| 978 | watchdog. */ | 1061 | watchdog. */ |
| 979 | if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { | 1062 | if (preop_val == WDOG_PREOP_PANIC) { |
| 980 | /* On some machines, the heartbeat will give | 1063 | /* On some machines, the heartbeat will give |
| 981 | an error and not work unless we re-enable | 1064 | an error and not work unless we re-enable |
| 982 | the timer. So do so. */ | 1065 | the timer. So do so. */ |
| @@ -985,18 +1068,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled) | |||
| 985 | panic(PFX "pre-timeout"); | 1068 | panic(PFX "pre-timeout"); |
| 986 | } | 1069 | } |
| 987 | 1070 | ||
| 988 | return NOTIFY_DONE; | 1071 | return NOTIFY_STOP; |
| 989 | } | 1072 | } |
| 990 | 1073 | ||
| 991 | static struct nmi_handler ipmi_nmi_handler = | 1074 | static struct notifier_block ipmi_nmi_handler = { |
| 992 | { | 1075 | .notifier_call = ipmi_nmi |
| 993 | .link = LIST_HEAD_INIT(ipmi_nmi_handler.link), | ||
| 994 | .dev_name = "ipmi_watchdog", | ||
| 995 | .dev_id = NULL, | ||
| 996 | .handler = ipmi_nmi, | ||
| 997 | .priority = 0, /* Call us last. */ | ||
| 998 | }; | 1076 | }; |
| 999 | int nmi_handler_registered; | ||
| 1000 | #endif | 1077 | #endif |
| 1001 | 1078 | ||
| 1002 | static int wdog_reboot_handler(struct notifier_block *this, | 1079 | static int wdog_reboot_handler(struct notifier_block *this, |
| @@ -1009,7 +1086,7 @@ static int wdog_reboot_handler(struct notifier_block *this, | |||
| 1009 | /* Make sure we only do this once. */ | 1086 | /* Make sure we only do this once. */ |
| 1010 | reboot_event_handled = 1; | 1087 | reboot_event_handled = 1; |
| 1011 | 1088 | ||
| 1012 | if (code == SYS_DOWN || code == SYS_HALT) { | 1089 | if (code == SYS_POWER_OFF || code == SYS_HALT) { |
| 1013 | /* Disable the WDT if we are shutting down. */ | 1090 | /* Disable the WDT if we are shutting down. */ |
| 1014 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | 1091 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; |
| 1015 | panic_halt_ipmi_set_timeout(); | 1092 | panic_halt_ipmi_set_timeout(); |
| @@ -1113,7 +1190,7 @@ static int preaction_op(const char *inval, char *outval) | |||
| 1113 | preaction_val = WDOG_PRETIMEOUT_NONE; | 1190 | preaction_val = WDOG_PRETIMEOUT_NONE; |
| 1114 | else if (strcmp(inval, "pre_smi") == 0) | 1191 | else if (strcmp(inval, "pre_smi") == 0) |
| 1115 | preaction_val = WDOG_PRETIMEOUT_SMI; | 1192 | preaction_val = WDOG_PRETIMEOUT_SMI; |
| 1116 | #ifdef HAVE_NMI_HANDLER | 1193 | #ifdef HAVE_DIE_NMI |
| 1117 | else if (strcmp(inval, "pre_nmi") == 0) | 1194 | else if (strcmp(inval, "pre_nmi") == 0) |
| 1118 | preaction_val = WDOG_PRETIMEOUT_NMI; | 1195 | preaction_val = WDOG_PRETIMEOUT_NMI; |
| 1119 | #endif | 1196 | #endif |
| @@ -1147,7 +1224,7 @@ static int preop_op(const char *inval, char *outval) | |||
| 1147 | 1224 | ||
| 1148 | static void check_parms(void) | 1225 | static void check_parms(void) |
| 1149 | { | 1226 | { |
| 1150 | #ifdef HAVE_NMI_HANDLER | 1227 | #ifdef HAVE_DIE_NMI |
| 1151 | int do_nmi = 0; | 1228 | int do_nmi = 0; |
| 1152 | int rv; | 1229 | int rv; |
| 1153 | 1230 | ||
| @@ -1160,20 +1237,9 @@ static void check_parms(void) | |||
| 1160 | preop_op("preop_none", NULL); | 1237 | preop_op("preop_none", NULL); |
| 1161 | do_nmi = 0; | 1238 | do_nmi = 0; |
| 1162 | } | 1239 | } |
| 1163 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 1164 | if (nmi_watchdog == NMI_IO_APIC) { | ||
| 1165 | printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" | ||
| 1166 | " mode (value is %d), that is incompatible" | ||
| 1167 | " with using NMI in the IPMI watchdog." | ||
| 1168 | " Disabling IPMI nmi pretimeout.\n", | ||
| 1169 | nmi_watchdog); | ||
| 1170 | preaction_val = WDOG_PRETIMEOUT_NONE; | ||
| 1171 | do_nmi = 0; | ||
| 1172 | } | ||
| 1173 | #endif | ||
| 1174 | } | 1240 | } |
| 1175 | if (do_nmi && !nmi_handler_registered) { | 1241 | if (do_nmi && !nmi_handler_registered) { |
| 1176 | rv = request_nmi(&ipmi_nmi_handler); | 1242 | rv = register_die_notifier(&ipmi_nmi_handler); |
| 1177 | if (rv) { | 1243 | if (rv) { |
| 1178 | printk(KERN_WARNING PFX | 1244 | printk(KERN_WARNING PFX |
| 1179 | "Can't register nmi handler\n"); | 1245 | "Can't register nmi handler\n"); |
| @@ -1181,7 +1247,7 @@ static void check_parms(void) | |||
| 1181 | } else | 1247 | } else |
| 1182 | nmi_handler_registered = 1; | 1248 | nmi_handler_registered = 1; |
| 1183 | } else if (!do_nmi && nmi_handler_registered) { | 1249 | } else if (!do_nmi && nmi_handler_registered) { |
| 1184 | release_nmi(&ipmi_nmi_handler); | 1250 | unregister_die_notifier(&ipmi_nmi_handler); |
| 1185 | nmi_handler_registered = 0; | 1251 | nmi_handler_registered = 0; |
| 1186 | } | 1252 | } |
| 1187 | #endif | 1253 | #endif |
| @@ -1217,9 +1283,9 @@ static int __init ipmi_wdog_init(void) | |||
| 1217 | 1283 | ||
| 1218 | rv = ipmi_smi_watcher_register(&smi_watcher); | 1284 | rv = ipmi_smi_watcher_register(&smi_watcher); |
| 1219 | if (rv) { | 1285 | if (rv) { |
| 1220 | #ifdef HAVE_NMI_HANDLER | 1286 | #ifdef HAVE_DIE_NMI |
| 1221 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | 1287 | if (nmi_handler_registered) |
| 1222 | release_nmi(&ipmi_nmi_handler); | 1288 | unregister_die_notifier(&ipmi_nmi_handler); |
| 1223 | #endif | 1289 | #endif |
| 1224 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1290 | atomic_notifier_chain_unregister(&panic_notifier_list, |
| 1225 | &wdog_panic_notifier); | 1291 | &wdog_panic_notifier); |
| @@ -1238,9 +1304,9 @@ static void __exit ipmi_wdog_exit(void) | |||
| 1238 | ipmi_smi_watcher_unregister(&smi_watcher); | 1304 | ipmi_smi_watcher_unregister(&smi_watcher); |
| 1239 | ipmi_unregister_watchdog(watchdog_ifnum); | 1305 | ipmi_unregister_watchdog(watchdog_ifnum); |
| 1240 | 1306 | ||
| 1241 | #ifdef HAVE_NMI_HANDLER | 1307 | #ifdef HAVE_DIE_NMI |
| 1242 | if (nmi_handler_registered) | 1308 | if (nmi_handler_registered) |
| 1243 | release_nmi(&ipmi_nmi_handler); | 1309 | unregister_die_notifier(&ipmi_nmi_handler); |
| 1244 | #endif | 1310 | #endif |
| 1245 | 1311 | ||
| 1246 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1312 | atomic_notifier_chain_unregister(&panic_notifier_list, |
