1 /*- 2 * Copyright (c) 2011 Sandvine Incorporated ULC. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* 27 * Support for Winbond watchdog. 28 * 29 * With minor abstractions it might be possible to add support for other 30 * different Winbond Super I/O chips as well. Winbond seems to have four 31 * different types of chips, four different ways to get into extended config 32 * mode. 33 * 34 * Note: there is no serialization between the debugging sysctl handlers and 35 * the watchdog functions and possibly others poking the registers at the same 36 * time. For that at least possibly interfering sysctls are hidden by default. 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/param.h> 43 #include <sys/kernel.h> 44 #include <sys/systm.h> 45 #include <sys/bus.h> 46 #include <sys/eventhandler.h> 47 #include <sys/lock.h> 48 #include <sys/module.h> 49 #include <sys/rman.h> 50 #include <sys/sbuf.h> 51 #include <sys/sysctl.h> 52 #include <sys/watchdog.h> 53 54 #include <isa/isavar.h> 55 56 #include <machine/bus.h> 57 #include <machine/resource.h> 58 59 /* 60 * Global registers. 61 */ 62 #define WB_DEVICE_ID_REG 0x20 /* Device ID */ 63 #define WB_DEVICE_REV_REG 0x21 /* Device revision */ 64 #define WB_CR26 0x26 /* Bit6: HEFRAS (base port selector) */ 65 66 /* LDN selection. */ 67 #define WB_LDN_REG 0x07 68 #define WB_LDN_REG_LDN8 0x08 /* GPIO 2, Watchdog */ 69 70 /* 71 * LDN8 (GPIO 2, Watchdog) specific registers and options. 72 */ 73 /* CR30: LDN8 activation control. */ 74 #define WB_LDN8_CR30 0x30 75 #define WB_LDN8_CR30_ACTIVE 0x01 /* 1: LD active */ 76 77 /* CRF5: Watchdog scale, P20. Mapped to reg_1. */ 78 #define WB_LDN8_CRF5 0xF5 79 #define WB_LDN8_CRF5_SCALE 0x08 /* 0: 1s, 1: 60s */ 80 #define WB_LDN8_CRF5_KEYB_P20 0x04 /* 1: keyb P20 forces timeout */ 81 82 /* CRF6: Watchdog Timeout (0 == off). Mapped to reg_timeout. */ 83 #define WB_LDN8_CRF6 0xF6 84 85 /* CRF7: Watchdog mouse, keyb, force, .. Mapped to reg_2. */ 86 #define WB_LDN8_CRF7 0xF7 87 #define WB_LDN8_CRF7_MOUSE 0x80 /* 1: mouse irq resets wd timer */ 88 #define WB_LDN8_CRF7_KEYB 0x40 /* 1: keyb irq resets wd timer */ 89 #define WB_LDN8_CRF7_FORCE 0x20 /* 1: force timeout (self-clear) */ 90 #define WB_LDN8_CRF7_TS 0x10 /* 0: counting, 1: fired */ 91 #define WB_LDN8_CRF7_IRQS 0x0f /* irq source for watchdog, 2 == SMI */ 92 #define WB_LDN8_CRF7_CLEAR_MASK \ 93 (WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_KEYB|WB_LDN8_CRF7_TS|WB_LDN8_CRF7_IRQS) 94 95 #define write_efir_1(sc, value) \ 96 bus_space_write_1((sc)->bst, (sc)->bsh, 0, (value)) 97 #define read_efir_1(sc) \ 98 bus_space_read_1((sc)->bst, (sc)->bsh, 0) 99 #define write_efdr_1(sc, value) \ 100 bus_space_write_1((sc)->bst, (sc)->bsh, 1, (value)) 101 #define read_efdr_1(sc) \ 102 bus_space_read_1((sc)->bst, (sc)->bsh, 1) 103 104 struct wb_softc { 105 device_t dev; 106 struct resource *portres; 107 bus_space_tag_t bst; 108 bus_space_handle_t bsh; 109 int rid; 110 eventhandler_tag ev_tag; 111 int (*ext_cfg_enter_f)(struct wb_softc *); 112 void (*ext_cfg_exit_f)(struct wb_softc *); 113 int debug_verbose; 114 115 /* 116 * Special feature to let the watchdog fire at a different 117 * timeout as set by watchdog(4) but still use that API to 118 * re-load it periodically. 119 */ 120 unsigned int timeout_override; 121 122 /* 123 * Space to save current state temporary and for sysctls. 124 * We want to know the timeout value and usually need two 125 * additional registers for options. Do not name them by 126 * register as these might be different by chip. 127 */ 128 uint8_t reg_timeout; 129 uint8_t reg_1; 130 uint8_t reg_2; 131 }; 132 133 static int ext_cfg_enter_0x87_0x87(struct wb_softc *); 134 static void ext_cfg_exit_0xaa(struct wb_softc *); 135 136 struct winbond_superio_cfg { 137 uint8_t efer; /* and efir */ 138 int (*ext_cfg_enter_f)(struct wb_softc *); 139 void (*ext_cfg_exit_f)(struct wb_softc *); 140 } probe_addrs[] = { 141 { 142 .efer = 0x2e, 143 .ext_cfg_enter_f = ext_cfg_enter_0x87_0x87, 144 .ext_cfg_exit_f = ext_cfg_exit_0xaa, 145 }, 146 { 147 .efer = 0x4e, 148 .ext_cfg_enter_f = ext_cfg_enter_0x87_0x87, 149 .ext_cfg_exit_f = ext_cfg_exit_0xaa, 150 }, 151 }; 152 153 struct winbond_vendor_device_id { 154 uint16_t vendor_id; 155 uint8_t device_id; 156 uint8_t device_rev; 157 const char * descr; 158 } wb_devs[] = { 159 { 160 .vendor_id = 0x5ca3, 161 .device_id = 0x52, 162 .device_rev = 0x17, 163 .descr = "Winbond 83627HF/F/HG/G Rev. G", 164 }, 165 { 166 .vendor_id = 0x5ca3, 167 .device_id = 0x52, 168 .device_rev = 0x3a, 169 .descr = "Winbond 83627HF/F/HG/G Rev. J", 170 }, 171 { 172 .vendor_id = 0x5ca3, 173 .device_id = 0x52, 174 .device_rev = 0x41, 175 .descr = "Winbond 83627HF/F/HG/G Rev. UD-A", 176 }, 177 { 178 .vendor_id = 0x5ca3, 179 .device_id = 0xa0, 180 .device_rev = 0x25, 181 .descr = "Winbond 83627DHG IC ver. 5", 182 }, 183 }; 184 185 /* 186 * Return the watchdog related registers as we last read them. This will 187 * usually not give the current timeout or state on whether the watchdog 188 * fired. 189 */ 190 static int 191 sysctl_wb_debug(SYSCTL_HANDLER_ARGS) 192 { 193 struct wb_softc *sc; 194 struct sbuf sb; 195 int error; 196 197 sc = arg1; 198 199 sbuf_new_for_sysctl(&sb, NULL, 64, req); 200 201 sbuf_printf(&sb, "LDN8 (GPIO2, Watchdog): "); 202 sbuf_printf(&sb, "CRF5 0x%02x ", sc->reg_1); 203 sbuf_printf(&sb, "CRF6 0x%02x ", sc->reg_timeout); 204 sbuf_printf(&sb, "CRF7 0x%02x ", sc->reg_2); 205 206 sbuf_trim(&sb); 207 error = sbuf_finish(&sb); 208 sbuf_delete(&sb); 209 return (error); 210 } 211 212 /* 213 * Read the current values before returning them. Given this might poke 214 * the registers the same time as the watchdog, this sysctl handler should 215 * be marked CTLFLAG_SKIP to not show up by default. 216 */ 217 static int 218 sysctl_wb_debug_current(SYSCTL_HANDLER_ARGS) 219 { 220 struct wb_softc *sc; 221 222 sc = arg1; 223 224 /* 225 * Enter extended function mode in case someone else has been 226 * poking on the registers. We will not leave it though. 227 */ 228 if ((*sc->ext_cfg_enter_f)(sc) != 0) 229 return (ENXIO); 230 231 /* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */ 232 write_efir_1(sc, WB_LDN_REG); 233 write_efdr_1(sc, WB_LDN_REG_LDN8); 234 235 write_efir_1(sc, WB_LDN8_CRF5); 236 sc->reg_1 = read_efdr_1(sc); 237 write_efir_1(sc, WB_LDN8_CRF6); 238 sc->reg_timeout = read_efdr_1(sc); 239 write_efir_1(sc, WB_LDN8_CRF7); 240 sc->reg_2 = read_efdr_1(sc); 241 242 return (sysctl_wb_debug(oidp, arg1, arg2, req)); 243 } 244 245 /* 246 * Sysctl handlers to force a watchdog timeout or to test the NMI functionality 247 * works as expetced. 248 * For testing we could set a test_nmi flag in the softc that, in case of NMI, a 249 * callback function from trap.c could check whether we fired and not report the 250 * timeout but clear the flag for the sysctl again. This is interesting given a 251 * lot of boards have jumpers to change the action on watchdog timeout or 252 * disable the watchdog completely. 253 * XXX-BZ notyet: currently no general infrastructure exists to do this. 254 */ 255 static int 256 sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS) 257 { 258 struct wb_softc *sc; 259 int error, test, val; 260 261 sc = arg1; 262 test = arg2; 263 264 #ifdef notyet 265 val = sc->test_nmi; 266 #else 267 val = 0; 268 #endif 269 error = sysctl_handle_int(oidp, &val, 0, req); 270 if (error || !req->newptr) 271 return (error); 272 273 #ifdef notyet 274 /* Manually clear the test for a value of 0 and do nothing else. */ 275 if (test && val == 0) { 276 sc->test_nmi = 0; 277 return (0); 278 } 279 #endif 280 281 /* 282 * Enter extended function mode in case someone else has been 283 * poking on the registers. We will not leave it though. 284 */ 285 if ((*sc->ext_cfg_enter_f)(sc) != 0) 286 return (ENXIO); 287 288 #ifdef notyet 289 /* 290 * If we are testing the NMI functionality, set the flag before 291 * forcing the timeout. 292 */ 293 if (test) 294 sc->test_nmi = 1; 295 #endif 296 297 /* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */ 298 write_efir_1(sc, WB_LDN_REG); 299 write_efdr_1(sc, WB_LDN_REG_LDN8); 300 301 /* Force watchdog to fire. */ 302 write_efir_1(sc, WB_LDN8_CRF7); 303 sc->reg_2 = read_efdr_1(sc); 304 sc->reg_2 |= WB_LDN8_CRF7_FORCE; 305 306 write_efir_1(sc, WB_LDN8_CRF7); 307 write_efdr_1(sc, sc->reg_2); 308 309 return (0); 310 } 311 312 /* 313 * Print current watchdog state. 314 * 315 * Note: it is the responsibility of the caller to update the registers 316 * upfront. 317 */ 318 static void 319 wb_print_state(struct wb_softc *sc, const char *msg) 320 { 321 322 device_printf(sc->dev, "%s%sWatchdog %sabled. %s" 323 "Scaling by %ds, timer at %d (%s=%ds%s). " 324 "CRF5 0x%02x CRF7 0x%02x\n", 325 (msg != NULL) ? msg : "", (msg != NULL) ? ": " : "", 326 (sc->reg_timeout > 0x00) ? "en" : "dis", 327 (sc->reg_2 & WB_LDN8_CRF7_TS) ? "Watchdog fired. " : "", 328 (sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1, 329 sc->reg_timeout, 330 (sc->reg_timeout > 0x00) ? "<" : "", 331 sc->reg_timeout * ((sc->reg_1 & WB_LDN8_CRF5_SCALE) ? 60 : 1), 332 (sc->reg_timeout > 0x00) ? " left" : "", 333 sc->reg_1, sc->reg_2); 334 } 335 336 /* 337 * Functions to enter and exit extended function mode. Possibly shared 338 * between different chips. 339 */ 340 static int 341 ext_cfg_enter_0x87_0x87(struct wb_softc *sc) 342 { 343 344 /* 345 * Enable extended function mode. 346 * Winbond does not allow us to validate so always return success. 347 */ 348 write_efir_1(sc, 0x87); 349 write_efir_1(sc, 0x87); 350 351 return (0); 352 } 353 354 static void 355 ext_cfg_exit_0xaa(struct wb_softc *sc) 356 { 357 358 write_efir_1(sc, 0xaa); 359 } 360 361 /* 362 * (Re)load the watchdog counter depending on timeout. A timeout of 0 will 363 * disable the watchdog. 364 */ 365 static int 366 wb_set_watchdog(struct wb_softc *sc, unsigned int timeout) 367 { 368 369 if (sc->debug_verbose) 370 wb_print_state(sc, "Before watchdog counter (re)load"); 371 372 /* 373 * Enter extended function mode in case someone else has been 374 * poking on the registers. We will not leave it though. 375 */ 376 if ((*sc->ext_cfg_enter_f)(sc) != 0) 377 return (ENXIO); 378 379 /* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog) */ 380 write_efir_1(sc, WB_LDN_REG); 381 write_efdr_1(sc, WB_LDN_REG_LDN8); 382 383 /* Disable and validate or arm/reset watchdog. */ 384 if (timeout == 0) { 385 /* Disable watchdog. */ 386 write_efir_1(sc, WB_LDN8_CRF6); 387 write_efdr_1(sc, 0x00); 388 389 /* Re-check. */ 390 write_efir_1(sc, WB_LDN8_CRF6); 391 sc->reg_timeout = read_efdr_1(sc); 392 393 if (sc->reg_timeout != 0x00) { 394 device_printf(sc->dev, "Failed to disable watchdog: " 395 "0x%02x.\n", sc->reg_timeout); 396 return (EIO); 397 } 398 399 } else { 400 /* 401 * In case an override is set, let it override. It may lead 402 * to strange results as we do not check the input of the sysctl. 403 */ 404 if (sc->timeout_override > 0) 405 timeout = sc->timeout_override; 406 407 /* Make sure we support the requested timeout. */ 408 if (timeout > 255 * 60) 409 return (EINVAL); 410 411 /* Read current scaling factor. */ 412 write_efir_1(sc, WB_LDN8_CRF5); 413 sc->reg_1 = read_efdr_1(sc); 414 415 if (timeout > 255) { 416 /* Set scaling factor to 60s. */ 417 sc->reg_1 |= WB_LDN8_CRF5_SCALE; 418 sc->reg_timeout = (timeout / 60); 419 if (timeout % 60) 420 sc->reg_timeout++; 421 } else { 422 /* Set scaling factor to 1s. */ 423 sc->reg_1 &= ~WB_LDN8_CRF5_SCALE; 424 sc->reg_timeout = timeout; 425 } 426 427 /* In case we fired before we need to clear to fire again. */ 428 write_efir_1(sc, WB_LDN8_CRF7); 429 sc->reg_2 = read_efdr_1(sc); 430 if (sc->reg_2 & WB_LDN8_CRF7_TS) { 431 sc->reg_2 &= ~WB_LDN8_CRF7_TS; 432 write_efir_1(sc, WB_LDN8_CRF7); 433 write_efdr_1(sc, sc->reg_2); 434 } 435 436 /* Write back scaling factor. */ 437 write_efir_1(sc, WB_LDN8_CRF5); 438 write_efdr_1(sc, sc->reg_1); 439 440 /* Set timer and arm/reset the watchdog. */ 441 write_efir_1(sc, WB_LDN8_CRF6); 442 write_efdr_1(sc, sc->reg_timeout); 443 } 444 445 if (sc->debug_verbose) 446 wb_print_state(sc, "After watchdog counter (re)load"); 447 448 return (0); 449 } 450 451 /* 452 * watchdog(9) EVENTHANDLER function implementation to (re)load the counter 453 * with the given timeout or disable the watchdog. 454 */ 455 static void 456 wb_watchdog_fn(void *private, u_int cmd, int *error) 457 { 458 struct wb_softc *sc; 459 unsigned int timeout; 460 int e; 461 462 sc = private; 463 KASSERT(sc != NULL, ("%s: watchdog handler function called without " 464 "softc.", __func__)); 465 466 cmd &= WD_INTERVAL; 467 if (cmd > 0 && cmd <= 63) { 468 /* Reset (and arm) watchdog. */ 469 timeout = ((uint64_t)1 << cmd) / 1000000000; 470 if (timeout == 0) 471 timeout = 1; 472 e = wb_set_watchdog(sc, timeout); 473 if (e == 0) { 474 if (error != NULL) 475 *error = 0; 476 } else { 477 /* On error, try to make sure the WD is disabled. */ 478 wb_set_watchdog(sc, 0); 479 } 480 481 } else { 482 /* Disable watchdog. */ 483 e = wb_set_watchdog(sc, 0); 484 if (e != 0 && cmd == 0 && error != NULL) { 485 /* Failed to disable watchdog. */ 486 *error = EOPNOTSUPP; 487 } 488 } 489 } 490 491 /* 492 * Probe/attach the Winbond Super I/O chip. 493 * 494 * Initial abstraction to possibly support more chips: 495 * - Iterate over the well known base ports, try to enable extended function 496 * mode and read and match the device ID and device revision. Unfortunately 497 * the Vendor ID is in the hardware monitoring section accessible by different 498 * base ports only. 499 * - Also HEFRAS, which would tell use the base port, is only accessible after 500 * entering extended function mode, for which the base port is needed. 501 * At least check HEFRAS to match the current base port we are probing. 502 * - On match set the description, remember functions to enter/exit extended 503 * function mode as well as the base port. 504 */ 505 static int 506 wb_probe_enable(device_t dev, int probe) 507 { 508 struct wb_softc *sc; 509 int error, found, i, j; 510 uint8_t dev_id, dev_rev, cr26; 511 512 sc = device_get_softc(dev); 513 bzero(sc, sizeof(*sc)); 514 sc->dev = dev; 515 516 error = ENXIO; 517 for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) { 518 519 /* Allocate bus resources for IO index/data register access. */ 520 sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 521 probe_addrs[i].efer, probe_addrs[i].efer + 1, 2, RF_ACTIVE); 522 if (sc->portres == NULL) 523 continue; 524 sc->bst = rman_get_bustag(sc->portres); 525 sc->bsh = rman_get_bushandle(sc->portres); 526 527 found = 0; 528 error = (*probe_addrs[i].ext_cfg_enter_f)(sc); 529 if (error != 0) 530 goto cleanup; 531 532 /* Identify the SuperIO chip. */ 533 write_efir_1(sc, WB_DEVICE_ID_REG); 534 dev_id = read_efdr_1(sc); 535 write_efir_1(sc, WB_DEVICE_REV_REG); 536 dev_rev = read_efdr_1(sc); 537 write_efir_1(sc, WB_CR26); 538 cr26 = read_efdr_1(sc); 539 540 /* HEFRAS of 0 means EFER at 0x2e, 1 means EFER at 0x4e. */ 541 if (((cr26 & 0x40) == 0x00 && probe_addrs[i].efer != 0x2e) || 542 ((cr26 & 0x40) == 0x40 && probe_addrs[i].efer != 0x4e)) { 543 device_printf(dev, "HEFRAS and EFER do not align: EFER " 544 "0x%02x DevID 0x%02x DevRev 0x%02x CR26 0x%02x\n", 545 probe_addrs[i].efer, dev_id, dev_rev, cr26); 546 goto cleanup; 547 } 548 549 for (j = 0; j < sizeof(wb_devs) / sizeof(*wb_devs); j++) { 550 if (wb_devs[j].device_id == dev_id && 551 wb_devs[j].device_rev == dev_rev) { 552 if (probe) 553 device_set_desc(dev, wb_devs[j].descr); 554 found++; 555 break; 556 } 557 } 558 if (probe && found && bootverbose) 559 device_printf(dev, "%s EFER 0x%02x ID 0x%02x Rev 0x%02x" 560 " CR26 0x%02x (probing)\n", device_get_desc(dev), 561 probe_addrs[i].efer, dev_id, dev_rev, cr26); 562 cleanup: 563 if (probe || !found) { 564 (*probe_addrs[i].ext_cfg_exit_f)(sc); 565 566 (void) bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, 567 sc->portres); 568 } 569 570 /* 571 * Stop probing if have successfully identified the SuperIO. 572 * Remember the extended function mode enter/exit functions 573 * for operations. 574 */ 575 if (found) { 576 sc->ext_cfg_enter_f = probe_addrs[i].ext_cfg_enter_f; 577 sc->ext_cfg_exit_f = probe_addrs[i].ext_cfg_exit_f; 578 error = BUS_PROBE_DEFAULT; 579 break; 580 } else 581 error = ENXIO; 582 } 583 584 return (error); 585 } 586 587 static int 588 wb_probe(device_t dev) 589 { 590 591 /* Make sure we do not claim some ISA PNP device. */ 592 if (isa_get_logicalid(dev) != 0) 593 return (ENXIO); 594 595 return (wb_probe_enable(dev, 1)); 596 } 597 598 static int 599 wb_attach(device_t dev) 600 { 601 struct wb_softc *sc; 602 struct sysctl_ctx_list *sctx; 603 struct sysctl_oid *soid; 604 unsigned long timeout; 605 int error; 606 607 error = wb_probe_enable(dev, 0); 608 if (error > 0) 609 return (ENXIO); 610 611 sc = device_get_softc(dev); 612 KASSERT(sc->ext_cfg_enter_f != NULL && sc->ext_cfg_exit_f != NULL, 613 ("%s: successfull probe result but not setup correctly", __func__)); 614 615 /* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */ 616 write_efir_1(sc, WB_LDN_REG); 617 write_efdr_1(sc, WB_LDN_REG_LDN8); 618 619 /* Make sure LDN8 is enabled (Do we need to? Also affects GPIO). */ 620 write_efir_1(sc, WB_LDN8_CR30); 621 write_efdr_1(sc, WB_LDN8_CR30_ACTIVE); 622 623 /* Read the current watchdog configuration. */ 624 write_efir_1(sc, WB_LDN8_CRF5); 625 sc->reg_1 = read_efdr_1(sc); 626 write_efir_1(sc, WB_LDN8_CRF6); 627 sc->reg_timeout = read_efdr_1(sc); 628 write_efir_1(sc, WB_LDN8_CRF7); 629 sc->reg_2 = read_efdr_1(sc); 630 631 /* Print current state if bootverbose or watchdog already enabled. */ 632 if (bootverbose || (sc->reg_timeout > 0x00)) 633 wb_print_state(sc, "Before watchdog attach"); 634 635 /* 636 * Clear a previous watchdog timeout event (if (still) set). 637 * Disable all all interrupt reset sources (defaults). 638 */ 639 sc->reg_1 &= ~(WB_LDN8_CRF5_KEYB_P20); 640 write_efir_1(sc, WB_LDN8_CRF5); 641 write_efir_1(sc, sc->reg_1); 642 643 sc->reg_2 &= ~WB_LDN8_CRF7_CLEAR_MASK; 644 write_efir_1(sc, WB_LDN8_CRF7); 645 write_efdr_1(sc, sc->reg_2); 646 647 /* Read global timeout override tunable, Add per device sysctls. */ 648 if (TUNABLE_ULONG_FETCH("hw.wbwd.timeout_override", &timeout)) { 649 if (timeout > 0) 650 sc->timeout_override = timeout; 651 } 652 sctx = device_get_sysctl_ctx(dev); 653 soid = device_get_sysctl_tree(dev); 654 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 655 "timeout_override", CTLFLAG_RW, &sc->timeout_override, 0, 656 "Timeout in seconds overriding default watchdog timeout"); 657 SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 658 "debug_verbose", CTLFLAG_RW, &sc->debug_verbose, 0, 659 "Enables extra debugging information"); 660 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug", 661 CTLTYPE_STRING|CTLFLAG_RD, sc, 0, sysctl_wb_debug, "A", 662 "Selected register information from last change by driver"); 663 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug_current", 664 CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_SKIP, sc, 0, 665 sysctl_wb_debug_current, "A", 666 "Selected register information (may interfere)"); 667 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "force_timeout", 668 CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_SKIP, sc, 0, 669 sysctl_wb_force_test_nmi, "I", "Enable to force watchdog to fire."); 670 671 /* Register watchdog. */ 672 sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, wb_watchdog_fn, sc, 673 0); 674 675 if (bootverbose) 676 wb_print_state(sc, "After watchdog attach"); 677 678 return (0); 679 } 680 681 static int 682 wb_detach(device_t dev) 683 { 684 struct wb_softc *sc; 685 686 sc = device_get_softc(dev); 687 688 /* Unregister and stop the watchdog if running. */ 689 if (sc->ev_tag) 690 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag); 691 wb_set_watchdog(sc, 0); 692 693 /* Disable extended function mode. */ 694 (*sc->ext_cfg_exit_f)(sc); 695 696 /* Cleanup resources. */ 697 (void) bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 698 699 /* Bus subroutines take care of sysctls already. */ 700 701 return (0); 702 } 703 704 static device_method_t wb_methods[] = { 705 /* Device interface */ 706 DEVMETHOD(device_probe, wb_probe), 707 DEVMETHOD(device_attach, wb_attach), 708 DEVMETHOD(device_detach, wb_detach), 709 710 { 0, 0 } 711 }; 712 713 static driver_t wb_isa_driver = { 714 "wbwd", 715 wb_methods, 716 sizeof(struct wb_softc) 717 }; 718 719 static devclass_t wb_devclass; 720 721 DRIVER_MODULE(wb, isa, wb_isa_driver, wb_devclass, NULL, NULL); 722