This tiny driver is only meant for a backup watchdog configuration on
QEMU, whose ICH watchdog, supported by ichwdt(4), seems broken.

ib700wdt(4) supports only 0-30 second timeouts but in practice it should
be good enough.

diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index fee3c2a..82e7de0 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -608,6 +608,7 @@ bktr0       at pci?
 radio* at bktr?
 
 #wdt0  at pci?                 # Ind Computer Source PCI-WDT50x driver
+#ib700wdt* at isa? port 0x441  # iBase 700 (IB700) Watchdog Timer
 
 # crypto support
 hifn*  at pci?                 # Hi/fn 7751 crypto card
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 0984e5b..dbb7df6 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -108,6 +108,7 @@ geodesc* at pci?            # Geode SC1100/SCx200 IAOC
 wdt0   at pci?                 # Ind Computer Source PCI-WDT50x driver
 berkwdt0 at pci?               # Berkshire PCI-PC Watchdog driver
 pwdog0 at pci?                 # Quancom PWDOG1 watchdog timer
+#ib700wdt* at isa? port 0x441  # iBase 700 (IB700) Watchdog Timer
 
 # National Semiconductor LM7[89] and compatible hardware monitors
 lm0    at isa? port 0x290
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 863d11c..92a9ecc 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -380,3 +380,8 @@ file        dev/isa/isagpio.c               isagpio
 #file  dev/isa/pcmcia_pcic.c           pcic | pcicmaster
 
 #file  dev/isa/pcmcia_isa.c            pcmcia
+
+# iBase 700 (IB700) Watchdog Timer
+device ib700wdt
+attach ib700wdt at isa
+file   dev/isa/ib700wdt.c              ib700wdt
diff --git a/sys/dev/isa/ib700wdt.c b/sys/dev/isa/ib700wdt.c
new file mode 100644
index 0000000..cdad79f
--- /dev/null
+++ b/sys/dev/isa/ib700wdt.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016 Masao Uebayashi <[email protected]>
+ *
+ * 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 <sys/kernel.h>
+#include <sys/timeout.h>
+#include <machine/bus.h>
+#include <sys/event.h>
+
+#include <dev/isa/isavar.h>
+
+/*
+ * IB700 USER'S MANUAL
+ * Version 1.0B
+ * p28
+ * Watchdog Timer Configuration
+ */
+
+#define        IB700WDT_BASE   0x441
+#define        IB700WDT_SIZE   3
+#define        IB700WDT_DIS    0       /* 0x441 */
+#define        IB700WDT_ENA    2       /* 0x443 */
+#define        IB700WDT_SEC_MIN        0
+#define        IB700WDT_SEC_MAX        30
+
+static inline uint8_t
+ib700wdt_sec2val(int sec)
+{
+       /* 0/1sec = 0xf, 2/3sec = 0xe, ..., 28/29 = 0x1, 30sec = 0x0 */
+       return (0xf - (sec * 0xf / 30));
+}
+
+/*
+ * Driver for iBase 700 Watchdog Timer
+ * Mainly meant for QEMU's "ib700" watchdog device
+ * Can't handle immediate reset (sec=0)
+ */
+
+struct ib700wdt_softc {
+       struct device sc_dev;
+       bus_space_tag_t sc_iot;
+       bus_space_handle_t sc_ioh;
+       int sc_period;
+};
+
+int    ib700wdt_match(struct device *, void *, void *);
+void   ib700wdt_attach(struct device *, struct device *, void *);
+int    ib700wdt_activate(struct device *, int);
+
+int    ib700wdt_cb(void *, int);
+
+struct cfattach ib700wdt_ca = {
+       sizeof(struct ib700wdt_softc),
+       ib700wdt_match, ib700wdt_attach, NULL, ib700wdt_activate
+};
+
+struct cfdriver ib700wdt_cd = {
+       NULL, "ib700wdt", DV_DULL
+};
+
+int
+ib700wdt_match(struct device *parent, void *match, void *aux)
+{
+       struct isa_attach_args *ia = aux;
+
+       ia->ia_iosize = IB700WDT_SIZE;
+       ia->ia_msize = 0;
+
+       return (1);
+}
+
+void
+ib700wdt_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct ib700wdt_softc *sc = (struct ib700wdt_softc *)self;
+       struct isa_attach_args *ia = aux;
+
+       sc->sc_iot = ia->ia_iot;
+
+       if (bus_space_map(sc->sc_iot, ia->ia_iobase, IB700WDT_SIZE, 0, 
&sc->sc_ioh))
+               return;
+
+       printf("\n");
+
+       wdog_register(ib700wdt_cb, sc);
+}
+
+int
+ib700wdt_activate(struct device *self, int act)
+{
+       switch (act) {
+       case DVACT_POWERDOWN:
+               wdog_shutdown(self);
+               break;
+       }
+
+       return (0);
+}
+
+int
+ib700wdt_cb(void *arg, int period)
+{
+       struct ib700wdt_softc *sc = arg;
+       uint8_t val;
+
+       if (period == 0) {
+               if (sc->sc_period != 0)
+                       bus_space_write_1(sc->sc_iot, sc->sc_ioh, IB700WDT_DIS, 
0);
+       } else {
+               if (period < IB700WDT_SEC_MIN)
+                       period = IB700WDT_SEC_MIN;
+               else if (period > IB700WDT_SEC_MAX)
+                       period = IB700WDT_SEC_MAX;
+               if (sc->sc_period != period) {
+                       val = ib700wdt_sec2val(period);
+                       bus_space_write_1(sc->sc_iot, sc->sc_ioh, IB700WDT_ENA, 
val);
+               }
+               if (sc->sc_period == 0)
+                       val = ib700wdt_sec2val(period);
+               else
+                       val = ib700wdt_sec2val(sc->sc_period);
+               bus_space_write_1(sc->sc_iot, sc->sc_ioh, IB700WDT_ENA, val);
+       }
+       sc->sc_period = period;
+
+       return (period);
+}

Reply via email to