[RFC] winbond watchdog driver for FreeBSD/i386 and FreeBSD/amd64

Andriy Gapon avg at FreeBSD.org
Wed Jun 29 09:22:39 UTC 2011


on 29/06/2011 01:32 Xin LI said the following:
> Hi,
> 
> I'd like to request for comments on the attached driver, which supports
> watchdogs on several Winbond super I/O chip models and have been tested
> on a few of recent Supermicro motherboards.

Some comments.

> From 343b2e7b6ed19e4b6ca2bf76c0ca6b8544dd4320 Mon Sep 17 00:00:00 2001
> From: Xin LI <d at delphij.net>
> Date: Mon, 27 Jun 2011 21:54:13 -0700
> Subject: [PATCH] Driver for Winbond watchdog.
> 
> ---
>  share/man/man4/Makefile        |    3 +
>  share/man/man4/winbondwd.4     |   88 ++++++++++
>  sys/amd64/conf/NOTES           |    2 +
>  sys/conf/files.amd64           |    1 +
>  sys/conf/files.i386            |    1 +
>  sys/dev/winbondwd/winbondwd.c  |  368 ++++++++++++++++++++++++++++++++++++++++
>  sys/dev/winbondwd/winbondwd.h  |   47 +++++
>  sys/i386/conf/NOTES            |    2 +
>  sys/modules/Makefile           |    3 +
>  sys/modules/winbondwd/Makefile |    8 +
>  10 files changed, 523 insertions(+), 0 deletions(-)
>  create mode 100644 share/man/man4/winbondwd.4
>  create mode 100644 sys/dev/winbondwd/winbondwd.c
>  create mode 100644 sys/dev/winbondwd/winbondwd.h
>  create mode 100644 sys/modules/winbondwd/Makefile
> 
> diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
> index 7ccccfb..777e2fd 100644
> --- a/share/man/man4/Makefile
> +++ b/share/man/man4/Makefile
> @@ -447,6 +447,7 @@ MAN=	aac.4 \
>  	tun.4 \
>  	twa.4 \
>  	twe.4 \
> +	tws.4 \

Looks like this has sneaked in accidentally.

