# HG changeset patch
# User dkiper@xxxxxxxxxxxx
# Date 1259015859 -3600
# Node ID 0ee2f293ec4c52c01fdbc65f8e274e52c9ba3cc2
# Parent  1db1bb63824b25f97d127449faeb3a56f1272c97
Intel TCO Timer/Watchdog driver backported
from Linux Kernel Ver. 2.6.29.2
Signed-off-by: Daniel Kiper <dkiper@xxxxxxxxxxxx>

diff -r 1db1bb63824b -r 0ee2f293ec4c buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32	Mon Nov 23 07:32:47 2009 +0000
+++ b/buildconfigs/linux-defconfig_xen_x86_32	Mon Nov 23 23:37:39 2009 +0100
@@ -1900,7 +1900,8 @@ CONFIG_IBMASR=m
 CONFIG_IBMASR=m
 CONFIG_WAFER_WDT=m
 CONFIG_I6300ESB_WDT=m
-CONFIG_I8XX_TCO=m
+CONFIG_ITCO_WDT=m
+CONFIG_ITCO_VENDOR_SUPPORT=y
 CONFIG_SC1200_WDT=m
 CONFIG_SCx200_WDT=m
 CONFIG_60XX_WDT=m
diff -r 1db1bb63824b -r 0ee2f293ec4c buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64	Mon Nov 23 07:32:47 2009 +0000
+++ b/buildconfigs/linux-defconfig_xen_x86_64	Mon Nov 23 23:37:39 2009 +0100
@@ -1778,7 +1778,8 @@ CONFIG_IBMASR=m
 CONFIG_IBMASR=m
 CONFIG_WAFER_WDT=m
 CONFIG_I6300ESB_WDT=m
-CONFIG_I8XX_TCO=m
+CONFIG_ITCO_WDT=m
+CONFIG_ITCO_VENDOR_SUPPORT=y
 CONFIG_SC1200_WDT=m
 CONFIG_60XX_WDT=m
 CONFIG_SBC8360_WDT=m
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/Kconfig
--- a/drivers/char/watchdog/Kconfig	Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/char/watchdog/Kconfig	Mon Nov 23 23:37:39 2009 +0100
@@ -280,15 +280,18 @@ config I6300ESB_WDT
 	  To compile this driver as a module, choose M here: the
 	  module will be called i6300esb.
 
-config I8XX_TCO
-	tristate "Intel i8xx TCO Timer/Watchdog"
+config ITCO_WDT
+	tristate "Intel TCO Timer/Watchdog"
 	depends on WATCHDOG && (X86 || IA64) && PCI
 	---help---
-	  Hardware driver for the TCO timer built into the Intel 82801
-	  I/O Controller Hub family.  The TCO (Total Cost of Ownership)
-	  timer is a watchdog timer that will reboot the machine after
-	  its second expiration. The expiration time can be configured
-	  with the "heartbeat" parameter.
+	  Hardware driver for the intel TCO timer based watchdog devices.
+	  These drivers are included in the Intel 82801 I/O Controller
+	  Hub family (from ICH0 up to ICH10) and in the Intel 63xxESB
+	  controller hub.
+
+	  The TCO (Total Cost of Ownership) timer is a watchdog timer
+	  that will reboot the machine after its second expiration. The
+	  expiration time can be configured with the "heartbeat" parameter.
 
 	  On some motherboards the driver may fail to reset the chipset's
 	  NO_REBOOT flag which prevents the watchdog from rebooting the
@@ -296,7 +299,15 @@ config I8XX_TCO
 	  "failed to reset NO_REBOOT flag, reboot disabled by hardware".
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called i8xx_tco.
+	  module will be called iTCO_wdt.
+
+config ITCO_VENDOR_SUPPORT
+	bool "Intel TCO Timer/Watchdog Specific Vendor Support"
+	depends on ITCO_WDT
+	---help---
+	  Add vendor specific support to the intel TCO timer based watchdog
+	  devices. At this moment we only have additional support for some
+	  SuperMicro Inc. motherboards.
 
 config SC1200_WDT
 	tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/Makefile
