diff options
-rw-r--r-- | arch/i386/kernel/traps.c | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/traps.c | 3 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 134 | ||||
-rw-r--r-- | include/asm-i386/kdebug.h | 1 | ||||
-rw-r--r-- | include/asm-x86_64/kdebug.h | 1 |
5 files changed, 42 insertions, 102 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index c05e7e861b29..90da0575fcff 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -733,11 +733,6 @@ static __kprobes void default_do_nmi(struct pt_regs * regs) | |||
733 | */ | 733 | */ |
734 | if (nmi_watchdog_tick(regs, reason)) | 734 | if (nmi_watchdog_tick(regs, reason)) |
735 | return; | 735 | return; |
736 | #endif | ||
737 | if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0) | ||
738 | == NOTIFY_STOP) | ||
739 | return; | ||
740 | #ifdef CONFIG_X86_LOCAL_APIC | ||
741 | if (!do_nmi_callback(regs, smp_processor_id())) | 736 | if (!do_nmi_callback(regs, smp_processor_id())) |
742 | #endif | 737 | #endif |
743 | unknown_nmi_error(reason, regs); | 738 | unknown_nmi_error(reason, regs); |
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index d28f01379b9b..cb29fb96948d 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -776,9 +776,6 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) | |||
776 | */ | 776 | */ |
777 | if (nmi_watchdog_tick(regs,reason)) | 777 | if (nmi_watchdog_tick(regs,reason)) |
778 | return; | 778 | return; |
779 | if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0) | ||
780 | == NOTIFY_STOP) | ||
781 | return; | ||
782 | if (!do_nmi_callback(regs,cpu)) | 779 | if (!do_nmi_callback(regs,cpu)) |
783 | unknown_nmi_error(reason, regs); | 780 | unknown_nmi_error(reason, regs); |
784 | 781 | ||
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 147c12047cf3..41f78e2c158f 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -50,18 +50,10 @@ | |||
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> | ||
54 | #include <asm/atomic.h> | 53 | #include <asm/atomic.h> |
55 | 54 | ||
56 | #ifdef CONFIG_X86 | 55 | #ifdef CONFIG_X86_LOCAL_APIC |
57 | /* This is ugly, but I've determined that x86 is the only architecture | 56 | #include <asm/apic.h> |
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 | #define HAVE_DIE_NMI_POST | ||
65 | #endif | 57 | #endif |
66 | 58 | ||
67 | #define PFX "IPMI Watchdog: " | 59 | #define PFX "IPMI Watchdog: " |
@@ -327,11 +319,6 @@ static unsigned char ipmi_version_minor; | |||
327 | /* If a pretimeout occurs, this is used to allow only one panic to happen. */ | 319 | /* If a pretimeout occurs, this is used to allow only one panic to happen. */ |
328 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); | 320 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); |
329 | 321 | ||
330 | #ifdef HAVE_DIE_NMI_POST | ||
331 | static int testing_nmi; | ||
332 | static int nmi_handler_registered; | ||
333 | #endif | ||
334 | |||
335 | static int ipmi_heartbeat(void); | 322 | static int ipmi_heartbeat(void); |
336 | static void panic_halt_ipmi_heartbeat(void); | 323 | static void panic_halt_ipmi_heartbeat(void); |
337 | 324 | ||
@@ -373,10 +360,6 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, | |||
373 | int hbnow = 0; | 360 | int hbnow = 0; |
374 | 361 | ||
375 | 362 | ||
376 | /* These can be cleared as we are setting the timeout. */ | ||
377 | ipmi_start_timer_on_heartbeat = 0; | ||
378 | pretimeout_since_last_heartbeat = 0; | ||
379 | |||
380 | data[0] = 0; | 363 | data[0] = 0; |
381 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); | 364 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); |
382 | 365 | ||
@@ -451,12 +434,13 @@ static int ipmi_set_timeout(int do_heartbeat) | |||
451 | 434 | ||
452 | wait_for_completion(&set_timeout_wait); | 435 | wait_for_completion(&set_timeout_wait); |
453 | 436 | ||
454 | mutex_unlock(&set_timeout_lock); | ||
455 | |||
456 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) | 437 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) |
457 | || ((send_heartbeat_now) | 438 | || ((send_heartbeat_now) |
458 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) | 439 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) |
440 | { | ||
459 | rv = ipmi_heartbeat(); | 441 | rv = ipmi_heartbeat(); |
442 | } | ||
443 | mutex_unlock(&set_timeout_lock); | ||
460 | 444 | ||
461 | out: | 445 | out: |
462 | return rv; | 446 | return rv; |
@@ -536,10 +520,12 @@ static int ipmi_heartbeat(void) | |||
536 | int rv; | 520 | int rv; |
537 | struct ipmi_system_interface_addr addr; | 521 | struct ipmi_system_interface_addr addr; |
538 | 522 | ||
539 | if (ipmi_ignore_heartbeat) | 523 | if (ipmi_ignore_heartbeat) { |
540 | return 0; | 524 | return 0; |
525 | } | ||
541 | 526 | ||
542 | if (ipmi_start_timer_on_heartbeat) { | 527 | if (ipmi_start_timer_on_heartbeat) { |
528 | ipmi_start_timer_on_heartbeat = 0; | ||
543 | ipmi_watchdog_state = action_val; | 529 | ipmi_watchdog_state = action_val; |
544 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | 530 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); |
545 | } else if (pretimeout_since_last_heartbeat) { | 531 | } else if (pretimeout_since_last_heartbeat) { |
@@ -547,6 +533,7 @@ static int ipmi_heartbeat(void) | |||
547 | We don't want to set the action, though, we want to | 533 | We don't want to set the action, though, we want to |
548 | leave that alone (thus it can't be combined with the | 534 | leave that alone (thus it can't be combined with the |
549 | above operation. */ | 535 | above operation. */ |
536 | pretimeout_since_last_heartbeat = 0; | ||
550 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | 537 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); |
551 | } | 538 | } |
552 | 539 | ||
@@ -934,45 +921,6 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
934 | printk(KERN_CRIT PFX "Unable to register misc device\n"); | 921 | printk(KERN_CRIT PFX "Unable to register misc device\n"); |
935 | } | 922 | } |
936 | 923 | ||
937 | #ifdef HAVE_DIE_NMI_POST | ||
938 | if (nmi_handler_registered) { | ||
939 | int old_pretimeout = pretimeout; | ||
940 | int old_timeout = timeout; | ||
941 | int old_preop_val = preop_val; | ||
942 | |||
943 | /* Set the pretimeout to go off in a second and give | ||
944 | ourselves plenty of time to stop the timer. */ | ||
945 | ipmi_watchdog_state = WDOG_TIMEOUT_RESET; | ||
946 | preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ | ||
947 | pretimeout = 99; | ||
948 | timeout = 100; | ||
949 | |||
950 | testing_nmi = 1; | ||
951 | |||
952 | rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | ||
953 | if (rv) { | ||
954 | printk(KERN_WARNING PFX "Error starting timer to" | ||
955 | " test NMI: 0x%x. The NMI pretimeout will" | ||
956 | " likely not work\n", rv); | ||
957 | rv = 0; | ||
958 | goto out_restore; | ||
959 | } | ||
960 | |||
961 | msleep(1500); | ||
962 | |||
963 | if (testing_nmi != 2) { | ||
964 | printk(KERN_WARNING PFX "IPMI NMI didn't seem to" | ||
965 | " occur. The NMI pretimeout will" | ||
966 | " likely not work\n"); | ||
967 | } | ||
968 | out_restore: | ||
969 | testing_nmi = 0; | ||
970 | preop_val = old_preop_val; | ||
971 | pretimeout = old_pretimeout; | ||
972 | timeout = old_timeout; | ||
973 | } | ||
974 | #endif | ||
975 | |||
976 | out: | 924 | out: |
977 | up_write(®ister_sem); | 925 | up_write(®ister_sem); |
978 | 926 | ||
@@ -982,10 +930,6 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
982 | ipmi_watchdog_state = action_val; | 930 | ipmi_watchdog_state = action_val; |
983 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | 931 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); |
984 | printk(KERN_INFO PFX "Starting now!\n"); | 932 | printk(KERN_INFO PFX "Starting now!\n"); |
985 | } else { | ||
986 | /* Stop the timer now. */ | ||
987 | ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | ||
988 | ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); | ||
989 | } | 933 | } |
990 | } | 934 | } |
991 | 935 | ||
@@ -1022,28 +966,17 @@ static void ipmi_unregister_watchdog(int ipmi_intf) | |||
1022 | up_write(®ister_sem); | 966 | up_write(®ister_sem); |
1023 | } | 967 | } |
1024 | 968 | ||
1025 | #ifdef HAVE_DIE_NMI_POST | 969 | #ifdef HAVE_NMI_HANDLER |
1026 | static int | 970 | static int |
1027 | ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) | 971 | ipmi_nmi(void *dev_id, int cpu, int handled) |
1028 | { | 972 | { |
1029 | if (val != DIE_NMI_POST) | ||
1030 | return NOTIFY_OK; | ||
1031 | |||
1032 | if (testing_nmi) { | ||
1033 | testing_nmi = 2; | ||
1034 | return NOTIFY_STOP; | ||
1035 | } | ||
1036 | |||
1037 | /* If we are not expecting a timeout, ignore it. */ | 973 | /* If we are not expecting a timeout, ignore it. */ |
1038 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | 974 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) |
1039 | return NOTIFY_OK; | 975 | return NOTIFY_DONE; |
1040 | |||
1041 | if (preaction_val != WDOG_PRETIMEOUT_NMI) | ||
1042 | return NOTIFY_OK; | ||
1043 | 976 | ||
1044 | /* If no one else handled the NMI, we assume it was the IPMI | 977 | /* If no one else handled the NMI, we assume it was the IPMI |
1045 | watchdog. */ | 978 | watchdog. */ |
1046 | if (preop_val == WDOG_PREOP_PANIC) { | 979 | if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { |
1047 | /* On some machines, the heartbeat will give | 980 | /* On some machines, the heartbeat will give |
1048 | an error and not work unless we re-enable | 981 | an error and not work unless we re-enable |
1049 | the timer. So do so. */ | 982 | the timer. So do so. */ |
@@ -1052,12 +985,18 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) | |||
1052 | panic(PFX "pre-timeout"); | 985 | panic(PFX "pre-timeout"); |
1053 | } | 986 | } |
1054 | 987 | ||
1055 | return NOTIFY_STOP; | 988 | return NOTIFY_DONE; |
1056 | } | 989 | } |
1057 | 990 | ||
1058 | static struct notifier_block ipmi_nmi_handler = { | 991 | static struct nmi_handler ipmi_nmi_handler = |
1059 | .notifier_call = ipmi_nmi | 992 | { |
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. */ | ||
1060 | }; | 998 | }; |
999 | int nmi_handler_registered; | ||
1061 | #endif | 1000 | #endif |
1062 | 1001 | ||
1063 | static int wdog_reboot_handler(struct notifier_block *this, | 1002 | static int wdog_reboot_handler(struct notifier_block *this, |
@@ -1174,7 +1113,7 @@ static int preaction_op(const char *inval, char *outval) | |||
1174 | preaction_val = WDOG_PRETIMEOUT_NONE; | 1113 | preaction_val = WDOG_PRETIMEOUT_NONE; |
1175 | else if (strcmp(inval, "pre_smi") == 0) | 1114 | else if (strcmp(inval, "pre_smi") == 0) |
1176 | preaction_val = WDOG_PRETIMEOUT_SMI; | 1115 | preaction_val = WDOG_PRETIMEOUT_SMI; |
1177 | #ifdef HAVE_DIE_NMI_POST | 1116 | #ifdef HAVE_NMI_HANDLER |
1178 | else if (strcmp(inval, "pre_nmi") == 0) | 1117 | else if (strcmp(inval, "pre_nmi") == 0) |
1179 | preaction_val = WDOG_PRETIMEOUT_NMI; | 1118 | preaction_val = WDOG_PRETIMEOUT_NMI; |
1180 | #endif | 1119 | #endif |
@@ -1208,7 +1147,7 @@ static int preop_op(const char *inval, char *outval) | |||
1208 | 1147 | ||
1209 | static void check_parms(void) | 1148 | static void check_parms(void) |
1210 | { | 1149 | { |
1211 | #ifdef HAVE_DIE_NMI_POST | 1150 | #ifdef HAVE_NMI_HANDLER |
1212 | int do_nmi = 0; | 1151 | int do_nmi = 0; |
1213 | int rv; | 1152 | int rv; |
1214 | 1153 | ||
@@ -1221,9 +1160,20 @@ static void check_parms(void) | |||
1221 | preop_op("preop_none", NULL); | 1160 | preop_op("preop_none", NULL); |
1222 | do_nmi = 0; | 1161 | do_nmi = 0; |
1223 | } | 1162 | } |
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 | ||
1224 | } | 1174 | } |
1225 | if (do_nmi && !nmi_handler_registered) { | 1175 | if (do_nmi && !nmi_handler_registered) { |
1226 | rv = register_die_notifier(&ipmi_nmi_handler); | 1176 | rv = request_nmi(&ipmi_nmi_handler); |
1227 | if (rv) { | 1177 | if (rv) { |
1228 | printk(KERN_WARNING PFX | 1178 | printk(KERN_WARNING PFX |
1229 | "Can't register nmi handler\n"); | 1179 | "Can't register nmi handler\n"); |
@@ -1231,7 +1181,7 @@ static void check_parms(void) | |||
1231 | } else | 1181 | } else |
1232 | nmi_handler_registered = 1; | 1182 | nmi_handler_registered = 1; |
1233 | } else if (!do_nmi && nmi_handler_registered) { | 1183 | } else if (!do_nmi && nmi_handler_registered) { |
1234 | unregister_die_notifier(&ipmi_nmi_handler); | 1184 | release_nmi(&ipmi_nmi_handler); |
1235 | nmi_handler_registered = 0; | 1185 | nmi_handler_registered = 0; |
1236 | } | 1186 | } |
1237 | #endif | 1187 | #endif |
@@ -1267,9 +1217,9 @@ static int __init ipmi_wdog_init(void) | |||
1267 | 1217 | ||
1268 | rv = ipmi_smi_watcher_register(&smi_watcher); | 1218 | rv = ipmi_smi_watcher_register(&smi_watcher); |
1269 | if (rv) { | 1219 | if (rv) { |
1270 | #ifdef HAVE_DIE_NMI_POST | 1220 | #ifdef HAVE_NMI_HANDLER |
1271 | if (nmi_handler_registered) | 1221 | if (preaction_val == WDOG_PRETIMEOUT_NMI) |
1272 | unregister_die_notifier(&ipmi_nmi_handler); | 1222 | release_nmi(&ipmi_nmi_handler); |
1273 | #endif | 1223 | #endif |
1274 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1224 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1275 | &wdog_panic_notifier); | 1225 | &wdog_panic_notifier); |
@@ -1288,9 +1238,9 @@ static void __exit ipmi_wdog_exit(void) | |||
1288 | ipmi_smi_watcher_unregister(&smi_watcher); | 1238 | ipmi_smi_watcher_unregister(&smi_watcher); |
1289 | ipmi_unregister_watchdog(watchdog_ifnum); | 1239 | ipmi_unregister_watchdog(watchdog_ifnum); |
1290 | 1240 | ||
1291 | #ifdef HAVE_DIE_NMI_POST | 1241 | #ifdef HAVE_NMI_HANDLER |
1292 | if (nmi_handler_registered) | 1242 | if (nmi_handler_registered) |
1293 | unregister_die_notifier(&ipmi_nmi_handler); | 1243 | release_nmi(&ipmi_nmi_handler); |
1294 | #endif | 1244 | #endif |
1295 | 1245 | ||
1296 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1246 | atomic_notifier_chain_unregister(&panic_notifier_list, |
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h index 05c3117788b9..a185b5f73e7f 100644 --- a/include/asm-i386/kdebug.h +++ b/include/asm-i386/kdebug.h | |||
@@ -27,7 +27,6 @@ enum die_val { | |||
27 | DIE_GPF, | 27 | DIE_GPF, |
28 | DIE_CALL, | 28 | DIE_CALL, |
29 | DIE_NMI_IPI, | 29 | DIE_NMI_IPI, |
30 | DIE_NMI_POST, | ||
31 | DIE_PAGE_FAULT, | 30 | DIE_PAGE_FAULT, |
32 | }; | 31 | }; |
33 | 32 | ||
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index 74feae945a26..d7e2bcf49e4f 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h | |||
@@ -22,7 +22,6 @@ enum die_val { | |||
22 | DIE_GPF, | 22 | DIE_GPF, |
23 | DIE_CALL, | 23 | DIE_CALL, |
24 | DIE_NMI_IPI, | 24 | DIE_NMI_IPI, |
25 | DIE_NMI_POST, | ||
26 | DIE_PAGE_FAULT, | 25 | DIE_PAGE_FAULT, |
27 | }; | 26 | }; |
28 | 27 | ||