1 /*- 2 * Copyright (c) 2009 Andriy Gapon <avg@FreeBSD.org> 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 /* 28 * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx 29 * southbridges. 30 * Please see the following specifications for the descriptions of the 31 * registers and flags: 32 * - AMD SB600 Register Reference Guide, Public Version, Rev. 3.03 (SB600 RRG) 33 * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/46155_sb600_rrg_pub_3.03.pdf 34 * - AMD SB700/710/750 Register Reference Guide (RRG) 35 * http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf 36 * - AMD SB700/710/750 Register Programming Requirements (RPR) 37 * http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf 38 * - AMD SB800-Series Southbridges Register Reference Guide (RRG) 39 * http://support.amd.com/us/Embedded_TechDocs/45482.pdf 40 * Please see the following for Watchdog Resource Table specification: 41 * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT) 42 * http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx 43 * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above 44 * specifications, but the table hasn't been spotted in the wild yet. 45 */ 46 47 #include <sys/cdefs.h> 48 __FBSDID("$FreeBSD$"); 49 50 #include <sys/param.h> 51 #include <sys/kernel.h> 52 #include <sys/module.h> 53 #include <sys/systm.h> 54 #include <sys/sysctl.h> 55 #include <sys/bus.h> 56 #include <machine/bus.h> 57 #include <sys/rman.h> 58 #include <machine/resource.h> 59 #include <sys/watchdog.h> 60 61 #include <dev/pci/pcivar.h> 62 #include <isa/isavar.h> 63 64 /* SB7xx RRG 2.3.3.1.1. */ 65 #define AMDSB_PMIO_INDEX 0xcd6 66 #define AMDSB_PMIO_DATA (PMIO_INDEX + 1) 67 #define AMDSB_PMIO_WIDTH 2 68 /* SB7xx RRG 2.3.3.2. */ 69 #define AMDSB_PM_RESET_STATUS0 0x44 70 #define AMDSB_PM_RESET_STATUS1 0x45 71 #define AMDSB_WD_RST_STS 0x02 72 /* SB7xx RRG 2.3.3.2, RPR 2.36. */ 73 #define AMDSB_PM_WDT_CTRL 0x69 74 #define AMDSB_WDT_DISABLE 0x01 75 #define AMDSB_WDT_RES_MASK (0x02 | 0x04) 76 #define AMDSB_WDT_RES_32US 0x00 77 #define AMDSB_WDT_RES_10MS 0x02 78 #define AMDSB_WDT_RES_100MS 0x04 79 #define AMDSB_WDT_RES_1S 0x06 80 #define AMDSB_PM_WDT_BASE_LSB 0x6c 81 #define AMDSB_PM_WDT_BASE_MSB 0x6f 82 /* SB8xx RRG 2.3.3. */ 83 #define AMDSB8_PM_WDT_EN 0x48 84 #define AMDSB8_WDT_DEC_EN 0x01 85 #define AMDSB8_WDT_DISABLE 0x02 86 #define AMDSB8_PM_WDT_CTRL 0x4c 87 #define AMDSB8_WDT_32KHZ 0x00 88 #define AMDSB8_WDT_1HZ 0x03 89 #define AMDSB8_WDT_RES_MASK 0x03 90 #define AMDSB8_PM_RESET_STATUS0 0xC0 91 #define AMDSB8_PM_RESET_STATUS1 0xC1 92 #define AMDSB8_WD_RST_STS 0x20 93 /* SB7xx RRG 2.3.4, WDRT. */ 94 #define AMDSB_WD_CTRL 0x00 95 #define AMDSB_WD_RUN 0x01 96 #define AMDSB_WD_FIRED 0x02 97 #define AMDSB_WD_SHUTDOWN 0x04 98 #define AMDSB_WD_DISABLE 0x08 99 #define AMDSB_WD_RESERVED 0x70 100 #define AMDSB_WD_RELOAD 0x80 101 #define AMDSB_WD_COUNT 0x04 102 #define AMDSB_WD_COUNT_MASK 0xffff 103 #define AMDSB_WDIO_REG_WIDTH 4 104 /* WDRT */ 105 #define MAXCOUNT_MIN_VALUE 511 106 /* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1. */ 107 #define AMDSB_SMBUS_DEVID 0x43851002 108 #define AMDSB8_SMBUS_REVID 0x40 109 #define AMDHUDSON_SMBUS_DEVID 0x780b1022 110 #define AMDKERNCZ_SMBUS_DEVID 0x790b1022 111 /* BKDG Family 16h Models 30h - 3Fh */ 112 #define AMDFCH16H3XH_PM_WDT_EN 0x00 113 #define AMDFCH_WDT_DEC_EN 0x80 114 #define AMDFCH16H3XH_PM_WDT_CTRL 0x03 115 #define AMDFCH_WDT_RES_MASK 0x03 116 #define AMDFCH_WDT_RES_32US 0x00 117 #define AMDFCH_WDT_RES_10MS 0x01 118 #define AMDFCH_WDT_RES_100MS 0x02 119 #define AMDFCH_WDT_RES_1S 0x03 120 #define AMDFCH_WDT_ENABLE_MASK 0x0c 121 #define AMDFCH_WDT_ENABLE 0x00 122 #define AMDFCH16H3XH_PM_MMIO_CTRL 0x04 123 #define AMDFCH_WDT_MMIO_EN 0x02 124 #define AMDFCH16H3XH_WDT_ADDR1 0xfed80b00u 125 #define AMDFCH16H3XH_WDT_ADDR2 0xfeb00000u 126 127 #define amdsbwd_verbose_printf(dev, ...) \ 128 do { \ 129 if (bootverbose) \ 130 device_printf(dev, __VA_ARGS__);\ 131 } while (0) 132 133 struct amdsbwd_softc { 134 device_t dev; 135 eventhandler_tag ev_tag; 136 struct resource *res_ctrl; 137 struct resource *res_count; 138 int rid_ctrl; 139 int rid_count; 140 int ms_per_tick; 141 int max_ticks; 142 int active; 143 unsigned int timeout; 144 }; 145 146 static void amdsbwd_identify(driver_t *driver, device_t parent); 147 static int amdsbwd_probe(device_t dev); 148 static int amdsbwd_attach(device_t dev); 149 static int amdsbwd_detach(device_t dev); 150 151 static device_method_t amdsbwd_methods[] = { 152 DEVMETHOD(device_identify, amdsbwd_identify), 153 DEVMETHOD(device_probe, amdsbwd_probe), 154 DEVMETHOD(device_attach, amdsbwd_attach), 155 DEVMETHOD(device_detach, amdsbwd_detach), 156 #if 0 157 DEVMETHOD(device_shutdown, amdsbwd_detach), 158 #endif 159 DEVMETHOD_END 160 }; 161 162 static devclass_t amdsbwd_devclass; 163 static driver_t amdsbwd_driver = { 164 "amdsbwd", 165 amdsbwd_methods, 166 sizeof(struct amdsbwd_softc) 167 }; 168 169 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL); 170 171 172 static uint8_t 173 pmio_read(struct resource *res, uint8_t reg) 174 { 175 bus_write_1(res, 0, reg); /* Index */ 176 return (bus_read_1(res, 1)); /* Data */ 177 } 178 179 static void 180 pmio_write(struct resource *res, uint8_t reg, uint8_t val) 181 { 182 bus_write_1(res, 0, reg); /* Index */ 183 bus_write_1(res, 1, val); /* Data */ 184 } 185 186 static uint32_t 187 wdctrl_read(struct amdsbwd_softc *sc) 188 { 189 return (bus_read_4(sc->res_ctrl, 0)); 190 } 191 192 static void 193 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val) 194 { 195 bus_write_4(sc->res_ctrl, 0, val); 196 } 197 198 static __unused uint32_t 199 wdcount_read(struct amdsbwd_softc *sc) 200 { 201 return (bus_read_4(sc->res_count, 0)); 202 } 203 204 static void 205 wdcount_write(struct amdsbwd_softc *sc, uint32_t val) 206 { 207 bus_write_4(sc->res_count, 0, val); 208 } 209 210 static void 211 amdsbwd_tmr_enable(struct amdsbwd_softc *sc) 212 { 213 uint32_t val; 214 215 val = wdctrl_read(sc); 216 val |= AMDSB_WD_RUN; 217 wdctrl_write(sc, val); 218 sc->active = 1; 219 amdsbwd_verbose_printf(sc->dev, "timer enabled\n"); 220 } 221 222 static void 223 amdsbwd_tmr_disable(struct amdsbwd_softc *sc) 224 { 225 uint32_t val; 226 227 val = wdctrl_read(sc); 228 val &= ~AMDSB_WD_RUN; 229 wdctrl_write(sc, val); 230 sc->active = 0; 231 amdsbwd_verbose_printf(sc->dev, "timer disabled\n"); 232 } 233 234 static void 235 amdsbwd_tmr_reload(struct amdsbwd_softc *sc) 236 { 237 uint32_t val; 238 239 val = wdctrl_read(sc); 240 val |= AMDSB_WD_RELOAD; 241 wdctrl_write(sc, val); 242 } 243 244 static void 245 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout) 246 { 247 248 timeout &= AMDSB_WD_COUNT_MASK; 249 wdcount_write(sc, timeout); 250 sc->timeout = timeout; 251 amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout); 252 } 253 254 static void 255 amdsbwd_event(void *arg, unsigned int cmd, int *error) 256 { 257 struct amdsbwd_softc *sc = arg; 258 unsigned int timeout; 259 260 /* convert from power-of-two-ns to WDT ticks */ 261 cmd &= WD_INTERVAL; 262 if (cmd < WD_TO_1SEC) 263 cmd = 0; 264 if (cmd) { 265 timeout = ((uint64_t)1 << (cmd - WD_TO_1MS)) / sc->ms_per_tick; 266 if (timeout > sc->max_ticks) 267 timeout = sc->max_ticks; 268 if (timeout != sc->timeout) { 269 amdsbwd_tmr_set(sc, timeout); 270 if (!sc->active) 271 amdsbwd_tmr_enable(sc); 272 } 273 amdsbwd_tmr_reload(sc); 274 *error = 0; 275 } else { 276 if (sc->active) 277 amdsbwd_tmr_disable(sc); 278 } 279 } 280 281 static void 282 amdsbwd_identify(driver_t *driver, device_t parent) 283 { 284 device_t child; 285 device_t smb_dev; 286 287 if (resource_disabled("amdsbwd", 0)) 288 return; 289 if (device_find_child(parent, "amdsbwd", -1) != NULL) 290 return; 291 292 /* 293 * Try to identify SB600/SB7xx by PCI Device ID of SMBus device 294 * that should be present at bus 0, device 20, function 0. 295 */ 296 smb_dev = pci_find_bsf(0, 20, 0); 297 if (smb_dev == NULL) 298 return; 299 if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID && 300 pci_get_devid(smb_dev) != AMDHUDSON_SMBUS_DEVID && 301 pci_get_devid(smb_dev) != AMDKERNCZ_SMBUS_DEVID) 302 return; 303 304 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1); 305 if (child == NULL) 306 device_printf(parent, "add amdsbwd child failed\n"); 307 } 308 309 310 static void 311 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr) 312 { 313 uint8_t val; 314 int i; 315 316 /* Report cause of previous reset for user's convenience. */ 317 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0); 318 if (val != 0) 319 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val); 320 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1); 321 if (val != 0) 322 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val); 323 if ((val & AMDSB_WD_RST_STS) != 0) 324 device_printf(dev, "Previous Reset was caused by Watchdog\n"); 325 326 /* Find base address of memory mapped WDT registers. */ 327 for (*addr = 0, i = 0; i < 4; i++) { 328 *addr <<= 8; 329 *addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i); 330 } 331 *addr &= ~0x07u; 332 333 /* Set watchdog timer tick to 1s. */ 334 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL); 335 val &= ~AMDSB_WDT_RES_MASK; 336 val |= AMDSB_WDT_RES_1S; 337 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val); 338 339 /* Enable watchdog device (in stopped state). */ 340 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL); 341 val &= ~AMDSB_WDT_DISABLE; 342 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val); 343 344 /* 345 * XXX TODO: Ensure that watchdog decode is enabled 346 * (register 0x41, bit 3). 347 */ 348 device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer"); 349 } 350 351 static void 352 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr) 353 { 354 uint8_t val; 355 int i; 356 357 /* Report cause of previous reset for user's convenience. */ 358 val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS0); 359 if (val != 0) 360 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val); 361 val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS1); 362 if (val != 0) 363 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val); 364 if ((val & AMDSB8_WD_RST_STS) != 0) 365 device_printf(dev, "Previous Reset was caused by Watchdog\n"); 366 367 /* Find base address of memory mapped WDT registers. */ 368 for (*addr = 0, i = 0; i < 4; i++) { 369 *addr <<= 8; 370 *addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i); 371 } 372 *addr &= ~0x07u; 373 374 /* Set watchdog timer tick to 1s. */ 375 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL); 376 val &= ~AMDSB8_WDT_RES_MASK; 377 val |= AMDSB8_WDT_1HZ; 378 pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val); 379 #ifdef AMDSBWD_DEBUG 380 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL); 381 amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#04x\n", val); 382 #endif 383 384 /* 385 * Enable watchdog device (in stopped state) 386 * and decoding of its address. 387 */ 388 val = pmio_read(pmres, AMDSB8_PM_WDT_EN); 389 val &= ~AMDSB8_WDT_DISABLE; 390 val |= AMDSB8_WDT_DEC_EN; 391 pmio_write(pmres, AMDSB8_PM_WDT_EN, val); 392 #ifdef AMDSBWD_DEBUG 393 val = pmio_read(pmres, AMDSB8_PM_WDT_EN); 394 device_printf(dev, "AMDSB8_PM_WDT_EN value = %#04x\n", val); 395 #endif 396 device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer"); 397 } 398 399 static void 400 amdsbwd_probe_fch_16h_3xh(device_t dev, struct resource *pmres, uint32_t *addr) 401 { 402 uint8_t val; 403 404 val = pmio_read(pmres, AMDFCH16H3XH_PM_MMIO_CTRL); 405 if ((val & AMDFCH_WDT_MMIO_EN) != 0) { 406 /* Fixed offset for the watchdog within ACPI MMIO range. */ 407 amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n"); 408 *addr = AMDFCH16H3XH_WDT_ADDR1; 409 } else { 410 /* 411 * Enable decoding of watchdog MMIO address. 412 */ 413 val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_EN); 414 val |= AMDFCH_WDT_DEC_EN; 415 pmio_write(pmres, AMDFCH16H3XH_PM_WDT_EN, val); 416 #ifdef AMDSBWD_DEBUG 417 val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_EN); 418 device_printf(dev, "AMDFCH16H3XH_PM_WDT_EN value = %#04x\n", 419 val); 420 #endif 421 422 /* Special fixed MMIO range for the watchdog. */ 423 *addr = AMDFCH16H3XH_WDT_ADDR2; 424 } 425 426 /* 427 * Set watchdog timer tick to 1s and 428 * enable the watchdog device (in stopped state). 429 */ 430 val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_CTRL); 431 val &= ~AMDFCH_WDT_RES_MASK; 432 val |= AMDFCH_WDT_RES_1S; 433 val &= ~AMDFCH_WDT_ENABLE_MASK; 434 val |= AMDFCH_WDT_ENABLE; 435 pmio_write(pmres, AMDFCH16H3XH_PM_WDT_CTRL, val); 436 #ifdef AMDSBWD_DEBUG 437 val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_CTRL); 438 amdsbwd_verbose_printf(dev, "AMDFCH16H3XH_PM_WDT_CTRL value = %#04x\n", 439 val); 440 #endif 441 device_set_desc(dev, "AMD FCH Rev 42h+ Watchdog Timer"); 442 } 443 444 static int 445 amdsbwd_probe(device_t dev) 446 { 447 struct resource *res; 448 device_t smb_dev; 449 uint32_t addr; 450 int rid; 451 int rc; 452 uint32_t devid; 453 uint8_t revid; 454 455 /* Do not claim some ISA PnP device by accident. */ 456 if (isa_get_logicalid(dev) != 0) 457 return (ENXIO); 458 459 rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX, 460 AMDSB_PMIO_WIDTH); 461 if (rc != 0) { 462 device_printf(dev, "bus_set_resource for IO failed\n"); 463 return (ENXIO); 464 } 465 rid = 0; 466 res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 467 RF_ACTIVE | RF_SHAREABLE); 468 if (res == NULL) { 469 device_printf(dev, "bus_alloc_resource for IO failed\n"); 470 return (ENXIO); 471 } 472 473 smb_dev = pci_find_bsf(0, 20, 0); 474 KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n")); 475 devid = pci_get_devid(smb_dev); 476 revid = pci_get_revid(smb_dev); 477 if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID) 478 amdsbwd_probe_sb7xx(dev, res, &addr); 479 else if (devid == AMDSB_SMBUS_DEVID || devid == AMDKERNCZ_SMBUS_DEVID || 480 (devid == AMDHUDSON_SMBUS_DEVID && revid < 0x42)) 481 amdsbwd_probe_sb8xx(dev, res, &addr); 482 else 483 amdsbwd_probe_fch_16h_3xh(dev, res, &addr); 484 485 bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 486 bus_delete_resource(dev, SYS_RES_IOPORT, rid); 487 488 amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr); 489 rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL, 490 AMDSB_WDIO_REG_WIDTH); 491 if (rc != 0) { 492 device_printf(dev, "bus_set_resource for control failed\n"); 493 return (ENXIO); 494 } 495 rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT, 496 AMDSB_WDIO_REG_WIDTH); 497 if (rc != 0) { 498 device_printf(dev, "bus_set_resource for count failed\n"); 499 return (ENXIO); 500 } 501 502 return (0); 503 } 504 505 static int 506 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc) 507 { 508 509 sc->max_ticks = UINT16_MAX; 510 sc->rid_ctrl = 0; 511 sc->rid_count = 1; 512 513 sc->ms_per_tick = 1000; 514 515 sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 516 &sc->rid_ctrl, RF_ACTIVE); 517 if (sc->res_ctrl == NULL) { 518 device_printf(dev, "bus_alloc_resource for ctrl failed\n"); 519 return (ENXIO); 520 } 521 sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 522 &sc->rid_count, RF_ACTIVE); 523 if (sc->res_count == NULL) { 524 device_printf(dev, "bus_alloc_resource for count failed\n"); 525 return (ENXIO); 526 } 527 return (0); 528 } 529 530 static int 531 amdsbwd_attach(device_t dev) 532 { 533 struct amdsbwd_softc *sc; 534 int rc; 535 536 sc = device_get_softc(dev); 537 sc->dev = dev; 538 539 rc = amdsbwd_attach_sb(dev, sc); 540 if (rc != 0) 541 goto fail; 542 543 #ifdef AMDSBWD_DEBUG 544 device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc)); 545 device_printf(dev, "wd count = %#04x\n", wdcount_read(sc)); 546 #endif 547 548 /* Setup initial state of Watchdog Control. */ 549 wdctrl_write(sc, AMDSB_WD_FIRED); 550 551 if (wdctrl_read(sc) & AMDSB_WD_DISABLE) { 552 device_printf(dev, "watchdog hardware is disabled\n"); 553 goto fail; 554 } 555 556 sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, amdsbwd_event, sc, 557 EVENTHANDLER_PRI_ANY); 558 559 return (0); 560 561 fail: 562 amdsbwd_detach(dev); 563 return (ENXIO); 564 } 565 566 static int 567 amdsbwd_detach(device_t dev) 568 { 569 struct amdsbwd_softc *sc; 570 571 sc = device_get_softc(dev); 572 if (sc->ev_tag != NULL) 573 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag); 574 575 if (sc->active) 576 amdsbwd_tmr_disable(sc); 577 578 if (sc->res_ctrl != NULL) 579 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl, 580 sc->res_ctrl); 581 582 if (sc->res_count != NULL) 583 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count, 584 sc->res_count); 585 586 return (0); 587 } 588 589