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