>  	tx.4 \
>  	txp.4 \
>  	u3g.4 \
> @@ -503,6 +504,7 @@ MAN=	aac.4 \
>  	watchdog.4 \
>  	wb.4 \
>  	wi.4 \
> +	${_winbondwd.4} \
>  	witness.4 \
>  	wlan.4 \
>  	wlan_acl.4 \
> @@ -706,6 +708,7 @@ _speaker.4=	speaker.4
>  _spkr.4=	spkr.4
>  _tpm.4=		tpm.4
>  _urtw.4=	urtw.4
> +_winbondwd.4=	winbondwd.4
>  _wpi.4=		wpi.4
>  _xen.4=		xen.4
>  
> diff --git a/share/man/man4/winbondwd.4 b/share/man/man4/winbondwd.4
> new file mode 100644
> index 0000000..6fd2719
> --- /dev/null
> +++ b/share/man/man4/winbondwd.4
> @@ -0,0 +1,88 @@
> +.\"-
> +.\" Copyright (c) 2011 Xin LI <delphij at FreeBSD.org>
> +.\" All rights reserved.
> +.\"
> +.\" Redistribution and use in source and binary forms, with or without
> +.\" modification, are permitted provided that the following conditions
> +.\" are met:
> +.\" 1. Redistributions of source code must retain the above copyright
> +.\"    notice, this list of conditions and the following disclaimer.
> +.\" 2. Redistributions in binary form must reproduce the above copyright
> +.\"    notice, this list of conditions and the following disclaimer in the
> +.\"    documentation and/or other materials provided with the distribution.
> +.\"
> +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> +.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> +.\" SUCH DAMAGE.
> +.\"
> +.\" $FreeBSD$
> +.\"
> +.Dd July 1, 2011
> +.Dt WINBONDWD 4
> +.Os
> +.Sh NAME
> +.Nm winbondwd
> +.Nd device driver for the Winbond Super I/O watchdog timer
> +.Sh SYNOPSIS
> +To compile this driver into the kernel,
> +place the following line in your
> +kernel configuration file:
> +.Bd -ragged -offset indent
> +.Cd "device winbondwd"
> +.Ed
> +.Pp
> +Alternatively, to load the driver as a
> +module at boot time, place the following line in
> +.Xr loader.conf 5 :
> +.Bd -literal -offset indent
> +winbondwd_load="YES"
> +.Ed
> +.Sh DESCRIPTION
> +The
> +.Nm
> +driver provides
> +.Xr watchdog 4
> +support for the watchdog interrupt timer present on
> +all Winbond super I/O controllers.
> +.Pp
> +The Winbond super I/O controller have a built-in watchdog timer,
> +which can be enabled and disabled by user's program and set between
> +1 to 255 seconds or 1 to 255 minutes.
> +Supported watchdog intervals range from 1 to 255 seconds.
> +.Pp
> +On some systems the watchdog timer is enabled and set to 5 minutes
> +by BIOS on boot.
> +The
> +.Nm
> +driver will detect and print out the existing setting, however, 
> +it will not make any changes unless told by the userland through
> +the
> +.Xr watchdog 4
> +interface,
> +for instance by using the
> +.Xr watchdogd 8
> +daemon.
> +.Sh SEE ALSO
> +.Xr watchdog 4 ,
> +.Xr watchdog 8 ,
> +.Xr watchdogd 8 ,
> +.Xr watchdog 9
> +.Sh HISTORY
> +The
> +.Nm
> +driver first appeared in
> +.Fx 9.0 .
> +.Sh AUTHORS
> +.An -nosplit
> +The
> +.Nm
> +driver and this manual page were written by
> +.An Xin LI Aq delphij at FreeBSD.org .
> diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
> index 4a47ace..3b25aea 100644
> --- a/sys/amd64/conf/NOTES
> +++ b/sys/amd64/conf/NOTES
> @@ -453,9 +453,11 @@ device		tpm
>  #
>  # ichwd: Intel ICH watchdog timer
>  # amdsbwd: AMD SB7xx watchdog timer
> +# winbondwd: Winbond watchdog timer
>  #
>  device		ichwd
>  device		amdsbwd
> +device		winbondwd
>  
>  #
>  # Temperature sensors:
> diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
> index 1388d01..18dbea6 100644
> --- a/sys/conf/files.amd64
> +++ b/sys/conf/files.amd64
> @@ -223,6 +223,7 @@ dev/tpm/tpm.c			optional	tpm
>  dev/tpm/tpm_acpi.c		optional	tpm acpi
>  dev/tpm/tpm_isa.c		optional	tpm isa
>  dev/uart/uart_cpu_amd64.c	optional	uart
> +dev/winbondwd/winbondwd.c	optional	winbondwd
>  dev/wpi/if_wpi.c		optional	wpi
>  isa/syscons_isa.c		optional	sc
>  isa/vga_isa.c			optional	vga
> diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
> index 41a1772..112115d 100644
> --- a/sys/conf/files.i386
> +++ b/sys/conf/files.i386
> @@ -238,6 +238,7 @@ dev/tpm/tpm_isa.c		optional tpm isa
>  dev/uart/uart_cpu_i386.c	optional uart
>  dev/acpica/acpi_if.m		standard
>  dev/acpi_support/acpi_wmi_if.m	standard
> +dev/winbondwd/winbondwd.c	optional winbondwd
>  dev/wpi/if_wpi.c		optional wpi
>  i386/acpica/acpi_machdep.c	optional acpi
>  acpi_wakecode.o			optional acpi				\
> diff --git a/sys/dev/winbondwd/winbondwd.c b/sys/dev/winbondwd/winbondwd.c
> new file mode 100644
> index 0000000..fa53735
> --- /dev/null
> +++ b/sys/dev/winbondwd/winbondwd.c
> @@ -0,0 +1,368 @@
> +/*-
> + * Copyright (c) 2010 iXsystems, Inc.
> + * All rights reserved.
> + *     Written by: Xin LI <delphij at FreeBSD.org>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +/*
> + * Winbond Watchdog Timer (WDT) driver
> + */
> +
> +#include <sys/cdefs.h>
> +__FBSDID("$FreeBSD$");
> +
> +#include <sys/param.h>
> +#include <sys/kernel.h>
> +#include <sys/module.h>
> +#include <sys/systm.h>
> +#include <sys/bus.h>
> +#include <machine/bus.h>
> +#include <sys/rman.h>
> +#include <machine/resource.h>
> +#include <sys/watchdog.h>
> +
> +#include <isa/isavar.h>
> +#include <dev/pci/pcivar.h>
> +
> +#include <dev/winbondwd/winbondwd.h>
> +
> +static devclass_t winbondwd_devclass;
> +
> +#define winbondwd_read_1(sc, off) \
> +	    bus_space_read_1((sc)->wb_bst, (sc)->wb_bsh, (off))
> +
> +#define winbondwd_write_1(sc, off, val) \
> +	    bus_space_write_1((sc)->wb_bst, (sc)->wb_bsh, (off), (val))
> +
> +/*
> + * Enter Winbond Extended Functions State
> + */
> +static __inline void
> +winbondwd_config_enter(struct winbondwd_softc *sc)
> +{
> +
> +	winbondwd_write_1(sc, 0, 0x87);
> +	winbondwd_write_1(sc, 0, 0x87);
> +}
> +
> +/*
> + * Leave Winbond Extended Functions State
> + */
> +static __inline void
> +winbondwd_config_leave(struct winbondwd_softc *sc)
> +{
> +
> +	winbondwd_write_1(sc, 0, 0xaa);
> +}
> +
> +static __inline unsigned char
> +winbondwd_read_reg(struct winbondwd_softc *sc, unsigned char reg)
> +{
> +
> +	winbondwd_write_1(sc, 0, reg);
> +	return (winbondwd_read_1(sc, 1));
> +}
> +
> +/*
> + * Write specified extended function register
> + */
> +static __inline void
> +winbondwd_write_reg(struct winbondwd_softc *sc, unsigned char reg, unsigned char val)
> +{
> +
> +	winbondwd_write_1(sc, 0, reg);
> +	winbondwd_write_1(sc, 1, val);
> +}
> +
> +/*
> + * Select the watchdog device (GPIO Port 2, Logical device 8)
> + */
> +static void
> +winbondwd_select(struct winbondwd_softc *sc)
> +{
> +
> +	winbondwd_config_enter(sc);
> +	winbondwd_write_reg(sc, /* LDN bit 7:1 */ 0x7, /* GPIO Port 2 */ 0x8);
> +	winbondwd_write_reg(sc, /* CR30 */ 0x30, /* Activate */ 0x1);
> +}
> +
> +/*
> + * Deselect the watchdog device (only a config_leave is needed)
> + */
> +static void
> +winbondwd_deselect(struct winbondwd_softc *sc)
> +{
> +
> +	winbondwd_config_leave(sc);
> +}
> +
> +/*
> + * Show timeout
> + */
> +static void
> +winbondwd_show_timeout(struct winbondwd_softc *sc)
> +{
> +	const char *mode_str;
> +	unsigned char timeout, mode;
> +
> +	winbondwd_select(sc);
> +	timeout = winbondwd_read_reg(sc, 0xf6 /* Timeout CR */);
> +	if (timeout == 0) {
> +		sc->active = 0;
> +		if (bootverbose)
> +			device_printf(sc->device,
> +			    "Winbond watchdog not running\n");
> +	} else {
> +		sc->active = 1;
> +		mode = winbondwd_read_reg(sc, 0xf5 /* Bit 3: count mode */);
> +		mode_str = (mode & (1 << 2))? "minute" : "second";
> +		device_printf(sc->device,
> +		    "Winbond watchdog will timeout after %hhu %s%s\n",
> +		    timeout, mode_str, ((timeout > 1)? "s" : ""));
> +	}
> +	winbondwd_deselect(sc);
> +}
> +
> +/*
> + * Set timeout in seconds; 0 = disable
> + */
> +static void
> +winbondwd_set_timeout(struct winbondwd_softc *sc, unsigned char timeout)
> +{
> +	unsigned char mode;
> +
> +	/* Don't bother to disable if the watchdog is not running */
> +	if (sc->active == 0 && timeout == 0)
> +		return;
> +
> +	winbondwd_select(sc);
> +	mode = winbondwd_read_reg(sc, 0xf5 /* Bit 3: count mode */);
> +	mode &= ~(1 << 2);	/* Choose seconds mode */
> +	winbondwd_write_reg(sc, 0xf5, mode);
> +
> +	winbondwd_write_reg(sc, 0xf6 /* Timeout CR */, timeout);
> +	winbondwd_deselect(sc);
> +
> +	if (bootverbose) {
> +		if (timeout == 0)
> +			device_printf(sc->device,
> +			    "Winbond watchdog disabled.\n");
> +		else
> +			device_printf(sc->device,
> +			    "Winbond watchdog timeout after %hhu seconds.\n",
> +			    timeout);
> +	}
> +
> +	sc->active = (timeout == 0) ? 0 : 1;
> +}
> +
> +/*
> + * Watchdog event handler - called by the framework to enable or disable
> + * the watchdog or change the initial timeout value.
> + */
> +static void
> +winbondwd_event(void *arg, unsigned int cmd, int *error)
> +{
> +	struct winbondwd_softc *sc = arg;
> +	unsigned char rtimeout;
> +	uint64_t timeout;
> +
> +	if (cmd == 0)
> +		winbondwd_set_timeout(sc, 0);
> +	else {
> +		timeout = (uint64_t)1 << (cmd & WD_INTERVAL);
> +		if (timeout < (uint64_t)0xff * 1000 * 1000 * 1000) {
> +			rtimeout = timeout / (1000 * 1000 * 1000);
> +			if (rtimeout == 0)
> +				rtimeout = 0xff;
> +			winbondwd_set_timeout(sc, rtimeout);
> +		} else {
> +			device_printf(sc->device,
> +			    "Value %u too big, disabling\n", cmd & WD_INTERVAL);
> +			/* Proposed timeout can not be satisified */
> +			winbondwd_set_timeout(sc, 0);
> +		}
> +	}
> +}
> +
> +/*
> + * A hack to probe Winbond chip's base port.
> + */
> +static unsigned int
> +winbondwd_baseport_probe(void)
> +{
> +	unsigned char val;
> +	int i;
> +	const unsigned int baseport_candidates[] = { 0x2e, 0x4e, 0 };

I also have a system with port 0x3f0.

> +	for (i = 0; baseport_candidates[i] != 0; i++) {
> +		/*
> +		 * Enter config mode.
> +		 *
> +		 * Output magic number twice to the index register
> +		 */
> +		outb(baseport_candidates[i], 0x87);
> +		outb(baseport_candidates[i], 0x87);
> +
> +		/*
> +		 * I know this is ugly but I didn't found a way to do
> +		 * this in a cleaner manner.
> +		 */
> +		/* Get data from CR 0x20 (Device ID) */
> +		outb(baseport_candidates[i], 0x20);
> +		val = inb(baseport_candidates[i]+1);
> +
> +		if (bootverbose)
> +			printf("winbondwd0: CR20 probing port 0x%x got 0x%x\n", baseport_candidates[i], val);
> +
> +		if (val != 0xff) {
> +			outb(baseport_candidates[i], 0xaa);
> +			return baseport_candidates[i];
> +		}
> +	}
> +
> +	return (unsigned int)(-1);
> +}
> +		
> +	
> +
> +/*
> + * Look for Winbond device.
> + */
> +static void
> +winbondwd_identify(driver_t *driver, device_t parent)
> +{
> +	unsigned int baseport;
> +	device_t dev;
> +
> +        if ((dev = device_find_child(parent, driver->name, 0)) == NULL) {
> +		if (resource_int_value("winbondwd", 0, "baseport", &baseport) != 0) {
> +			baseport = winbondwd_baseport_probe();
> +			if (baseport == (unsigned int)(-1)) {
> +				printf("winbondwd0: Compatible Winbond Super I/O not found.\n");
> +				return;
> +			}
> +		}
> +
> +		dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);
> +
> +		bus_set_resource(dev, SYS_RES_IOPORT, 0, baseport, 2);
> +	}
> +
> +	if (dev == NULL)
> +		return;

