xref: /freebsd/sys/dev/amdsbwd/amdsbwd.c (revision 04708d25e0f89d975f40757248bade347d5dc994)
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