[ previous ] [ next ] [ threads ]
 
 From:  Manuel Kasper <mk at neon1 dot net>
 To:  Mike Tancsa <mike at sentex dot net>
 Cc:  m0n0wall at lists dot m0n0 dot ch, phk at freebsd dot org
 Subject:  watchdog diffs for 4.8 (was: Re: [m0n0wall] pb11r409 released)
 Date:  Thu, 26 Jun 2003 19:09:24 +0200 (CEST)
On Wed, 25 Jun 2003, Mike Tancsa wrote:

> Thanks for the reply!  Is it possible to post the diffs ?  phk at freebsd dot org
> said he would commit the diffs to RELENG_4 if someone could provide a patch
> set.

Attached to this message:

- diff for sys/i386/i386/elan_mmcr.c from FreeBSD 4.8
- watchdog.h that goes in sys/sys/watchdog.h

I have tested this under FreeBSD 4.8-RELEASE using watchdog-test from
http://wleiden.webweaving.org:8080/svn/node-config/soekris/watchdog/watchdog-test.c
and the watchdog reset the box properly in the last test.

HTH,

Manuel
/*-
 * Copyright (c) 2003 Poul-Henning Kamp
 * 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: /repoman/r/ncvs/src/sys/sys/watchdog.h,v 1.1 2003/02/27 21:07:36 phk Exp $
 */
#ifndef _SYS_WATCHDOG_H
#define	_SYS__WATCHDOG_H

#include <sys/ioccom.h>

#define WDIOCPATPAT	_IOW('W', 42, u_int)

#define WD_ACTIVE	0x8000000
	/* 
	 * Watchdog reset, timeout set to value in WD_INTERVAL field.
	 * The kernel will arm the watchdog and unless the userland
	 * program calls WDIOCPATPAT again before the timer expires
	 * the system will reinitialize.
	 */

#define WD_PASSIVE	0x0400000
	/*
	 * Set the watchdog in passive mode.
	 * The kernel will chose an appropriate timeout duration and
	 * periodically reset the timer provided everything looks all
	 * right to the kernel.
 	 */

#define WD_INTERVAL	0x00000ff
	/*
	 * Mask for duration bits.
	 * The watchdog will have a nominal patience of 2^N * nanoseconds.
	 * Example:  N == 30 gives a patience of 2^30 nanoseconds ~= 1 second.
	 * NB: Expect variance in the +/- 10-20% range.
	 */

#ifdef _KERNEL
#define __WD_LEGAL	(WD_ACTIVE | WD_PASSIVE | WD_INTERVAL)
#endif

/* Handy macros for humans not used to power of two nanoseconds */
#define WD_TO_NEVER	0
#define WD_TO_1MS	20
#define WD_TO_125MS	27
#define WD_TO_250MS	28
#define WD_TO_500MS	29
#define WD_TO_1SEC	30
#define WD_TO_2SEC	31
#define WD_TO_4SEC	32
#define WD_TO_8SEC	33
#define WD_TO_16SEC	34
#define WD_TO_32SEC	35

#endif /* _SYS_WATCHDOG_H */
--- sys/i386/i386/elan-mmcr.c.orig	Mon Jun  9 13:11:58 2003
+++ sys/i386/i386/elan-mmcr.c	Mon Jun  9 13:14:12 2003
@@ -25,6 +25,7 @@
 #include <sys/proc.h>
 #include <sys/sysctl.h>
 #include <sys/time.h>
+#include <sys/watchdog.h>
 
 #include <machine/md_var.h>
 
@@ -126,8 +127,71 @@
 }
 
 static int
+elan_watchdog(u_int spec)
+{
+	u_int u, v;
+	static u_int cur;
+
+	if (spec & ~__WD_LEGAL)
+		return (EINVAL);
+	switch (spec & (WD_ACTIVE|WD_PASSIVE)) {
+	case WD_ACTIVE:
+		u = spec & WD_INTERVAL;
+		if (u > 35)
+			return (EINVAL);
+		u = imax(u - 5, 24);
+		v = 2 << (u - 24);
+		v |= 0xc000;
+
+		/*
+		 * There is a bug in some silicon which prevents us from
+		 * writing to the WDTMRCTL register if the GP echo mode is
+		 * enabled.  GP echo mode on the other hand is desirable
+		 * for other reasons.  Save and restore the GP echo mode
+		 * around our hardware tom-foolery.
+		 */
+		u = elan_mmcr[0xc00 / 2];
+		elan_mmcr[0xc00 / 2] = 0;
+		if (v != cur) {
+			/* Clear the ENB bit */
+			elan_mmcr[0xcb0 / 2] = 0x3333;
+			elan_mmcr[0xcb0 / 2] = 0xcccc;
+			elan_mmcr[0xcb0 / 2] = 0;
+
+			/* Set new value */
+			elan_mmcr[0xcb0 / 2] = 0x3333;
+			elan_mmcr[0xcb0 / 2] = 0xcccc;
+			elan_mmcr[0xcb0 / 2] = v;
+			cur = v;
+		} else {
+			/* Just reset timer */
+			elan_mmcr[0xcb0 / 2] = 0xaaaa;
+			elan_mmcr[0xcb0 / 2] = 0x5555;
+		}
+		elan_mmcr[0xc00 / 2] = u;
+		return (0);
+	case WD_PASSIVE:
+		return (EOPNOTSUPP);
+	case 0:
+		u = elan_mmcr[0xc00 / 2];
+		elan_mmcr[0xc00 / 2] = 0;
+		elan_mmcr[0xcb0 / 2] = 0x3333;
+		elan_mmcr[0xcb0 / 2] = 0xcccc;
+		elan_mmcr[0xcb0 / 2] = 0x4080;
+		elan_mmcr[0xc00 / 2] = u;
+		cur = 0;
+		return (0);
+	default:
+		return (EINVAL);
+	}
+}
+
+static int
 elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
 {
+	if (cmd == WDIOCPATPAT)
+		return elan_watchdog(*((u_int*)arg));
+
 	return(ENOENT);
 }