These last two lines are redundant?

Also, maybe I am confused, but I think that in ISA identify method you don't
actually need to parse any hints/tunables.  That is, you can use standard hints
approach like e.g.:
hint.winbondwd.0.at="isa"
hint.winbondwd.0.port="0x3F0"
and ISA will automatically add a winbondwd child with an I/O port resource at
0x3F0.  The identify method should only add a child for a no-hints/auto-probing
case.
E.g. see boiler-plate code for the ISA case in
share/examples/drivers/make_device_driver.sh, especially the comments.

I am not saying that your approach won't work (apparently it does) or that it is
inherently bad.  It just seems to be different from how other ISA drivers do
their identify+probe dance.

> +}
> +
> +static int
> +winbondwd_probe(device_t dev)
> +{
> +
> +	/* Do not claim some ISA PnP device by accident. */
> +	if (isa_get_logicalid(dev) != 0)
> +		return (ENXIO);
> +	return (0);
> +}
> +
> +static int
> +winbondwd_attach(device_t dev)
> +{
> +	struct winbondwd_softc *sc;
> +	unsigned int baseport;
> +
> +	sc = device_get_softc(dev);
> +	sc->device = dev;
> +
> +	if (resource_int_value("winbondwd", 0, "baseport", &baseport) != 0) {
> +		baseport = winbondwd_baseport_probe();
> +		if (baseport == (unsigned int)(-1)) {
> +			device_printf(dev,
> +			    "No compatible Winbond Super I/O found.\n");
> +			return (ENXIO);
> +		}
> +	}
> +
> +	/* allocate I/O register space */
> +	sc->wb_rid = 0;
> +	sc->wb_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->wb_rid,
> +	    baseport, baseport + 1, 2, RF_ACTIVE | RF_SHAREABLE);
> +	if (sc->wb_res == NULL) {
> +		device_printf(dev, "Unable to reserve Extended Function Registers\n");
> +		goto fail;
> +	}
> +	sc->wb_bst = rman_get_bustag(sc->wb_res);
> +	sc->wb_bsh = rman_get_bushandle(sc->wb_res);
> +
> +	/* Display the device status */
> +	winbondwd_show_timeout(sc);
> +
> +	/* register the watchdog event handler */
> +	sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, winbondwd_event, sc, 0);
> +
> +	return (0);
> +
> +fail:
> +	if (sc->wb_res != NULL)
> +		bus_release_resource(dev, SYS_RES_IOPORT,
> +		    sc->wb_rid, sc->wb_res);
> +	return (ENXIO);
> +}
> +
> +static int
> +winbondwd_detach(device_t dev)
> +{
> +	struct winbondwd_softc *sc;
> +
> +	sc = device_get_softc(dev);
> +
> +	/* deregister event handler */
> +	if (sc->ev_tag != NULL)
> +		EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
> +	sc->ev_tag = NULL;
> +
> +	/* Disable the watchdog */
> +	if (sc->active)
> +		winbondwd_set_timeout(sc, 0);
> +
> +	/* deallocate I/O register space */
> +	bus_release_resource(dev, SYS_RES_IOPORT, sc->wb_rid, sc->wb_res);
> +
> +	return (0);
> +}
> +
> +static device_method_t winbondwd_methods[] = {
> +	DEVMETHOD(device_identify, winbondwd_identify),
> +	DEVMETHOD(device_probe,	winbondwd_probe),
> +	DEVMETHOD(device_attach, winbondwd_attach),
> +	DEVMETHOD(device_detach, winbondwd_detach),
> +	DEVMETHOD(device_shutdown, winbondwd_detach),
> +	{0,0}
> +};
> +
> +static driver_t winbondwd_driver = {
> +	"winbondwd",
> +	winbondwd_methods,
> +	sizeof(struct winbondwd_softc),
> +};
> +
> +DRIVER_MODULE(winbondwd, isa, winbondwd_driver, winbondwd_devclass, NULL, NULL);
> diff --git a/sys/dev/winbondwd/winbondwd.h b/sys/dev/winbondwd/winbondwd.h
> new file mode 100644
> index 0000000..57a1a23
> --- /dev/null
> +++ b/sys/dev/winbondwd/winbondwd.h
> @@ -0,0 +1,47 @@
> +/*-
> + * Copyright (c) 2010 iXsystems, Inc.
> + * All rights reserved.
> + *     Written by: Xin LI <delphij at FreeBSD.org>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD$
> + */
> +
> +#ifndef _WINBONDWD_H_
> +#define _WINBONDWD_H_
> +
> +struct winbondwd_softc {
> +	device_t		 device;
> +
> +	int			 active;
> +	unsigned int		 timeout;
> +
> +	int			 wb_rid;
> +	struct resource		*wb_res;
> +	bus_space_tag_t		 wb_bst;
> +	bus_space_handle_t	 wb_bsh;
> +
> +	eventhandler_tag	 ev_tag;
> +};
> +
> +#endif /* _WINBONDWD_H_ */
> diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
> index 866e641..80d82a2 100644
> --- a/sys/i386/conf/NOTES
> +++ b/sys/i386/conf/NOTES
> @@ -828,9 +828,11 @@ hint.pcf.0.irq="5"
>  #
>  # ichwd: Intel ICH watchdog timer
>  # amdsbwd: AMD SB7xx watchdog timer
> +# winbondwd: Winbond watchdog timer
>  #
>  device		ichwd
>  device		amdsbwd
> +device		winbondwd
>  
>  #
>  # Temperature sensors:
> diff --git a/sys/modules/Makefile b/sys/modules/Makefile
> index 2dbc3d9..de533e4 100644
> --- a/sys/modules/Makefile
> +++ b/sys/modules/Makefile
> @@ -320,6 +320,7 @@ SUBDIR=	${_3dfx} \
>  	vx \
>  	wb \
>  	${_wi} \
> +	${_winbondwd} \
>  	wlan \
>  	wlan_acl \
>  	wlan_amrr \
> @@ -469,6 +470,7 @@ _stg=		stg
>  _streams=	streams
>  _svr4=		svr4
>  _wi=		wi
> +_winbondwd=	winbondwd
>  _xe=		xe
>  .if ${MK_ZFS} != "no" || defined(ALL_MODULES)
>  _zfs=		zfs
> @@ -623,6 +625,7 @@ _twa=		twa
>  _vesa=		vesa
>  _x86bios=	x86bios
>  _wi=		wi
> +_winbondwd=	winbondwd
>  _wpi=		wpi
>  _wpifw=		wpifw
>  .if ${MK_ZFS} != "no" || defined(ALL_MODULES)
> diff --git a/sys/modules/winbondwd/Makefile b/sys/modules/winbondwd/Makefile
> new file mode 100644
> index 0000000..382d37f
> --- /dev/null
> +++ b/sys/modules/winbondwd/Makefile
> @@ -0,0 +1,8 @@
> +# $FreeBSD$
> +
> +.PATH: ${.CURDIR}/../../dev/winbondwd
> +
> +KMOD=	winbondwd
> +SRCS=	winbondwd.c device_if.h bus_if.h pci_if.h isa_if.h
> +
> +.include <bsd.kmod.mk>

I once wrote a similar driver, but of non-production quality for experimental
purposes:
http://thread.gmane.org/gmane.os.freebsd.devel.hackers/40276/focus=40752
(btw, there are other interesting posts in that thread).

And a litte bit of information just in case:  many Winbond Super I/Os support
several pins as possible "Watchdog Output" signal.  One thing that I've noticed
is that on some (admittedly consumer) systems they do connect one of those pins
to the chipset reset input pin.  But BIOS doesn't do any additional Super I/O
configuration for watchdog to actually work.  For example, sometimes they forget
to configure the pin to actually serve as WDTO function.  I had to hack in some
additional configuration code for that.  I intended to support configuration for
all supported pins, but actually stopped after one pin that I really need.

Also, just for fun, I also added some led(4) bits to control power indicator (it
was also driven via Super I/O), but that was totally, well, just for fun.
-- 
Andriy Gapon


More information about the freebsd-current mailing list