[kernel] r16673 - in dists/sid/linux-2.6/debian: . config/kernelarch-x86 patches/bugfix/all patches/features/all patches/series

Ben Hutchings benh at alioth.debian.org
Mon Dec 6 04:17:07 UTC 2010


Author: benh
Date: Mon Dec  6 04:16:52 2010
New Revision: 16673

Log:
[x86] Add support for Fintek hardware watchdogs (Closes: #601187)

Added:
   dists/sid/linux-2.6/debian/patches/bugfix/all/hwmon-f71882fg-Acquire-I-O-regions-while-we-re-worki.patch
   dists/sid/linux-2.6/debian/patches/features/all/f71882fg-use-a-muxed-resource-lock-for-the-Sup.patch
   dists/sid/linux-2.6/debian/patches/features/all/resource-shared-I-O-region-support.patch
   dists/sid/linux-2.6/debian/patches/features/all/watchdog-f71808e_wdt-driver-for-Fintek-F718108E-F71882FG.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/config/kernelarch-x86/config
   dists/sid/linux-2.6/debian/patches/series/29

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Mon Dec  6 03:28:39 2010	(r16672)
+++ dists/sid/linux-2.6/debian/changelog	Mon Dec  6 04:16:52 2010	(r16673)
@@ -15,6 +15,10 @@
     (Closes: #600694)
   * perf: Use libiberty, not libbfd, for symbol demangling
     (Closes: #590226, #606050)
+  * [x86] Add support for Fintek hardware watchdogs (Closes: #601187)
+    - resource: Add shared I/O region support
+    - hwmon: f71882fg: Use a muxed resource lock for the Super I/O port
+    - watchdog: Add f71808e_wdt driver
 
   [ dann frazier ]
   * net: clear heap allocation for ETHTOOL_GRXCLSRLALL (CVE-2010-3861)

Modified: dists/sid/linux-2.6/debian/config/kernelarch-x86/config
==============================================================================
--- dists/sid/linux-2.6/debian/config/kernelarch-x86/config	Mon Dec  6 03:28:39 2010	(r16672)
+++ dists/sid/linux-2.6/debian/config/kernelarch-x86/config	Mon Dec  6 04:16:52 2010	(r16673)
@@ -1299,6 +1299,7 @@
 CONFIG_ADVANTECH_WDT=m
 CONFIG_ALIM1535_WDT=m
 CONFIG_ALIM7101_WDT=m
+CONFIG_F71808E_WDT=m
 CONFIG_SC520_WDT=m
 CONFIG_EUROTECH_WDT=m
 CONFIG_IB700_WDT=m

Added: dists/sid/linux-2.6/debian/patches/bugfix/all/hwmon-f71882fg-Acquire-I-O-regions-while-we-re-worki.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/hwmon-f71882fg-Acquire-I-O-regions-while-we-re-worki.patch	Mon Dec  6 04:16:52 2010	(r16673)
@@ -0,0 +1,44 @@
+From: Giel van Schijndel <me at mortis.eu>
+Date: Thu, 27 May 2010 19:58:43 +0200
+Subject: [PATCH] hwmon: (f71882fg) Acquire I/O regions while we're working with them
+
+commit 729d273aa7c86eb1406ade4eadf249cff188bf9a upstream.
+
+Acquire the I/O region for the Super I/O chip while we're working on it.
+
+Signed-off-by: Giel van Schijndel <me at mortis.eu>
+Cc: Hans de Goede <hdegoede at redhat.com>
+Signed-off-by: Jean Delvare <khali at linux-fr.org>
+---
+ drivers/hwmon/f71882fg.c |    8 ++++++++
+ 1 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
+index ca34e5c..537841e 100644
+--- a/drivers/hwmon/f71882fg.c
++++ b/drivers/hwmon/f71882fg.c
+@@ -2178,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 	int err = -ENODEV;
+ 	u16 devid;
+ 
++	/* Don't step on other drivers' I/O space by accident */
++	if (!request_region(sioaddr, 2, DRVNAME)) {
++		printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
++				(int)sioaddr);
++		return -EBUSY;
++	}
++
+ 	superio_enter(sioaddr);
+ 
+ 	devid = superio_inw(sioaddr, SIO_REG_MANID);
+@@ -2232,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
+ exit:
+ 	superio_exit(sioaddr);
++	release_region(sioaddr, 2);
+ 	return err;
+ }
+ 
+-- 
+1.7.2.3
+

Added: dists/sid/linux-2.6/debian/patches/features/all/f71882fg-use-a-muxed-resource-lock-for-the-Sup.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/f71882fg-use-a-muxed-resource-lock-for-the-Sup.patch	Mon Dec  6 04:16:52 2010	(r16673)
@@ -0,0 +1,122 @@
+From b4682d1c9ec80faa66161e0890df2aa8490cb473 Mon Sep 17 00:00:00 2001
+From: Giel van Schijndel <me at mortis.eu>
+Date: Sun, 3 Oct 2010 08:09:49 -0400
+Subject: [PATCH] hwmon: f71882fg: use a muxed resource lock for the Super I/O port
+
+commit cadb86570c41fe52a0ea741f1f9775e3412f0167 upstream.
+
+Sleep while acquiring a resource lock on the Super I/O port. This should
+prevent collisions from causing the hardware probe to fail with -EBUSY.
+
+Signed-off-by: Giel van Schijndel <me at mortis.eu>
+Acked-by: Hans de Goede <hdegoede at redhat.com>
+Signed-off-by: Guenter Roeck <guenter.roeck at ericsson.com>
+[bwh: Adjust context for 2.6.32]
+---
+ drivers/hwmon/f71882fg.c |   32 +++++++++++++++++++-------------
+ 1 files changed, 19 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
+index 746c839..60f0abb 100644
+--- a/drivers/hwmon/f71882fg.c
++++ b/drivers/hwmon/f71882fg.c
+@@ -111,7 +111,7 @@ static struct platform_device *f71882fg_pdev;
+ /* Super-I/O Function prototypes */
+ static inline int superio_inb(int base, int reg);
+ static inline int superio_inw(int base, int reg);
+-static inline void superio_enter(int base);
++static inline int superio_enter(int base);
+ static inline void superio_select(int base, int ld);
+ static inline void superio_exit(int base);
+ 
+@@ -863,11 +863,20 @@ static int superio_inw(int base, int reg)
+ 	return val;
+ }
+ 
+-static inline void superio_enter(int base)
++static inline int superio_enter(int base)
+ {
++	/* Don't step on other drivers' I/O space by accident */
++	if (!request_muxed_region(base, 2, DRVNAME)) {
++		printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
++				base);
++		return -EBUSY;
++	}
++
+ 	/* according to the datasheet the key must be send twice! */
+ 	outb( SIO_UNLOCK_KEY, base);
+ 	outb( SIO_UNLOCK_KEY, base);
++
++	return 0;
+ }
+ 
+ static inline void superio_select( int base, int ld)
+@@ -879,6 +888,7 @@ static inline void superio_select( int base, int ld)
+ static inline void superio_exit(int base)
+ {
+ 	outb(SIO_LOCK_KEY, base);
++	release_region(base, 2);
+ }
+ 
+ static inline int fan_from_reg(u16 reg)
+@@ -2106,21 +2116,15 @@ static int f71882fg_remove(struct platform_device *pdev)
+ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 	struct f71882fg_sio_data *sio_data)
+ {
+-	int err = -ENODEV;
+ 	u16 devid;
+-
+-	/* Don't step on other drivers' I/O space by accident */
+-	if (!request_region(sioaddr, 2, DRVNAME)) {
+-		printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
+-				(int)sioaddr);
+-		return -EBUSY;
+-	}
+-
+-	superio_enter(sioaddr);
++	int err = superio_enter(sioaddr);
++	if (err)
++		return err;
+ 
+ 	devid = superio_inw(sioaddr, SIO_REG_MANID);
+ 	if (devid != SIO_FINTEK_ID) {
+ 		pr_debug(DRVNAME ": Not a Fintek device\n");
++		err = -ENODEV;
+ 		goto exit;
+ 	}
+ 
+@@ -2144,6 +2148,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 	default:
+ 		printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
+ 		       (unsigned int)devid);
++		err = -ENODEV;
+ 		goto exit;
+ 	}
+ 
+@@ -2154,6 +2159,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 
+ 	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+ 		printk(KERN_WARNING DRVNAME ": Device not activated\n");
++		err = -ENODEV;
+ 		goto exit;
+ 	}
+ 
+@@ -2161,6 +2167,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 	if (*address == 0)
+ 	{
+ 		printk(KERN_WARNING DRVNAME ": Base address not set\n");
++		err = -ENODEV;
+ 		goto exit;
+ 	}
+ 	*address &= ~(REGION_LENGTH - 1);	/* Ignore 3 LSB */
+@@ -2171,7 +2178,6 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
+ exit:
+ 	superio_exit(sioaddr);
+-	release_region(sioaddr, 2);
+ 	return err;
+ }
+ 
+-- 
+1.7.2.3
+

