]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Mar 2011 00:09:29 +0000 (17:09 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Mar 2011 00:09:29 +0000 (17:09 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
  watchdog: booke_wdt: clean up status messages
  watchdog: cleanup spaces before tabs
  watchdog: convert to DEFINE_PCI_DEVICE_TABLE
  watchdog: Xen watchdog driver
  watchdog: Intel SCU Watchdog Timer Driver for Moorestown and Medfield platforms.
  watchdog: jz4740_wdt - fix magic character checking
  watchdog: add JZ4740 watchdog driver
  watchdog: it87_wdt: Add support for IT8721F watchdog
  watchdog: hpwdt: build hpwdt as module by default with NMI_DECODING enabled
  watchdog: hpwdt: Fix a couple of typos

42 files changed:
arch/mips/include/asm/mach-jz4740/platform.h
arch/mips/jz4740/platform.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/alim1535_wdt.c
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/bfin_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/eurotechwdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/intel_scu_watchdog.c [new file with mode: 0644]
drivers/watchdog/intel_scu_watchdog.h [new file with mode: 0644]
drivers/watchdog/it8712f_wdt.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/jz4740_wdt.c [new file with mode: 0644]
drivers/watchdog/machzwd.c
drivers/watchdog/max63xx_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/nv_tco.c
drivers/watchdog/omap_wdt.h
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pcwd_pci.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sbc8360.c
drivers/watchdog/sbc_fitpc2_wdt.c
drivers/watchdog/smsc37b787_wdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/w83697ug_wdt.c
drivers/watchdog/wdt.c
drivers/watchdog/wdt977.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/xen_wdt.c [new file with mode: 0644]
include/xen/interface/sched.h

index 8987a76e9676a310492e9b67783c0ad47eb7f78b..564ab81d6cdc338b5f7033248d7d2e02c8fd3f00 100644 (file)
@@ -30,6 +30,7 @@ extern struct platform_device jz4740_i2s_device;
 extern struct platform_device jz4740_pcm_device;
 extern struct platform_device jz4740_codec_device;
 extern struct platform_device jz4740_adc_device;
+extern struct platform_device jz4740_wdt_device;
 
 void jz4740_serial_device_register(void);
 
index 1cc9e544d16bd16609aaef30bd5779ad26f5dc14..10929e2bc6d82a77714243175073f8ef31a60fcf 100644 (file)
@@ -289,3 +289,19 @@ void jz4740_serial_device_register(void)
 
        platform_device_register(&jz4740_uart_device);
 }
+
+/* Watchdog */
+static struct resource jz4740_wdt_resources[] = {
+       {
+               .start = JZ4740_WDT_BASE_ADDR,
+               .end   = JZ4740_WDT_BASE_ADDR + 0x10 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device jz4740_wdt_device = {
+       .name          = "jz4740-wdt",
+       .id            = -1,
+       .num_resources = ARRAY_SIZE(jz4740_wdt_resources),
+       .resource      = jz4740_wdt_resources,
+};
index 908160e938dc75080fc592d546768ab31bd5d71d..b69d71482554a2f6a0518b6879a9860188f39251 100644 (file)
@@ -533,6 +533,16 @@ config I6300ESB_WDT
          To compile this driver as a module, choose M here: the
          module will be called i6300esb.
 
+config INTEL_SCU_WATCHDOG
+       bool "Intel SCU Watchdog for Mobile Platforms"
+       depends on WATCHDOG
+       depends on INTEL_SCU_IPC
+       ---help---
+         Hardware driver for the watchdog time built into the Intel SCU
+         for Intel Mobile Platforms.
+
+         To compile this driver as a module, choose M here.
+
 config ITCO_WDT
        tristate "Intel TCO Timer/Watchdog"
        depends on (X86 || IA64) && PCI
@@ -580,7 +590,7 @@ config IT87_WDT
        depends on X86 && EXPERIMENTAL
        ---help---
          This is the driver for the hardware watchdog on the ITE IT8702,
-         IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips.
+         IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
          This watchdog simply watches your kernel to make sure it doesn't
          freeze, and if it does, it reboots your computer after a certain
          amount of time.
@@ -589,18 +599,20 @@ config IT87_WDT
          be called it87_wdt.
 
 config HP_WATCHDOG
-       tristate "HP Proliant iLO2+ Hardware Watchdog Timer"
+       tristate "HP ProLiant iLO2+ Hardware Watchdog Timer"
        depends on X86
+       default m
        help
          A software monitoring watchdog and NMI sourcing driver. This driver
          will detect lockups and provide a stack trace. This is a driver that
-         will only load on a HP ProLiant system with a minimum of iLO2 support.
+         will only load on an HP ProLiant system with a minimum of iLO2 support.
          To compile this driver as a module, choose M here: the module will be
          called hpwdt.
 
 config HPWDT_NMI_DECODING
        bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
        depends on HP_WATCHDOG
+       default y
        help
          When an NMI occurs this feature will make the necessary BIOS calls to
          log the cause of the NMI.
@@ -903,6 +915,12 @@ config INDYDOG
          timer expired and no process has written to /dev/watchdog during
          that time.
 
+config JZ4740_WDT
+       tristate "Ingenic jz4740 SoC hardware watchdog"
+       depends on MACH_JZ4740
+       help
+         Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
+
 config WDT_MTX1
        tristate "MTX-1 Hardware Watchdog"
        depends on MIPS_MTX1
@@ -1111,6 +1129,16 @@ config WATCHDOG_RIO
 
 # XTENSA Architecture
 
+# Xen Architecture
+
+config XEN_WDT
+       tristate "Xen Watchdog support"
+       depends on XEN
+       help
+         Say Y here to support the hypervisor watchdog capability provided
+         by Xen 4.0 and newer.  The watchdog timeout period is normally one
+         minute but can be changed with a boot-time parameter.
+
 #
 # ISA-based Watchdog Cards
 #
index 20e44c4782b37761ae67ec344ea95c4c83540e2a..d520bf9c3355878eb4cfa2073161fc19ab53d061 100644 (file)
@@ -102,6 +102,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
+obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
 
 # M32R Architecture
 
@@ -114,6 +115,7 @@ obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
 obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
 obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
 obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
 obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
 obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
@@ -148,6 +150,9 @@ obj-$(CONFIG_WATCHDOG_CP1XXX)               += cpwd.o
 
 # XTENSA Architecture
 
+# Xen
+obj-$(CONFIG_XEN_WDT) += xen_wdt.o
+
 # Architecture Independant
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
index fa4d36033552fac0594bfabea42fbe10233e47f7..f16dcbd475fb7feb8c7314a1f0964a09310f0fa3 100644 (file)
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
  *     want to register another driver on the same PCI id.
  */
 
-static struct pci_device_id ali_pci_tbl[] __used = {
+static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = {
        { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
        { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
        { 0, },
@@ -362,12 +362,12 @@ static int __init ali_find_watchdog(void)
  */
 
 static const struct file_operations ali_fops = {
-       .owner          =       THIS_MODULE,
-       .llseek         =       no_llseek,
+       .owner          =       THIS_MODULE,
+       .llseek         =       no_llseek,
        .write          =       ali_write,
        .unlocked_ioctl =       ali_ioctl,
-       .open           =       ali_open,
-       .release        =       ali_release,
+       .open           =       ali_open,
+       .release        =       ali_release,
 };
 
 static struct miscdevice ali_miscdev = {
index 4b7a2b4138ed917a703c5d08b0b07616ba2d66b5..46f4b85b46de46706ff1b7f6972f624f9500c491 100644 (file)
@@ -430,7 +430,7 @@ err_out:
 module_init(alim7101_wdt_init);
 module_exit(alim7101_wdt_unload);
 
-static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = {
+static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { }
index 5f245522397bfbfc810ef6e6cbd7be1de5c281dd..bd44417c84d40940302fe484373818b84ac70982 100644 (file)
@@ -150,8 +150,8 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
 }
 
 static const struct watchdog_info bcm47xx_wdt_info = {
-       .identity       = DRV_NAME,
-       .options        = WDIOF_SETTIMEOUT |
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT |
                                WDIOF_KEEPALIVEPING |
                                WDIOF_MAGICCLOSE,
 };
index 9042a95fc98c04e2bf3a0f10c3d9bcf460a849fc..b9fa9b71583a68b49ed1e8026329c1cc24bb431c 100644 (file)
@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(bfin_wdt_spinlock);
 /**
  *     bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
  *
- *     The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ *     The Userspace watchdog got a KeepAlive: schedule the next timeout.
  */
 static int bfin_wdt_keepalive(void)
 {
@@ -337,7 +337,7 @@ static int bfin_wdt_resume(struct platform_device *pdev)
 static const struct file_operations bfin_wdt_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
-       .write          = bfin_wdt_write,
+       .write          = bfin_wdt_write,
        .unlocked_ioctl = bfin_wdt_ioctl,
        .open           = bfin_wdt_open,
        .release        = bfin_wdt_release,
index 7e7ec9c35b6a442e1569f4c25d5711ea6668e586..337265b47305b7f74d7935f7da1b4c85e7fd99cf 100644 (file)
@@ -4,7 +4,7 @@
  * Author: Matthew McClintock
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc.
+ * Copyright 2005, 2008, 2010-2011 Freescale Semiconductor Inc.
  *
  * 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
@@ -221,9 +221,8 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
        if (booke_wdt_enabled == 0) {
                booke_wdt_enabled = 1;
                on_each_cpu(__booke_wdt_enable, NULL, 0);
-               printk(KERN_INFO
-                     "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
-                               booke_wdt_period);
+               pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+                       period_to_sec(booke_wdt_period));
        }
        spin_unlock(&booke_wdt_lock);
 
@@ -240,6 +239,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
         */
        on_each_cpu(__booke_wdt_disable, NULL, 0);
        booke_wdt_enabled = 0;
+       pr_debug("booke_wdt: watchdog disabled\n");
 #endif
 
        clear_bit(0, &wdt_is_active);
@@ -271,21 +271,20 @@ static int __init booke_wdt_init(void)
 {
        int ret = 0;
 
-       printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+       pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
        ident.firmware_version = cur_cpu_spec->pvr_value;
 
        ret = misc_register(&booke_wdt_miscdev);
        if (ret) {
-               printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n",
-                               WATCHDOG_MINOR, ret);
+               pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
+                      WATCHDOG_MINOR, ret);
                return ret;
        }
 
        spin_lock(&booke_wdt_lock);
        if (booke_wdt_enabled == 1) {
-               printk(KERN_INFO
-                     "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
-                               booke_wdt_period);
+               pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+                       period_to_sec(booke_wdt_period));
                on_each_cpu(__booke_wdt_enable, NULL, 0);
        }
        spin_unlock(&booke_wdt_lock);
index 65911678453d0633f21afe611d21cb693cb07bb9..1e013e8457b7c1ee24c7d8731ba48c7ab4357583 100644 (file)
@@ -5,10 +5,10 @@
  * interface and Solaris-compatible ioctls as best it is
  * able.
  *
- * NOTE:       CP1400 systems appear to have a defective intr_mask
- *                     register on the PLD, preventing the disabling of
- *                     timer interrupts.  We use a timer to periodically
- *                     reset 'stopped' watchdogs on affected platforms.
+ * NOTE:       CP1400 systems appear to have a defective intr_mask
+ *                     register on the PLD, preventing the disabling of
+ *                     timer interrupts.  We use a timer to periodically
+ *                     reset 'stopped' watchdogs on affected platforms.
  *
  * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
@@ -107,13 +107,13 @@ static struct cpwd *cpwd_device;
  * -------------------
  * |-  counter val  -|
  * -------------------
- * dcntr -     Current 16-bit downcounter value.
- *                     When downcounter reaches '0' watchdog expires.
- *                     Reading this register resets downcounter with
- *                     'limit' value.
- * limit -     16-bit countdown value in 1/10th second increments.
- *                     Writing this register begins countdown with input value.
- *                     Reading from this register does not affect counter.
+ * dcntr -     Current 16-bit downcounter value.
+ *                     When downcounter reaches '0' watchdog expires.
+ *                     Reading this register resets downcounter with
+ *                     'limit' value.
+ * limit -     16-bit countdown value in 1/10th second increments.
+ *                     Writing this register begins countdown with input value.
+ *                     Reading from this register does not affect counter.
  * NOTES:      After watchdog reset, dcntr and limit contain '1'
  *
  * status register (byte access):
@@ -123,7 +123,7 @@ static struct cpwd *cpwd_device;
  * |-   UNUSED  -| EXP | RUN |
  * ---------------------------
  * status-     Bit 0 - Watchdog is running
- *                     Bit 1 - Watchdog has expired
+ *                     Bit 1 - Watchdog has expired
  *
  *** PLD register block definition (struct wd_pld_regblk)
  *
@@ -197,7 +197,7 @@ static u8 cpwd_readb(void __iomem *addr)
  * Because of the CP1400 defect this should only be
  * called during initialzation or by wd_[start|stop]timer()
  *
- * index       - sub-device index, or -1 for 'all'
+ * index       - sub-device index, or -1 for 'all'
  * enable      - non-zero to enable interrupts, zero to disable
  */
 static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
@@ -317,13 +317,13 @@ static int cpwd_getstatus(struct cpwd *p, int index)
                } else {
                        /* Fudge WD_EXPIRED status for defective CP1400--
                         * IF timer is running
-                        *      AND brokenstop is set
-                        *      AND an interrupt has been serviced
+                        *      AND brokenstop is set
+                        *      AND an interrupt has been serviced
                         * we are WD_EXPIRED.
                         *
                         * IF timer is running
-                        *      AND brokenstop is set
-                        *      AND no interrupt has been serviced
+                        *      AND brokenstop is set
+                        *      AND no interrupt has been serviced
                         * we are WD_FREERUN.
                         */
                        if (p->broken &&
@@ -613,7 +613,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
 
        if (p->broken) {
                init_timer(&cpwd_timer);
-               cpwd_timer.function     = cpwd_brokentimer;
+               cpwd_timer.function     = cpwd_brokentimer;
                cpwd_timer.data         = (unsigned long) p;
                cpwd_timer.expires      = WD_BTIMEOUT;
 
index 3f3dc093ad68030d4d22442df70cfd532ace9039..f1d1da662fbec73262f98e9289884184f67a30d0 100644 (file)
@@ -201,7 +201,7 @@ static void eurwdt_ping(void)
 static ssize_t eurwdt_write(struct file *file, const char __user *buf,
 size_t count, loff_t *ppos)
 {
-       if (count)      {
+       if (count) {
                if (!nowayout) {
                        size_t i;
 
index 204a5603c4ae34e44d1df071a9af24c832a83a81..8cb26855bfede30eeb6782f693a29add442cdaa1 100644 (file)
@@ -52,7 +52,7 @@ static void __iomem *pci_mem_addr;            /* the PCI-memory address */
 static unsigned long __iomem *hpwdt_timer_reg;
 static unsigned long __iomem *hpwdt_timer_con;
 
-static struct pci_device_id hpwdt_devices[] = {
+static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = {
        { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) },   /* iLO2 */
        { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) },       /* iLO3 */
        {0},                    /* terminate list */
index bb9750a03942fb8786c0bcaddd32732e2266d866..db45091ef4349c93b039da2efe1deace7e5cf7e3 100644 (file)
@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = {
 /*
  * Data for PCI driver interface
  */
-static struct pci_device_id esb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
        { 0, },                 /* End of list */
 };
index 2c6c2b4ad8bf5f8a6d1cfbd68d923fb4da2fc4cf..35a0d12dad7351340fdd1cfc8b84cb221556e059 100644 (file)
@@ -247,7 +247,7 @@ static struct {
        {NULL, 0}
 };
 
-#define ITCO_PCI_DEVICE(dev, data)     \
+#define ITCO_PCI_DEVICE(dev, data) \
        .vendor = PCI_VENDOR_ID_INTEL,  \
        .device = dev,                  \
        .subvendor = PCI_ANY_ID,        \
@@ -262,7 +262,7 @@ static struct {
  * 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[] = {
+static DEFINE_PCI_DEVICE_TABLE(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)},
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
new file mode 100644 (file)
index 0000000..919bdd1
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ *      Intel_SCU 0.2:  An Intel SCU IOH Based Watchdog Device
+ *                     for Intel part #(s):
+ *                             - AF82MP20 PCH
+ *
+ *      Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License as published by the Free Software Foundation.
+ *
+ *      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.
+ *      The full GNU General Public License is included in this
+ *      distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sfi.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/intel_scu_ipc.h>
+#include <asm/apb_timer.h>
+#include <asm/mrst.h>
+
+#include "intel_scu_watchdog.h"
+
+/* Bounds number of times we will retry loading time count */
+/* This retry is a work around for a silicon bug.         */
+#define MAX_RETRY 16
+
+#define IPC_SET_WATCHDOG_TIMER 0xF8
+
+static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
+module_param(timer_margin, int, 0);
+MODULE_PARM_DESC(timer_margin,
+               "Watchdog timer margin"
+               "Time between interrupt and resetting the system"
+               "The range is from 1 to 160"
+               "This is the time for all keep alives to arrive");
+
+static int timer_set = DEFAULT_TIME;
+module_param(timer_set, int, 0);
+MODULE_PARM_DESC(timer_set,
+               "Default Watchdog timer setting"
+               "Complete cycle time"
+               "The range is from 1 to 170"
+               "This is the time for all keep alives to arrive");
+
+/* After watchdog device is closed, check force_boot. If:
+ * force_boot == 0, then force boot on next watchdog interrupt after close,
+ * force_boot == 1, then force boot immediately when device is closed.
+ */
+static int force_boot;
+module_param(force_boot, int, 0);
+MODULE_PARM_DESC(force_boot,
+               "A value of 1 means that the driver will reboot"
+               "the system immediately if the /dev/watchdog device is closed"
+               "A value of 0 means that when /dev/watchdog device is closed"
+               "the watchdog timer will be refreshed for one more interval"
+               "of length: timer_set. At the end of this interval, the"
+               "watchdog timer will reset the system."
+               );
+
+/* there is only one device in the system now; this can be made into
+ * an array in the future if we have more than one device */
+
+static struct intel_scu_watchdog_dev watchdog_device;
+
+/* Forces restart, if force_reboot is set */
+static void watchdog_fire(void)
+{
+       if (force_boot) {
+               printk(KERN_CRIT PFX "Initiating system reboot.\n");
+               emergency_restart();
+               printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+       }
+
+       else {
+               printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
+               printk(KERN_CRIT PFX
+                       "System will reset when watchdog timer times out!\n");
+       }
+}
+
+static int check_timer_margin(int new_margin)
+{
+       if ((new_margin < MIN_TIME_CYCLE) ||
+           (new_margin > MAX_TIME - timer_set)) {
+               pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
+                         new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * IPC operations
+ */
+static int watchdog_set_ipc(int soft_threshold, int threshold)
+{
+       u32     *ipc_wbuf;
+       u8       cbuf[16] = { '\0' };
+       int      ipc_ret = 0;
+
+       ipc_wbuf = (u32 *)&cbuf;
+       ipc_wbuf[0] = soft_threshold;
+       ipc_wbuf[1] = threshold;
+
+       ipc_ret = intel_scu_ipc_command(
+                       IPC_SET_WATCHDOG_TIMER,
+                       0,
+                       ipc_wbuf,
+                       2,
+                       NULL,
+                       0);
+
+       if (ipc_ret != 0)
+               pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
+
+       return ipc_ret;
+};
+
+/*
+ *      Intel_SCU operations
+ */
+
+/* timer interrupt handler */
+static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
+{
+       int int_status;
+       int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
+
+       pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
+
+       if (int_status != 0)
+               return IRQ_NONE;
+
+       /* has the timer been started? If not, then this is spurious */
+       if (watchdog_device.timer_started == 0) {
+               pr_debug("Watchdog timer: spurious interrupt received\n");
+               return IRQ_HANDLED;
+       }
+
+       /* temporarily disable the timer */
+       iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+       /* set the timer to the threshold */
+       iowrite32(watchdog_device.threshold,
+                 watchdog_device.timer_load_count_addr);
+
+       /* allow the timer to run */
+       iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+       return IRQ_HANDLED;
+}
+
+static int intel_scu_keepalive(void)
+{
+
+       /* read eoi register - clears interrupt */
+       ioread32(watchdog_device.timer_clear_interrupt_addr);
+
+       /* temporarily disable the timer */
+       iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+       /* set the timer to the soft_threshold */
+       iowrite32(watchdog_device.soft_threshold,
+                 watchdog_device.timer_load_count_addr);
+
+       /* allow the timer to run */
+       iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+       return 0;
+}
+
+static int intel_scu_stop(void)
+{
+       iowrite32(0, watchdog_device.timer_control_addr);
+       return 0;
+}
+
+static int intel_scu_set_heartbeat(u32 t)
+{
+       int                      ipc_ret;
+       int                      retry_count;
+       u32                      soft_value;
+       u32                      hw_pre_value;
+       u32                      hw_value;
+
+       watchdog_device.timer_set = t;
+       watchdog_device.threshold =
+               timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+       watchdog_device.soft_threshold =
+               (watchdog_device.timer_set - timer_margin)
+               * watchdog_device.timer_tbl_ptr->freq_hz;
+
+       pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
+               watchdog_device.timer_tbl_ptr->freq_hz);
+       pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
+               watchdog_device.timer_set);
+       pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
+               timer_margin);
+       pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
+               watchdog_device.threshold);
+       pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
+               watchdog_device.soft_threshold);
+
+       /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
+       /* watchdog timing come out right. */
+       watchdog_device.threshold =
+               watchdog_device.threshold / FREQ_ADJUSTMENT;
+       watchdog_device.soft_threshold =
+               watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
+
+       /* temporarily disable the timer */
+       iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+       /* send the threshold and soft_threshold via IPC to the processor */
+       ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
+                                  watchdog_device.threshold);
+
+       if (ipc_ret != 0) {
+               /* Make sure the watchdog timer is stopped */
+               intel_scu_stop();
+               return ipc_ret;
+       }
+
+       /* Soft Threshold set loop. Early versions of silicon did */
+       /* not always set this count correctly.  This loop checks */
+       /* the value and retries if it was not set correctly.     */
+
+       retry_count = 0;
+       soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
+       do {
+
+               /* Make sure timer is stopped */
+               intel_scu_stop();
+
+               if (MAX_RETRY < retry_count++) {
+                       /* Unable to set timer value */
+                       pr_err("Watchdog timer: Unable to set timer\n");
+                       return -ENODEV;
+               }
+
+               /* set the timer to the soft threshold */
+               iowrite32(watchdog_device.soft_threshold,
+                       watchdog_device.timer_load_count_addr);
+
+               /* read count value before starting timer */
+               hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
+               hw_pre_value = hw_pre_value & 0xFFFF0000;
+
+               /* Start the timer */
+               iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+               /* read the value the time loaded into its count reg */
+               hw_value = ioread32(watchdog_device.timer_load_count_addr);
+               hw_value = hw_value & 0xFFFF0000;
+
+
+       } while (soft_value != hw_value);
+
+       watchdog_device.timer_started = 1;
+
+       return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int intel_scu_open(struct inode *inode, struct file *file)
+{
+
+       /* Set flag to indicate that watchdog device is open */
+       if (test_and_set_bit(0, &watchdog_device.driver_open))
+               return -EBUSY;
+
+       /* Check for reopen of driver. Reopens are not allowed */
+       if (watchdog_device.driver_closed)
+               return -EPERM;
+
+       return nonseekable_open(inode, file);
+}
+
+static int intel_scu_release(struct inode *inode, struct file *file)
+{
+       /*
+        * This watchdog should not be closed, after the timer
+        * is started with the WDIPC_SETTIMEOUT ioctl
+        * If force_boot is set watchdog_fire() will cause an
+        * immediate reset. If force_boot is not set, the watchdog
+        * timer is refreshed for one more interval. At the end
+        * of that interval, the watchdog timer will reset the system.
+        */
+
+       if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
+               pr_debug("Watchdog timer: intel_scu_release, without open\n");
+               return -ENOTTY;
+       }
+
+       if (!watchdog_device.timer_started) {
+               /* Just close, since timer has not been started */
+               pr_debug("Watchdog timer: closed, without starting timer\n");
+               return 0;
+       }
+
+       printk(KERN_CRIT PFX
+              "Unexpected close of /dev/watchdog!\n");
+
+       /* Since the timer was started, prevent future reopens */
+       watchdog_device.driver_closed = 1;
+
+       /* Refresh the timer for one more interval */
+       intel_scu_keepalive();
+
+       /* Reboot system (if force_boot is set) */
+       watchdog_fire();
+
+       /* We should only reach this point if force_boot is not set */
+       return 0;
+}
+
+static ssize_t intel_scu_write(struct file *file,
+                             char const *data,
+                             size_t len,
+                             loff_t *ppos)
+{
+
+       if (watchdog_device.timer_started)
+               /* Watchdog already started, keep it alive */
+               intel_scu_keepalive();
+       else
+               /* Start watchdog with timer value set by init */
+               intel_scu_set_heartbeat(watchdog_device.timer_set);
+
+       return len;
+}
+
+static long intel_scu_ioctl(struct file *file,
+                          unsigned int cmd,
+                          unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       u32 __user *p = argp;
+       u32 new_margin;
+
+
+       static const struct watchdog_info ident = {
+               .options =          WDIOF_SETTIMEOUT
+                                   | WDIOF_KEEPALIVEPING,
+               .firmware_version = 0,  /* @todo Get from SCU via
+                                                ipc_get_scu_fw_version()? */
+               .identity =         "Intel_SCU IOH Watchdog"  /* len < 32 */
+       };
+
+       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:
+               intel_scu_keepalive();
+
+               return 0;
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_margin, p))
+                       return -EFAULT;
+
+               if (check_timer_margin(new_margin))
+                       return -EINVAL;
+
+               if (intel_scu_set_heartbeat(new_margin))
+                       return -EINVAL;
+               return 0;
+       case WDIOC_GETTIMEOUT:
+               return put_user(watchdog_device.soft_threshold, p);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+/*
+ *      Notifier for system down
+ */
+static int intel_scu_notify_sys(struct notifier_block *this,
+                              unsigned long code,
+                              void *another_unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               /* Turn off the watchdog timer. */
+               intel_scu_stop();
+       return NOTIFY_DONE;
+}
+
+/*
+ *      Kernel Interfaces
+ */
+static const struct file_operations intel_scu_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = intel_scu_write,
+       .unlocked_ioctl = intel_scu_ioctl,
+       .open           = intel_scu_open,
+       .release        = intel_scu_release,
+};
+
+static int __init intel_scu_watchdog_init(void)
+{
+       int ret;
+       u32 __iomem *tmp_addr;
+
+       /*
+        * We don't really need to check this as the SFI timer get will fail
+        * but if we do so we can exit with a clearer reason and no noise.
+        *
+        * If it isn't an intel MID device then it doesn't have this watchdog
+        */
+       if (!mrst_identify_cpu())
+               return -ENODEV;
+
+       /* Check boot parameters to verify that their initial values */
+       /* are in range. */
+       /* Check value of timer_set boot parameter */
+       if ((timer_set < MIN_TIME_CYCLE) ||
+           (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
+               pr_err("Watchdog timer: value of timer_set %x (hex) "
+                 "is out of range from %x to %x (hex)\n",
+                 timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+               return -EINVAL;
+       }
+
+       /* Check value of timer_margin boot parameter */
+       if (check_timer_margin(timer_margin))
+               return -EINVAL;
+
+       watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
+
+       if (watchdog_device.timer_tbl_ptr == NULL) {
+               pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
+               return -ENODEV;
+       }
+       /* make sure the timer exists */
+       if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
+               pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
+                                                               sfi_mtimer_num);
+               return -ENODEV;
+       }
+
+       if (watchdog_device.timer_tbl_ptr->irq == 0) {
+               pr_debug("Watchdog timer: timer %d invalid irq\n",
+                                                       sfi_mtimer_num);
+               return -ENODEV;
+       }
+
+       tmp_addr = ioremap_nocache(watchdog_device.timer_tbl_ptr->phys_addr,
+                       20);
+
+       if (tmp_addr == NULL) {
+               pr_debug("Watchdog timer: timer unable to ioremap\n");
+               return -ENOMEM;
+       }
+
+       watchdog_device.timer_load_count_addr = tmp_addr++;
+       watchdog_device.timer_current_value_addr = tmp_addr++;
+       watchdog_device.timer_control_addr = tmp_addr++;
+       watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
+       watchdog_device.timer_interrupt_status_addr = tmp_addr++;
+
+       /* Set the default time values in device structure */
+
+       watchdog_device.timer_set = timer_set;
+       watchdog_device.threshold =
+               timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+       watchdog_device.soft_threshold =
+               (watchdog_device.timer_set - timer_margin)
+               * watchdog_device.timer_tbl_ptr->freq_hz;
+
+
+       watchdog_device.intel_scu_notifier.notifier_call =
+               intel_scu_notify_sys;
+
+       ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
+       if (ret) {
+               pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
+               goto register_reboot_error;
+       }
+
+       watchdog_device.miscdev.minor = WATCHDOG_MINOR;
+       watchdog_device.miscdev.name = "watchdog";
+       watchdog_device.miscdev.fops = &intel_scu_fops;
+
+       ret = misc_register(&watchdog_device.miscdev);
+       if (ret) {
+               pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
+                                                       WATCHDOG_MINOR, ret);
+               goto misc_register_error;
+       }
+
+       ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
+               watchdog_timer_interrupt,
+               IRQF_SHARED, "watchdog",
+               &watchdog_device.timer_load_count_addr);
+       if (ret) {
+               pr_err("Watchdog timer: error requesting irq %d\n", ret);
+               goto request_irq_error;
+       }
+       /* Make sure timer is disabled before returning */
+       intel_scu_stop();
+       return 0;
+
+/* error cleanup */
+
+request_irq_error:
+       misc_deregister(&watchdog_device.miscdev);
+misc_register_error:
+       unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+register_reboot_error:
+       intel_scu_stop();
+       iounmap(watchdog_device.timer_load_count_addr);
+       return ret;
+}
+
+static void __exit intel_scu_watchdog_exit(void)
+{
+
+       misc_deregister(&watchdog_device.miscdev);
+       unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+       /* disable the timer */
+       iowrite32(0x00000002, watchdog_device.timer_control_addr);
+       iounmap(watchdog_device.timer_load_count_addr);
+}
+
+late_initcall(intel_scu_watchdog_init);
+module_exit(intel_scu_watchdog_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_VERSION(WDT_VER);
diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h
new file mode 100644 (file)
index 0000000..d2b074a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *      Intel_SCU 0.2:  An Intel SCU IOH Based Watchdog Device
+ *                     for Intel part #(s):
+ *                             - AF82MP20 PCH
+ *
+ *      Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License as published by the Free Software Foundation.
+ *
+ *      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.
+ *      The full GNU General Public License is included in this
+ *      distribution in the file called COPYING.
+ *
+ */
+
+#ifndef __INTEL_SCU_WATCHDOG_H
+#define __INTEL_SCU_WATCHDOG_H
+
+#define PFX "Intel_SCU: "
+#define WDT_VER "0.3"
+
+/* minimum time between interrupts */
+#define MIN_TIME_CYCLE 1
+
+/* Time from warning to reboot is 2 seconds */
+#define DEFAULT_SOFT_TO_HARD_MARGIN 2
+
+#define MAX_TIME 170
+
+#define DEFAULT_TIME 5
+
+#define MAX_SOFT_TO_HARD_MARGIN (MAX_TIME-MIN_TIME_CYCLE)
+
+/* Ajustment to clock tick frequency to make timing come out right */
+#define FREQ_ADJUSTMENT 8
+
+struct intel_scu_watchdog_dev {
+       ulong driver_open;
+       ulong driver_closed;
+       u32 timer_started;
+       u32 timer_set;
+       u32 threshold;
+       u32 soft_threshold;
+       u32 __iomem *timer_load_count_addr;
+       u32 __iomem *timer_current_value_addr;
+       u32 __iomem *timer_control_addr;
+       u32 __iomem *timer_clear_interrupt_addr;
+       u32 __iomem *timer_interrupt_status_addr;
+       struct sfi_timer_table_entry *timer_tbl_ptr;
+       struct notifier_block intel_scu_notifier;
+       struct miscdevice miscdev;
+};
+
+extern int sfi_mtimer_num;
+
+/* extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); */
+#endif /* __INTEL_SCU_WATCHDOG_H */
index b32c6c045b1ad0cd34758e4e90d673bf9ccf4f7f..6143f52ba6b8d4f019794cb04896e8dc20de4e18 100644 (file)
@@ -69,7 +69,7 @@ static unsigned short address;
 #define IT8712F_DEVID  0x8712
 
 #define LDN_GPIO       0x07    /* GPIO and Watch Dog Timer */
-#define LDN_GAME       0x09    /* Game Port */
+#define LDN_GAME       0x09    /* Game Port */
 
 #define WDT_CONTROL    0x71    /* WDT Register: Control */
 #define WDT_CONFIG     0x72    /* WDT Register: Configuration */
index dad29245a6a7ed0617ef3c976a47c3c65257b710..b1bc72f9a20940f1be3d341f29b5fc9567fcede6 100644 (file)
@@ -12,7 +12,7 @@
  *                 http://www.ite.com.tw/
  *
  *     Support of the watchdog timers, which are available on
- *     IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726.
+ *     IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -45,7 +45,7 @@
 
 #include <asm/system.h>
 
-#define WATCHDOG_VERSION       "1.13"
+#define WATCHDOG_VERSION       "1.14"
 #define WATCHDOG_NAME          "IT87 WDT"
 #define PFX                    WATCHDOG_NAME ": "
 #define DRIVER_VERSION         WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
@@ -54,7 +54,7 @@
 /* Defaults for Module Parameter */
 #define DEFAULT_NOGAMEPORT     0
 #define DEFAULT_EXCLUSIVE      1
-#define DEFAULT_TIMEOUT        60
+#define DEFAULT_TIMEOUT                60
 #define DEFAULT_TESTMODE       0
 #define DEFAULT_NOWAYOUT       WATCHDOG_NOWAYOUT
 
@@ -70,9 +70,9 @@
 /* Configuration Registers and Functions */
 #define LDNREG         0x07
 #define CHIPID         0x20
-#define CHIPREV        0x22
+#define CHIPREV                0x22
 #define ACTREG         0x30
-#define BASEREG        0x60
+#define BASEREG                0x60
 
 /* Chip Id numbers */
 #define NO_DEV_ID      0xffff
 #define IT8716_ID      0x8716
 #define IT8718_ID      0x8718
 #define IT8720_ID      0x8720
+#define IT8721_ID      0x8721
 #define IT8726_ID      0x8726  /* the data sheet suggest wrongly 0x8716 */
 
 /* GPIO Configuration Registers LDN=0x07 */
-#define WDTCTRL        0x71
+#define WDTCTRL                0x71
 #define WDTCFG         0x72
 #define WDTVALLSB      0x73
 #define WDTVALMSB      0x74
@@ -94,7 +95,7 @@
 #define WDT_CIRINT     0x80
 #define WDT_MOUSEINT   0x40
 #define WDT_KYBINT     0x20
-#define WDT_GAMEPORT   0x10 /* not in it8718, it8720 */
+#define WDT_GAMEPORT   0x10 /* not in it8718, it8720, it8721 */
 #define WDT_FORCE      0x02
 #define WDT_ZERO       0x01
 
 #define WDT_TOV1       0x80
 #define WDT_KRST       0x40
 #define WDT_TOVE       0x20
-#define WDT_PWROK      0x10
+#define WDT_PWROK      0x10 /* not in it8721 */
 #define WDT_INT_MASK   0x0f
 
 /* CIR Configuration Register LDN=0x0a */
-#define CIR_ILS        0x70
+#define CIR_ILS                0x70
 
 /* The default Base address is not always available, we use this */
 #define CIR_BASE       0x0208
 #define WDTS_USE_GP    4
 #define WDTS_EXPECTED  5
 
-static unsigned int base, gpact, ciract, max_units;
+static unsigned int base, gpact, ciract, max_units, chip_type;
 static unsigned long wdt_status;
 static DEFINE_SPINLOCK(spinlock);
 
@@ -215,7 +216,7 @@ static inline void superio_outw(int val, int reg)
 /* Internal function, should be called after superio_select(GPIO) */
 static void wdt_update_timeout(void)
 {
-       unsigned char cfg = WDT_KRST | WDT_PWROK;
+       unsigned char cfg = WDT_KRST;
        int tm = timeout;
 
        if (testmode)
@@ -226,6 +227,9 @@ static void wdt_update_timeout(void)
        else
                tm /= 60;
 
+       if (chip_type != IT8721_ID)
+               cfg |= WDT_PWROK;
+
        superio_outb(cfg, WDTCFG);
        superio_outb(tm, WDTVALLSB);
        if (max_units > 255)
@@ -555,7 +559,6 @@ static int __init it87_wdt_init(void)
 {
        int rc = 0;
        int try_gameport = !nogameport;
-       u16 chip_type;
        u8  chip_rev;
        unsigned long flags;
 
@@ -581,6 +584,7 @@ static int __init it87_wdt_init(void)
                break;
        case IT8718_ID:
        case IT8720_ID:
+       case IT8721_ID:
                max_units = 65535;
                try_gameport = 0;
                break;
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
new file mode 100644 (file)
index 0000000..684ba01
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ *  Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net>
+ *  JZ4740 Watchdog driver
+ *
+ *  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.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <asm/mach-jz4740/timer.h>
+
+#define JZ_REG_WDT_TIMER_DATA     0x0
+#define JZ_REG_WDT_COUNTER_ENABLE 0x4
+#define JZ_REG_WDT_TIMER_COUNTER  0x8
+#define JZ_REG_WDT_TIMER_CONTROL  0xC
+
+#define JZ_WDT_CLOCK_PCLK 0x1
+#define JZ_WDT_CLOCK_RTC  0x2
+#define JZ_WDT_CLOCK_EXT  0x4
+
+#define WDT_IN_USE        0
+#define WDT_OK_TO_CLOSE   1
+
+#define JZ_WDT_CLOCK_DIV_SHIFT   3
+
+#define JZ_WDT_CLOCK_DIV_1    (0 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_4    (1 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_16   (2 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_64   (3 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_256  (4 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_1024 (5 << JZ_WDT_CLOCK_DIV_SHIFT)
+
+#define DEFAULT_HEARTBEAT 5
+#define MAX_HEARTBEAT     2048
+
+static struct {
+       void __iomem *base;
+       struct resource *mem;
+       struct clk *rtc_clk;
+       unsigned long status;
+} jz4740_wdt;
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+
+static void jz4740_wdt_service(void)
+{
+       writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+}
+
+static void jz4740_wdt_set_heartbeat(int new_heartbeat)
+{
+       unsigned int rtc_clk_rate;
+       unsigned int timeout_value;
+       unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
+
+       heartbeat = new_heartbeat;
+
+       rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
+
+       timeout_value = rtc_clk_rate * heartbeat;
+       while (timeout_value > 0xffff) {
+               if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
+                       /* Requested timeout too high;
+                       * use highest possible value. */
+                       timeout_value = 0xffff;
+                       break;
+               }
+               timeout_value >>= 2;
+               clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
+       }
+
+       writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+       writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+
+       writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
+       writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+       writew(clock_div | JZ_WDT_CLOCK_RTC,
+               jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+
+       writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+}
+
+static void jz4740_wdt_enable(void)
+{
+       jz4740_timer_enable_watchdog();
+       jz4740_wdt_set_heartbeat(heartbeat);
+}
+
+static void jz4740_wdt_disable(void)
+{
+       jz4740_timer_disable_watchdog();
+       writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+}
+
+static int jz4740_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
+               return -EBUSY;
+
+       jz4740_wdt_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t jz4740_wdt_write(struct file *file, const char *data,
+               size_t len, loff_t *ppos)
+{
+       if (len) {
+               size_t i;
+
+               clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
+               for (i = 0; i != len; i++) {
+                       char c;
+
+                       if (get_user(c, data + i))
+                               return -EFAULT;
+
+                       if (c == 'V')
+                               set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
+               }
+               jz4740_wdt_service();
+       }
+
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options = WDIOF_KEEPALIVEPING,
+       .identity = "jz4740 Watchdog",
+};
+
+static long jz4740_wdt_ioctl(struct file *file,
+                                       unsigned int cmd, unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int heartbeat_seconds;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                               sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               jz4740_wdt_service();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(heartbeat_seconds, (int __user *)arg))
+                       return -EFAULT;
+
+               jz4740_wdt_set_heartbeat(heartbeat_seconds);
+               return 0;
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(heartbeat, (int *)arg);
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static int jz4740_wdt_release(struct inode *inode, struct file *file)
+{
+       jz4740_wdt_service();
+
+       if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
+               jz4740_wdt_disable();
+
+       clear_bit(WDT_IN_USE, &jz4740_wdt.status);
+       return 0;
+}
+
+static const struct file_operations jz4740_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = jz4740_wdt_write,
+       .unlocked_ioctl = jz4740_wdt_ioctl,
+       .open = jz4740_wdt_open,
+       .release = jz4740_wdt_release,
+};
+
+static struct miscdevice jz4740_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &jz4740_wdt_fops,
+};
+
+static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
+{
+       int ret = 0, size;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "failed to get memory region resource\n");
+               return -ENXIO;
+       }
+
+       size = resource_size(res);
+       jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
+       if (jz4740_wdt.mem == NULL) {
+               dev_err(dev, "failed to get memory region\n");
+               return -EBUSY;
+       }
+
+       jz4740_wdt.base = ioremap_nocache(res->start, size);
+       if (jz4740_wdt.base == NULL) {
+               dev_err(dev, "failed to map memory region\n");
+               ret = -EBUSY;
+               goto err_release_region;
+       }
+
+       jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
+       if (IS_ERR(jz4740_wdt.rtc_clk)) {
+               dev_err(dev, "cannot find RTC clock\n");
+               ret = PTR_ERR(jz4740_wdt.rtc_clk);
+               goto err_iounmap;
+       }
+
+       ret = misc_register(&jz4740_wdt_miscdev);
+       if (ret < 0) {
+               dev_err(dev, "cannot register misc device\n");
+               goto err_disable_clk;
+       }
+
+       return 0;
+
+err_disable_clk:
+       clk_put(jz4740_wdt.rtc_clk);
+err_iounmap:
+       iounmap(jz4740_wdt.base);
+err_release_region:
+       release_mem_region(jz4740_wdt.mem->start,
+                       resource_size(jz4740_wdt.mem));
+       return ret;
+}
+
+
+static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
+{
+       jz4740_wdt_disable();
+       misc_deregister(&jz4740_wdt_miscdev);
+       clk_put(jz4740_wdt.rtc_clk);
+
+       iounmap(jz4740_wdt.base);
+       jz4740_wdt.base = NULL;
+
+       release_mem_region(jz4740_wdt.mem->start,
+                               resource_size(jz4740_wdt.mem));
+       jz4740_wdt.mem = NULL;
+
+       return 0;
+}
+
+
+static struct platform_driver jz4740_wdt_driver = {
+       .probe = jz4740_wdt_probe,
+       .remove = __devexit_p(jz4740_wdt_remove),
+       .driver = {
+               .name = "jz4740-wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+
+static int __init jz4740_wdt_init(void)
+{
+       return platform_driver_register(&jz4740_wdt_driver);
+}
+module_init(jz4740_wdt_init);
+
+static void __exit jz4740_wdt_exit(void)
+{
+       platform_driver_unregister(&jz4740_wdt_driver);
+}
+module_exit(jz4740_wdt_exit);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("jz4740 Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+               "Watchdog heartbeat period in seconds from 1 to "
+               __MODULE_STRING(MAX_HEARTBEAT) ", default "
+               __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:jz4740-wdt");
index 928035069396e8117dedca9c5284b7841057d372..1332b838cc5830f0be76fe104abdcf8c4e40cd93 100644 (file)
@@ -54,7 +54,7 @@
 
 /* indexes */                  /* size */
 #define ZFL_VERSION    0x02    /* 16   */
-#define CONTROL        0x10    /* 16   */
+#define CONTROL                0x10    /* 16   */
 #define STATUS         0x12    /* 8    */
 #define COUNTER_1      0x0C    /* 16   */
 #define COUNTER_2      0x0E    /* 8    */
index 3053ff05ca410b7d4fba52cadd7d86071d3c4896..7a82ce5a6337e3948adc1d9e42eab5c72aecf654 100644 (file)
@@ -41,7 +41,7 @@ static int nowayout  = WATCHDOG_NOWAYOUT;
  * to ping the watchdog.
  */
 #define MAX6369_WDSET  (7 << 0)
-#define MAX6369_WDI    (1 << 3)
+#define MAX6369_WDI    (1 << 3)
 
 static DEFINE_SPINLOCK(io_lock);
 
index ea438ad530559c401cba603e970a5564234c9092..6709d723e017a0965ac179ccd6513c127c152e51 100644 (file)
@@ -2,9 +2,9 @@
  * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
  *
  * Authors: Dave Updegraff <dave@cray.org>
- *         Kumar Gala <galak@kernel.crashing.org>
- *             Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
- *                             ..and from sc520_wdt
+ *         Kumar Gala <galak@kernel.crashing.org>
+ *             Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
+ *                             ..and from sc520_wdt
  * Copyright (c) 2008  MontaVista Software, Inc.
  *                     Anton Vorontsov <avorontsov@ru.mvista.com>
  *
index b8ec7aca3c8ea4696c96a5cb2d6f000905577ab9..2b4af222b5f260647de91b8bba56cd68b4ba8659 100644 (file)
@@ -172,7 +172,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
 
        /*
         *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
+        *      Lock it in if it's a module and we set nowayout
         */
        if (wdt->expect_close == 42)
                mpcore_wdt_stop(wdt);
index 08e8a6ab74e11f11c3ea22cddc4a785cc9c1aaf0..5ec5ac1f78782296c5343ac07ec43932f25ad14e 100644 (file)
@@ -190,19 +190,19 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
 }
 
 static const struct file_operations mtx1_wdt_fops = {
-       .owner          = THIS_MODULE,
+       .owner          = THIS_MODULE,
        .llseek         = no_llseek,
        .unlocked_ioctl = mtx1_wdt_ioctl,
-       .open           = mtx1_wdt_open,
-       .write          = mtx1_wdt_write,
-       .release        = mtx1_wdt_release,
+       .open           = mtx1_wdt_open,
+       .write          = mtx1_wdt_write,
+       .release        = mtx1_wdt_release,
 };
 
 
 static struct miscdevice mtx1_wdt_misc = {
-       .minor  = WATCHDOG_MINOR,
-       .name   = "watchdog",
-       .fops   = &mtx1_wdt_fops,
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &mtx1_wdt_fops,
 };
 
 
index 1a50aa7079bfed3ca4b20f1bd12222f9f2e0b8c6..267377a5a83ebf9311995541c92bc2adf5740086 100644 (file)
@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = {
  * 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 tco_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tco_pci_tbl) = {
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
index fc02ec6a03869a6a6bb0daa9889b1ebf10d558ec..09b774cf75b9be8ebd83fefbdbc199e2c432a631 100644 (file)
@@ -44,7 +44,7 @@
  * months before firing.  These limits work without scaling,
  * with the 60 second default assumed by most tools and docs.
  */
-#define TIMER_MARGIN_MAX       (24 * 60 * 60)  /* 1 day */
+#define TIMER_MARGIN_MAX       (24 * 60 * 60)  /* 1 day */
 #define TIMER_MARGIN_DEFAULT   60      /* 60 secs */
 #define TIMER_MARGIN_MIN       1
 
index 3a56bc3609247f4fbb6e8fe5fffd5bacb2e209d1..139d773300c6f29feb8bb3128919027736347c3d 100644 (file)
@@ -514,7 +514,7 @@ static struct miscdevice pc87413_miscdev = {
 /* -- Module init functions -------------------------------------*/
 
 /**
- *     pc87413_init: module's "constructor"
+ *     pc87413_init: module's "constructor"
  *
  *     Set up the WDT watchdog board. All we have to do is grab the
  *     resources we require and bitch if anyone beat us to them.
index 64374d636f096aaa8b18a6fdee7bb83800c1e6d5..b8d14f88f0b53bec64e81164538d605d7653ef48 100644 (file)
@@ -817,7 +817,7 @@ static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
        cards_found--;
 }
 
-static struct pci_device_id pcipcwd_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = {
        { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0 },                  /* End of list */
index bf5b97c546eb4d699edbbd0fa3aa3f22727c7570..c7cf4cbf8ab3f302c2efc75bebf7f5a752d2d08b 100644 (file)
@@ -4,7 +4,7 @@
  * Watchdog driver for PNX4008 board
  *
  * Authors: Dmitry Chigirev <source@mvista.com>,
- *         Vitaly Wool <vitalywool@gmail.com>
+ *         Vitaly Wool <vitalywool@gmail.com>
  * Based on sa1100 driver,
  * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
  *
index ae53662c29bce78ce4a674155e7ee24577818950..25b39bf35925b11bc1b1f4c2edc2c15dfd6c66cc 100644 (file)
@@ -224,7 +224,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
 {
        /*
         *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
+        *      Lock it in if it's a module and we set nowayout
         */
 
        if (expect_close == 42)
index 68e2e2d6f73d80a085660baa78fe7fbbc736a6df..514ec23050f7814565a209649c809f0763426151 100644 (file)
@@ -114,7 +114,7 @@ static char expect_close;
  *     C |     6.5s    65s     650s    1300s
  *     D |     7s      70s     700s    1400s
  *     E |     7.5s    75s     750s    1500s
- *     F |     8s      80s     800s    1600s
+ *     F |     8s      80s     800s    1600s
  *
  * Another way to say the same things is:
  *  For N=1, Timeout = (M+1) * 0.5s
index 79906255eeb6bde9b6bd6ebb5653280833819b50..d5d399464599f3dcc43accc1ba861ee5bc24a1d8 100644 (file)
@@ -41,7 +41,7 @@ static DEFINE_MUTEX(wdt_lock);
 #define IFACE_ON_COMMAND       1
 #define REBOOT_COMMAND         2
 
-#define WATCHDOG_NAME          "SBC-FITPC2 Watchdog"
+#define WATCHDOG_NAME          "SBC-FITPC2 Watchdog"
 
 static void wdt_send_data(unsigned char command, unsigned char data)
 {
index 8a1f0bc3e271f3b7d52f86650837fee402a912e3..df88cfa05f35c59d02be9622c804ea09edb7346c 100644 (file)
@@ -434,11 +434,11 @@ static long wb_smsc_wdt_ioctl(struct file *file,
        } uarg;
 
        static const struct watchdog_info ident = {
-               .options =              WDIOF_KEEPALIVEPING |
+               .options =              WDIOF_KEEPALIVEPING |
                                        WDIOF_SETTIMEOUT |
                                        WDIOF_MAGICCLOSE,
                .firmware_version =     0,
-               .identity =             "SMsC 37B787 Watchdog",
+               .identity =             "SMsC 37B787 Watchdog",
        };
 
        uarg.i = (int __user *)arg;
index 833f49f43d43b61ca6267dd5bdf7aaa2bbea31b3..100b114e3c3c754bcffe7fb7b1abb28c951c9bf3 100644 (file)
@@ -151,7 +151,7 @@ static int softdog_release(struct inode *inode, struct file *file)
 {
        /*
         *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
+        *      Lock it in if it's a module and we set nowayout
         */
        if (expect_close == 42) {
                softdog_stop();
index 808372883e88ec4f1492b6af93eec524685dfe55..1bc493848ed4f7bdd5cd0d2117c6238ecded933b 100644 (file)
@@ -259,7 +259,7 @@ static struct miscdevice sp5100_tco_miscdev = {
  * register a pci_driver, because someone else might
  * want to register another driver on the same PCI id.
  */
-static struct pci_device_id sp5100_tco_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sp5100_tco_pci_tbl) = {
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
          PCI_ANY_ID, },
        { 0, },                 /* End of list */
index 18cdeb4c4258a67ccdba77fc517596eaa71819b9..5a90a4a871ddf7c06f8c73b3f515d9000b7b3702 100644 (file)
@@ -68,7 +68,7 @@ struct platform_device *ts72xx_wdt_pdev;
  * to control register):
  *     value   description
  *     -------------------------
- *     0x00    watchdog disabled
+ *     0x00    watchdog disabled
  *     0x01    250ms
  *     0x02    500ms
  *     0x03    1s
index df2a64dc9672dee584995e4b518ea5f8b0494df7..be9c4d839e152336d6e992bc5850f31c802a9a2d 100644 (file)
@@ -87,10 +87,10 @@ static int w83697ug_select_wd_register(void)
        outb_p(0x87, WDT_EFER); /* Enter extended function mode */
        outb_p(0x87, WDT_EFER); /* Again according to manual */
 
-       outb(0x20, WDT_EFER);   /* check chip version   */
+       outb(0x20, WDT_EFER);   /* check chip version   */
        version = inb(WDT_EFDR);
 
-       if (version == 0x68) {  /* W83697UG             */
+       if (version == 0x68) {  /* W83697UG             */
                printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
                        "W83697UG/UF found at 0x%04x\n", version, wdt_io);
 
index 552a4381e78f83037b7a0eb100fbab304bf42de0..bb03e151a1d01fb34fd6fbed8e413c44f7da677d 100644 (file)
@@ -581,7 +581,7 @@ static void __exit wdt_exit(void)
 }
 
 /**
- *     wdt_init:
+ *     wdt_init:
  *
  *     Set up the WDT watchdog board. All we have to do is grab the
  *     resources we require and bitch if anyone beat us to them.
index 5c2521fc836c3fa7c7829d3ad63fe5de5ebcdbe0..a2f01c9f5c341af0e27079185fb0094adca3a539 100644 (file)
@@ -281,7 +281,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
 {
        /*
         *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
+        *      Lock it in if it's a module and we set nowayout
         */
        if (expect_close == 42) {
                wdt977_stop();
index 6130c88fa5acac85387d0544c7ea53b7d92fca68..172dad6c7693a1399e53d001e46876662f7ac27b 100644 (file)
@@ -31,7 +31,7 @@
  *             Jeff Garzik     :       PCI cleanups
  *             Tigran Aivazian :       Restructured wdtpci_init_one() to handle
  *                                     failures
- *             Joel Becker     :       Added WDIOC_GET/SETTIMEOUT
+ *             Joel Becker     :       Added WDIOC_GET/SETTIMEOUT
  *             Zwane Mwaikambo :       Magic char closing, locking changes,
  *                                     cleanups
  *             Matt Domsch     :       nowayout module option
@@ -727,7 +727,7 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
 }
 
 
-static struct pci_device_id wdtpci_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(wdtpci_pci_tbl) = {
        {
                .vendor    = PCI_VENDOR_ID_ACCESSIO,
                .device    = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
@@ -764,7 +764,7 @@ static void __exit wdtpci_cleanup(void)
 
 
 /**
- *     wdtpci_init:
+ *     wdtpci_init:
  *
  *     Set up the WDT watchdog board. All we have to do is grab the
  *     resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
new file mode 100644 (file)
index 0000000..49bd9d3
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ *     Xen Watchdog Driver
+ *
+ *     (c) Copyright 2010 Novell, Inc.
+ *
+ *     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.
+ */
+
+#define DRV_NAME       "wdt"
+#define DRV_VERSION    "0.01"
+#define PFX            DRV_NAME ": "
+
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <xen/xen.h>
+#include <asm/xen/hypercall.h>
+#include <xen/interface/sched.h>
+
+static struct platform_device *platform_device;
+static DEFINE_SPINLOCK(wdt_lock);
+static struct sched_watchdog wdt;
+static __kernel_time_t wdt_expires;
+static bool is_active, expect_release;
+
+#define WATCHDOG_TIMEOUT 60 /* in seconds */
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
+       "(default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+       "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static inline __kernel_time_t set_timeout(void)
+{
+       wdt.timeout = timeout;
+       return ktime_to_timespec(ktime_get()).tv_sec + timeout;
+}
+
+static int xen_wdt_start(void)
+{
+       __kernel_time_t expires;
+       int err;
+
+       spin_lock(&wdt_lock);
+
+       expires = set_timeout();
+       if (!wdt.id)
+               err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+       else
+               err = -EBUSY;
+       if (err > 0) {
+               wdt.id = err;
+               wdt_expires = expires;
+               err = 0;
+       } else
+               BUG_ON(!err);
+
+       spin_unlock(&wdt_lock);
+
+       return err;
+}
+
+static int xen_wdt_stop(void)
+{
+       int err = 0;
+
+       spin_lock(&wdt_lock);
+
+       wdt.timeout = 0;
+       if (wdt.id)
+               err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+       if (!err)
+               wdt.id = 0;
+
+       spin_unlock(&wdt_lock);
+
+       return err;
+}
+
+static int xen_wdt_kick(void)
+{
+       __kernel_time_t expires;
+       int err;
+
+       spin_lock(&wdt_lock);
+
+       expires = set_timeout();
+       if (wdt.id)
+               err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+       else
+               err = -ENXIO;
+       if (!err)
+               wdt_expires = expires;
+
+       spin_unlock(&wdt_lock);
+
+       return err;
+}
+
+static int xen_wdt_open(struct inode *inode, struct file *file)
+{
+       int err;
+
+       /* /dev/watchdog can only be opened once */
+       if (xchg(&is_active, true))
+               return -EBUSY;
+
+       err = xen_wdt_start();
+       if (err == -EBUSY)
+               err = xen_wdt_kick();
+       return err ?: nonseekable_open(inode, file);
+}
+
+static int xen_wdt_release(struct inode *inode, struct file *file)
+{
+       if (expect_release)
+               xen_wdt_stop();
+       else {
+               printk(KERN_CRIT PFX
+                      "unexpected close, not stopping watchdog!\n");
+               xen_wdt_kick();
+       }
+       is_active = false;
+       expect_release = false;
+       return 0;
+}
+
+static ssize_t xen_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;
+
+                       /* in case it was set long ago */
+                       expect_release = false;
+
+                       /* 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 = true;
+                       }
+               }
+
+               /* someone wrote to us, we should reload the timer */
+               xen_wdt_kick();
+       }
+       return len;
+}
+
+static long xen_wdt_ioctl(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       int new_options, retval = -EINVAL;
+       int new_timeout;
+       int __user *argp = (void __user *)arg;
+       static const struct watchdog_info ident = {
+               .options =              WDIOF_SETTIMEOUT | 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, argp);
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(new_options, argp))
+                       return -EFAULT;
+
+               if (new_options & WDIOS_DISABLECARD)
+                       retval = xen_wdt_stop();
+               if (new_options & WDIOS_ENABLECARD) {
+                       retval = xen_wdt_start();
+                       if (retval == -EBUSY)
+                               retval = xen_wdt_kick();
+               }
+               return retval;
+
+       case WDIOC_KEEPALIVE:
+               xen_wdt_kick();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, argp))
+                       return -EFAULT;
+               if (!new_timeout)
+                       return -EINVAL;
+               timeout = new_timeout;
+               xen_wdt_kick();
+               /* fall through */
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, argp);
+
+       case WDIOC_GETTIMELEFT:
+               retval = wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
+               return put_user(retval, argp);
+       }
+
+       return -ENOTTY;
+}
+
+static const struct file_operations xen_wdt_fops = {
+       .owner =                THIS_MODULE,
+       .llseek =               no_llseek,
+       .write =                xen_wdt_write,
+       .unlocked_ioctl =       xen_wdt_ioctl,
+       .open =                 xen_wdt_open,
+       .release =              xen_wdt_release,
+};
+
+static struct miscdevice xen_wdt_miscdev = {
+       .minor =        WATCHDOG_MINOR,
+       .name =         "watchdog",
+       .fops =         &xen_wdt_fops,
+};
+
+static int __devinit xen_wdt_probe(struct platform_device *dev)
+{
+       struct sched_watchdog wd = { .id = ~0 };
+       int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);
+
+       switch (ret) {
+       case -EINVAL:
+               if (!timeout) {
+                       timeout = WATCHDOG_TIMEOUT;
+                       printk(KERN_INFO PFX
+                              "timeout value invalid, using %d\n", timeout);
+               }
+
+               ret = misc_register(&xen_wdt_miscdev);
+               if (ret) {
+                       printk(KERN_ERR PFX
+                              "cannot register miscdev on minor=%d (%d)\n",
+                              WATCHDOG_MINOR, ret);
+                       break;
+               }
+
+               printk(KERN_INFO PFX
+                      "initialized (timeout=%ds, nowayout=%d)\n",
+                      timeout, nowayout);
+               break;
+
+       case -ENOSYS:
+               printk(KERN_INFO PFX "not supported\n");
+               ret = -ENODEV;
+               break;
+
+       default:
+               printk(KERN_INFO PFX "bogus return value %d\n", ret);
+               break;
+       }
+
+       return ret;
+}
+
+static int __devexit xen_wdt_remove(struct platform_device *dev)
+{
+       /* Stop the timer before we leave */
+       if (!nowayout)
+               xen_wdt_stop();
+
+       misc_deregister(&xen_wdt_miscdev);
+
+       return 0;
+}
+
+static void xen_wdt_shutdown(struct platform_device *dev)
+{
+       xen_wdt_stop();
+}
+
+static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
+{
+       return xen_wdt_stop();
+}
+
+static int xen_wdt_resume(struct platform_device *dev)
+{
+       return xen_wdt_start();
+}
+
+static struct platform_driver xen_wdt_driver = {
+       .probe          = xen_wdt_probe,
+       .remove         = __devexit_p(xen_wdt_remove),
+       .shutdown       = xen_wdt_shutdown,
+       .suspend        = xen_wdt_suspend,
+       .resume         = xen_wdt_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = DRV_NAME,
+       },
+};
+
+static int __init xen_wdt_init_module(void)
+{
+       int err;
+
+       if (!xen_domain())
+               return -ENODEV;
+
+       printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
+
+       err = platform_driver_register(&xen_wdt_driver);
+       if (err)
+               return err;
+
+       platform_device = platform_device_register_simple(DRV_NAME,
+                                                                 -1, NULL, 0);
+       if (IS_ERR(platform_device)) {
+               err = PTR_ERR(platform_device);
+               platform_driver_unregister(&xen_wdt_driver);
+       }
+
+       return err;
+}
+
+static void __exit xen_wdt_cleanup_module(void)
+{
+       platform_device_unregister(platform_device);
+       platform_driver_unregister(&xen_wdt_driver);
+       printk(KERN_INFO PFX "module unloaded\n");
+}
+
+module_init(xen_wdt_init_module);
+module_exit(xen_wdt_cleanup_module);
+
+MODULE_AUTHOR("Jan Beulich <jbeulich@novell.com>");
+MODULE_DESCRIPTION("Xen WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 5fec575a800a74b8ea73b1df62d13519b42e3d2f..dd55dac340de8e86195a3b16c6cba11c0684deb7 100644 (file)
@@ -64,6 +64,39 @@ struct sched_poll {
 };
 DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
 
+/*
+ * Declare a shutdown for another domain. The main use of this function is
+ * in interpreting shutdown requests and reasons for fully-virtualized
+ * domains.  A para-virtualized domain may use SCHEDOP_shutdown directly.
+ * @arg == pointer to sched_remote_shutdown structure.
+ */
+#define SCHEDOP_remote_shutdown        4
+struct sched_remote_shutdown {
+    domid_t domain_id;         /* Remote domain ID */
+    unsigned int reason;       /* SHUTDOWN_xxx reason */
+};
+
+/*
+ * Latch a shutdown code, so that when the domain later shuts down it
+ * reports this code to the control tools.
+ * @arg == as for SCHEDOP_shutdown.
+ */
+#define SCHEDOP_shutdown_code 5
+
+/*
+ * Setup, poke and destroy a domain watchdog timer.
+ * @arg == pointer to sched_watchdog structure.
+ * With id == 0, setup a domain watchdog timer to cause domain shutdown
+ *               after timeout, returns watchdog id.
+ * With id != 0 and timeout == 0, destroy domain watchdog timer.
+ * With id != 0 and timeout != 0, poke watchdog timer and set new timeout.
+ */
+#define SCHEDOP_watchdog    6
+struct sched_watchdog {
+    uint32_t id;                /* watchdog ID */
+    uint32_t timeout;           /* timeout */
+};
+
 /*
  * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
  * software to determine the appropriate action. For the most part, Xen does
@@ -73,5 +106,6 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
 #define SHUTDOWN_reboot     1  /* Clean up, kill, and then restart.          */
 #define SHUTDOWN_suspend    2  /* Clean up, save suspend info, kill.         */
 #define SHUTDOWN_crash      3  /* Tell controller we've crashed.             */
+#define SHUTDOWN_watchdog   4  /* Restart because watchdog time expired.     */
 
 #endif /* __XEN_PUBLIC_SCHED_H__ */