diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 146 |
1 files changed, 105 insertions, 41 deletions
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 19a8683bd25d..e686fc925168 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: " |
@@ -313,6 +322,11 @@ static unsigned char ipmi_version_minor; | |||
313 | /* 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. */ |
314 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); | 323 | static atomic_t preop_panic_excl = ATOMIC_INIT(-1); |
315 | 324 | ||
325 | #ifdef HAVE_DIE_NMI | ||
326 | static int testing_nmi; | ||
327 | static int nmi_handler_registered; | ||
328 | #endif | ||
329 | |||
316 | static int ipmi_heartbeat(void); | 330 | static int ipmi_heartbeat(void); |
317 | 331 | ||
318 | /* 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 |
@@ -352,6 +366,9 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, | |||
352 | int hbnow = 0; | 366 | int hbnow = 0; |
353 | 367 | ||
354 | 368 | ||
369 | /* These can be cleared as we are setting the timeout. */ | ||
370 | pretimeout_since_last_heartbeat = 0; | ||
371 | |||
355 | data[0] = 0; | 372 | data[0] = 0; |
356 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); | 373 | WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); |
357 | 374 | ||
@@ -426,13 +443,12 @@ static int ipmi_set_timeout(int do_heartbeat) | |||
426 | 443 | ||
427 | wait_for_completion(&set_timeout_wait); | 444 | wait_for_completion(&set_timeout_wait); |
428 | 445 | ||
446 | mutex_unlock(&set_timeout_lock); | ||
447 | |||
429 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) | 448 | if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) |
430 | || ((send_heartbeat_now) | 449 | || ((send_heartbeat_now) |
431 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) | 450 | && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) |
432 | { | ||
433 | rv = ipmi_heartbeat(); | 451 | rv = ipmi_heartbeat(); |
434 | } | ||
435 | mutex_unlock(&set_timeout_lock); | ||
436 | 452 | ||
437 | out: | 453 | out: |
438 | return rv; | 454 | return rv; |
@@ -556,9 +572,8 @@ static int ipmi_heartbeat(void) | |||
556 | int rv; | 572 | int rv; |
557 | struct ipmi_system_interface_addr addr; | 573 | struct ipmi_system_interface_addr addr; |
558 | 574 | ||
559 | if (ipmi_ignore_heartbeat) { | 575 | if (ipmi_ignore_heartbeat) |
560 | return 0; | 576 | return 0; |
561 | } | ||
562 | 577 | ||
563 | if (ipmi_start_timer_on_heartbeat) { | 578 | if (ipmi_start_timer_on_heartbeat) { |
564 | ipmi_start_timer_on_heartbeat = 0; | 579 | ipmi_start_timer_on_heartbeat = 0; |
@@ -569,7 +584,6 @@ static int ipmi_heartbeat(void) | |||
569 | 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 |
570 | leave that alone (thus it can't be combined with the | 585 | leave that alone (thus it can't be combined with the |
571 | above operation. */ | 586 | above operation. */ |
572 | pretimeout_since_last_heartbeat = 0; | ||
573 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); | 587 | return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); |
574 | } | 588 | } |
575 | 589 | ||
@@ -927,6 +941,45 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
927 | printk(KERN_CRIT PFX "Unable to register misc device\n"); | 941 | printk(KERN_CRIT PFX "Unable to register misc device\n"); |
928 | } | 942 | } |
929 | 943 | ||
944 | #ifdef HAVE_DIE_NMI | ||
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); | ||
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 | |||
930 | out: | 983 | out: |
931 | if ((start_now) && (rv == 0)) { | 984 | if ((start_now) && (rv == 0)) { |
932 | /* Run from startup, so start the timer now. */ | 985 | /* Run from startup, so start the timer now. */ |
@@ -934,6 +987,10 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
934 | ipmi_watchdog_state = action_val; | 987 | ipmi_watchdog_state = action_val; |
935 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); | 988 | ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); |
936 | 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); | ||
937 | } | 994 | } |
938 | } | 995 | } |
939 | 996 | ||
@@ -968,17 +1025,41 @@ static void ipmi_unregister_watchdog(int ipmi_intf) | |||
968 | return; | 1025 | return; |
969 | } | 1026 | } |
970 | 1027 | ||
971 | #ifdef HAVE_NMI_HANDLER | 1028 | #ifdef HAVE_DIE_NMI |
972 | static int | 1029 | static int |
973 | ipmi_nmi(void *dev_id, int cpu, int handled) | 1030 | ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) |
974 | { | 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 | |||
975 | /* If we are not expecting a timeout, ignore it. */ | 1053 | /* If we are not expecting a timeout, ignore it. */ |
976 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | 1054 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) |
977 | return NOTIFY_DONE; | 1055 | return NOTIFY_OK; |
1056 | |||
1057 | if (preaction_val != WDOG_PRETIMEOUT_NMI) | ||
1058 | return NOTIFY_OK; | ||
978 | 1059 | ||
979 | /* 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 |
980 | watchdog. */ | 1061 | watchdog. */ |
981 | if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { | 1062 | if (preop_val == WDOG_PREOP_PANIC) { |
982 | /* On some machines, the heartbeat will give | 1063 | /* On some machines, the heartbeat will give |
983 | an error and not work unless we re-enable | 1064 | an error and not work unless we re-enable |
984 | the timer. So do so. */ | 1065 | the timer. So do so. */ |
@@ -987,18 +1068,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled) | |||
987 | panic(PFX "pre-timeout"); | 1068 | panic(PFX "pre-timeout"); |
988 | } | 1069 | } |
989 | 1070 | ||
990 | return NOTIFY_DONE; | 1071 | return NOTIFY_STOP; |
991 | } | 1072 | } |
992 | 1073 | ||
993 | static struct nmi_handler ipmi_nmi_handler = | 1074 | static struct notifier_block ipmi_nmi_handler = { |
994 | { | 1075 | .notifier_call = ipmi_nmi |
995 | .link = LIST_HEAD_INIT(ipmi_nmi_handler.link), | ||
996 | .dev_name = "ipmi_watchdog", | ||
997 | .dev_id = NULL, | ||
998 | .handler = ipmi_nmi, | ||
999 | .priority = 0, /* Call us last. */ | ||
1000 | }; | 1076 | }; |
1001 | int nmi_handler_registered; | ||
1002 | #endif | 1077 | #endif |
1003 | 1078 | ||
1004 | static int wdog_reboot_handler(struct notifier_block *this, | 1079 | static int wdog_reboot_handler(struct notifier_block *this, |
@@ -1115,7 +1190,7 @@ static int preaction_op(const char *inval, char *outval) | |||
1115 | preaction_val = WDOG_PRETIMEOUT_NONE; | 1190 | preaction_val = WDOG_PRETIMEOUT_NONE; |
1116 | else if (strcmp(inval, "pre_smi") == 0) | 1191 | else if (strcmp(inval, "pre_smi") == 0) |
1117 | preaction_val = WDOG_PRETIMEOUT_SMI; | 1192 | preaction_val = WDOG_PRETIMEOUT_SMI; |
1118 | #ifdef HAVE_NMI_HANDLER | 1193 | #ifdef HAVE_DIE_NMI |
1119 | else if (strcmp(inval, "pre_nmi") == 0) | 1194 | else if (strcmp(inval, "pre_nmi") == 0) |
1120 | preaction_val = WDOG_PRETIMEOUT_NMI; | 1195 | preaction_val = WDOG_PRETIMEOUT_NMI; |
1121 | #endif | 1196 | #endif |
@@ -1149,7 +1224,7 @@ static int preop_op(const char *inval, char *outval) | |||
1149 | 1224 | ||
1150 | static void check_parms(void) | 1225 | static void check_parms(void) |
1151 | { | 1226 | { |
1152 | #ifdef HAVE_NMI_HANDLER | 1227 | #ifdef HAVE_DIE_NMI |
1153 | int do_nmi = 0; | 1228 | int do_nmi = 0; |
1154 | int rv; | 1229 | int rv; |
1155 | 1230 | ||
@@ -1162,20 +1237,9 @@ static void check_parms(void) | |||
1162 | preop_op("preop_none", NULL); | 1237 | preop_op("preop_none", NULL); |
1163 | do_nmi = 0; | 1238 | do_nmi = 0; |
1164 | } | 1239 | } |
1165 | #ifdef CONFIG_X86_LOCAL_APIC | ||
1166 | if (nmi_watchdog == NMI_IO_APIC) { | ||
1167 | printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" | ||
1168 | " mode (value is %d), that is incompatible" | ||
1169 | " with using NMI in the IPMI watchdog." | ||
1170 | " Disabling IPMI nmi pretimeout.\n", | ||
1171 | nmi_watchdog); | ||
1172 | preaction_val = WDOG_PRETIMEOUT_NONE; | ||
1173 | do_nmi = 0; | ||
1174 | } | ||
1175 | #endif | ||
1176 | } | 1240 | } |
1177 | if (do_nmi && !nmi_handler_registered) { | 1241 | if (do_nmi && !nmi_handler_registered) { |
1178 | rv = request_nmi(&ipmi_nmi_handler); | 1242 | rv = register_die_notifier(&ipmi_nmi_handler); |
1179 | if (rv) { | 1243 | if (rv) { |
1180 | printk(KERN_WARNING PFX | 1244 | printk(KERN_WARNING PFX |
1181 | "Can't register nmi handler\n"); | 1245 | "Can't register nmi handler\n"); |
@@ -1183,7 +1247,7 @@ static void check_parms(void) | |||
1183 | } else | 1247 | } else |
1184 | nmi_handler_registered = 1; | 1248 | nmi_handler_registered = 1; |
1185 | } else if (!do_nmi && nmi_handler_registered) { | 1249 | } else if (!do_nmi && nmi_handler_registered) { |
1186 | release_nmi(&ipmi_nmi_handler); | 1250 | unregister_die_notifier(&ipmi_nmi_handler); |
1187 | nmi_handler_registered = 0; | 1251 | nmi_handler_registered = 0; |
1188 | } | 1252 | } |
1189 | #endif | 1253 | #endif |
@@ -1219,9 +1283,9 @@ static int __init ipmi_wdog_init(void) | |||
1219 | 1283 | ||
1220 | rv = ipmi_smi_watcher_register(&smi_watcher); | 1284 | rv = ipmi_smi_watcher_register(&smi_watcher); |
1221 | if (rv) { | 1285 | if (rv) { |
1222 | #ifdef HAVE_NMI_HANDLER | 1286 | #ifdef HAVE_DIE_NMI |
1223 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | 1287 | if (nmi_handler_registered) |
1224 | release_nmi(&ipmi_nmi_handler); | 1288 | unregister_die_notifier(&ipmi_nmi_handler); |
1225 | #endif | 1289 | #endif |
1226 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1290 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1227 | &wdog_panic_notifier); | 1291 | &wdog_panic_notifier); |
@@ -1240,9 +1304,9 @@ static void __exit ipmi_wdog_exit(void) | |||
1240 | ipmi_smi_watcher_unregister(&smi_watcher); | 1304 | ipmi_smi_watcher_unregister(&smi_watcher); |
1241 | ipmi_unregister_watchdog(watchdog_ifnum); | 1305 | ipmi_unregister_watchdog(watchdog_ifnum); |
1242 | 1306 | ||
1243 | #ifdef HAVE_NMI_HANDLER | 1307 | #ifdef HAVE_DIE_NMI |
1244 | if (nmi_handler_registered) | 1308 | if (nmi_handler_registered) |
1245 | release_nmi(&ipmi_nmi_handler); | 1309 | unregister_die_notifier(&ipmi_nmi_handler); |
1246 | #endif | 1310 | #endif |
1247 | 1311 | ||
1248 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1312 | atomic_notifier_chain_unregister(&panic_notifier_list, |