--- a/drivers/char/watchdog/Makefile	Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/char/watchdog/Makefile	Mon Nov 23 23:37:39 2009 +0100
@@ -44,7 +44,10 @@ obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
+ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
+obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
+endif
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/iTCO_vendor.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/char/watchdog/iTCO_vendor.h	Mon Nov 23 23:37:39 2009 +0100
@@ -0,0 +1,15 @@
+/* iTCO Vendor Specific Support hooks */
+#ifdef CONFIG_ITCO_VENDOR_SUPPORT
+extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
+extern void iTCO_vendor_pre_stop(unsigned long);
+extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
+extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
+extern int iTCO_vendor_check_noreboot_on(void);
+#else
+#define iTCO_vendor_pre_start(acpibase, heartbeat)	{}
+#define iTCO_vendor_pre_stop(acpibase)			{}
+#define iTCO_vendor_pre_keepalive(acpibase, heartbeat)	{}
+#define iTCO_vendor_pre_set_heartbeat(heartbeat)	{}
+#define iTCO_vendor_check_noreboot_on()			1
+				/* 1=check noreboot; 0=don't check */
+#endif
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/iTCO_vendor_support.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/char/watchdog/iTCO_vendor_support.c	Mon Nov 23 23:37:39 2009 +0100
@@ -0,0 +1,312 @@
+/*
+ *	intel TCO vendor specific watchdog driver support
+ *
+ *	(c) Copyright 2006-2009 Wim Van Sebroeck <wim@xxxxxxxxx>.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ *	provide warranty for any of this software. This material is
+ *	provided "AS-IS" and at no charge.
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+/* Module and version information */
+#define DRV_NAME	"iTCO_vendor_support"
+#define DRV_VERSION	"1.03"
+#define PFX		DRV_NAME ": "
+
+/* Includes */
+#include <linux/module.h>		/* For module specific items */
+#include <linux/moduleparam.h>		/* For new moduleparam's */
+#include <linux/types.h>		/* For standard types (like size_t) */
+#include <linux/errno.h>		/* For the -ENODEV/... values */
+#include <linux/kernel.h>		/* For printk/panic/... */
+#include <linux/init.h>			/* For __init/__exit/... */
+#include <linux/ioport.h>		/* For io-port access */
+#include <linux/io.h>			/* For inb/outb/... */
+
+#include "iTCO_vendor.h"
+
+/* iTCO defines */
+#define	SMI_EN		acpibase + 0x30	/* SMI Control and Enable Register */
+#define	TCOBASE		acpibase + 0x60	/* TCO base address */
+#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register */
+
+/* List of vendor support modes */
+/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
+#define SUPERMICRO_OLD_BOARD	1
+/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
+#define SUPERMICRO_NEW_BOARD	2
+
+static int vendorsupport;
+module_param(vendorsupport, int, 0);
+MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
+
+/*
+ *	Vendor Specific Support
+ */
+
+/*
+ *	Vendor Support: 1
+ *	Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
+ *	iTCO chipset: ICH2
+ *
+ *	Code contributed by: R. Seretny <lkpatches@xxxxxxxxx>
+ *	Documentation obtained by R. Seretny from SuperMicro Technical Support
+ *
+ *	To enable Watchdog function:
+ *	    BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
+ *	    This setting enables SMI to clear the watchdog expired flag.
+ *	    If BIOS or CPU fail which may cause SMI hang, then system will
+ *	    reboot. When application starts to use watchdog function,
+ *	    application has to take over the control from SMI.
+ *
+ *	    For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
+ *	    function.
+ *
+ *	    Note: The system will reboot when Expire Flag is set TWICE.
+ *	    So, if the watchdog timer is 20 seconds, then the maximum hang
+ *	    time is about 40 seconds, and the minimum hang time is about
+ *	    20.6 seconds.
+ */
+
+static void supermicro_old_pre_start(unsigned long acpibase)
+{
+	unsigned long val32;
+
+	/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
+	val32 = inl(SMI_EN);
+	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
+	outl(val32, SMI_EN);	/* Needed to activate watchdog */
+}
+
+static void supermicro_old_pre_stop(unsigned long acpibase)
+{
+	unsigned long val32;
+
+	/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
+	val32 = inl(SMI_EN);
+	val32 |= 0x00002000;	/* Turn on SMI clearing watchdog */
+	outl(val32, SMI_EN);	/* Needed to deactivate watchdog */
+}
+
+static void supermicro_old_pre_keepalive(unsigned long acpibase)
+{
+	/* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
+	/* Clear "Expire Flag" (Bit 3 of TC01_STS register) */
+	outb(0x08, TCO1_STS);
+}
+
+/*
+ *	Vendor Support: 2
+ *	Board: Super Micro Computer Inc. P4SBx, P4DPx
+ *	iTCO chipset: ICH4
+ *
+ *	Code contributed by: R. Seretny <lkpatches@xxxxxxxxx>
+ *	Documentation obtained by R. Seretny from SuperMicro Technical Support
+ *
+ *	To enable Watchdog function:
+ *	 1. BIOS
+ *	  For P4SBx:
+ *	  BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
+ *	  For P4DPx:
+ *	  BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
+ *	 This setting enables or disables Watchdog function. When enabled, the
+ *	 default watchdog timer is set to be 5 minutes (about 4m35s). It is
+ *	 enough to load and run the OS. The application (service or driver) has
+ *	 to take over the control once OS is running up and before watchdog
+ *	 expires.
+ *
+ *	 2. JUMPER
+ *	  For P4SBx: JP39
+ *	  For P4DPx: JP37
+ *	  This jumper is used for safety.  Closed is enabled. This jumper
+ *	  prevents user enables watchdog in BIOS by accident.
+ *
+ *	 To enable Watch Dog function, both BIOS and JUMPER must be enabled.
+ *
+ *	The documentation lists motherboards P4SBx and P4DPx series as of
+ *	20-March-2002. However, this code works flawlessly with much newer
+ *	motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
+ *
+ *	The original iTCO driver as written does not actually reset the
+ *	watchdog timer on these machines, as a result they reboot after five
+ *	minutes.
+ *
+ *	NOTE: You may leave the Watchdog function disabled in the SuperMicro
+ *	BIOS to avoid a "boot-race"... This driver will enable watchdog
+ *	functionality even if it's disabled in the BIOS once the /dev/watchdog
+ *	file is opened.
+ */
+
+/* I/O Port's */
+#define SM_REGINDEX	0x2e	/* SuperMicro ICH4+ Register Index */
+#define SM_DATAIO	0x2f	/* SuperMicro ICH4+ Register Data I/O */
+
+/* Control Register's */
+#define SM_CTLPAGESW	0x07	/* SuperMicro ICH4+ Control Page Switch */
+#define SM_CTLPAGE	0x08	/* SuperMicro ICH4+ Control Page Num */
+
+#define SM_WATCHENABLE	0x30	/* Watchdog enable: Bit 0: 0=off, 1=on */
+
+#define SM_WATCHPAGE	0x87	/* Watchdog unlock control page */
+
+#define SM_ENDWATCH	0xAA	/* Watchdog lock control page */
+
+#define SM_COUNTMODE	0xf5	/* Watchdog count mode select */
+				/* (Bit 3: 0 = seconds, 1 = minutes */
+
+#define SM_WATCHTIMER	0xf6	/* 8-bits, Watchdog timer counter (RW) */
+
+#define SM_RESETCONTROL	0xf7	/* Watchdog reset control */
+				/* Bit 6: timer is reset by kbd interrupt */
+				/* Bit 7: timer is reset by mouse interrupt */
+
+static void supermicro_new_unlock_watchdog(void)
+{
+	/* Write 0x87 to port 0x2e twice */
+	outb(SM_WATCHPAGE, SM_REGINDEX);
+	outb(SM_WATCHPAGE, SM_REGINDEX);
+	/* Switch to watchdog control page */
+	outb(SM_CTLPAGESW, SM_REGINDEX);
+	outb(SM_CTLPAGE, SM_DATAIO);
+}
+
+static void supermicro_new_lock_watchdog(void)
+{
+	outb(SM_ENDWATCH, SM_REGINDEX);
+}
+
+static void supermicro_new_pre_start(unsigned int heartbeat)
+{
+	unsigned int val;
+
+	supermicro_new_unlock_watchdog();
+
+	/* Watchdog timer setting needs to be in seconds*/
+	outb(SM_COUNTMODE, SM_REGINDEX);
+	val = inb(SM_DATAIO);
+	val &= 0xF7;
+	outb(val, SM_DATAIO);
+
+	/* Write heartbeat interval to WDOG */
+	outb(SM_WATCHTIMER, SM_REGINDEX);
+	outb((heartbeat & 255), SM_DATAIO);
+
+	/* Make sure keyboard/mouse interrupts don't interfere */
+	outb(SM_RESETCONTROL, SM_REGINDEX);
+	val = inb(SM_DATAIO);
+	val &= 0x3f;
+	outb(val, SM_DATAIO);
+
+	/* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
+	outb(SM_WATCHENABLE, SM_REGINDEX);
+	val = inb(SM_DATAIO);
+	val |= 0x01;
+	outb(val, SM_DATAIO);
+
+	supermicro_new_lock_watchdog();
+}
+
+static void supermicro_new_pre_stop(void)
+{
+	unsigned int val;
+
+	supermicro_new_unlock_watchdog();
+
+	/* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
+	outb(SM_WATCHENABLE, SM_REGINDEX);
+	val = inb(SM_DATAIO);
+	val &= 0xFE;
+	outb(val, SM_DATAIO);
+
+	supermicro_new_lock_watchdog();
+}
+
+static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
+{
+	supermicro_new_unlock_watchdog();
+
+	/* reset watchdog timeout to heartveat value */
+	outb(SM_WATCHTIMER, SM_REGINDEX);
+	outb((heartbeat & 255), SM_DATAIO);
+
+	supermicro_new_lock_watchdog();
+}
+
+/*
+ *	Generic Support Functions
+ */
+
+void iTCO_vendor_pre_start(unsigned long acpibase,
+			   unsigned int heartbeat)
+{
+	if (vendorsupport == SUPERMICRO_OLD_BOARD)
+		supermicro_old_pre_start(acpibase);
+	else if (vendorsupport == SUPERMICRO_NEW_BOARD)
+		supermicro_new_pre_start(heartbeat);
+}
+EXPORT_SYMBOL(iTCO_vendor_pre_start);
+
+void iTCO_vendor_pre_stop(unsigned long acpibase)
+{
+	if (vendorsupport == SUPERMICRO_OLD_BOARD)
+		supermicro_old_pre_stop(acpibase);
+	else if (vendorsupport == SUPERMICRO_NEW_BOARD)
+		supermicro_new_pre_stop();
+}
+EXPORT_SYMBOL(iTCO_vendor_pre_stop);
+
+void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
+{
+	if (vendorsupport == SUPERMICRO_OLD_BOARD)
+		supermicro_old_pre_keepalive(acpibase);
+	else if (vendorsupport == SUPERMICRO_NEW_BOARD)
+		supermicro_new_pre_set_heartbeat(heartbeat);
+}
+EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
+
+void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
+{
+	if (vendorsupport == SUPERMICRO_NEW_BOARD)
+		supermicro_new_pre_set_heartbeat(heartbeat);
+}
+EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
+
+int iTCO_vendor_check_noreboot_on(void)
+{
+	switch (vendorsupport) {
+	case SUPERMICRO_OLD_BOARD:
+		return 0;
+	default:
+		return 1;
+	}
+}
+EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
+
+static int __init iTCO_vendor_init_module(void)
+{
+	printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
+	return 0;
+}
+
+static void __exit iTCO_vendor_exit_module(void)
+{
+	printk(KERN_INFO PFX "Module Unloaded\n");
+}
+
+module_init(iTCO_vendor_init_module);
+module_exit(iTCO_vendor_exit_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@xxxxxxxxx>, R. Seretny <lkpatches@xxxxxxxxx>");
+MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/iTCO_wdt.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/char/watchdog/iTCO_wdt.c	Mon Nov 23 23:37:39 2009 +0100
@@ -0,0 +1,857 @@
+/*
+ *	intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets)
+ *
+ *	(c) Copyright 2006-2009 Wim Van Sebroeck <wim@xxxxxxxxx>.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ *	provide warranty for any of this software. This material is
+ *	provided "AS-IS" and at no charge.
+ *
+ *	The TCO watchdog is implemented in the following I/O controller hubs:
+ *	(See the intel documentation on http://developer.intel.com.)
+ *	82801AA  (ICH)       : document number 290655-003, 290677-014,
+ *	82801AB  (ICHO)      : document number 290655-003, 290677-014,
+ *	82801BA  (ICH2)      : document number 290687-002, 298242-027,
+ *	82801BAM (ICH2-M)    : document number 290687-002, 298242-027,
+ *	82801CA  (ICH3-S)    : document number 290733-003, 290739-013,
+ *	82801CAM (ICH3-M)    : document number 290716-001, 290718-007,
+ *	82801DB  (ICH4)      : document number 290744-001, 290745-025,
+ *	82801DBM (ICH4-M)    : document number 252337-001, 252663-008,
+ *	82801E   (C-ICH)     : document number 273599-001, 273645-002,
+ *	82801EB  (ICH5)      : document number 252516-001, 252517-028,
+ *	82801ER  (ICH5R)     : document number 252516-001, 252517-028,
+ *	6300ESB  (6300ESB)   : document number 300641-004, 300884-013,
+ *	82801FB  (ICH6)      : document number 301473-002, 301474-026,
+ *	82801FR  (ICH6R)     : document number 301473-002, 301474-026,
+ *	82801FBM (ICH6-M)    : document number 301473-002, 301474-026,
+ *	82801FW  (ICH6W)     : document number 301473-001, 301474-026,
+ *	82801FRW (ICH6RW)    : document number 301473-001, 301474-026,
+ *	631xESB  (631xESB)   : document number 313082-001, 313075-006,
+ *	632xESB  (632xESB)   : document number 313082-001, 313075-006,
+ *	82801GB  (ICH7)      : document number 307013-003, 307014-024,
+ *	82801GR  (ICH7R)     : document number 307013-003, 307014-024,
+ *	82801GDH (ICH7DH)    : document number 307013-003, 307014-024,
+ *	82801GBM (ICH7-M)    : document number 307013-003, 307014-024,
+ *	82801GHM (ICH7-M DH) : document number 307013-003, 307014-024,
+ *	82801GU  (ICH7-U)    : document number 307013-003, 307014-024,
+ *	82801HB  (ICH8)      : document number 313056-003, 313057-017,
+ *	82801HR  (ICH8R)     : document number 313056-003, 313057-017,
+ *	82801HBM (ICH8M)     : document number 313056-003, 313057-017,
+ *	82801HH  (ICH8DH)    : document number 313056-003, 313057-017,
+ *	82801HO  (ICH8DO)    : document number 313056-003, 313057-017,
+ *	82801HEM (ICH8M-E)   : document number 313056-003, 313057-017,
+ *	82801IB  (ICH9)      : document number 316972-004, 316973-012,
+ *	82801IR  (ICH9R)     : document number 316972-004, 316973-012,
+ *	82801IH  (ICH9DH)    : document number 316972-004, 316973-012,
+ *	82801IO  (ICH9DO)    : document number 316972-004, 316973-012,
+ *	82801IBM (ICH9M)     : document number 316972-004, 316973-012,
+ *	82801IEM (ICH9M-E)   : document number 316972-004, 316973-012,
+ *	82801JIB (ICH10)     : document number 319973-002, 319974-002,
+ *	82801JIR (ICH10R)    : document number 319973-002, 319974-002,
+ *	82801JD  (ICH10D)    : document number 319973-002, 319974-002,
+ *	82801JDO (ICH10DO)   : document number 319973-002, 319974-002
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+/* Module and version information */
+#define DRV_NAME	"iTCO_wdt"
+#define DRV_VERSION	"1.05"
+#define PFX		DRV_NAME ": "
+
+/* Includes */
+#include <linux/module.h>		/* For module specific items */
+#include <linux/moduleparam.h>		/* For new moduleparam's */
+#include <linux/types.h>		/* For standard types (like size_t) */
+#include <linux/errno.h>		/* For the -ENODEV/... values */
+#include <linux/kernel.h>		/* For printk/panic/... */
+#include <linux/miscdevice.h>		/* For MODULE_ALIAS_MISCDEV
+							(WATCHDOG_MINOR) */
+#include <linux/watchdog.h>		/* For the watchdog specific items */
+#include <linux/init.h>			/* For __init/__exit/... */
+#include <linux/fs.h>			/* For file operations */
+#include <linux/platform_device.h>	/* For platform_driver framework */
+#include <linux/pci.h>			/* For pci functions */
+#include <linux/ioport.h>		/* For io-port access */
+#include <linux/spinlock.h>		/* For spin_lock/spin_unlock/... */
+#include <linux/uaccess.h>		/* For copy_to_user/put_user/... */
+#include <linux/io.h>			/* For inb/outb/... */
+
+#include "iTCO_vendor.h"
+
+/* TCO related info */
+enum iTCO_chipsets {
+	TCO_ICH = 0,	/* ICH */
+	TCO_ICH0,	/* ICH0 */
+	TCO_ICH2,	/* ICH2 */
+	TCO_ICH2M,	/* ICH2-M */
+	TCO_ICH3,	/* ICH3-S */
+	TCO_ICH3M,	/* ICH3-M */
+	TCO_ICH4,	/* ICH4 */
+	TCO_ICH4M,	/* ICH4-M */
+	TCO_CICH,	/* C-ICH */
+	TCO_ICH5,	/* ICH5 & ICH5R */
+	TCO_6300ESB,	/* 6300ESB */
+	TCO_ICH6,	/* ICH6 & ICH6R */
+	TCO_ICH6M,	/* ICH6-M */
+	TCO_ICH6W,	/* ICH6W & ICH6RW */
+	TCO_631XESB,	/* 631xESB/632xESB */
+	TCO_ICH7,	/* ICH7 & ICH7R */
+	TCO_ICH7DH,	/* ICH7DH */
+	TCO_ICH7M,	/* ICH7-M & ICH7-U */
+	TCO_ICH7MDH,	/* ICH7-M DH */
+	TCO_ICH8,	/* ICH8 & ICH8R */
+	TCO_ICH8DH,	/* ICH8DH */
+	TCO_ICH8DO,	/* ICH8DO */
+	TCO_ICH8M,	/* ICH8M */
+	TCO_ICH8ME,	/* ICH8M-E */
+	TCO_ICH9,	/* ICH9 */
+	TCO_ICH9R,	/* ICH9R */
+	TCO_ICH9DH,	/* ICH9DH */
+	TCO_ICH9DO,	/* ICH9DO */
+	TCO_ICH9M,	/* ICH9M */
+	TCO_ICH9ME,	/* ICH9M-E */
+	TCO_ICH10,	/* ICH10 */
+	TCO_ICH10R,	/* ICH10R */
+	TCO_ICH10D,	/* ICH10D */
+	TCO_ICH10DO,	/* ICH10DO */
+};
+
+static struct {
+	char *name;
+	unsigned int iTCO_version;
+} iTCO_chipset_info[] __devinitdata = {
+	{"ICH", 1},
+	{"ICH0", 1},
+	{"ICH2", 1},
+	{"ICH2-M", 1},
+	{"ICH3-S", 1},
+	{"ICH3-M", 1},
+	{"ICH4", 1},
+	{"ICH4-M", 1},
+	{"C-ICH", 1},
+	{"ICH5 or ICH5R", 1},
+	{"6300ESB", 1},
+	{"ICH6 or ICH6R", 2},
+	{"ICH6-M", 2},
+	{"ICH6W or ICH6RW", 2},
+	{"631xESB/632xESB", 2},
+	{"ICH7 or ICH7R", 2},
+	{"ICH7DH", 2},
+	{"ICH7-M or ICH7-U", 2},
+	{"ICH7-M DH", 2},
+	{"ICH8 or ICH8R", 2},
+	{"ICH8DH", 2},
+	{"ICH8DO", 2},
+	{"ICH8M", 2},
+	{"ICH8M-E", 2},
+	{"ICH9", 2},
+	{"ICH9R", 2},
+	{"ICH9DH", 2},
+	{"ICH9DO", 2},
+	{"ICH9M", 2},
+	{"ICH9M-E", 2},
+	{"ICH10", 2},
+	{"ICH10R", 2},
+	{"ICH10D", 2},
+	{"ICH10DO", 2},
+	{NULL, 0}
+};
+
+#define ITCO_PCI_DEVICE(dev, data) 	\
+	.vendor = PCI_VENDOR_ID_INTEL,	\
+	.device = dev,			\
+	.subvendor = PCI_ANY_ID,	\
+	.subdevice = PCI_ANY_ID,	\
+	.class = 0,			\
+	.class_mask = 0,		\
+	.driver_data = data
+
+/*
+ * This data only exists for exporting the supported PCI ids
+ * via MODULE_DEVICE_TABLE.  We do not actually register a
+ * pci_driver, because the I/O Controller Hub has also other
+ * functions that probably will be registered by other drivers.
+ */
+static struct pci_device_id iTCO_wdt_pci_tbl[] = {
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,	TCO_ICH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,	TCO_ICH0)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,	TCO_ICH2)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,	TCO_ICH2M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,	TCO_ICH3)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,	TCO_ICH3M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,	TCO_ICH4)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,	TCO_ICH4M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,		TCO_CICH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,	TCO_ICH5)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,		TCO_6300ESB)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,		TCO_ICH6)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,		TCO_ICH6M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,		TCO_ICH6W)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,		TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2671,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2672,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2673,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2674,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2675,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2676,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2677,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2678,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x2679,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267a,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267b,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267c,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267d,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267e,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(0x267f,				TCO_631XESB)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,		TCO_ICH7)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,		TCO_ICH7DH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,		TCO_ICH7M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,		TCO_ICH7MDH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,		TCO_ICH8)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,		TCO_ICH8DH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,		TCO_ICH8DO)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,		TCO_ICH8M)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,		TCO_ICH8ME)},
+	{ ITCO_PCI_DEVICE(0x2918,				TCO_ICH9)},
+	{ ITCO_PCI_DEVICE(0x2916,				TCO_ICH9R)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,		TCO_ICH9DH)},
+	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,		TCO_ICH9DO)},
+	{ ITCO_PCI_DEVICE(0x2919,				TCO_ICH9M)},
+	{ ITCO_PCI_DEVICE(0x2917,				TCO_ICH9ME)},
+	{ ITCO_PCI_DEVICE(0x3a18,				TCO_ICH10)},
+	{ ITCO_PCI_DEVICE(0x3a16,				TCO_ICH10R)},
+	{ ITCO_PCI_DEVICE(0x3a1a,				TCO_ICH10D)},
+	{ ITCO_PCI_DEVICE(0x3a14,				TCO_ICH10DO)},
+	{ 0, },			/* End of list */
+};
+MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
+
+/* Address definitions for the TCO */
+/* TCO base address */
+#define TCOBASE		iTCO_wdt_private.ACPIBASE + 0x60
+/* SMI Control and Enable Register */
+#define SMI_EN		iTCO_wdt_private.ACPIBASE + 0x30
+
+#define TCO_RLD		TCOBASE + 0x00	/* TCO Timer Reload and Curr. Value */
+#define TCOv1_TMR	TCOBASE + 0x01	/* TCOv1 Timer Initial Value	*/
+#define TCO_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
+#define TCO_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
+#define TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
+#define TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
+#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
+#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
+#define TCOv2_TMR	TCOBASE + 0x12	/* TCOv2 Timer Initial Value	*/
+
+/* internal variables */
+static unsigned long is_active;
+static char expect_release;
+static struct {		/* this is private data for the iTCO_wdt device */
+	/* TCO version/generation */
+	unsigned int iTCO_version;
+	/* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
+	unsigned long ACPIBASE;
+	/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
+	unsigned long __iomem *gcs;
+	/* the lock for io operations */
+	spinlock_t io_lock;
+	/* the PCI-device */
+	struct pci_dev *pdev;
+} iTCO_wdt_private;
+
+/* the watchdog platform device */
+static struct platform_device *iTCO_wdt_platform_device;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Some TCO specific functions
+ */
+
+static inline unsigned int seconds_to_ticks(int seconds)
+{
+	/* the internal timer is stored as ticks which decrement
+	 * every 0.6 seconds */
+	return (seconds * 10) / 6;
+}
+
+static void iTCO_wdt_set_NO_REBOOT_bit(void)
+{
+	u32 val32;
+
+	/* Set the NO_REBOOT bit: this disables reboots */
+	if (iTCO_wdt_private.iTCO_version == 2) {
+		val32 = readl(iTCO_wdt_private.gcs);
+		val32 |= 0x00000020;
+		writel(val32, iTCO_wdt_private.gcs);
+	} else if (iTCO_wdt_private.iTCO_version == 1) {
+		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+		val32 |= 0x00000002;
+		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+	}
+}
+
+static int iTCO_wdt_unset_NO_REBOOT_bit(void)
+{
+	int ret = 0;
+	u32 val32;
+
+	/* Unset the NO_REBOOT bit: this enables reboots */
+	if (iTCO_wdt_private.iTCO_version == 2) {
+		val32 = readl(iTCO_wdt_private.gcs);
+		val32 &= 0xffffffdf;
+		writel(val32, iTCO_wdt_private.gcs);
+
+		val32 = readl(iTCO_wdt_private.gcs);
+		if (val32 & 0x00000020)
+			ret = -EIO;
+	} else if (iTCO_wdt_private.iTCO_version == 1) {
+		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+		val32 &= 0xfffffffd;
+		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+
+		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+		if (val32 & 0x00000002)
+			ret = -EIO;
+	}
+
+	return ret; /* returns: 0 = OK, -EIO = Error */
+}
+
+static int iTCO_wdt_start(void)
+{
+	unsigned int val;
+
+	spin_lock(&iTCO_wdt_private.io_lock);
+
+	iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
+
+	/* disable chipset's NO_REBOOT bit */
+	if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+		spin_unlock(&iTCO_wdt_private.io_lock);
+		printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+		return -EIO;
+	}
+
+	/* Force the timer to its reload value by writing to the TCO_RLD
+	   register */
+	if (iTCO_wdt_private.iTCO_version == 2)
+		outw(0x01, TCO_RLD);
+	else if (iTCO_wdt_private.iTCO_version == 1)
+		outb(0x01, TCO_RLD);
+
+	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
+	val = inw(TCO1_CNT);
+	val &= 0xf7ff;
+	outw(val, TCO1_CNT);
+	val = inw(TCO1_CNT);
+	spin_unlock(&iTCO_wdt_private.io_lock);
+
+	if (val & 0x0800)
+		return -1;
+	return 0;
+}
+
+static int iTCO_wdt_stop(void)
+{
+	unsigned int val;
+
+	spin_lock(&iTCO_wdt_private.io_lock);
+
+	iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
+
+	/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
+	val = inw(TCO1_CNT);
+	val |= 0x0800;
+	outw(val, TCO1_CNT);
+	val = inw(TCO1_CNT);
+
+	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+	iTCO_wdt_set_NO_REBOOT_bit();
+
+	spin_unlock(&iTCO_wdt_private.io_lock);
+
+	if ((val & 0x0800) == 0)
+		return -1;
+	return 0;
+}
+
+static int iTCO_wdt_keepalive(void)
+{
+	spin_lock(&iTCO_wdt_private.io_lock);
+
+	iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
+
+	/* Reload the timer by writing to the TCO Timer Counter register */
+	if (iTCO_wdt_private.iTCO_version == 2)
+		outw(0x01, TCO_RLD);
+	else if (iTCO_wdt_private.iTCO_version == 1)
+		outb(0x01, TCO_RLD);
+
+	spin_unlock(&iTCO_wdt_private.io_lock);
+	return 0;
+}
+
+static int iTCO_wdt_set_heartbeat(int t)
+{
+	unsigned int val16;
+	unsigned char val8;
+	unsigned int tmrval;
+
+	tmrval = seconds_to_ticks(t);
+	/* from the specs: */
+	/* "Values of 0h-3h are ignored and should not be attempted" */
+	if (tmrval < 0x04)
+		return -EINVAL;
+	if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
+	    ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
+		return -EINVAL;
+
+	iTCO_vendor_pre_set_heartbeat(tmrval);
+
+	/* Write new heartbeat to watchdog */
+	if (iTCO_wdt_private.iTCO_version == 2) {
+		spin_lock(&iTCO_wdt_private.io_lock);
+		val16 = inw(TCOv2_TMR);
+		val16 &= 0xfc00;
+		val16 |= tmrval;
+		outw(val16, TCOv2_TMR);
+		val16 = inw(TCOv2_TMR);
+		spin_unlock(&iTCO_wdt_private.io_lock);
+
+		if ((val16 & 0x3ff) != tmrval)
+			return -EINVAL;
+	} else if (iTCO_wdt_private.iTCO_version == 1) {
+		spin_lock(&iTCO_wdt_private.io_lock);
+		val8 = inb(TCOv1_TMR);
+		val8 &= 0xc0;
+		val8 |= (tmrval & 0xff);
+		outb(val8, TCOv1_TMR);
+		val8 = inb(TCOv1_TMR);
+		spin_unlock(&iTCO_wdt_private.io_lock);
+
+		if ((val8 & 0x3f) != tmrval)
+			return -EINVAL;
+	}
+
+	heartbeat = t;
+	return 0;
+}
+
+static int iTCO_wdt_get_timeleft(int *time_left)
+{
+	unsigned int val16;
+	unsigned char val8;
+
+	/* read the TCO Timer */
+	if (iTCO_wdt_private.iTCO_version == 2) {
+		spin_lock(&iTCO_wdt_private.io_lock);
+		val16 = inw(TCO_RLD);
+		val16 &= 0x3ff;
+		spin_unlock(&iTCO_wdt_private.io_lock);
+
+		*time_left = (val16 * 6) / 10;
+	} else if (iTCO_wdt_private.iTCO_version == 1) {
+		spin_lock(&iTCO_wdt_private.io_lock);
+		val8 = inb(TCO_RLD);
+		val8 &= 0x3f;
+		spin_unlock(&iTCO_wdt_private.io_lock);
+
+		*time_left = (val8 * 6) / 10;
+	} else
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int iTCO_wdt_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &is_active))
+		return -EBUSY;
+
+	/*
+	 *      Reload and activate timer
+	 */
+	iTCO_wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+static int iTCO_wdt_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (expect_release == 42) {
+		iTCO_wdt_stop();
+	} else {
+		printk(KERN_CRIT PFX
+			"Unexpected close, not stopping watchdog!\n");
+		iTCO_wdt_keepalive();
+	}
+	clear_bit(0, &is_active);
+	expect_release = 0;
+	return 0;
+}
+
+static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
+			      size_t len, loff_t *ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic
+			   character five months ago... */
+			expect_release = 0;
+
+			/* scan to see whether or not we got the
+			   magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_release = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		iTCO_wdt_keepalive();
+	}
+	return len;
+}
+
+static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
+							unsigned long arg)
+{
+	int new_options, retval = -EINVAL;
+	int new_heartbeat;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		DRV_NAME,
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+		if (get_user(new_options, p))
+			return -EFAULT;
+
+		if (new_options & WDIOS_DISABLECARD) {
+			iTCO_wdt_stop();
+			retval = 0;
+		}
+		if (new_options & WDIOS_ENABLECARD) {
+			iTCO_wdt_keepalive();
+			iTCO_wdt_start();
+			retval = 0;
+		}
+		return retval;
+	}
+	case WDIOC_KEEPALIVE:
+		iTCO_wdt_keepalive();
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+	{
+		if (get_user(new_heartbeat, p))
+			return -EFAULT;
+		if (iTCO_wdt_set_heartbeat(new_heartbeat))
+			return -EINVAL;
+		iTCO_wdt_keepalive();
+		/* Fall */
+	}
+	case WDIOC_GETTIMEOUT:
+		return put_user(heartbeat, p);
+	case WDIOC_GETTIMELEFT:
+	{
+		int time_left;
+		if (iTCO_wdt_get_timeleft(&time_left))
+			return -EINVAL;
+		return put_user(time_left, p);
+	}
+	default:
+		return -ENOTTY;
+	}
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static const struct file_operations iTCO_wdt_fops = {
+	.owner =		THIS_MODULE,
+	.llseek =		no_llseek,
+	.write =		iTCO_wdt_write,
+	.unlocked_ioctl =	iTCO_wdt_ioctl,
+	.open =			iTCO_wdt_open,
+	.release =		iTCO_wdt_release,
+};
+
+static struct miscdevice iTCO_wdt_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&iTCO_wdt_fops,
+};
+
+/*
+ *	Init & exit routines
+ */
+
+static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
+		const struct pci_device_id *ent, struct platform_device *dev)
+{
+	int ret;
+	u32 base_address;
+	unsigned long RCBA;
+	unsigned long val32;
+
+	/*
+	 *      Find the ACPI/PM base I/O address which is the base
+	 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
+	 *      ACPIBASE is bits [15:7] from 0x40-0x43
+	 */
+	pci_read_config_dword(pdev, 0x40, &base_address);
+	base_address &= 0x0000ff80;
+	if (base_address == 0x00000000) {
+		/* Something's wrong here, ACPIBASE has to be set */
+		printk(KERN_ERR PFX "failed to get TCOBASE address\n");
+		pci_dev_put(pdev);
+		return -ENODEV;
+	}
+	iTCO_wdt_private.iTCO_version =
+			iTCO_chipset_info[ent->driver_data].iTCO_version;
+	iTCO_wdt_private.ACPIBASE = base_address;
+	iTCO_wdt_private.pdev = pdev;
+
+	/* Get the Memory-Mapped GCS register, we need it for the
+	   NO_REBOOT flag (TCO v2). To get access to it you have to
+	   read RCBA from PCI Config space 0xf0 and use it as base.
+	   GCS = RCBA + ICH6_GCS(0x3410). */
+	if (iTCO_wdt_private.iTCO_version == 2) {
+		pci_read_config_dword(pdev, 0xf0, &base_address);
+		RCBA = base_address & 0xffffc000;
+		iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
+	}
+
+	/* Check chipset's NO_REBOOT bit */
+	if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
+		printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+		ret = -ENODEV;	/* Cannot reset NO_REBOOT bit */
+		goto out;
+	}
+
+	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+	iTCO_wdt_set_NO_REBOOT_bit();
+
+	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
+	if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
+		printk(KERN_ERR PFX
+			"I/O address 0x%04lx already in use\n", SMI_EN);
+		ret = -EIO;
+		goto out;
+	}
+	/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
+	val32 = inl(SMI_EN);
+	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
+	outl(val32, SMI_EN);
+
+	/* The TCO I/O registers reside in a 32-byte range pointed to
+	   by the TCOBASE value */
+	if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
+		printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
+			TCOBASE);
+		ret = -EIO;
+		goto unreg_smi_en;
+	}
+
+	printk(KERN_INFO PFX
+		"Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+			iTCO_chipset_info[ent->driver_data].name,
+			iTCO_chipset_info[ent->driver_data].iTCO_version,
+			TCOBASE);
+
+	/* Clear out the (probably old) status */
+	outb(8, TCO1_STS);	/* Clear the Time Out Status bit */
+	outb(2, TCO2_STS);	/* Clear SECOND_TO_STS bit */
+	outb(4, TCO2_STS);	/* Clear BOOT_STS bit */
+
+	/* Make sure the watchdog is not running */
+	iTCO_wdt_stop();
+
+	/* Check that the heartbeat value is within it's range;
+	   if not reset to the default */
+	if (iTCO_wdt_set_heartbeat(heartbeat)) {
+		iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
+		printk(KERN_INFO PFX "heartbeat value must be 2 < heartbeat < 39 (TCO v1) or 613 (TCO v2), using %d\n",
+							heartbeat);
+	}
+
+	ret = misc_register(&iTCO_wdt_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX
+			"cannot register miscdev on minor=%d (err=%d)\n",
+							WATCHDOG_MINOR, ret);
+		goto unreg_region;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+							heartbeat, nowayout);
+
+	return 0;
+
+unreg_region:
+	release_region(TCOBASE, 0x20);
+unreg_smi_en:
+	release_region(SMI_EN, 4);
+out:
+	if (iTCO_wdt_private.iTCO_version == 2)
+		iounmap(iTCO_wdt_private.gcs);
+	pci_dev_put(iTCO_wdt_private.pdev);
+	iTCO_wdt_private.ACPIBASE = 0;
+	return ret;
+}
+
+static void __devexit iTCO_wdt_cleanup(void)
+{
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		iTCO_wdt_stop();
+
+	/* Deregister */
+	misc_deregister(&iTCO_wdt_miscdev);
+	release_region(TCOBASE, 0x20);
+	release_region(SMI_EN, 4);
+	if (iTCO_wdt_private.iTCO_version == 2)
+		iounmap(iTCO_wdt_private.gcs);
+	pci_dev_put(iTCO_wdt_private.pdev);
+	iTCO_wdt_private.ACPIBASE = 0;
+}
+
+static int __devinit iTCO_wdt_probe(struct platform_device *dev)
+{
+	int found = 0;
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *ent;
+
+	spin_lock_init(&iTCO_wdt_private.io_lock);
+
+	for_each_pci_dev(pdev) {
+		ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
+		if (ent) {
+			if (!(iTCO_wdt_init(pdev, ent, dev))) {
+				found++;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		printk(KERN_INFO PFX "No card detected\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int __devexit iTCO_wdt_remove(struct platform_device *dev)
+{
+	if (iTCO_wdt_private.ACPIBASE)
+		iTCO_wdt_cleanup();
+
+	return 0;
+}
+
+static void iTCO_wdt_shutdown(struct platform_device *dev)
+{
+	iTCO_wdt_stop();
+}
+
+#define iTCO_wdt_suspend NULL
+#define iTCO_wdt_resume  NULL
+
+static struct platform_driver iTCO_wdt_driver = {
+	.probe          = iTCO_wdt_probe,
+	.remove         = __devexit_p(iTCO_wdt_remove),
+	.shutdown       = iTCO_wdt_shutdown,
+	.suspend        = iTCO_wdt_suspend,
+	.resume         = iTCO_wdt_resume,
+	.driver         = {
+		.owner  = THIS_MODULE,
+		.name   = DRV_NAME,
+	},
+};
+
+static int __init iTCO_wdt_init_module(void)
+{
+	int err;
+
+	printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
+		DRV_VERSION);
+
+	err = platform_driver_register(&iTCO_wdt_driver);
+	if (err)
+		return err;
+
+	iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
+								-1, NULL, 0);
+	if (IS_ERR(iTCO_wdt_platform_device)) {
+		err = PTR_ERR(iTCO_wdt_platform_device);
+		goto unreg_platform_driver;
+	}
+
+	return 0;
+
+unreg_platform_driver:
+	platform_driver_unregister(&iTCO_wdt_driver);
+	return err;
+}
+
+static void __exit iTCO_wdt_cleanup_module(void)
+{
+	platform_device_unregister(iTCO_wdt_platform_device);
+	platform_driver_unregister(&iTCO_wdt_driver);
+	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+}
+
+module_init(iTCO_wdt_init_module);
+module_exit(iTCO_wdt_cleanup_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@xxxxxxxxx>");
+MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/i8xx_tco.c
--- a/drivers/char/watchdog/i8xx_tco.c	Mon Nov 23 07:32:47 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,566 +0,0 @@
-/*
- *	i8xx_tco:	TCO timer driver for i8xx chipsets
- *
- *	(c) Copyright 2000 kernel concepts <nils@xxxxxxxxxxxxxxxxx>, All Rights Reserved.
- *				http://www.kernelconcepts.de
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- *
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide
- *	warranty for any of this software. This material is provided
- *	"AS-IS" and at no charge.
- *
- *	(c) Copyright 2000	kernel concepts <nils@xxxxxxxxxxxxxxxxx>
- *				developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *	TCO timer driver for i8xx chipsets
- *	based on softdog.c by Alan Cox <alan@xxxxxxxxxx>
- *
- *	The TCO timer is implemented in the following I/O controller hubs:
- *	(See the intel documentation on http://developer.intel.com.)
- *	82801AA  (ICH)    : document number 290655-003, 290677-014,
- *	82801AB  (ICHO)   : document number 290655-003, 290677-014,
- *	82801BA  (ICH2)   : document number 290687-002, 298242-027,
- *	82801BAM (ICH2-M) : document number 290687-002, 298242-027,
- *	82801CA  (ICH3-S) : document number 290733-003, 290739-013,
- *	82801CAM (ICH3-M) : document number 290716-001, 290718-007,
- *	82801DB  (ICH4)   : document number 290744-001, 290745-020,
- *	82801DBM (ICH4-M) : document number 252337-001, 252663-005,
- *	82801E   (C-ICH)  : document number 273599-001, 273645-002,
- *	82801EB  (ICH5)   : document number 252516-001, 252517-003,
- *	82801ER  (ICH5R)  : document number 252516-001, 252517-003,
- *
- *  20000710 Nils Faerber
- *	Initial Version 0.01
- *  20000728 Nils Faerber
- *	0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
- *  20011214 Matt Domsch <Matt_Domsch@xxxxxxxx>
- *	0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- *	     Didn't add timeout option as i810_margin already exists.
- *  20020224 Joel Becker, Wim Van Sebroeck
- *	0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
- *	     add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
- *  20020412 Rob Radez <rob@xxxxxxxxxxxxxx>, Wim Van Sebroeck
- *	0.05 Fix possible timer_alive race, add expect close support,
- *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
- *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
- *	     removed boot_status, removed tco_timer_read,
- *	     added support for 82801DB and 82801E chipset,
- *	     added support for 82801EB and 8280ER chipset,
- *	     general cleanup.
- *  20030921 Wim Van Sebroeck <wim@xxxxxxxxx>
- *	0.06 change i810_margin to heartbeat, use module_param,
- *	     added notify system support, renamed module to i8xx_tco.
- *  20050128 Wim Van Sebroeck <wim@xxxxxxxxx>
- *	0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW
- *	     chipsets. Also added support for the "undocumented" ICH7 chipset.
- *  20050807 Wim Van Sebroeck <wim@xxxxxxxxx>
- *	0.08 Make sure that the watchdog is only "armed" when started.
- *	     (Kernel Bug 4251)
- *  20060416 Wim Van Sebroeck <wim@xxxxxxxxx>
- *	0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and
- *	     ICH7 chipsets. (See Kernel Bug 6031 - other code will support these
- *	     chipsets)
- */
-
-/*
- *	Includes, defines, variables, module parameters, ...
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "i8xx_tco.h"
-
-/* Module and version information */
-#define TCO_VERSION "0.09"
-#define TCO_MODULE_NAME "i8xx TCO timer"
-#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
-
-/* internal variables */
-static unsigned int ACPIBASE;
-static spinlock_t tco_lock;	/* Guards the hardware */
-static unsigned long timer_alive;
-static char tco_expect_close;
-static struct pci_dev *i8xx_tco_pci;
-
-/* module parameters */
-#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat (2<heartbeat<39) */
-static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
-
-/*
- * Some TCO specific functions
- */
-
-static inline unsigned char seconds_to_ticks(int seconds)
-{
-	/* the internal timer is stored as ticks which decrement
-	 * every 0.6 seconds */
-	return (seconds * 10) / 6;
-}
-
-static int tco_timer_start (void)
-{
-	unsigned char val;
-
-	spin_lock(&tco_lock);
-
-	/* disable chipset's NO_REBOOT bit */
-	pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
-	val &= 0xfd;
-	pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
-
-	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
-	val = inb (TCO1_CNT + 1);
-	val &= 0xf7;
-	outb (val, TCO1_CNT + 1);
-	val = inb (TCO1_CNT + 1);
-
-	spin_unlock(&tco_lock);
-
-	if (val & 0x08)
-		return -1;
-	return 0;
-}
-
-static int tco_timer_stop (void)
-{
-	unsigned char val, val1;
-
-	spin_lock(&tco_lock);
-	/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
-	val = inb (TCO1_CNT + 1);
-	val |= 0x08;
-	outb (val, TCO1_CNT + 1);
-	val = inb (TCO1_CNT + 1);
-
-	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-	pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-	val1 |= 0x02;
-	pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
-	spin_unlock(&tco_lock);
-
-	if ((val & 0x08) == 0)
-		return -1;
-	return 0;
-}
-
-static int tco_timer_keepalive (void)
-{
-	spin_lock(&tco_lock);
-	/* Reload the timer by writing to the TCO Timer Reload register */
-	outb (0x01, TCO1_RLD);
-	spin_unlock(&tco_lock);
-	return 0;
-}
-
-static int tco_timer_set_heartbeat (int t)
-{
-	unsigned char val;
-	unsigned char tmrval;
-
-	tmrval = seconds_to_ticks(t);
-	/* from the specs: */
-	/* "Values of 0h-3h are ignored and should not be attempted" */
-	if (tmrval > 0x3f || tmrval < 0x04)
-		return -EINVAL;
-
-	/* Write new heartbeat to watchdog */
-	spin_lock(&tco_lock);
-	val = inb (TCO1_TMR);
-	val &= 0xc0;
-	val |= tmrval;
-	outb (val, TCO1_TMR);
-	val = inb (TCO1_TMR);
-	spin_unlock(&tco_lock);
-
-	if ((val & 0x3f) != tmrval)
-		return -EINVAL;
-
-	heartbeat = t;
-	return 0;
-}
-
-static int tco_timer_get_timeleft (int *time_left)
-{
-	unsigned char val;
-
-	spin_lock(&tco_lock);
-
-	/* read the TCO Timer */
-	val = inb (TCO1_RLD);
-	val &= 0x3f;
-
-	spin_unlock(&tco_lock);
-
-	*time_left = (int)((val * 6) / 10);
-
-	return 0;
-}
-
-/*
- *	/dev/watchdog handling
- */
-
-static int i8xx_tco_open (struct inode *inode, struct file *file)
-{
-	/* /dev/watchdog can only be opened once */
-	if (test_and_set_bit(0, &timer_alive))
-		return -EBUSY;
-
-	/*
-	 *      Reload and activate timer
-	 */
-	tco_timer_keepalive ();
-	tco_timer_start ();
-	return nonseekable_open(inode, file);
-}
-
-static int i8xx_tco_release (struct inode *inode, struct file *file)
-{
-	/*
-	 *      Shut off the timer.
-	 */
-	if (tco_expect_close == 42) {
-		tco_timer_stop ();
-	} else {
-		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
-		tco_timer_keepalive ();
-	}
-	clear_bit(0, &timer_alive);
-	tco_expect_close = 0;
-	return 0;
-}
-
-static ssize_t i8xx_tco_write (struct file *file, const char __user *data,
-			      size_t len, loff_t * ppos)
-{
-	/* See if we got the magic character 'V' and reload the timer */
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			/* note: just in case someone wrote the magic character
-			 * five months ago... */
-			tco_expect_close = 0;
-
-			/* scan to see whether or not we got the magic character */
-			for (i = 0; i != len; i++) {
-				char c;
-				if(get_user(c, data+i))
-					return -EFAULT;
-				if (c == 'V')
-					tco_expect_close = 42;
-			}
-		}
-
-		/* someone wrote to us, we should reload the timer */
-		tco_timer_keepalive ();
-	}
-	return len;
-}
-
-static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg)
-{
-	int new_options, retval = -EINVAL;
-	int new_heartbeat;
-	int time_left;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	static struct watchdog_info ident = {
-		.options =		WDIOF_SETTIMEOUT |
-					WDIOF_KEEPALIVEPING |
-					WDIOF_MAGICCLOSE,
-		.firmware_version =	0,
-		.identity =		TCO_MODULE_NAME,
-	};
-
-	switch (cmd) {
-		case WDIOC_GETSUPPORT:
-			return copy_to_user(argp, &ident,
-				sizeof (ident)) ? -EFAULT : 0;
-
-		case WDIOC_GETSTATUS:
-		case WDIOC_GETBOOTSTATUS:
-			return put_user (0, p);
-
-		case WDIOC_KEEPALIVE:
-			tco_timer_keepalive ();
-			return 0;
-
-		case WDIOC_SETOPTIONS:
-		{
-			if (get_user (new_options, p))
-				return -EFAULT;
-
-			if (new_options & WDIOS_DISABLECARD) {
-				tco_timer_stop ();
-				retval = 0;
-			}
-
-			if (new_options & WDIOS_ENABLECARD) {
-				tco_timer_keepalive ();
-				tco_timer_start ();
-				retval = 0;
-			}
-
-			return retval;
-		}
-
-		case WDIOC_SETTIMEOUT:
-		{
-			if (get_user(new_heartbeat, p))
-				return -EFAULT;
-
-			if (tco_timer_set_heartbeat(new_heartbeat))
-				return -EINVAL;
-
-			tco_timer_keepalive ();
-			/* Fall */
-		}
-
-		case WDIOC_GETTIMEOUT:
-			return put_user(heartbeat, p);
-
-		case WDIOC_GETTIMELEFT:
-		{
-			if (tco_timer_get_timeleft(&time_left))
-				return -EINVAL;
-
-			return put_user(time_left, p);
-		}
-
-		default:
-			return -ENOIOCTLCMD;
-	}
-}
-
-/*
- *	Notify system
- */
-
-static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
-{
-	if (code==SYS_DOWN || code==SYS_HALT) {
-		/* Turn the WDT off */
-		tco_timer_stop ();
-	}
-
-	return NOTIFY_DONE;
-}
-
-/*
- *	Kernel Interfaces
- */
-
-static const struct file_operations i8xx_tco_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.write =	i8xx_tco_write,
-	.ioctl =	i8xx_tco_ioctl,
-	.open =		i8xx_tco_open,
-	.release =	i8xx_tco_release,
-};
-
-static struct miscdevice i8xx_tco_miscdev = {
-	.minor =	WATCHDOG_MINOR,
-	.name =		"watchdog",
-	.fops =		&i8xx_tco_fops,
-};
-
-static struct notifier_block i8xx_tco_notifier = {
-	.notifier_call =	i8xx_tco_notify_sys,
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id i8xx_tco_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, },			/* End of list */
-};
-MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
-
-/*
- *	Init & exit routines
- */
-
-static unsigned char __init i8xx_tco_getdevice (void)
-{
-	struct pci_dev *dev = NULL;
-	u8 val1, val2;
-	u16 badr;
-	/*
-	 *      Find the PCI device
-	 */
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
-			i8xx_tco_pci = dev;
-			break;
-		}
-	}
-
-	if (i8xx_tco_pci) {
-		/*
-		 *      Find the ACPI base I/O address which is the base
-		 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
-		 *      ACPIBASE is bits [15:7] from 0x40-0x43
-		 */
-		pci_read_config_byte (i8xx_tco_pci, 0x40, &val1);
-		pci_read_config_byte (i8xx_tco_pci, 0x41, &val2);
-		badr = ((val2 << 1) | (val1 >> 7)) << 7;
-		ACPIBASE = badr;
-		/* Something's wrong here, ACPIBASE has to be set */
-		if (badr == 0x0001 || badr == 0x0000) {
-			printk (KERN_ERR PFX "failed to get TCOBASE address\n");
-			return 0;
-		}
-
-		/* Check chipset's NO_REBOOT bit */
-		pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-		if (val1 & 0x02) {
-			val1 &= 0xfd;
-			pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-			pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-			if (val1 & 0x02) {
-				printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
-				return 0;	/* Cannot reset NO_REBOOT bit */
-			}
-		}
-		/* Disable reboots untill the watchdog starts */
-		val1 |= 0x02;
-		pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
-		/* Set the TCO_EN bit in SMI_EN register */
-		if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
-			printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
-				SMI_EN + 1);
-			return 0;
-		}
-		val1 = inb (SMI_EN + 1);
-		val1 &= 0xdf;
-		outb (val1, SMI_EN + 1);
-		release_region (SMI_EN + 1, 1);
-		return 1;
-	}
-	return 0;
-}
-
-static int __init watchdog_init (void)
-{
-	int ret;
-
-	spin_lock_init(&tco_lock);
-
-	/* Check whether or not the hardware watchdog is there */
-	if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
-		return -ENODEV;
-
-	if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
-		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
-			TCOBASE);
-		ret = -EIO;
-		goto out;
-	}
-
-	/* Clear out the (probably old) status */
-	outb (0, TCO1_STS);
-	outb (3, TCO2_STS);
-
-	/* Check that the heartbeat value is within it's range ; if not reset to the default */
-	if (tco_timer_set_heartbeat (heartbeat)) {
-		heartbeat = WATCHDOG_HEARTBEAT;
-		tco_timer_set_heartbeat (heartbeat);
-		printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
-			heartbeat);
-	}
-
-	ret = register_reboot_notifier(&i8xx_tco_notifier);
-	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			ret);
-		goto unreg_region;
-	}
-
-	ret = misc_register(&i8xx_tco_miscdev);
-	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
-		goto unreg_notifier;
-	}
-
-	tco_timer_stop ();
-
-	printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
-		TCOBASE, heartbeat, nowayout);
-
-	return 0;
-
-unreg_notifier:
-	unregister_reboot_notifier(&i8xx_tco_notifier);
-unreg_region:
-	release_region (TCOBASE, 0x10);
-out:
-	return ret;
-}
-
-static void __exit watchdog_cleanup (void)
-{
-	/* Stop the timer before we leave */
-	if (!nowayout)
-		tco_timer_stop ();
-
-	/* Deregister */
-	misc_deregister (&i8xx_tco_miscdev);
-	unregister_reboot_notifier(&i8xx_tco_notifier);
-	release_region (TCOBASE, 0x10);
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
-
-MODULE_AUTHOR("Nils Faerber");
-MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -r 1db1bb63824b -r 0ee2f293ec4c drivers/char/watchdog/i8xx_tco.h
--- a/drivers/char/watchdog/i8xx_tco.h	Mon Nov 23 07:32:47 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- *	i8xx_tco:	TCO timer driver for i8xx chipsets
- *
- *	(c) Copyright 2000 kernel concepts <nils@xxxxxxxxxxxxxxxxx>, All Rights Reserved.
- *				http://www.kernelconcepts.de
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- *
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide
- *	warranty for any of this software. This material is provided
- *	"AS-IS" and at no charge.
- *
- *	(c) Copyright 2000	kernel concepts <nils@xxxxxxxxxxxxxxxxx>
- *				developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *	TCO timer driver for i8xx chipsets
- *	based on softdog.c by Alan Cox <alan@xxxxxxxxxx>
- *
- *	For history and the complete list of supported I/O Controller Hub's
- *	see i8xx_tco.c
- */
-
-
-/*
- * Some address definitions for the TCO
- */
-
-#define	TCOBASE		ACPIBASE + 0x60	/* TCO base address		*/
-#define TCO1_RLD	TCOBASE + 0x00	/* TCO Timer Reload and Current Value */
-#define TCO1_TMR	TCOBASE + 0x01	/* TCO Timer Initial Value	*/
-#define	TCO1_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
-#define	TCO1_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
-#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
-#define	TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
-#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
-#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
-
-#define	SMI_EN		ACPIBASE + 0x30	/* SMI Control and Enable Register */