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 * $FreeBSD: src/sys/dev/amdsbwd/amdsbwd.c,v 1.3 2011/06/07 06:18:02 avg Exp $
47 */
48
49 #include <sys/param.h>
50 #include <sys/kernel.h>
51 #include <sys/module.h>
52 #include <sys/systm.h>
53 #include <sys/sysctl.h>
54 #include <sys/bus.h>
55 #include <sys/rman.h>
56 #include <sys/resource.h>
57 #include <sys/wdog.h>
58
59 #include <bus/isa/isavar.h>
60 #include <bus/pci/pcivar.h>
61
62 #include "amd_chipset.h"
63
64 /*
65 * Registers in the Watchdog IO space.
66 * See SB7xx RRG 2.3.4, WDRT.
67 */
68 #define AMDSB_WD_CTRL 0x00
69 #define AMDSB_WD_RUN 0x01
70 #define AMDSB_WD_FIRED 0x02
71 #define AMDSB_WD_SHUTDOWN 0x04
72 #define AMDSB_WD_DISABLE 0x08
73 #define AMDSB_WD_RESERVED 0x70
74 #define AMDSB_WD_RELOAD 0x80
75 #define AMDSB_WD_COUNT 0x04
76 #define AMDSB_WD_COUNT_MASK 0xffff
77 #define AMDSB_WDIO_REG_WIDTH 4
78
79 #define amdsbwd_verbose_printf(dev, ...) \
80 do { \
81 if (bootverbose) \
82 device_printf(dev, __VA_ARGS__);\
83 } while (0)
84
85 struct amdsbwd_softc {
86 device_t dev;
87 struct watchdog wdog;
88 struct resource *res_ctrl;
89 struct resource *res_count;
90 int rid_ctrl;
91 int rid_count;
92 int ms_per_tick;
93 int max_ticks;
94 int active;
95 unsigned int timeout;
96 };
97
98 static void amdsbwd_identify(driver_t *driver, device_t parent);
99 static int amdsbwd_probe(device_t dev);
100 static int amdsbwd_attach(device_t dev);
101 static int amdsbwd_detach(device_t dev);
102 static int amdsbwd_suspend(device_t dev);
103 static int amdsbwd_resume(device_t dev);
104
105 static device_method_t amdsbwd_methods[] = {
106 DEVMETHOD(device_identify, amdsbwd_identify),
107 DEVMETHOD(device_probe, amdsbwd_probe),
108 DEVMETHOD(device_attach, amdsbwd_attach),
109 DEVMETHOD(device_detach, amdsbwd_detach),
110 DEVMETHOD(device_suspend, amdsbwd_suspend),
111 DEVMETHOD(device_resume, amdsbwd_resume),
112 #if 0
113 DEVMETHOD(device_shutdown, amdsbwd_detach),
114 #endif
115 DEVMETHOD_END
116 };
117
118 static devclass_t amdsbwd_devclass;
119 static driver_t amdsbwd_driver = {
120 "amdsbwd",
121 amdsbwd_methods,
122 sizeof(struct amdsbwd_softc)
123 };
124
125 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL);
126 MODULE_VERSION(amdsbwd, 1);
127
128
129 static uint8_t
pmio_read(struct resource * res,uint8_t reg)130 pmio_read(struct resource *res, uint8_t reg)
131 {
132 bus_write_1(res, 0, reg); /* Index */
133 return (bus_read_1(res, 1)); /* Data */
134 }
135
136 static void
pmio_write(struct resource * res,uint8_t reg,uint8_t val)137 pmio_write(struct resource *res, uint8_t reg, uint8_t val)
138 {
139 bus_write_1(res, 0, reg); /* Index */
140 bus_write_1(res, 1, val); /* Data */
141 }
142
143 static uint32_t
wdctrl_read(struct amdsbwd_softc * sc)144 wdctrl_read(struct amdsbwd_softc *sc)
145 {
146 return (bus_read_4(sc->res_ctrl, 0));
147 }
148
149 static void
wdctrl_write(struct amdsbwd_softc * sc,uint32_t val)150 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val)
151 {
152 bus_write_4(sc->res_ctrl, 0, val);
153 }
154
155 static __unused uint32_t
wdcount_read(struct amdsbwd_softc * sc)156 wdcount_read(struct amdsbwd_softc *sc)
157 {
158 return (bus_read_4(sc->res_count, 0));
159 }
160
161 static void
wdcount_write(struct amdsbwd_softc * sc,uint32_t val)162 wdcount_write(struct amdsbwd_softc *sc, uint32_t val)
163 {
164 bus_write_4(sc->res_count, 0, val);
165 }
166
167 static void
amdsbwd_tmr_enable(struct amdsbwd_softc * sc)168 amdsbwd_tmr_enable(struct amdsbwd_softc *sc)
169 {
170 uint32_t val;
171
172 val = wdctrl_read(sc);
173 val |= AMDSB_WD_RUN;
174 wdctrl_write(sc, val);
175 sc->active = 1;
176 amdsbwd_verbose_printf(sc->dev, "timer enabled\n");
177 }
178
179 static void
amdsbwd_tmr_disable(struct amdsbwd_softc * sc)180 amdsbwd_tmr_disable(struct amdsbwd_softc *sc)
181 {
182 uint32_t val;
183
184 val = wdctrl_read(sc);
185 val &= ~AMDSB_WD_RUN;
186 wdctrl_write(sc, val);
187 sc->active = 0;
188 amdsbwd_verbose_printf(sc->dev, "timer disabled\n");
189 }
190
191 static void
amdsbwd_tmr_reload(struct amdsbwd_softc * sc)192 amdsbwd_tmr_reload(struct amdsbwd_softc *sc)
193 {
194 uint32_t val;
195
196 val = wdctrl_read(sc);
197 val |= AMDSB_WD_RELOAD;
198 wdctrl_write(sc, val);
199 }
200
201 static void
amdsbwd_tmr_set(struct amdsbwd_softc * sc,uint16_t timeout)202 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout)
203 {
204
205 timeout &= AMDSB_WD_COUNT_MASK;
206 wdcount_write(sc, timeout);
207 sc->timeout = timeout;
208 amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout);
209 }
210
211 static int
amdsb_watchdog(void * arg,int period)212 amdsb_watchdog(void *arg, int period)
213 {
214 unsigned int timeout;
215 struct amdsbwd_softc *sc = arg;
216
217 timeout = (period * 1000) / sc->ms_per_tick;
218 if (timeout > sc->max_ticks)
219 timeout = sc->max_ticks;
220 if (timeout != sc->timeout) {
221 amdsbwd_tmr_set(sc, timeout);
222 if (!sc->active)
223 amdsbwd_tmr_enable(sc);
224 }
225 amdsbwd_tmr_reload(sc);
226
227 return period;
228 }
229
230 static void
amdsbwd_identify(driver_t * driver,device_t parent)231 amdsbwd_identify(driver_t *driver, device_t parent)
232 {
233 device_t child;
234 device_t smb_dev;
235
236 if (resource_disabled("amdsbwd", 0))
237 return;
238 if (device_find_child(parent, "amdsbwd", -1) != NULL)
239 return;
240
241 /*
242 * Try to identify SB600/SB7xx by PCI Device ID of SMBus device
243 * that should be present at bus 0, device 20, function 0.
244 */
245 smb_dev = pci_find_bsf(0, 20, 0);
246 if (smb_dev == NULL)
247 return;
248 if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
249 pci_get_devid(smb_dev) != AMDFCH_SMBUS_DEVID &&
250 pci_get_devid(smb_dev) != AMDCZ_SMBUS_DEVID) {
251 return;
252 }
253
254 child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_SPECULATIVE,
255 "amdsbwd", -1);
256 if (child == NULL)
257 device_printf(parent, "add amdsbwd child failed\n");
258 }
259
260
261 static void
amdsbwd_probe_sb7xx(device_t dev,struct resource * pmres,uint32_t * addr)262 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
263 {
264 uint8_t val;
265 int i;
266
267 /* Report cause of previous reset for user's convenience. */
268 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0);
269 if (val != 0)
270 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
271 val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1);
272 if (val != 0)
273 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
274 if ((val & AMDSB_WD_RST_STS) != 0)
275 device_printf(dev, "Previous Reset was caused by Watchdog\n");
276
277 /* Find base address of memory mapped WDT registers. */
278 for (*addr = 0, i = 0; i < 4; i++) {
279 *addr <<= 8;
280 *addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
281 }
282 *addr &= ~0x07U;
283
284 /* Set watchdog timer tick to 1s. */
285 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
286 val &= ~AMDSB_WDT_RES_MASK;
287 val |= AMDSB_WDT_RES_1S;
288 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
289
290 /* Enable watchdog device (in stopped state). */
291 val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
292 val &= ~AMDSB_WDT_DISABLE;
293 pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
294
295 /*
296 * XXX TODO: Ensure that watchdog decode is enabled
297 * (register 0x41, bit 3).
298 */
299 device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
300 }
301
302 static void
amdsbwd_probe_sb8xx(device_t dev,struct resource * pmres,uint32_t * addr)303 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
304 {
305 uint32_t val;
306 int i;
307
308 /* Report cause of previous reset for user's convenience. */
309
310 val = pmio_read(pmres, AMDSB8_PM_RESET_CTRL);
311 if ((val & AMDSB8_RST_STS_DIS) != 0) {
312 val &= ~AMDSB8_RST_STS_DIS;
313 pmio_write(pmres, AMDSB8_PM_RESET_CTRL, val);
314 }
315 val = 0;
316 for (i = 3; i >= 0; i--) {
317 val <<= 8;
318 val |= pmio_read(pmres, AMDSB8_PM_RESET_STATUS + i);
319 }
320 if (val != 0)
321 amdsbwd_verbose_printf(dev, "ResetStatus = 0x%08x\n", val);
322 if ((val & AMDSB8_WD_RST_STS) != 0)
323 device_printf(dev, "Previous Reset was caused by Watchdog\n");
324
325 /* Find base address of memory mapped WDT registers. */
326 for (*addr = 0, i = 0; i < 4; i++) {
327 *addr <<= 8;
328 *addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i);
329 }
330 *addr &= ~0x07u;
331
332 /* Set watchdog timer tick to 1s. */
333 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
334 val &= ~AMDSB8_WDT_RES_MASK;
335 val |= AMDSB8_WDT_1HZ;
336 pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val);
337 #ifdef AMDSBWD_DEBUG
338 val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
339 amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#04x\n", val);
340 #endif
341
342 /*
343 * Enable watchdog device (in stopped state)
344 * and decoding of its address.
345 */
346 val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
347 val &= ~AMDSB8_WDT_DISABLE;
348 val |= AMDSB8_WDT_DEC_EN;
349 pmio_write(pmres, AMDSB8_PM_WDT_EN, val);
350 #ifdef AMDSBWD_DEBUG
351 val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
352 device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val);
353 #endif
354 device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
355 }
356
357 static void
amdsbwd_probe_fch41(device_t dev,struct resource * pmres,uint32_t * addr)358 amdsbwd_probe_fch41(device_t dev, struct resource *pmres, uint32_t *addr)
359 {
360 uint8_t val;
361
362 val = pmio_read(pmres, AMDFCH41_PM_ISA_CTRL);
363 if ((val & AMDFCH41_MMIO_EN) != 0) {
364 /* Fixed offset for the watchdog within ACPI MMIO range. */
365 amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n");
366 *addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_WDT_OFF;
367 } else {
368 /*
369 * Enable decoding of watchdog MMIO address.
370 */
371 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
372 val |= AMDFCH41_WDT_EN;
373 pmio_write(pmres, AMDFCH41_PM_DECODE_EN0, val);
374 #ifdef AMDSBWD_DEBUG
375 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
376 device_printf(dev, "AMDFCH41_PM_DECODE_EN0 value = %#04x\n",
377 val);
378 #endif
379
380 /* Special fixed MMIO range for the watchdog. */
381 *addr = AMDFCH41_WDT_FIXED_ADDR;
382 }
383
384 /*
385 * Set watchdog timer tick to 1s and
386 * enable the watchdog device (in stopped state).
387 */
388 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
389 val &= ~AMDFCH41_WDT_RES_MASK;
390 val |= AMDFCH41_WDT_RES_1S;
391 val &= ~AMDFCH41_WDT_EN_MASK;
392 val |= AMDFCH41_WDT_ENABLE;
393 pmio_write(pmres, AMDFCH41_PM_DECODE_EN3, val);
394 #ifdef AMDSBWD_DEBUG
395 val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
396 amdsbwd_verbose_printf(dev, "AMDFCH41_PM_DECODE_EN3 value = %#04x\n",
397 val);
398 #endif
399 device_set_desc(dev, "AMD FCH Rev 41h+ Watchdog Timer");
400 }
401
402 static int
amdsbwd_probe(device_t dev)403 amdsbwd_probe(device_t dev)
404 {
405 struct resource *res;
406 device_t smb_dev;
407 uint32_t addr;
408 int rid;
409 int rc;
410 uint32_t devid;
411 uint8_t revid;
412
413 /* Do not claim some ISA PnP device by accident. */
414 if (isa_get_logicalid(dev) != 0)
415 return (ENXIO);
416
417 rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
418 AMDSB_PMIO_WIDTH, -1);
419 if (rc != 0) {
420 device_printf(dev, "bus_set_resource for IO failed\n");
421 return (ENXIO);
422 }
423 rid = 0;
424 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul,
425 AMDSB_PMIO_WIDTH, RF_ACTIVE | RF_SHAREABLE);
426 if (res == NULL) {
427 device_printf(dev, "bus_alloc_resource for IO failed\n");
428 return (ENXIO);
429 }
430
431 smb_dev = pci_find_bsf(0, 20, 0);
432 KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
433 devid = pci_get_devid(smb_dev);
434 revid = pci_get_revid(smb_dev);
435 if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID) {
436 amdsbwd_probe_sb7xx(dev, res, &addr);
437 } else if (devid == AMDSB_SMBUS_DEVID ||
438 (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
439 (devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) {
440 amdsbwd_probe_sb8xx(dev, res, &addr);
441 } else {
442 amdsbwd_probe_fch41(dev, res, &addr);
443 }
444
445 bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
446 bus_delete_resource(dev, SYS_RES_IOPORT, rid);
447
448 amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr);
449 rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL,
450 AMDSB_WDIO_REG_WIDTH, -1);
451 if (rc != 0) {
452 device_printf(dev, "bus_set_resource for control failed\n");
453 return (ENXIO);
454 }
455 rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT,
456 AMDSB_WDIO_REG_WIDTH, -1);
457 if (rc != 0) {
458 device_printf(dev, "bus_set_resource for count failed\n");
459 return (ENXIO);
460 }
461
462 return (0);
463 }
464
465 static int
amdsbwd_attach_sb(device_t dev,struct amdsbwd_softc * sc)466 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
467 {
468 sc->max_ticks = UINT16_MAX;
469 sc->rid_ctrl = 0;
470 sc->rid_count = 1;
471
472 sc->ms_per_tick = 1000;
473
474 sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
475 &sc->rid_ctrl, RF_ACTIVE);
476 if (sc->res_ctrl == NULL) {
477 device_printf(dev, "bus_alloc_resource for ctrl failed\n");
478 return (ENXIO);
479 }
480 sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
481 &sc->rid_count, RF_ACTIVE);
482 if (sc->res_count == NULL) {
483 device_printf(dev, "bus_alloc_resource for count failed\n");
484 return (ENXIO);
485 }
486 return (0);
487 }
488
489 static int
amdsbwd_attach(device_t dev)490 amdsbwd_attach(device_t dev)
491 {
492 struct amdsbwd_softc *sc;
493 int rc;
494
495 sc = device_get_softc(dev);
496 sc->dev = dev;
497
498 rc = amdsbwd_attach_sb(dev, sc);
499 if (rc != 0)
500 goto fail;
501
502 #ifdef AMDSBWD_DEBUG
503 device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc));
504 device_printf(dev, "wd count = %#04x\n", wdcount_read(sc));
505 #endif
506
507 /* Setup initial state of Watchdog Control. */
508 wdctrl_write(sc, AMDSB_WD_FIRED);
509
510 if (wdctrl_read(sc) & AMDSB_WD_DISABLE) {
511 device_printf(dev, "watchdog hardware is disabled\n");
512 goto fail;
513 }
514
515 sc->wdog.name = "AMD southbridge";
516 sc->wdog.wdog_fn = amdsb_watchdog;
517 sc->wdog.arg = sc;
518 sc->wdog.period_max = (UINT16_MAX*1000) / 10;
519 wdog_register(&sc->wdog);
520
521 return (0);
522
523 fail:
524 amdsbwd_detach(dev);
525 return (ENXIO);
526 }
527
528 static int
amdsbwd_detach(device_t dev)529 amdsbwd_detach(device_t dev)
530 {
531 struct amdsbwd_softc *sc;
532
533 sc = device_get_softc(dev);
534 if (sc->wdog.name)
535 wdog_unregister(&sc->wdog);
536
537 if (sc->active)
538 amdsbwd_tmr_disable(sc);
539
540 if (sc->res_ctrl != NULL)
541 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl,
542 sc->res_ctrl);
543
544 if (sc->res_count != NULL)
545 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count,
546 sc->res_count);
547
548 return (0);
549 }
550
551 static int
amdsbwd_suspend(device_t dev)552 amdsbwd_suspend(device_t dev)
553 {
554 struct amdsbwd_softc *sc;
555 uint32_t val;
556
557 sc = device_get_softc(dev);
558 val = wdctrl_read(sc);
559 val &= ~AMDSB_WD_RUN;
560 wdctrl_write(sc, val);
561 return (0);
562 }
563
564 static int
amdsbwd_resume(device_t dev)565 amdsbwd_resume(device_t dev)
566 {
567 struct amdsbwd_softc *sc;
568
569 sc = device_get_softc(dev);
570 wdctrl_write(sc, AMDSB_WD_FIRED);
571 if (sc->active) {
572 amdsbwd_tmr_set(sc, sc->timeout);
573 amdsbwd_tmr_enable(sc);
574 amdsbwd_tmr_reload(sc);
575 }
576 return (0);
577 }
578