Added: dists/sid/linux-2.6/debian/patches/features/all/resource-shared-I-O-region-support.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/resource-shared-I-O-region-support.patch	Mon Dec  6 04:16:52 2010	(r16673)
@@ -0,0 +1,120 @@
+From: Alan Cox <alan at linux.intel.com>
+Date: Mon, 29 Mar 2010 19:38:00 +0200
+Subject: [PATCH] resource: shared I/O region support
+
+commit 8b6d043b7ee2d1b819dc833d677ea2aead71a0c0 upstream.
+
+SuperIO devices share regions and use lock/unlock operations to chip
+select.  We therefore need to be able to request a resource and wait for
+it to be freed by whichever other SuperIO device currently hogs it.
+Right now you have to poll which is horrible.
+
+Add a MUXED field to IO port resources. If the MUXED field is set on the
+resource and on the request (via request_muxed_region) then we block
+until the previous owner of the muxed resource releases their region.
+
+This allows us to implement proper resource sharing and locking for
+superio chips using code of the form
+
+enable_my_superio_dev() {
+	request_muxed_region(0x44, 0x02, "superio:watchdog");
+	outb() ..sequence to enable chip
+}
+
+disable_my_superio_dev() {
+	outb() .. sequence of disable chip
+	release_region(0x44, 0x02);
+}
+
+Signed-off-by: Giel van Schijndel <me at mortis.eu>
+Signed-off-by: Alan Cox <alan at linux.intel.com>
+Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
+[Mike Hommey: Adjust context for 2.6.32]
+[bwh: Hide the added #include from genksyms]
+---
+ include/linux/ioport.h |    4 +++-
+ kernel/resource.c      |   18 +++++++++++++++++-
+ 2 files changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/ioport.h b/include/linux/ioport.h
+index 83aa812..140b00d 100644
+--- a/include/linux/ioport.h
++++ b/include/linux/ioport.h
+@@ -50,6 +50,7 @@ struct resource_list {
+ #define IORESOURCE_STARTALIGN	0x00040000	/* start field is alignment */
+ 
+ #define IORESOURCE_MEM_64	0x00100000
++#define IORESOURCE_MUXED	0x00400000	/* Resource is software muxed */
+ 
+ #define IORESOURCE_EXCLUSIVE	0x08000000	/* Userland may not map this resource */
+ #define IORESOURCE_DISABLED	0x10000000
+@@ -136,7 +137,8 @@ static inline unsigned long resource_type(struct resource *res)
+ }
+ 
+ /* Convenience shorthand with allocation */
+-#define request_region(start,n,name)	__request_region(&ioport_resource, (start), (n), (name), 0)
++#define request_region(start,n,name)		__request_region(&ioport_resource, (start), (n), (name), 0)
++#define request_muxed_region(start,n,name)	__request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
+ #define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
+ #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
+ #define request_mem_region_exclusive(start,n,name) \
+diff --git a/kernel/resource.c b/kernel/resource.c
+index fb11a58..06bd8ef 100644
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -15,6 +15,9 @@
+ #include <linux/spinlock.h>
+ #include <linux/fs.h>
+ #include <linux/proc_fs.h>
++#ifndef __GENKSYMS__
++#include <linux/sched.h>
++#endif
+ #include <linux/seq_file.h>
+ #include <linux/device.h>
+ #include <linux/pfn.h>
+@@ -601,6 +604,8 @@ resource_size_t resource_alignment(struct resource *res)
+  * release_region releases a matching busy region.
+  */
+ 
++static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait);
++
+ /**
+  * __request_region - create a new busy resource region
+  * @parent: parent resource descriptor
+@@ -613,6 +618,7 @@ struct resource * __request_region(struct resource *parent,
+ 				   resource_size_t start, resource_size_t n,
+ 				   const char *name, int flags)
+ {
++	DECLARE_WAITQUEUE(wait, current);
+ 	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+ 
+ 	if (!res)
+@@ -637,7 +643,15 @@ struct resource * __request_region(struct resource *parent,
+ 			if (!(conflict->flags & IORESOURCE_BUSY))
+ 				continue;
+ 		}
+-
++		if (conflict->flags & flags & IORESOURCE_MUXED) {
++			add_wait_queue(&muxed_resource_wait, &wait);
++			write_unlock(&resource_lock);
++			set_current_state(TASK_UNINTERRUPTIBLE);
++			schedule();
++			remove_wait_queue(&muxed_resource_wait, &wait);
++			write_lock(&resource_lock);
++			continue;
++		}
+ 		/* Uhhuh, that didn't work out.. */
+ 		kfree(res);
+ 		res = NULL;
+@@ -711,6 +725,8 @@ void __release_region(struct resource *parent, resource_size_t start,
+ 				break;
+ 			*p = res->sibling;
+ 			write_unlock(&resource_lock);
++			if (res->flags & IORESOURCE_MUXED)
++				wake_up(&muxed_resource_wait);
+ 			kfree(res);
+ 			return;
+ 		}
+-- 
+1.7.2.3
+

