commit e362cb8ff856e51df7443a85152916dc61e1e8c9
Author: YASUOKA Masahiko <yasuoka@yasuoka.net>
Date:   Thu Feb 20 21:15:35 2014 +0900

    add octwdoc(4).

diff --git a/sys/arch/octeon/conf/GENERIC b/sys/arch/octeon/conf/GENERIC
index 267affd..35122fe 100644
--- a/sys/arch/octeon/conf/GENERIC
+++ b/sys/arch/octeon/conf/GENERIC
@@ -35,6 +35,7 @@ octrtc0		at mainbus0
 
 octcf0		at iobus0
 octrng0		at iobus0
+octwdog0	at iobus0
 
 com0		at uartbus0
 com1		at uartbus0
diff --git a/sys/arch/octeon/conf/files.octeon b/sys/arch/octeon/conf/files.octeon
index b7a7f41..76ba3ca 100644
--- a/sys/arch/octeon/conf/files.octeon
+++ b/sys/arch/octeon/conf/files.octeon
@@ -77,6 +77,11 @@ device	octrng
 attach	octrng at iobus
 file	arch/octeon/dev/octrng.c			octrng
 
+# On-board Watchdog
+device	octwdog
+attach	octwdog at iobus
+file	arch/octeon/dev/octwdog.c			octwdog
+
 device	cn30xxgmx {}
 attach	cn30xxgmx at iobus
 file	arch/octeon/dev/cn30xxgmx.c			cn30xxgmx
diff --git a/sys/arch/octeon/dev/octeon_intr.c b/sys/arch/octeon/dev/octeon_intr.c
index 8b6e6d9..42f17b9 100644
--- a/sys/arch/octeon/dev/octeon_intr.c
+++ b/sys/arch/octeon/dev/octeon_intr.c
@@ -226,6 +226,14 @@ octeon_iointr(uint32_t hwpend, struct trap_frame *frame)
 	imr = bus_space_read_8(&iobus_tag, iobus_h, en0);
 	bit = 63;
 
+	if ((isr & (1ULL << CIU_INT_WDOG_SUM)) != 0) {
+		for (ih = (struct intrhand *)octeon_intrhand[CIU_INT_WDOG_SUM];
+		    ih != NULL; ih = ih->ih_next) {
+			splraise(ih->ih_level);
+			(*ih->ih_fun)(ih->ih_arg);
+		}
+	}
+
 	isr &= imr;
 	if (isr == 0)
 		return 0;	/* not for us */
diff --git a/sys/arch/octeon/dev/octeon_iobus.c b/sys/arch/octeon/dev/octeon_iobus.c
index 4dab97c..e8b920d 100644
--- a/sys/arch/octeon/dev/octeon_iobus.c
+++ b/sys/arch/octeon/dev/octeon_iobus.c
@@ -129,12 +129,14 @@ const struct iobus_unit iobus_units[] = {
 	{ 0, 0 },				/* pcibus */
 	{ GMX0_BASE_PORT0, CIU_INT_GMX_DRP0 },	/* cn30xxgmx */
 	{ OCTEON_RNG_BASE, 0 },			/* octrng */
+	{ 0,  CIU_INT_WDOG_SUM	},		/* octwdog */
 };
 struct iobus_attach_args iobus_children[] = {
 	IOBUSDEV("octcf", 0, &iobus_units[0]),
 	IOBUSDEV("pcibus", 0, &iobus_units[1]),
 	IOBUSDEV("cn30xxgmx", 0, &iobus_units[2]),
-	IOBUSDEV("octrng", 0, &iobus_units[3])
+	IOBUSDEV("octrng", 0, &iobus_units[3]),
+	IOBUSDEV("octwdog", 0, &iobus_units[4])
 };
 #undef	IOBUSDEV
 
