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 */
66struct 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 */
84struct 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 */
102struct 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 */
126static int
127wdatwd_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
210fail:
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 */
219static int
220wdatwd_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 */
228static int
229wdatwd_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 */
251static int
252wdatwd_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 */
260static int
261wdatwd_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 */
269static int
270wdatwd_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 */
283static int
284wdatwd_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 */
298static int
299wdatwd_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 */
307static int
308wdatwd_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 */
316static void
317wdatwd_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
375static ssize_t
376wdat_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 */
396static void
397wdat_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 */
420static struct wdat_res *
421wdat_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 */
448static int
449wdat_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 */
481static void
482wdat_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 */
566static void
567wdat_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
598static int
599wdatwd_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
640static int
641wdatwd_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
786fail:
787	wdat_release_resource(dev);
788
789	return (ENXIO);
790}
791
792static int
793wdatwd_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
807static int
808wdatwd_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
820static int
821wdatwd_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
833static 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
844static driver_t	wdatwd_driver = {
845	"wdatwd",
846	wdatwd_methods,
847	sizeof(struct wdatwd_softc),
848};
849
850DRIVER_MODULE(wdatwd, acpi, wdatwd_driver, 0, 0);
851MODULE_DEPEND(wdatwd, acpi, 1, 1, 1);
852