From 32f034facadd2bc887e7df30339620c3c74985ce Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Thu, 27 Feb 2003 21:13:08 +0000 Subject: [PATCH] Add support for the Elan CPU hardware watchdog used in "active" mode. --- sys/i386/i386/elan-mmcr.c | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/sys/i386/i386/elan-mmcr.c b/sys/i386/i386/elan-mmcr.c index cf324d31090..bd68670dbd4 100644 --- a/sys/i386/i386/elan-mmcr.c +++ b/sys/i386/i386/elan-mmcr.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -320,6 +321,67 @@ elan_mmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nprot) return (0); } +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 thread *tdr) { @@ -340,6 +402,9 @@ elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr) return (error); #endif /* ELAN_PPS */ + if (cmd == WDIOCPATPAT) + return elan_watchdog(*((u_int*)arg)); + /* Other future ioctl handling here */ return(error); }