1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2004 Poul-Henning Kamp 5 * Copyright (c) 2013 iXsystems.com, 6 * author: Alfred Perlstein <alfred@freebsd.org> 7 * 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include "opt_ddb.h" 34 35 #include <sys/cdefs.h> 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/conf.h> 39 #include <sys/eventhandler.h> 40 #include <sys/kdb.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> 43 #include <sys/module.h> 44 #include <sys/mutex.h> 45 #include <sys/sysctl.h> 46 #include <sys/syslog.h> 47 #include <sys/systm.h> 48 #include <sys/uio.h> 49 #include <sys/watchdog.h> 50 #include <machine/bus.h> 51 52 #include <sys/syscallsubr.h> /* kern_clock_gettime() */ 53 54 static int wd_set_pretimeout(int newtimeout, int disableiftoolong); 55 static void wd_timeout_cb(void *arg); 56 57 static struct callout wd_pretimeo_handle; 58 static int wd_pretimeout; 59 static int wd_pretimeout_act = WD_SOFT_LOG; 60 61 static struct callout wd_softtimeo_handle; 62 static int wd_softtimer; /* true = use softtimer instead of hardware 63 watchdog */ 64 static int wd_softtimeout_act = WD_SOFT_LOG; /* action for the software timeout */ 65 66 static struct cdev *wd_dev; 67 static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ 68 static u_int wd_last_u_sysctl; /* last timeout value set by kern_do_pat */ 69 static u_int wd_last_u_sysctl_secs; /* wd_last_u in seconds */ 70 71 SYSCTL_NODE(_hw, OID_AUTO, watchdog, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 72 "Main watchdog device"); 73 SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u, CTLFLAG_RD, 74 &wd_last_u_sysctl, 0, "Watchdog last update time"); 75 SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD, 76 &wd_last_u_sysctl_secs, 0, "Watchdog last update time"); 77 78 static int wd_lastpat_valid = 0; 79 static time_t wd_lastpat = 0; /* when the watchdog was last patted */ 80 81 /* Hook for external software watchdog to register for use if needed */ 82 void (*wdog_software_attach)(void); 83 84 static void 85 pow2ns_to_ts(int pow2ns, struct timespec *ts) 86 { 87 uint64_t ns; 88 89 ns = 1ULL << pow2ns; 90 ts->tv_sec = ns / 1000000000ULL; 91 ts->tv_nsec = ns % 1000000000ULL; 92 } 93 94 static int 95 pow2ns_to_ticks(int pow2ns) 96 { 97 struct timeval tv; 98 struct timespec ts; 99 100 pow2ns_to_ts(pow2ns, &ts); 101 TIMESPEC_TO_TIMEVAL(&tv, &ts); 102 return (tvtohz(&tv)); 103 } 104 105 static int 106 seconds_to_pow2ns(int seconds) 107 { 108 uint64_t power; 109 uint64_t ns; 110 uint64_t shifted; 111 112 ns = ((uint64_t)seconds) * 1000000000ULL; 113 power = flsll(ns); 114 shifted = 1ULL << power; 115 if (shifted <= ns) { 116 power++; 117 } 118 return (power); 119 } 120 121 int 122 wdog_kern_pat(u_int utim) 123 { 124 int error; 125 static int first = 1; 126 127 if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) 128 return (EINVAL); 129 130 if ((utim & WD_LASTVAL) != 0) { 131 /* 132 * if WD_LASTVAL is set, fill in the bits for timeout 133 * from the saved value in wd_last_u. 134 */ 135 MPASS((wd_last_u & ~WD_INTERVAL) == 0); 136 utim &= ~WD_LASTVAL; 137 utim |= wd_last_u; 138 } else { 139 /* 140 * Otherwise save the new interval. 141 * This can be zero (to disable the watchdog) 142 */ 143 wd_last_u = (utim & WD_INTERVAL); 144 wd_last_u_sysctl = wd_last_u; 145 wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz; 146 } 147 if ((utim & WD_INTERVAL) == WD_TO_NEVER) { 148 utim = 0; 149 150 /* Assume all is well; watchdog signals failure. */ 151 error = 0; 152 } else { 153 /* Assume no watchdog available; watchdog flags success */ 154 error = EOPNOTSUPP; 155 } 156 if (wd_softtimer) { 157 if (utim == 0) { 158 callout_stop(&wd_softtimeo_handle); 159 } else { 160 (void) callout_reset(&wd_softtimeo_handle, 161 pow2ns_to_ticks(utim), wd_timeout_cb, "soft"); 162 } 163 error = 0; 164 } else { 165 EVENTHANDLER_INVOKE(watchdog_list, utim, &error); 166 } 167 /* 168 * If we no hardware watchdog responded, we have not tried to 169 * attach an external software watchdog, and one is available, 170 * attach it now and retry. 171 */ 172 if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) { 173 (*wdog_software_attach)(); 174 EVENTHANDLER_INVOKE(watchdog_list, utim, &error); 175 } 176 first = 0; 177 178 wd_set_pretimeout(wd_pretimeout, true); 179 /* 180 * If we were able to arm/strobe the watchdog, then 181 * update the last time it was strobed for WDIOC_GETTIMELEFT 182 */ 183 if (!error) { 184 struct timespec ts; 185 186 error = kern_clock_gettime(curthread /* XXX */, 187 CLOCK_MONOTONIC_FAST, &ts); 188 if (!error) { 189 wd_lastpat = ts.tv_sec; 190 wd_lastpat_valid = 1; 191 } 192 } 193 return (error); 194 } 195 196 static int 197 wd_valid_act(int act) 198 { 199 200 if ((act & ~(WD_SOFT_MASK)) != 0) 201 return false; 202 return true; 203 } 204 205 static int 206 wd_ioctl_patpat(caddr_t data) 207 { 208 u_int u; 209 210 u = *(u_int *)data; 211 if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) 212 return (EINVAL); 213 if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE)) 214 return (EINVAL); 215 if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 || 216 (u & WD_LASTVAL) != 0)) 217 return (EINVAL); 218 if (u & WD_PASSIVE) 219 return (ENOSYS); /* XXX Not implemented yet */ 220 u &= ~(WD_ACTIVE | WD_PASSIVE); 221 222 return (wdog_kern_pat(u)); 223 } 224 225 static int 226 wd_get_time_left(struct thread *td, time_t *remainp) 227 { 228 struct timespec ts; 229 int error; 230 231 error = kern_clock_gettime(td, CLOCK_MONOTONIC_FAST, &ts); 232 if (error) 233 return (error); 234 if (!wd_lastpat_valid) 235 return (ENOENT); 236 *remainp = ts.tv_sec - wd_lastpat; 237 return (0); 238 } 239 240 static void 241 wd_timeout_cb(void *arg) 242 { 243 const char *type = arg; 244 245 #ifdef DDB 246 if ((wd_pretimeout_act & WD_SOFT_DDB)) { 247 char kdb_why[80]; 248 snprintf(kdb_why, sizeof(kdb_why), "watchdog %s-timeout", type); 249 kdb_backtrace(); 250 kdb_enter(KDB_WHY_WATCHDOG, kdb_why); 251 } 252 #endif 253 if ((wd_pretimeout_act & WD_SOFT_LOG)) 254 log(LOG_EMERG, "watchdog %s-timeout, WD_SOFT_LOG\n", type); 255 if ((wd_pretimeout_act & WD_SOFT_PRINTF)) 256 printf("watchdog %s-timeout, WD_SOFT_PRINTF\n", type); 257 if ((wd_pretimeout_act & WD_SOFT_PANIC)) 258 panic("watchdog %s-timeout, WD_SOFT_PANIC set", type); 259 } 260 261 /* 262 * Called to manage timeouts. 263 * newtimeout needs to be in the range of 0 to actual watchdog timeout. 264 * if 0, we disable the pre-timeout. 265 * otherwise we set the pre-timeout provided it's not greater than the 266 * current actual watchdog timeout. 267 */ 268 static int 269 wd_set_pretimeout(int newtimeout, int disableiftoolong) 270 { 271 u_int utime; 272 struct timespec utime_ts; 273 int timeout_ticks; 274 275 utime = wdog_kern_last_timeout(); 276 pow2ns_to_ts(utime, &utime_ts); 277 /* do not permit a pre-timeout >= than the timeout. */ 278 if (newtimeout >= utime_ts.tv_sec) { 279 /* 280 * If 'disableiftoolong' then just fall through 281 * so as to disable the pre-watchdog 282 */ 283 if (disableiftoolong) 284 newtimeout = 0; 285 else 286 return EINVAL; 287 } 288 289 /* disable the pre-timeout */ 290 if (newtimeout == 0) { 291 wd_pretimeout = 0; 292 callout_stop(&wd_pretimeo_handle); 293 return 0; 294 } 295 296 timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); 297 #if 0 298 printf("wd_set_pretimeout: " 299 "newtimeout: %d, " 300 "utime: %d -> utime_ticks: %d, " 301 "hz*newtimeout: %d, " 302 "timeout_ticks: %d -> sec: %d\n", 303 newtimeout, 304 utime, pow2ns_to_ticks(utime), 305 hz*newtimeout, 306 timeout_ticks, timeout_ticks / hz); 307 #endif 308 309 /* We determined the value is sane, so reset the callout */ 310 (void) callout_reset(&wd_pretimeo_handle, 311 timeout_ticks, wd_timeout_cb, "pre"); 312 wd_pretimeout = newtimeout; 313 return 0; 314 } 315 316 static int 317 wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, 318 int flags __unused, struct thread *td) 319 { 320 u_int u; 321 time_t timeleft; 322 int error; 323 324 error = 0; 325 326 switch (cmd) { 327 case WDIOC_SETSOFT: 328 u = *(int *)data; 329 /* do nothing? */ 330 if (u == wd_softtimer) 331 break; 332 /* If there is a pending timeout disallow this ioctl */ 333 if (wd_last_u != 0) { 334 error = EINVAL; 335 break; 336 } 337 wd_softtimer = u; 338 break; 339 case WDIOC_SETSOFTTIMEOUTACT: 340 u = *(int *)data; 341 if (wd_valid_act(u)) { 342 wd_softtimeout_act = u; 343 } else { 344 error = EINVAL; 345 } 346 break; 347 case WDIOC_SETPRETIMEOUTACT: 348 u = *(int *)data; 349 if (wd_valid_act(u)) { 350 wd_pretimeout_act = u; 351 } else { 352 error = EINVAL; 353 } 354 break; 355 case WDIOC_GETPRETIMEOUT: 356 *(int *)data = (int)wd_pretimeout; 357 break; 358 case WDIOC_SETPRETIMEOUT: 359 error = wd_set_pretimeout(*(int *)data, false); 360 break; 361 case WDIOC_GETTIMELEFT: 362 error = wd_get_time_left(td, &timeleft); 363 if (error) 364 break; 365 *(int *)data = (int)timeleft; 366 break; 367 case WDIOC_SETTIMEOUT: 368 u = *(u_int *)data; 369 error = wdog_kern_pat(seconds_to_pow2ns(u)); 370 break; 371 case WDIOC_GETTIMEOUT: 372 u = wdog_kern_last_timeout(); 373 *(u_int *)data = u; 374 break; 375 case WDIOCPATPAT: 376 error = wd_ioctl_patpat(data); 377 break; 378 default: 379 error = ENOIOCTL; 380 break; 381 } 382 return (error); 383 } 384 385 /* 386 * Return the last timeout set, this is NOT the seconds from NOW until timeout, 387 * rather it is the amount of seconds passed to WDIOCPATPAT/WDIOC_SETTIMEOUT. 388 */ 389 u_int 390 wdog_kern_last_timeout(void) 391 { 392 393 return (wd_last_u); 394 } 395 396 static struct cdevsw wd_cdevsw = { 397 .d_version = D_VERSION, 398 .d_ioctl = wd_ioctl, 399 .d_name = "watchdog", 400 }; 401 402 static int 403 watchdog_modevent(module_t mod __unused, int type, void *data __unused) 404 { 405 switch(type) { 406 case MOD_LOAD: 407 callout_init(&wd_pretimeo_handle, 1); 408 callout_init(&wd_softtimeo_handle, 1); 409 wd_dev = make_dev(&wd_cdevsw, 0, 410 UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG); 411 return 0; 412 case MOD_UNLOAD: 413 callout_stop(&wd_pretimeo_handle); 414 callout_stop(&wd_softtimeo_handle); 415 callout_drain(&wd_pretimeo_handle); 416 callout_drain(&wd_softtimeo_handle); 417 destroy_dev(wd_dev); 418 return 0; 419 case MOD_SHUTDOWN: 420 return 0; 421 default: 422 return EOPNOTSUPP; 423 } 424 } 425 426 DEV_MODULE(watchdog, watchdog_modevent, NULL); 427