diff --git a/sys/arch/octeon/dev/octwdog.c b/sys/arch/octeon/dev/octwdog.c
new file mode 100644
index 0000000..a3467a5
--- /dev/null
+++ b/sys/arch/octeon/dev/octwdog.c
@@ -0,0 +1,146 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) YASUOKA Masahiko <yasuoka@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/octeonvar.h>
+#include <octeon/dev/cn30xxciureg.h>
+#include <octeon/dev/iobusvar.h>
+
+#define WDOG_NCYCLE			256
+#define WDOG_MODE_OFF			0
+#define WDOG_MODE_INTR			1
+#define WDOG_MODE_INTR_NMI		2
+#define WDOG_MODE_INTR_NMI_SOFTRST	3
+
+int	 octwdog_match(struct device *, void *, void *);
+void	 octwdog_attach(struct device *, struct device *, void *);
+int	 octwdog_intr(void *);
+int	 octwdog_ctl(void *, int);
+
+struct octwdog_softc {
+	struct device		 sc_dev;
+	void			*sc_ih;
+	bus_space_tag_t		 sc_iot;
+	bus_space_handle_t	 sc_ioh;
+	int			 sc_wdog_period;
+};
+
+struct cfattach octwdog_ca = {
+	sizeof(struct octwdog_softc), octwdog_match, octwdog_attach
+};
+
+struct cfdriver octwdog_cd = {
+	NULL, "octwdog", DV_DULL
+};
+
+int
+octwdog_match(struct device *parent, void *match, void *aux)
+{
+	struct iobus_attach_args	*aa = aux;
+	struct cfdata			*cf = match;
+
+	if (aa->aa_name == NULL ||
+	    strcmp(aa->aa_name, cf->cf_driver->cd_name) != 0)
+		return (0);
+
+	return (1);
+}
+
+void
+octwdog_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct octwdog_softc		*sc = (struct octwdog_softc *)self;
+	struct iobus_attach_args	*aa = aux;
+	extern bus_space_handle_t	 iobus_h;	/* ugly? */
+
+	/* Using parent iobus's bus_space for the moment */
+	sc->sc_iot = aa->aa_bust;
+	sc->sc_ioh = iobus_h;
+
+	/* Setup interrupt */
+	sc->sc_ih = octeon_intr_establish(aa->aa_unit->irq, IPL_CLOCK,
+	    octwdog_intr, sc, NULL);
+
+	/* Enable interrupt */
+	bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_INT0_EN1_OFFSET,
+	    bus_space_read_8(sc->sc_iot, sc->sc_ioh, CIU_INT0_EN1_OFFSET) | 3);
+
+	/* Register as a watchdog(4) */
+	wdog_register(octwdog_ctl, self);
+
+	printf("\n");
+}
+
+int
+octwdog_ctl(void *ctx, int period)
+{
+	struct octwdog_softc	*sc = ctx;
+	uint64_t		 reg, len;
+	int			 newperiod;
+
+	reg = bus_space_read_8(sc->sc_iot, sc->sc_ioh, CIU_WDOG0_OFFSET);
+
+	newperiod = period;
+	if (newperiod > 0) {
+		/* LEN is MSB 16 bits of 24 bits value in WDOG_NCYCLE cycles. */
+		len = newperiod * (curcpu()->ci_hw.clock / WDOG_NCYCLE);
+		if (len >= (1ULL << 24)) {
+			len = (1ULL << 24) - 1;
+			newperiod = len / (curcpu()->ci_hw.clock / WDOG_NCYCLE);
+		}
+
+		if (sc->sc_wdog_period != newperiod) {
+			/* Set the watchdog timer */
+			reg &= ~(CIU_WDOGX_MODE|CIU_WDOGX_GSTOPEN|
+			    CIU_WDOGX_DSTOP|CIU_WDOGX_LEN);
+			reg |= WDOG_MODE_INTR_NMI_SOFTRST |
+			    (len & CIU_WDOGX_LEN);
+			bus_space_write_8(sc->sc_iot, sc->sc_ioh,
+			    CIU_WDOG0_OFFSET, reg);
+			sc->sc_wdog_period = newperiod;
+		} else
+			/* Poke the watchdog timer */
+			bus_space_write_8(sc->sc_iot, sc->sc_ioh,
+			    CIU_PP_POKE0_OFFSET, 1ULL);
+
+		return (sc->sc_wdog_period);
+	} else {
+		reg &= ~CIU_WDOGX_MODE;
+		reg |= WDOG_MODE_OFF;
+		bus_space_write_8(sc->sc_iot, sc->sc_ioh, CIU_WDOG0_OFFSET,
+		    reg);
+		sc->sc_wdog_period = 0;
+	}
+
+	return (0);
+}
+
+int
+octwdog_intr(void *ctx)
+{
+	struct octwdog_softc	*sc = ctx;
+
+	octwdog_ctl(sc, 0);		/* stop the watchdog */
+	panic("watchdog failed");
+
+	/* NOTREACHED */
+	return (0);
+}
diff --git a/sys/arch/octeon/include/octeonreg.h b/sys/arch/octeon/include/octeonreg.h
index d0bf309..348a2d7 100644
--- a/sys/arch/octeon/include/octeonreg.h
+++ b/sys/arch/octeon/include/octeonreg.h
@@ -89,7 +89,7 @@
 #define CIU_INT_PCI_MSIB	41
 #define CIU_INT_PCI_MSIC	42
 #define CIU_INT_PCI_MSID	43
-#define CIU_INT_44		44
+#define CIU_INT_WDOG_SUM	44
 #define CIU_INT_TWSI		45
 #define CIU_INT_RML		46
 #define CIU_INT_TRACE		47
