diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_watchdog.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 141 |
1 files changed, 88 insertions, 53 deletions
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index accaaf1a6b69..78280380a905 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -134,13 +134,14 @@ | |||
134 | 134 | ||
135 | static int nowayout = WATCHDOG_NOWAYOUT; | 135 | static int nowayout = WATCHDOG_NOWAYOUT; |
136 | 136 | ||
137 | static ipmi_user_t watchdog_user = NULL; | 137 | static ipmi_user_t watchdog_user; |
138 | static int watchdog_ifnum; | ||
138 | 139 | ||
139 | /* Default the timeout to 10 seconds. */ | 140 | /* Default the timeout to 10 seconds. */ |
140 | static int timeout = 10; | 141 | static int timeout = 10; |
141 | 142 | ||
142 | /* The pre-timeout is disabled by default. */ | 143 | /* The pre-timeout is disabled by default. */ |
143 | static int pretimeout = 0; | 144 | static int pretimeout; |
144 | 145 | ||
145 | /* Default action is to reset the board on a timeout. */ | 146 | /* Default action is to reset the board on a timeout. */ |
146 | static unsigned char action_val = WDOG_TIMEOUT_RESET; | 147 | static unsigned char action_val = WDOG_TIMEOUT_RESET; |
@@ -155,12 +156,14 @@ static unsigned char preop_val = WDOG_PREOP_NONE; | |||
155 | 156 | ||
156 | static char preop[16] = "preop_none"; | 157 | static char preop[16] = "preop_none"; |
157 | static DEFINE_SPINLOCK(ipmi_read_lock); | 158 | static DEFINE_SPINLOCK(ipmi_read_lock); |
158 | static char data_to_read = 0; | 159 | static char data_to_read; |
159 | static DECLARE_WAIT_QUEUE_HEAD(read_q); | 160 | static DECLARE_WAIT_QUEUE_HEAD(read_q); |
160 | static struct fasync_struct *fasync_q = NULL; | 161 | static struct fasync_struct *fasync_q; |
161 | static char pretimeout_since_last_heartbeat = 0; | 162 | static char pretimeout_since_last_heartbeat; |
162 | static char expect_close; | 163 | static char expect_close; |
163 | 164 | ||
165 | static int ifnum_to_use = -1; | ||
166 | |||
164 | static DECLARE_RWSEM(register_sem); | 167 | static DECLARE_RWSEM(register_sem); |
165 | 168 | ||
166 | /* Parameters to ipmi_set_timeout */ | 169 | /* Parameters to ipmi_set_timeout */ |
@@ -169,10 +172,12 @@ static DECLARE_RWSEM(register_sem); | |||
169 | #define IPMI_SET_TIMEOUT_FORCE_HB 2 | 172 | #define IPMI_SET_TIMEOUT_FORCE_HB 2 |
170 | 173 | ||
171 | static int ipmi_set_timeout(int do_heartbeat); | 174 | static int ipmi_set_timeout(int do_heartbeat); |
175 | static void ipmi_register_watchdog(int ipmi_intf); | ||
176 | static void ipmi_unregister_watchdog(int ipmi_intf); | ||
172 | 177 | ||
173 | /* If true, the driver will start running as soon as it is configured | 178 | /* If true, the driver will start running as soon as it is configured |
174 | and ready. */ | 179 | and ready. */ |
175 | static int start_now = 0; | 180 | static int start_now; |
176 | 181 | ||
177 | static int set_param_int(const char *val, struct kernel_param *kp) | 182 | static int set_param_int(const char *val, struct kernel_param *kp) |
178 | { | 183 | { |
@@ -245,6 +250,26 @@ static int get_param_str(char *buffer, struct kernel_param *kp) | |||
245 | return strlen(buffer); | 250 | return strlen(buffer); |
246 | } | 251 | } |
247 | 252 | ||
253 | |||
254 | static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp) | ||
255 | { | ||
256 | int rv = param_set_int(val, kp); | ||
257 | if (rv) | ||
258 | return rv; | ||
259 | if ((ifnum_to_use < 0) || (ifnum_to_use == watchdog_ifnum)) | ||
260 | return 0; | ||
261 | |||
262 | ipmi_unregister_watchdog(watchdog_ifnum); | ||
263 | ipmi_register_watchdog(ifnum_to_use); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int, | ||
268 | &ifnum_to_use, 0644); | ||
269 | MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " | ||
270 | "timer. Setting to -1 defaults to the first registered " | ||
271 | "interface"); | ||
272 | |||
248 | module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); | 273 | module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); |
249 | MODULE_PARM_DESC(timeout, "Timeout value in seconds."); | 274 | MODULE_PARM_DESC(timeout, "Timeout value in seconds."); |
250 | 275 | ||
@@ -263,27 +288,28 @@ module_param_call(preop, set_param_str, get_param_str, preop_op, 0644); | |||
263 | MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " | 288 | MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " |
264 | "preop_none, preop_panic, preop_give_data."); | 289 | "preop_none, preop_panic, preop_give_data."); |
265 | 290 | ||
266 | module_param(start_now, int, 0); | 291 | module_param(start_now, int, 0444); |
267 | MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" | 292 | MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" |
268 | "soon as the driver is loaded."); | 293 | "soon as the driver is loaded."); |
269 | 294 | ||
270 | module_param(nowayout, int, 0644); | 295 | module_param(nowayout, int, 0644); |
271 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 296 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " |
297 | "(default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
272 | 298 | ||
273 | /* Default state of the timer. */ | 299 | /* Default state of the timer. */ |
274 | static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; | 300 | static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE; |
275 | 301 | ||
276 | /* If shutting down via IPMI, we ignore the heartbeat. */ | 302 | /* If shutting down via IPMI, we ignore the heartbeat. */ |
277 | static int ipmi_ignore_heartbeat = 0; | 303 | static int ipmi_ignore_heartbeat; |
278 | 304 | ||
279 | /* Is someone using the watchdog? Only one user is allowed. */ | 305 | /* Is someone using the watchdog? Only one user is allowed. */ |
280 | static unsigned long ipmi_wdog_open = 0; | 306 | static unsigned long ipmi_wdog_open; |
281 | 307 | ||
282 | /* If set to 1, the heartbeat command will set the state to reset and | 308 | /* If set to 1, the heartbeat command will set the state to reset and |
283 | start the timer. The timer doesn't normally run when the driver is | 309 | start the timer. The timer doesn't normally run when the driver is |
284 | first opened until the heartbeat is set the first time, this | 310 | first opened until the heartbeat is set the first time, this |
285 | variable is used to accomplish this. */ | 311 | variable is used to accomplish this. */ |
286 | static int ipmi_start_timer_on_heartbeat = 0; | 312 | static int ipmi_start_timer_on_heartbeat; |
287 | 313 | ||
288 | /* IPMI version of the BMC. */ | 314 | /* IPMI version of the BMC. */ |
289 | static unsigned char ipmi_version_major; | 315 | static unsigned char ipmi_version_major; |
@@ -872,6 +898,11 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
872 | if (watchdog_user) | 898 | if (watchdog_user) |
873 | goto out; | 899 | goto out; |
874 | 900 | ||
901 | if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf)) | ||
902 | goto out; | ||
903 | |||
904 | watchdog_ifnum = ipmi_intf; | ||
905 | |||
875 | rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); | 906 | rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user); |
876 | if (rv < 0) { | 907 | if (rv < 0) { |
877 | printk(KERN_CRIT PFX "Unable to register with ipmi\n"); | 908 | printk(KERN_CRIT PFX "Unable to register with ipmi\n"); |
@@ -901,9 +932,42 @@ static void ipmi_register_watchdog(int ipmi_intf) | |||
901 | } | 932 | } |
902 | } | 933 | } |
903 | 934 | ||
935 | static void ipmi_unregister_watchdog(int ipmi_intf) | ||
936 | { | ||
937 | int rv; | ||
938 | |||
939 | down_write(®ister_sem); | ||
940 | |||
941 | if (!watchdog_user) | ||
942 | goto out; | ||
943 | |||
944 | if (watchdog_ifnum != ipmi_intf) | ||
945 | goto out; | ||
946 | |||
947 | /* Make sure no one can call us any more. */ | ||
948 | misc_deregister(&ipmi_wdog_miscdev); | ||
949 | |||
950 | /* Wait to make sure the message makes it out. The lower layer has | ||
951 | pointers to our buffers, we want to make sure they are done before | ||
952 | we release our memory. */ | ||
953 | while (atomic_read(&set_timeout_tofree)) | ||
954 | schedule_timeout_uninterruptible(1); | ||
955 | |||
956 | /* Disconnect from IPMI. */ | ||
957 | rv = ipmi_destroy_user(watchdog_user); | ||
958 | if (rv) { | ||
959 | printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", | ||
960 | rv); | ||
961 | } | ||
962 | watchdog_user = NULL; | ||
963 | |||
964 | out: | ||
965 | up_write(®ister_sem); | ||
966 | } | ||
967 | |||
904 | #ifdef HAVE_NMI_HANDLER | 968 | #ifdef HAVE_NMI_HANDLER |
905 | static int | 969 | static int |
906 | ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) | 970 | ipmi_nmi(void *dev_id, int cpu, int handled) |
907 | { | 971 | { |
908 | /* If we are not expecting a timeout, ignore it. */ | 972 | /* If we are not expecting a timeout, ignore it. */ |
909 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) | 973 | if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) |
@@ -1004,9 +1068,7 @@ static void ipmi_new_smi(int if_num, struct device *device) | |||
1004 | 1068 | ||
1005 | static void ipmi_smi_gone(int if_num) | 1069 | static void ipmi_smi_gone(int if_num) |
1006 | { | 1070 | { |
1007 | /* This can never be called, because once the watchdog is | 1071 | ipmi_unregister_watchdog(if_num); |
1008 | registered, the interface can't go away until the watchdog | ||
1009 | is unregistered. */ | ||
1010 | } | 1072 | } |
1011 | 1073 | ||
1012 | static struct ipmi_smi_watcher smi_watcher = | 1074 | static struct ipmi_smi_watcher smi_watcher = |
@@ -1148,30 +1210,32 @@ static int __init ipmi_wdog_init(void) | |||
1148 | 1210 | ||
1149 | check_parms(); | 1211 | check_parms(); |
1150 | 1212 | ||
1213 | register_reboot_notifier(&wdog_reboot_notifier); | ||
1214 | atomic_notifier_chain_register(&panic_notifier_list, | ||
1215 | &wdog_panic_notifier); | ||
1216 | |||
1151 | rv = ipmi_smi_watcher_register(&smi_watcher); | 1217 | rv = ipmi_smi_watcher_register(&smi_watcher); |
1152 | if (rv) { | 1218 | if (rv) { |
1153 | #ifdef HAVE_NMI_HANDLER | 1219 | #ifdef HAVE_NMI_HANDLER |
1154 | if (preaction_val == WDOG_PRETIMEOUT_NMI) | 1220 | if (preaction_val == WDOG_PRETIMEOUT_NMI) |
1155 | release_nmi(&ipmi_nmi_handler); | 1221 | release_nmi(&ipmi_nmi_handler); |
1156 | #endif | 1222 | #endif |
1223 | atomic_notifier_chain_unregister(&panic_notifier_list, | ||
1224 | &wdog_panic_notifier); | ||
1225 | unregister_reboot_notifier(&wdog_reboot_notifier); | ||
1157 | printk(KERN_WARNING PFX "can't register smi watcher\n"); | 1226 | printk(KERN_WARNING PFX "can't register smi watcher\n"); |
1158 | return rv; | 1227 | return rv; |
1159 | } | 1228 | } |
1160 | 1229 | ||
1161 | register_reboot_notifier(&wdog_reboot_notifier); | ||
1162 | atomic_notifier_chain_register(&panic_notifier_list, | ||
1163 | &wdog_panic_notifier); | ||
1164 | |||
1165 | printk(KERN_INFO PFX "driver initialized\n"); | 1230 | printk(KERN_INFO PFX "driver initialized\n"); |
1166 | 1231 | ||
1167 | return 0; | 1232 | return 0; |
1168 | } | 1233 | } |
1169 | 1234 | ||
1170 | static __exit void ipmi_unregister_watchdog(void) | 1235 | static void __exit ipmi_wdog_exit(void) |
1171 | { | 1236 | { |
1172 | int rv; | 1237 | ipmi_smi_watcher_unregister(&smi_watcher); |
1173 | 1238 | ipmi_unregister_watchdog(watchdog_ifnum); | |
1174 | down_write(®ister_sem); | ||
1175 | 1239 | ||
1176 | #ifdef HAVE_NMI_HANDLER | 1240 | #ifdef HAVE_NMI_HANDLER |
1177 | if (nmi_handler_registered) | 1241 | if (nmi_handler_registered) |
@@ -1179,37 +1243,8 @@ static __exit void ipmi_unregister_watchdog(void) | |||
1179 | #endif | 1243 | #endif |
1180 | 1244 | ||
1181 | atomic_notifier_chain_unregister(&panic_notifier_list, | 1245 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1182 | &wdog_panic_notifier); | 1246 | &wdog_panic_notifier); |
1183 | unregister_reboot_notifier(&wdog_reboot_notifier); | 1247 | unregister_reboot_notifier(&wdog_reboot_notifier); |
1184 | |||
1185 | if (! watchdog_user) | ||
1186 | goto out; | ||
1187 | |||
1188 | /* Make sure no one can call us any more. */ | ||
1189 | misc_deregister(&ipmi_wdog_miscdev); | ||
1190 | |||
1191 | /* Wait to make sure the message makes it out. The lower layer has | ||
1192 | pointers to our buffers, we want to make sure they are done before | ||
1193 | we release our memory. */ | ||
1194 | while (atomic_read(&set_timeout_tofree)) | ||
1195 | schedule_timeout_uninterruptible(1); | ||
1196 | |||
1197 | /* Disconnect from IPMI. */ | ||
1198 | rv = ipmi_destroy_user(watchdog_user); | ||
1199 | if (rv) { | ||
1200 | printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n", | ||
1201 | rv); | ||
1202 | } | ||
1203 | watchdog_user = NULL; | ||
1204 | |||
1205 | out: | ||
1206 | up_write(®ister_sem); | ||
1207 | } | ||
1208 | |||
1209 | static void __exit ipmi_wdog_exit(void) | ||
1210 | { | ||
1211 | ipmi_smi_watcher_unregister(&smi_watcher); | ||
1212 | ipmi_unregister_watchdog(); | ||
1213 | } | 1248 | } |
1214 | module_exit(ipmi_wdog_exit); | 1249 | module_exit(ipmi_wdog_exit); |
1215 | module_init(ipmi_wdog_init); | 1250 | module_init(ipmi_wdog_init); |