[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