Added: dists/sid/linux-2.6/debian/patches/features/all/watchdog-f71808e_wdt-driver-for-Fintek-F718108E-F71882FG.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/watchdog-f71808e_wdt-driver-for-Fintek-F718108E-F71882FG.patch	Mon Dec  6 04:16:52 2010	(r16673)
@@ -0,0 +1,829 @@
+From: Giel van Schijndel <me at mortis.eu>
+Date: Sun, 1 Aug 2010 15:30:55 +0200
+Subject: [PATCH] watchdog: f71808e_wdt: new watchdog driver for Fintek F71808E and F71882FG
+
+commit 96cb4eb019ce3185ec0d946a74b5a2202f5067c9 upstream.
+
+Add a new watchdog driver for the Fintek F71808E and F71882FG Super I/O
+controllers.
+
+Signed-off-by: Giel van Schijndel <me at mortis.eu>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/Kconfig       |   11 +
+ drivers/watchdog/Makefile      |    1 +
+ drivers/watchdog/f71808e_wdt.c |  768 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 780 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/watchdog/f71808e_wdt.c
+
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index b04b184..910e09f 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -401,6 +401,17 @@ config ALIM7101_WDT
+ 
+ 	  Most people will say N.
+ 
++config F71808E_WDT
++	tristate "Fintek F71808E and F71882FG Watchdog"
++	depends on X86 && EXPERIMENTAL
++	help
++	  This is the driver for the hardware watchdog on the Fintek
++	  F71808E and F71882FG Super I/O controllers.
++
++	  You can compile this driver directly into the kernel, or use
++	  it as a module.  The module will be called f71808e_wdt.
++
++
+ config GEODE_WDT
+ 	tristate "AMD Geode CS5535/CS5536 Watchdog"
+ 	depends on CS5535_MFGPT
+diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
+index e30289a..0010ae5 100644
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -66,6 +66,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
+ obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
+ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
++obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
+ obj-$(CONFIG_GEODE_WDT) += geodewdt.o
+ obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
+ obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o
+diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
+new file mode 100644
+index 0000000..7e5c266
+--- /dev/null
++++ b/drivers/watchdog/f71808e_wdt.c
+@@ -0,0 +1,768 @@
++/***************************************************************************
++ *   Copyright (C) 2006 by Hans Edgington <hans at edgington.nl>              *
++ *   Copyright (C) 2007-2009 Hans de Goede <hdegoede at redhat.com>           *
++ *   Copyright (C) 2010 Giel van Schijndel <me at mortis.eu>                  *
++ *                                                                         *
++ *   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.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
++ ***************************************************************************/
++
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/uaccess.h>
++#include <linux/watchdog.h>
++
++#define DRVNAME "f71808e_wdt"
++
++#define SIO_F71808FG_LD_WDT	0x07	/* Watchdog timer logical device */
++#define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
++#define SIO_LOCK_KEY		0xAA	/* Key to diasble Super-I/O */
++
++#define SIO_REG_LDSEL		0x07	/* Logical device select */
++#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
++#define SIO_REG_DEVREV		0x22	/* Device revision */
++#define SIO_REG_MANID		0x23	/* Fintek ID (2 bytes) */
++#define SIO_REG_ENABLE		0x30	/* Logical device enable */
++#define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
++
++#define SIO_FINTEK_ID		0x1934	/* Manufacturers ID */
++#define SIO_F71808_ID		0x0901  /* Chipset ID */
++#define SIO_F71858_ID		0x0507  /* Chipset ID */
++#define SIO_F71862_ID		0x0601	/* Chipset ID */
++#define SIO_F71882_ID		0x0541	/* Chipset ID */
++#define SIO_F71889_ID		0x0723	/* Chipset ID */
++
++#define	F71882FG_REG_START		0x01
++
++#define F71808FG_REG_WDO_CONF		0xf0
++#define F71808FG_REG_WDT_CONF		0xf5
++#define F71808FG_REG_WD_TIME		0xf6
++
++#define F71808FG_FLAG_WDOUT_EN		7
++
++#define F71808FG_FLAG_WDTMOUT_STS	5
++#define F71808FG_FLAG_WD_EN		5
++#define F71808FG_FLAG_WD_PULSE		4
++#define F71808FG_FLAG_WD_UNIT		3
++
++/* Default values */
++#define WATCHDOG_TIMEOUT	60	/* 1 minute default timeout */
++#define WATCHDOG_MAX_TIMEOUT	(60 * 255)
++#define WATCHDOG_PULSE_WIDTH	125	/* 125 ms, default pulse width for
++					   watchdog signal */
++
++static unsigned short force_id;
++module_param(force_id, ushort, 0);
++MODULE_PARM_DESC(force_id, "Override the detected device ID");
++
++static const int max_timeout = WATCHDOG_MAX_TIMEOUT;
++static int timeout = 60;	/* default timeout in seconds */
++module_param(timeout, int, 0);
++MODULE_PARM_DESC(timeout,
++	"Watchdog timeout in seconds. 1<= timeout <="
++			__MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
++			__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
++
++static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
++module_param(pulse_width, uint, 0);
++MODULE_PARM_DESC(pulse_width,
++	"Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
++			" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
++
++static int nowayout = WATCHDOG_NOWAYOUT;
++module_param(nowayout, bool, 0444);
++MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
++
++static unsigned int start_withtimeout;
++module_param(start_withtimeout, uint, 0);
++MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
++	" given initial timeout. Zero (default) disables this feature.");
++
++enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg };
++
++static const char *f71808e_names[] = {
++	"f71808fg",
++	"f71858fg",
++	"f71862fg",
++	"f71882fg",
++	"f71889fg",
++};
++
++/* Super-I/O Function prototypes */
++static inline int superio_inb(int base, int reg);
++static inline int superio_inw(int base, int reg);
++static inline void superio_outb(int base, int reg, u8 val);
++static inline void superio_set_bit(int base, int reg, int bit);
++static inline void superio_clear_bit(int base, int reg, int bit);
++static inline int superio_enter(int base);
++static inline void superio_select(int base, int ld);
++static inline void superio_exit(int base);
++
++struct watchdog_data {
++	unsigned short	sioaddr;
++	enum chips	type;
++	unsigned long	opened;
++	struct mutex	lock;
++	char		expect_close;
++	struct watchdog_info ident;
++
++	unsigned short	timeout;
++	u8		timer_val;	/* content for the wd_time register */
++	char		minutes_mode;
++	u8		pulse_val;	/* pulse width flag */
++	char		pulse_mode;	/* enable pulse output mode? */
++	char		caused_reboot;	/* last reboot was by the watchdog */
++};
++
++static struct watchdog_data watchdog = {
++	.lock = __MUTEX_INITIALIZER(watchdog.lock),
++};
++
++/* Super I/O functions */
++static inline int superio_inb(int base, int reg)
++{
++	outb(reg, base);
++	return inb(base + 1);
++}
++
++static int superio_inw(int base, int reg)
++{
++	int val;
++	val  = superio_inb(base, reg) << 8;
++	val |= superio_inb(base, reg + 1);
++	return val;
++}
++
++static inline void superio_outb(int base, int reg, u8 val)
++{
++	outb(reg, base);
++	outb(val, base + 1);
++}
++
++static inline void superio_set_bit(int base, int reg, int bit)
++{
++	unsigned long val = superio_inb(base, reg);
++	__set_bit(bit, &val);
++	superio_outb(base, reg, val);
++}
++
++static inline void superio_clear_bit(int base, int reg, int bit)
++{
++	unsigned long val = superio_inb(base, reg);
++	__clear_bit(bit, &val);
++	superio_outb(base, reg, val);
++}
++
++static inline int superio_enter(int base)
++{
++	/* Don't step on other drivers' I/O space by accident */
++	if (!request_muxed_region(base, 2, DRVNAME)) {
++		printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
++				(int)base);
++		return -EBUSY;
++	}
++
++	/* according to the datasheet the key must be send twice! */
++	outb(SIO_UNLOCK_KEY, base);
++	outb(SIO_UNLOCK_KEY, base);
++
++	return 0;
++}
++
++static inline void superio_select(int base, int ld)
++{
++	outb(SIO_REG_LDSEL, base);
++	outb(ld, base + 1);
++}
++
++static inline void superio_exit(int base)
++{
++	outb(SIO_LOCK_KEY, base);
++	release_region(base, 2);
++}
++
++static int watchdog_set_timeout(int timeout)
++{
++	if (timeout <= 0
++	 || timeout >  max_timeout) {
++		printk(KERN_ERR DRVNAME ": watchdog timeout out of range\n");
++		return -EINVAL;
++	}
++
++	mutex_lock(&watchdog.lock);
++
++	watchdog.timeout = timeout;
++	if (timeout > 0xff) {
++		watchdog.timer_val = DIV_ROUND_UP(timeout, 60);
++		watchdog.minutes_mode = true;
++	} else {
++		watchdog.timer_val = timeout;
++		watchdog.minutes_mode = false;
++	}
++
++	mutex_unlock(&watchdog.lock);
++
++	return 0;
++}
++
++static int watchdog_set_pulse_width(unsigned int pw)
++{
++	int err = 0;
++
++	mutex_lock(&watchdog.lock);
++
++	if        (pw <=    1) {
++		watchdog.pulse_val = 0;
++	} else if (pw <=   25) {
++		watchdog.pulse_val = 1;
++	} else if (pw <=  125) {
++		watchdog.pulse_val = 2;
++	} else if (pw <= 5000) {
++		watchdog.pulse_val = 3;
++	} else {
++		printk(KERN_ERR DRVNAME ": pulse width out of range\n");
++		err = -EINVAL;
++		goto exit_unlock;
++	}
++
++	watchdog.pulse_mode = pw;
++
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++	return err;
++}
++
++static int watchdog_keepalive(void)
++{
++	int err = 0;
++
++	mutex_lock(&watchdog.lock);
++	err = superio_enter(watchdog.sioaddr);
++	if (err)
++		goto exit_unlock;
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++	if (watchdog.minutes_mode)
++		/* select minutes for timer units */
++		superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++				F71808FG_FLAG_WD_UNIT);
++	else
++		/* select seconds for timer units */
++		superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++				F71808FG_FLAG_WD_UNIT);
++
++	/* Set timer value */
++	superio_outb(watchdog.sioaddr, F71808FG_REG_WD_TIME,
++			   watchdog.timer_val);
++
++	superio_exit(watchdog.sioaddr);
++
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++	return err;
++}
++
++static int watchdog_start(void)
++{
++	/* Make sure we don't die as soon as the watchdog is enabled below */
++	int err = watchdog_keepalive();
++	if (err)
++		return err;
++
++	mutex_lock(&watchdog.lock);
++	err = superio_enter(watchdog.sioaddr);
++	if (err)
++		goto exit_unlock;
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++	/* Watchdog pin configuration */
++	switch (watchdog.type) {
++	case f71808fg:
++		/* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
++		superio_clear_bit(watchdog.sioaddr, 0x2a, 3);
++		superio_clear_bit(watchdog.sioaddr, 0x2b, 3);
++		break;
++
++	case f71882fg:
++		/* Set pin 56 to WDTRST# */
++		superio_set_bit(watchdog.sioaddr, 0x29, 1);
++		break;
++
++	default:
++		/*
++		 * 'default' label to shut up the compiler and catch
++		 * programmer errors
++		 */
++		err = -ENODEV;
++		goto exit_superio;
++	}
++
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++	superio_set_bit(watchdog.sioaddr, SIO_REG_ENABLE, 0);
++	superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDO_CONF,
++			F71808FG_FLAG_WDOUT_EN);
++
++	superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++			F71808FG_FLAG_WD_EN);
++
++	if (watchdog.pulse_mode) {
++		/* Select "pulse" output mode with given duration */
++		u8 wdt_conf = superio_inb(watchdog.sioaddr,
++				F71808FG_REG_WDT_CONF);
++
++		/* Set WD_PSWIDTH bits (1:0) */
++		wdt_conf = (wdt_conf & 0xfc) | (watchdog.pulse_val & 0x03);
++		/* Set WD_PULSE to "pulse" mode */
++		wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
++
++		superio_outb(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++				wdt_conf);
++	} else {
++		/* Select "level" output mode */
++		superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++				F71808FG_FLAG_WD_PULSE);
++	}
++
++exit_superio:
++	superio_exit(watchdog.sioaddr);
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++
++	return err;
++}
++
++static int watchdog_stop(void)
++{
++	int err = 0;
++
++	mutex_lock(&watchdog.lock);
++	err = superio_enter(watchdog.sioaddr);
++	if (err)
++		goto exit_unlock;
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++	superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
++			F71808FG_FLAG_WD_EN);
++
++	superio_exit(watchdog.sioaddr);
++
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++
++	return err;
++}
++
++static int watchdog_get_status(void)
++{
++	int status = 0;
++
++	mutex_lock(&watchdog.lock);
++	status = (watchdog.caused_reboot) ? WDIOF_CARDRESET : 0;
++	mutex_unlock(&watchdog.lock);
++
++	return status;
++}
++
++static bool watchdog_is_running(void)
++{
++	/*
++	 * if we fail to determine the watchdog's status assume it to be
++	 * running to be on the safe side
++	 */
++	bool is_running = true;
++
++	mutex_lock(&watchdog.lock);
++	if (superio_enter(watchdog.sioaddr))
++		goto exit_unlock;
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++	is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0))
++		&& (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF)
++			& F71808FG_FLAG_WD_EN);
++
++	superio_exit(watchdog.sioaddr);
++
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++	return is_running;
++}
++
++/* /dev/watchdog api */
++
++static int watchdog_open(struct inode *inode, struct file *file)
++{
++	int err;
++
++	/* If the watchdog is alive we don't need to start it again */
++	if (test_and_set_bit(0, &watchdog.opened))
++		return -EBUSY;
++
++	err = watchdog_start();
++	if (err) {
++		clear_bit(0, &watchdog.opened);
++		return err;
++	}
++
++	if (nowayout)
++		__module_get(THIS_MODULE);
++
++	watchdog.expect_close = 0;
++	return nonseekable_open(inode, file);
++}
++
++static int watchdog_release(struct inode *inode, struct file *file)
++{
++	clear_bit(0, &watchdog.opened);
++
++	if (!watchdog.expect_close) {
++		watchdog_keepalive();
++		printk(KERN_CRIT DRVNAME
++			": Unexpected close, not stopping watchdog!\n");
++	} else if (!nowayout) {
++		watchdog_stop();
++	}
++	return 0;
++}
++
++/*
++ *      watchdog_write:
++ *      @file: file handle to the watchdog
++ *      @buf: buffer to write
++ *      @count: count of bytes
++ *      @ppos: pointer to the position to write. No seeks allowed
++ *
++ *      A write to a watchdog device is defined as a keepalive signal. Any
++ *      write of data will do, as we we don't define content meaning.
++ */
++
++static ssize_t watchdog_write(struct file *file, const char __user *buf,
++			    size_t count, loff_t *ppos)
++{
++	if (count) {
++		if (!nowayout) {
++			size_t i;
++
++			/* In case it was set long ago */
++			bool expect_close = false;
++
++			for (i = 0; i != count; i++) {
++				char c;
++				if (get_user(c, buf + i))
++					return -EFAULT;
++				expect_close = (c == 'V');
++			}
++
++			/* Properly order writes across fork()ed processes */
++			mutex_lock(&watchdog.lock);
++			watchdog.expect_close = expect_close;
++			mutex_unlock(&watchdog.lock);
++		}
++
++		/* someone wrote to us, we should restart timer */
++		watchdog_keepalive();
++	}
++	return count;
++}
++
++/*
++ *      watchdog_ioctl:
++ *      @inode: inode of the device
++ *      @file: file handle to the device
++ *      @cmd: watchdog command
++ *      @arg: argument pointer
++ *
++ *      The watchdog API defines a common set of functions for all watchdogs
++ *      according to their available features.
++ */
++static long watchdog_ioctl(struct file *file, unsigned int cmd,
++	unsigned long arg)
++{
++	int status;
++	int new_options;
++	int new_timeout;
++	union {
++		struct watchdog_info __user *ident;
++		int __user *i;
++	} uarg;
++
++	uarg.i = (int __user *)arg;
++
++	switch (cmd) {
++	case WDIOC_GETSUPPORT:
++		return copy_to_user(uarg.ident, &watchdog.ident,
++			sizeof(watchdog.ident)) ? -EFAULT : 0;
++
++	case WDIOC_GETSTATUS:
++		status = watchdog_get_status();
++		if (status < 0)
++			return status;
++		return put_user(status, uarg.i);
++
++	case WDIOC_GETBOOTSTATUS:
++		return put_user(0, uarg.i);
++
++	case WDIOC_SETOPTIONS:
++		if (get_user(new_options, uarg.i))
++			return -EFAULT;
++
++		if (new_options & WDIOS_DISABLECARD)
++			watchdog_stop();
++
++		if (new_options & WDIOS_ENABLECARD)
++			return watchdog_start();
++
++
++	case WDIOC_KEEPALIVE:
++		watchdog_keepalive();
++		return 0;
++
++	case WDIOC_SETTIMEOUT:
++		if (get_user(new_timeout, uarg.i))
++			return -EFAULT;
++
++		if (watchdog_set_timeout(new_timeout))
++			return -EINVAL;
++
++		watchdog_keepalive();
++		/* Fall */
++
++	case WDIOC_GETTIMEOUT:
++		return put_user(watchdog.timeout, uarg.i);
++
++	default:
++		return -ENOTTY;
++
++	}
++}
++
++static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
++	void *unused)
++{
++	if (code == SYS_DOWN || code == SYS_HALT)
++		watchdog_stop();
++	return NOTIFY_DONE;
++}
++
++static const struct file_operations watchdog_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.open		= watchdog_open,
++	.release	= watchdog_release,
++	.write		= watchdog_write,
++	.unlocked_ioctl	= watchdog_ioctl,
++};
++
++static struct miscdevice watchdog_miscdev = {
++	.minor		= WATCHDOG_MINOR,
++	.name		= "watchdog",
++	.fops		= &watchdog_fops,
++};
++
++static struct notifier_block watchdog_notifier = {
++	.notifier_call = watchdog_notify_sys,
++};
++
++static int __init watchdog_init(int sioaddr)
++{
++	int wdt_conf, err = 0;
++
++	/* No need to lock watchdog.lock here because no entry points
++	 * into the module have been registered yet.
++	 */
++	watchdog.sioaddr = sioaddr;
++	watchdog.ident.options = WDIOC_SETTIMEOUT
++				| WDIOF_MAGICCLOSE
++				| WDIOF_KEEPALIVEPING;
++
++	snprintf(watchdog.ident.identity,
++		sizeof(watchdog.ident.identity), "%s watchdog",
++		f71808e_names[watchdog.type]);
++
++	err = superio_enter(sioaddr);
++	if (err)
++		return err;
++	superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++	wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
++	watchdog.caused_reboot = wdt_conf & F71808FG_FLAG_WDTMOUT_STS;
++
++	superio_exit(sioaddr);
++
++	err = watchdog_set_timeout(timeout);
++	if (err)
++		return err;
++	err = watchdog_set_pulse_width(pulse_width);
++	if (err)
++		return err;
++
++	err = register_reboot_notifier(&watchdog_notifier);
++	if (err)
++		return err;
++
++	err = misc_register(&watchdog_miscdev);
++	if (err) {
++		printk(KERN_ERR DRVNAME
++			": cannot register miscdev on minor=%d\n",
++				watchdog_miscdev.minor);
++		goto exit_reboot;
++	}
++
++	if (start_withtimeout) {
++		if (start_withtimeout <= 0
++		 || start_withtimeout >  max_timeout) {
++			printk(KERN_ERR DRVNAME
++				": starting timeout out of range\n");
++			err = -EINVAL;
++			goto exit_miscdev;
++		}
++
++		err = watchdog_start();
++		if (err) {
++			printk(KERN_ERR DRVNAME
++				": cannot start watchdog timer\n");
++			goto exit_miscdev;
++		}
++
++		mutex_lock(&watchdog.lock);
++		err = superio_enter(sioaddr);
++		if (err)
++			goto exit_unlock;
++		superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
++
++		if (start_withtimeout > 0xff) {
++			/* select minutes for timer units */
++			superio_set_bit(sioaddr, F71808FG_REG_WDT_CONF,
++				F71808FG_FLAG_WD_UNIT);
++			superio_outb(sioaddr, F71808FG_REG_WD_TIME,
++				DIV_ROUND_UP(start_withtimeout, 60));
++		} else {
++			/* select seconds for timer units */
++			superio_clear_bit(sioaddr, F71808FG_REG_WDT_CONF,
++				F71808FG_FLAG_WD_UNIT);
++			superio_outb(sioaddr, F71808FG_REG_WD_TIME,
++				start_withtimeout);
++		}
++
++		superio_exit(sioaddr);
++		mutex_unlock(&watchdog.lock);
++
++		if (nowayout)
++			__module_get(THIS_MODULE);
++
++		printk(KERN_INFO DRVNAME
++			": watchdog started with initial timeout of %u sec\n",
++			start_withtimeout);
++	}
++
++	return 0;
++
++exit_unlock:
++	mutex_unlock(&watchdog.lock);
++exit_miscdev:
++	misc_deregister(&watchdog_miscdev);
++exit_reboot:
++	unregister_reboot_notifier(&watchdog_notifier);
++
++	return err;
++}
++
++static int __init f71808e_find(int sioaddr)
++{
++	u16 devid;
++	int err = superio_enter(sioaddr);
++	if (err)
++		return err;
++
++	devid = superio_inw(sioaddr, SIO_REG_MANID);
++	if (devid != SIO_FINTEK_ID) {
++		pr_debug(DRVNAME ": Not a Fintek device\n");
++		err = -ENODEV;
++		goto exit;
++	}
++
++	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
++	switch (devid) {
++	case SIO_F71808_ID:
++		watchdog.type = f71808fg;
++		break;
++	case SIO_F71882_ID:
++		watchdog.type = f71882fg;
++		break;
++	case SIO_F71862_ID:
++	case SIO_F71889_ID:
++		/* These have a watchdog, though it isn't implemented (yet). */
++		err = -ENOSYS;
++		goto exit;
++	case SIO_F71858_ID:
++		/* Confirmed (by datasheet) not to have a watchdog. */
++		err = -ENODEV;
++		goto exit;
++	default:
++		printk(KERN_INFO DRVNAME ": Unrecognized Fintek device: %04x\n",
++		       (unsigned int)devid);
++		err = -ENODEV;
++		goto exit;
++	}
++
++	printk(KERN_INFO DRVNAME ": Found %s watchdog chip, revision %d\n",
++		f71808e_names[watchdog.type],
++		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
++exit:
++	superio_exit(sioaddr);
++	return err;
++}
++
++static int __init f71808e_init(void)
++{
++	static const unsigned short addrs[] = { 0x2e, 0x4e };
++	int err = -ENODEV;
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
++		err = f71808e_find(addrs[i]);
++		if (err == 0)
++			break;
++	}
++	if (i == ARRAY_SIZE(addrs))
++		return err;
++
++	return watchdog_init(addrs[i]);
++}
++
++static void __exit f71808e_exit(void)
++{
++	if (watchdog_is_running()) {
++		printk(KERN_WARNING DRVNAME
++			": Watchdog timer still running, stopping it\n");
++		watchdog_stop();
++	}
++	misc_deregister(&watchdog_miscdev);
++	unregister_reboot_notifier(&watchdog_notifier);
++}
++
++MODULE_DESCRIPTION("F71808E Watchdog Driver");
++MODULE_AUTHOR("Giel van Schijndel <me at mortis.eu>");
++MODULE_LICENSE("GPL");
++
++module_init(f71808e_init);
++module_exit(f71808e_exit);
+-- 
+1.7.2.3
+

Modified: dists/sid/linux-2.6/debian/patches/series/29
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/29	Mon Dec  6 03:28:39 2010	(r16672)
+++ dists/sid/linux-2.6/debian/patches/series/29	Mon Dec  6 04:16:52 2010	(r16673)
@@ -11,3 +11,7 @@
 + bugfix/all/dm-Deal-with-merge_bvec_fn-in-component-devices-bett.patch
 + bugfix/all/net-clear-heap-allocation-for-ETHTOOL_GRXCLSRLALL.patch
 + bugfix/all/perf-symbols-allow-forcing-use-of-cplus_demangle.patch
++ features/all/resource-shared-I-O-region-support.patch
++ bugfix/all/hwmon-f71882fg-Acquire-I-O-regions-while-we-re-worki.patch
++ features/all/f71882fg-use-a-muxed-resource-lock-for-the-Sup.patch
++ features/all/watchdog-f71808e_wdt-driver-for-Fintek-F718108E-F71882FG.patch



More information about the Kernel-svn-changes mailing list