1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Tetsuya Uemura <t_uemura@macome.co.jp> 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 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_acpi.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/callout.h> 37 #include <sys/eventhandler.h> 38 #include <sys/interrupt.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/queue.h> 43 #include <sys/rman.h> 44 #include <sys/sysctl.h> 45 #include <sys/watchdog.h> 46 #include <vm/vm.h> 47 #include <vm/pmap.h> 48 49 #include <contrib/dev/acpica/include/acpi.h> 50 #include <contrib/dev/acpica/include/accommon.h> 51 #include <contrib/dev/acpica/include/aclocal.h> 52 #include <contrib/dev/acpica/include/actables.h> 53 54 #include <dev/acpica/acpivar.h> 55 56 /* 57 * Resource entry. Every instruction has the corresponding ACPI GAS but two or 58 * more instructions may access the same or adjacent register region(s). So we 59 * need to merge all the specified resources. 60 * 61 * res Resource when allocated. 62 * start Region start address. 63 * end Region end address + 1. 64 * rid Resource rid assigned when allocated. 65 * type ACPI resource type, SYS_RES_IOPORT or SYS_RES_MEMORY. 66 * link Next/previous resource entry. 67 */ 68 struct wdat_res { 69 struct resource *res; 70 uint64_t start; 71 uint64_t end; 72 int rid; 73 int type; 74 TAILQ_ENTRY(wdat_res) link; 75 }; 76 77 /* 78 * Instruction entry. Every instruction itself is actually a single register 79 * read or write (and subsequent bit operation(s)). 80 * 0 or more instructions are tied to every watchdog action and once an action 81 * is kicked, the corresponding entries run sequentially. 82 * 83 * entry Permanent copy of ACPI_WDAT_ENTRY entry (sub-table). 84 * next Next instruction entry. 85 */ 86 struct wdat_instr { 87 ACPI_WDAT_ENTRY entry; 88 STAILQ_ENTRY(wdat_instr) next; 89 }; 90 91 /* 92 * dev Watchdog device. 93 * wdat ACPI WDAT table, can be accessed until AcpiPutTable(). 94 * default_timeout BIOS configured watchdog ticks to fire. 95 * timeout User configured timeout in millisecond or 0 if isn't set. 96 * max Max. supported watchdog ticks to be set. 97 * min Min. supported watchdog ticks to be set. 98 * period Milliseconds per watchdog tick. 99 * running True if this watchdog is running or false if stopped. 100 * stop_in_sleep False if this watchdog keeps counting down during sleep. 101 * ev_tag Tag for EVENTHANDLER_*(). 102 * action Array of watchdog instruction sets, each indexed by action. 103 */ 104 struct wdatwd_softc { 105 device_t dev; 106 ACPI_TABLE_WDAT *wdat; 107 uint64_t default_timeout; 108 uint64_t timeout; 109 u_int max; 110 u_int min; 111 u_int period; 112 bool running; 113 bool stop_in_sleep; 114 eventhandler_tag ev_tag; 115 STAILQ_HEAD(, wdat_instr) action[ACPI_WDAT_ACTION_RESERVED]; 116 TAILQ_HEAD(res_head, wdat_res) res; 117 }; 118 119 #define WDATWD_VERBOSE_PRINTF(dev, ...) \ 120 do { \ 121 if (bootverbose) \ 122 device_printf(dev, __VA_ARGS__); \ 123 } while (0) 124 125 /* 126 * Do requested action. 127 */ 128 static int 129 wdatwd_action(const struct wdatwd_softc *sc, const u_int action, const uint64_t val, uint64_t *ret) 130 { 131 struct wdat_instr *wdat; 132 const char *rw = NULL; 133 ACPI_STATUS status; 134 135 if (STAILQ_EMPTY(&sc->action[action])) { 136 WDATWD_VERBOSE_PRINTF(sc->dev, 137 "action not supported: 0x%02x\n", action); 138 return (EOPNOTSUPP); 139 } 140 141 STAILQ_FOREACH(wdat, &sc->action[action], next) { 142 ACPI_GENERIC_ADDRESS *gas = &wdat->entry.RegisterRegion; 143 uint64_t x, y; 144 145 switch (wdat->entry.Instruction 146 & ~ACPI_WDAT_PRESERVE_REGISTER) { 147 case ACPI_WDAT_READ_VALUE: 148 status = AcpiRead(&x, gas); 149 if (ACPI_FAILURE(status)) { 150 rw = "AcpiRead"; 151 goto fail; 152 } 153 x >>= gas->BitOffset; 154 x &= wdat->entry.Mask; 155 *ret = (x == wdat->entry.Value) ? 1 : 0; 156 break; 157 case ACPI_WDAT_READ_COUNTDOWN: 158 status = AcpiRead(&x, gas); 159 if (ACPI_FAILURE(status)) { 160 rw = "AcpiRead"; 161 goto fail; 162 } 163 x >>= gas->BitOffset; 164 x &= wdat->entry.Mask; 165 *ret = x; 166 break; 167 case ACPI_WDAT_WRITE_VALUE: 168 x = wdat->entry.Value & wdat->entry.Mask; 169 x <<= gas->BitOffset; 170 if (wdat->entry.Instruction 171 & ACPI_WDAT_PRESERVE_REGISTER) { 172 status = AcpiRead(&y, gas); 173 if (ACPI_FAILURE(status)) { 174 rw = "AcpiRead"; 175 goto fail; 176 } 177 y &= ~(wdat->entry.Mask << gas->BitOffset); 178 x |= y; 179 } 180 status = AcpiWrite(x, gas); 181 if (ACPI_FAILURE(status)) { 182 rw = "AcpiWrite"; 183 goto fail; 184 } 185 break; 186 case ACPI_WDAT_WRITE_COUNTDOWN: 187 x = val & wdat->entry.Mask; 188 x <<= gas->BitOffset; 189 if (wdat->entry.Instruction 190 & ACPI_WDAT_PRESERVE_REGISTER) { 191 status = AcpiRead(&y, gas); 192 if (ACPI_FAILURE(status)) { 193 rw = "AcpiRead"; 194 goto fail; 195 } 196 y &= ~(wdat->entry.Mask << gas->BitOffset); 197 x |= y; 198 } 199 status = AcpiWrite(x, gas); 200 if (ACPI_FAILURE(status)) { 201 rw = "AcpiWrite"; 202 goto fail; 203 } 204 break; 205 default: 206 return (EINVAL); 207 } 208 } 209 210 return (0); 211 212 fail: 213 device_printf(sc->dev, "action: 0x%02x, %s() returned: %d\n", 214 action, rw, status); 215 return (ENXIO); 216 } 217 218 /* 219 * Reset the watchdog countdown. 220 */ 221 static int 222 wdatwd_reset_countdown(const struct wdatwd_softc *sc) 223 { 224 return wdatwd_action(sc, ACPI_WDAT_RESET, 0, NULL); 225 } 226 227 /* 228 * Set the watchdog countdown value. In WDAT specification, this is optional. 229 */ 230 static int 231 wdatwd_set_countdown(struct wdatwd_softc *sc, u_int cmd) 232 { 233 uint64_t timeout; 234 int e; 235 236 cmd &= WD_INTERVAL; 237 timeout = ((uint64_t) 1 << cmd) / 1000000 / sc->period; 238 if (timeout > sc->max) 239 timeout = sc->max; 240 else if (timeout < sc->min) 241 timeout = sc->min; 242 243 e = wdatwd_action(sc, ACPI_WDAT_SET_COUNTDOWN, timeout, NULL); 244 if (e == 0) 245 sc->timeout = timeout * sc->period; 246 247 return (e); 248 } 249 250 /* 251 * Get the watchdog current countdown value. 252 */ 253 static int 254 wdatwd_get_current_countdown(const struct wdatwd_softc *sc, uint64_t *timeout) 255 { 256 return wdatwd_action(sc, ACPI_WDAT_GET_CURRENT_COUNTDOWN, 0, timeout); 257 } 258 259 /* 260 * Get the watchdog countdown value the watchdog is configured to fire. 261 */ 262 static int 263 wdatwd_get_countdown(const struct wdatwd_softc *sc, uint64_t *timeout) 264 { 265 return wdatwd_action(sc, ACPI_WDAT_GET_COUNTDOWN, 0, timeout); 266 } 267 268 /* 269 * Set the watchdog to running state. 270 */ 271 static int 272 wdatwd_set_running(struct wdatwd_softc *sc) 273 { 274 int e; 275 276 e = wdatwd_action(sc, ACPI_WDAT_SET_RUNNING_STATE, 0, NULL); 277 if (e == 0) 278 sc->running = true; 279 return (e); 280 } 281 282 /* 283 * Set the watchdog to stopped state. 284 */ 285 static int 286 wdatwd_set_stop(struct wdatwd_softc *sc) 287 { 288 int e; 289 290 e = wdatwd_action(sc, ACPI_WDAT_SET_STOPPED_STATE, 0, NULL); 291 if (e == 0) 292 sc->running = false; 293 return (e); 294 } 295 296 /* 297 * Clear the watchdog's boot status if the current boot was caused by the 298 * watchdog firing. 299 */ 300 static int 301 wdatwd_clear_status(const struct wdatwd_softc *sc) 302 { 303 return wdatwd_action(sc, ACPI_WDAT_SET_STATUS, 0, NULL); 304 } 305 306 /* 307 * Set the watchdog to reboot when it is fired. 308 */ 309 static int 310 wdatwd_set_reboot(const struct wdatwd_softc *sc) 311 { 312 return wdatwd_action(sc, ACPI_WDAT_SET_REBOOT, 0, NULL); 313 } 314 315 /* 316 * Watchdog event handler. 317 */ 318 static void 319 wdatwd_event(void *private, u_int cmd, int *error) 320 { 321 struct wdatwd_softc *sc = private; 322 uint64_t cur[2], cnt[2]; 323 bool run[2]; 324 325 if (bootverbose) { 326 run[0] = sc->running; 327 if (wdatwd_get_countdown(sc, &cnt[0]) != 0) 328 cnt[0] = 0; 329 if (wdatwd_get_current_countdown(sc, &cur[0]) != 0) 330 cur[0] = 0; 331 } 332 333 if ((cmd & WD_INTERVAL) == 0) 334 wdatwd_set_stop(sc); 335 else { 336 if (!sc->running) { 337 /* ACPI_WDAT_SET_COUNTDOWN may not be implemented. */ 338 wdatwd_set_countdown(sc, cmd); 339 wdatwd_set_running(sc); 340 /* 341 * In the first wdatwd_event() call, it sets the 342 * watchdog timeout to a considerably larger value such 343 * as 137 seconds, then kicks the watchdog to start 344 * counting down. Weirdly though, on a Dell R210 BIOS 345 * 1.12.0, a supplemental reset action must be 346 * triggered for the newly set timeout value to take 347 * effect. Without it, the watchdog fires 2.4 seconds 348 * after starting, where 2.4 seconds is its initially 349 * set timeout. This failure scenario is seen by first 350 * starting watchdogd(8) without wdatwd registered then 351 * kldload it. In steady state, watchdogd pats the 352 * watchdog every 10 or so seconds which is much longer 353 * than 2.4 seconds timeout. 354 */ 355 } 356 wdatwd_reset_countdown(sc); 357 } 358 359 if (bootverbose) { 360 run[1] = sc->running; 361 if (wdatwd_get_countdown(sc, &cnt[1]) != 0) 362 cnt[1] = 0; 363 if (wdatwd_get_current_countdown(sc, &cur[1]) != 0) 364 cur[1] = 0; 365 WDATWD_VERBOSE_PRINTF(sc->dev, "cmd: %u, sc->running: " 366 "%d -> %d, cnt: %llu -> %llu, cur: %llu -> %llu\n", cmd, 367 run[0], run[1], 368 (unsigned long long) cnt[0], 369 (unsigned long long) cnt[1], 370 (unsigned long long)cur[0], 371 (unsigned long long)cur[1]); 372 } 373 374 return; 375 } 376 377 static ssize_t 378 wdat_set_action(struct wdatwd_softc *sc, ACPI_WDAT_ENTRY *addr, ssize_t remaining) 379 { 380 ACPI_WDAT_ENTRY *entry = addr; 381 struct wdat_instr *wdat; 382 383 if (remaining < sizeof(ACPI_WDAT_ENTRY)) 384 return (-EINVAL); 385 386 /* Skip actions beyond specification. */ 387 if (entry->Action < nitems(sc->action)) { 388 wdat = malloc(sizeof(*wdat), M_DEVBUF, M_WAITOK | M_ZERO); 389 wdat->entry = *entry; 390 STAILQ_INSERT_TAIL(&sc->action[entry->Action], wdat, next); 391 } 392 return sizeof(ACPI_WDAT_ENTRY); 393 } 394 395 /* 396 * Transform every ACPI_WDAT_ENTRY to wdat_instr by calling wdat_set_action(). 397 */ 398 static void 399 wdat_parse_action_table(struct wdatwd_softc *sc) 400 { 401 ACPI_TABLE_WDAT *wdat = sc->wdat; 402 ssize_t remaining, consumed; 403 char *cp; 404 405 remaining = wdat->Header.Length - sizeof(ACPI_TABLE_WDAT); 406 while (remaining > 0) { 407 cp = (char *)wdat + wdat->Header.Length - remaining; 408 consumed = wdat_set_action(sc, (ACPI_WDAT_ENTRY *)cp, 409 remaining); 410 if (consumed < 0) { 411 device_printf(sc->dev, "inconsistent WDAT table.\n"); 412 break; 413 } 414 remaining -= consumed; 415 } 416 } 417 418 /* 419 * Decode the given GAS rr and set its type, start and end (actually end + 1) 420 * in the newly malloc()'ed res. 421 */ 422 static struct wdat_res * 423 wdat_alloc_region(ACPI_GENERIC_ADDRESS *rr) 424 { 425 struct wdat_res *res; 426 427 if (rr->AccessWidth < 1 || rr->AccessWidth > 4) 428 return (NULL); 429 430 res = malloc(sizeof(*res), 431 M_DEVBUF, M_WAITOK | M_ZERO); 432 if (res != NULL) { 433 res->start = rr->Address; 434 res->end = res->start + (1 << (rr->AccessWidth - 1)); 435 res->type = rr->SpaceId; 436 } 437 return (res); 438 } 439 440 #define OVERLAP_NONE 0x0 // no overlap. 441 #define OVERLAP_SUBSET 0x1 // res2 is fully covered by res1. 442 #define OVERLAP_START 0x2 // the start of res2 is overlaped. 443 #define OVERLAP_END 0x4 // the end of res2 is overlapped. 444 445 /* 446 * Compare the given res1 and res2, and one of the above OVERLAP_* constant, or 447 * in case res2 is larger than res1 at both the start and the end, 448 * OVERLAP_START | OVERLAP_END, is returned. 449 */ 450 static int 451 wdat_compare_region(const struct wdat_res *res1, const struct wdat_res *res2) 452 { 453 int overlap; 454 455 /* 456 * a) both have different resource type. == OVERLAP_NONE 457 * b) res2 and res1 have no overlap. == OVERLAP_NONE 458 * c) res2 is fully covered by res1. == OVERLAP_SUBSET 459 * d) res2 and res1 overlap partially. == OVERLAP_START or 460 * OVERLAP_END 461 * e) res2 fully covers res1. == OVERLAP_START | OVERLAP_END 462 */ 463 overlap = 0; 464 465 if (res1->type != res2->type || res1->start > res2->end 466 || res1->end < res2->start) 467 overlap |= OVERLAP_NONE; 468 else { 469 if (res1->start <= res2->start && res1->end >= res2->end) 470 overlap |= OVERLAP_SUBSET; 471 if (res1->start > res2->start) 472 overlap |= OVERLAP_START; 473 if (res1->end < res2->end) 474 overlap |= OVERLAP_END; 475 } 476 477 return (overlap); 478 } 479 480 /* 481 * Try to merge the given newres with the existing sc->res. 482 */ 483 static void 484 wdat_merge_region(struct wdatwd_softc *sc, struct wdat_res *newres) 485 { 486 struct wdat_res *res1, *res2, *res_safe, *res_itr; 487 int overlap; 488 489 if (TAILQ_EMPTY(&sc->res)) { 490 TAILQ_INSERT_HEAD(&sc->res, newres, link); 491 return; 492 } 493 494 overlap = OVERLAP_NONE; 495 496 TAILQ_FOREACH_SAFE(res1, &sc->res, link, res_safe) { 497 overlap = wdat_compare_region(res1, newres); 498 499 /* Try next res if newres isn't mergeable. */ 500 if (overlap == OVERLAP_NONE) 501 continue; 502 503 /* This res fully covers newres. */ 504 if (overlap == OVERLAP_SUBSET) 505 break; 506 507 /* Newres extends the existing res res1 to lower. */ 508 if ((overlap & OVERLAP_START)) { 509 res1->start = newres->start; 510 res_itr = res1; 511 /* Try to merge more res if possible. */ 512 while ((res2 = TAILQ_PREV(res_itr, res_head, link))) { 513 if (res1->type != res2->type) { 514 res_itr = res2; 515 continue; 516 } else if (res1->start <= res2->end) { 517 res1->start = res2->start; 518 TAILQ_REMOVE(&sc->res, res2, link); 519 free(res2, M_DEVBUF); 520 } else 521 break; 522 } 523 } 524 /* Newres extends the existing res res1 to upper. */ 525 if ((overlap & OVERLAP_END)) { 526 res1->end = newres->end; 527 res_itr = res1; 528 /* Try to merge more res if possible. */ 529 while ((res2 = TAILQ_NEXT(res_itr, link))) { 530 if (res1->type != res2->type) { 531 res_itr = res2; 532 continue; 533 } else if (res1->end >= res2->start) { 534 res1->end = res2->end; 535 TAILQ_REMOVE(&sc->res, res2, link); 536 free(res2, M_DEVBUF); 537 } else 538 break; 539 } 540 } 541 break; 542 } 543 544 /* 545 * If newres extends the existing res, newres must be free()'ed. 546 * Otherwise insert newres into sc->res at appropriate position 547 * (the lowest address region appears first). 548 */ 549 if (overlap > OVERLAP_NONE) 550 free(newres, M_DEVBUF); 551 else { 552 TAILQ_FOREACH(res1, &sc->res, link) { 553 if (newres->type != res1->type) 554 continue; 555 if (newres->start < res1->start) { 556 TAILQ_INSERT_BEFORE(res1, newres, link); 557 break; 558 } 559 } 560 if (res1 == NULL) 561 TAILQ_INSERT_TAIL(&sc->res, newres, link); 562 } 563 } 564 565 /* 566 * Release the already allocated resource. 567 */ 568 static void 569 wdat_release_resource(device_t dev) 570 { 571 struct wdatwd_softc *sc; 572 struct wdat_instr *wdat; 573 struct wdat_res *res; 574 int i; 575 576 sc = device_get_softc(dev); 577 578 TAILQ_FOREACH(res, &sc->res, link) 579 if (res->res != NULL) { 580 bus_release_resource(dev, res->type, 581 res->rid, res->res); 582 bus_delete_resource(dev, res->type, res->rid); 583 res->res = NULL; 584 } 585 586 for (i = 0; i < nitems(sc->action); ++i) 587 while (!STAILQ_EMPTY(&sc->action[i])) { 588 wdat = STAILQ_FIRST(&sc->action[i]); 589 STAILQ_REMOVE_HEAD(&sc->action[i], next); 590 free(wdat, M_DEVBUF); 591 } 592 593 while (!TAILQ_EMPTY(&sc->res)) { 594 res = TAILQ_FIRST(&sc->res); 595 TAILQ_REMOVE(&sc->res, res, link); 596 free(res, M_DEVBUF); 597 } 598 } 599 600 static int 601 wdatwd_probe(device_t dev) 602 { 603 ACPI_TABLE_WDAT *wdat; 604 ACPI_STATUS status; 605 606 /* Without WDAT table we have nothing to do. */ 607 status = AcpiGetTable(ACPI_SIG_WDAT, 0, (ACPI_TABLE_HEADER **)&wdat); 608 if (ACPI_FAILURE(status)) 609 return (ENXIO); 610 611 /* Try to allocate one resource and assume wdatwd is already attached 612 * if it fails. */ 613 { 614 int type, rid = 0; 615 struct resource *res; 616 617 if (acpi_bus_alloc_gas(dev, &type, &rid, 618 &((ACPI_WDAT_ENTRY *)(wdat + 1))->RegisterRegion, 619 &res, 0)) 620 return (ENXIO); 621 bus_release_resource(dev, type, rid, res); 622 bus_delete_resource(dev, type, rid); 623 } 624 625 WDATWD_VERBOSE_PRINTF(dev, "Flags: 0x%x, TimerPeriod: %d ms/cnt, " 626 "MaxCount: %d cnt (%d ms), MinCount: %d cnt (%d ms)\n", 627 (int)wdat->Flags, (int)wdat->TimerPeriod, 628 (int)wdat->MaxCount, (int)(wdat->MaxCount * wdat->TimerPeriod), 629 (int)wdat->MinCount, (int)(wdat->MinCount * wdat->TimerPeriod)); 630 /* WDAT timer consistency. */ 631 if ((wdat->TimerPeriod < 1) || (wdat->MinCount > wdat->MaxCount)) { 632 device_printf(dev, "inconsistent timer variables.\n"); 633 return (EINVAL); 634 } 635 636 AcpiPutTable((ACPI_TABLE_HEADER *)wdat); 637 638 device_set_desc(dev, "ACPI WDAT Watchdog Interface"); 639 return (BUS_PROBE_DEFAULT); 640 } 641 642 static int 643 wdatwd_attach(device_t dev) 644 { 645 struct wdatwd_softc *sc; 646 struct wdat_instr *wdat; 647 struct wdat_res *res; 648 struct sysctl_ctx_list *sctx; 649 struct sysctl_oid *soid; 650 ACPI_STATUS status; 651 int e, i, rid; 652 653 sc = device_get_softc(dev); 654 sc->dev = dev; 655 656 for (i = 0; i < nitems(sc->action); ++i) 657 STAILQ_INIT(&sc->action[i]); 658 659 /* Search and parse WDAT table. */ 660 status = AcpiGetTable(ACPI_SIG_WDAT, 0, 661 (ACPI_TABLE_HEADER **)&sc->wdat); 662 if (ACPI_FAILURE(status)) 663 return (ENXIO); 664 665 /* Parse watchdog variables. */ 666 sc->period = sc->wdat->TimerPeriod; 667 sc->max = sc->wdat->MaxCount; 668 sc->min = sc->wdat->MinCount; 669 sc->stop_in_sleep = (sc->wdat->Flags & ACPI_WDAT_STOPPED) 670 ? true : false; 671 /* Parse defined watchdog actions. */ 672 wdat_parse_action_table(sc); 673 674 AcpiPutTable((ACPI_TABLE_HEADER *)sc->wdat); 675 676 /* Verbose logging. */ 677 if (bootverbose) { 678 for (i = 0; i < nitems(sc->action); ++i) 679 STAILQ_FOREACH(wdat, &sc->action[i], next) { 680 WDATWD_VERBOSE_PRINTF(dev, "action: 0x%02x, " 681 "%s %s at 0x%llx (%d bit(s), offset %d bit(s))\n", 682 i, 683 wdat->entry.RegisterRegion.SpaceId 684 == ACPI_ADR_SPACE_SYSTEM_MEMORY 685 ? "mem" 686 : wdat->entry.RegisterRegion.SpaceId 687 == ACPI_ADR_SPACE_SYSTEM_IO 688 ? "io " 689 : "???", 690 wdat->entry.RegisterRegion.AccessWidth == 1 691 ? "byte " 692 : wdat->entry.RegisterRegion.AccessWidth == 2 693 ? "word " 694 : wdat->entry.RegisterRegion.AccessWidth == 3 695 ? "dword" 696 : wdat->entry.RegisterRegion.AccessWidth == 4 697 ? "qword" 698 : "undef", 699 (unsigned long long ) 700 wdat->entry.RegisterRegion.Address, 701 wdat->entry.RegisterRegion.BitWidth, 702 wdat->entry.RegisterRegion.BitOffset); 703 } 704 } 705 706 /* Canonicalize the requested resources. */ 707 TAILQ_INIT(&sc->res); 708 for (i = 0; i < nitems(sc->action); ++i) 709 STAILQ_FOREACH(wdat, &sc->action[i], next) { 710 res = wdat_alloc_region(&wdat->entry.RegisterRegion); 711 if (res == NULL) 712 goto fail; 713 wdat_merge_region(sc, res); 714 } 715 716 /* Resource allocation. */ 717 rid = 0; 718 TAILQ_FOREACH(res, &sc->res, link) { 719 switch (res->type) { 720 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 721 res->type = SYS_RES_MEMORY; 722 break; 723 case ACPI_ADR_SPACE_SYSTEM_IO: 724 res->type = SYS_RES_IOPORT; 725 break; 726 default: 727 goto fail; 728 } 729 730 res->rid = rid++; 731 bus_set_resource(dev, res->type, res->rid, 732 res->start, res->end - res->start); 733 res->res = bus_alloc_resource_any( 734 dev, res->type, &res->rid, RF_ACTIVE); 735 if (res->res == NULL) { 736 bus_delete_resource(dev, res->type, res->rid); 737 device_printf(dev, "%s at 0x%llx (%lld byte(s)): " 738 "alloc' failed\n", 739 res->type == SYS_RES_MEMORY ? "mem" : "io ", 740 (unsigned long long )res->start, 741 (unsigned long long )(res->end - res->start)); 742 goto fail; 743 } 744 WDATWD_VERBOSE_PRINTF(dev, "%s at 0x%llx (%lld byte(s)): " 745 "alloc'ed\n", 746 res->type == SYS_RES_MEMORY ? "mem" : "io ", 747 (unsigned long long )res->start, 748 (unsigned long long) (res->end - res->start)); 749 } 750 751 /* Initialize the watchdog hardware. */ 752 if (wdatwd_set_stop(sc) != 0) 753 goto fail; 754 if ((e = wdatwd_clear_status(sc)) && e != EOPNOTSUPP) 755 goto fail; 756 if ((e = wdatwd_set_reboot(sc)) && e != EOPNOTSUPP) 757 goto fail; 758 if ((e = wdatwd_get_countdown(sc, &sc->default_timeout)) 759 && e != EOPNOTSUPP) 760 goto fail; 761 WDATWD_VERBOSE_PRINTF(dev, "initialized.\n"); 762 763 /* Some sysctls. Most of them should go to WDATWD_VERBOSE_PRINTF(). */ 764 sctx = device_get_sysctl_ctx(dev); 765 soid = device_get_sysctl_tree(dev); 766 SYSCTL_ADD_U64(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 767 "timeout_default", CTLFLAG_RD, SYSCTL_NULL_U64_PTR, 768 sc->default_timeout * sc->period, 769 "The default watchdog timeout in millisecond."); 770 SYSCTL_ADD_BOOL(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 771 "timeout_configurable", CTLFLAG_RD, SYSCTL_NULL_BOOL_PTR, 772 STAILQ_EMPTY(&sc->action[ACPI_WDAT_SET_COUNTDOWN]) ? false : true, 773 "Whether the watchdog timeout is configurable or not."); 774 SYSCTL_ADD_U64(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 775 "timeout", CTLFLAG_RD, &sc->timeout, 0, 776 "The current watchdog timeout in millisecond. " 777 "If 0, the default timeout is used."); 778 SYSCTL_ADD_BOOL(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, 779 "running", CTLFLAG_RD, &sc->running, 0, 780 "Whether the watchdog timer is running or not."); 781 782 sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, wdatwd_event, sc, 783 EVENTHANDLER_PRI_ANY); 784 WDATWD_VERBOSE_PRINTF(dev, "watchdog registered.\n"); 785 786 return (0); 787 788 fail: 789 wdat_release_resource(dev); 790 791 return (ENXIO); 792 } 793 794 static int 795 wdatwd_detach(device_t dev) 796 { 797 struct wdatwd_softc *sc; 798 int e; 799 800 sc = device_get_softc(dev); 801 802 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag); 803 e = wdatwd_set_stop(sc); 804 wdat_release_resource(dev); 805 806 return (e); 807 } 808 809 static int 810 wdatwd_suspend(device_t dev) 811 { 812 struct wdatwd_softc *sc; 813 814 sc = device_get_softc(dev); 815 816 if (!sc->stop_in_sleep) 817 return (0); 818 819 return wdatwd_set_stop(sc); 820 } 821 822 static int 823 wdatwd_resume(device_t dev) 824 { 825 struct wdatwd_softc *sc; 826 827 sc = device_get_softc(dev); 828 829 if (!sc->stop_in_sleep) 830 return (0); 831 832 return (wdatwd_reset_countdown(sc) || wdatwd_set_running(sc)); 833 } 834 835 static device_method_t wdatwd_methods[] = { 836 /* Device interface */ 837 DEVMETHOD(device_probe, wdatwd_probe), 838 DEVMETHOD(device_attach, wdatwd_attach), 839 DEVMETHOD(device_detach, wdatwd_detach), 840 DEVMETHOD(device_shutdown, wdatwd_detach), 841 DEVMETHOD(device_suspend, wdatwd_suspend), 842 DEVMETHOD(device_resume, wdatwd_resume), 843 DEVMETHOD_END 844 }; 845 846 static driver_t wdatwd_driver = { 847 "wdatwd", 848 wdatwd_methods, 849 sizeof(struct wdatwd_softc), 850 }; 851 852 DRIVER_MODULE(wdatwd, acpi, wdatwd_driver, 0, 0); 853 MODULE_DEPEND(wdatwd, acpi, 1, 1, 1); 854