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