Commit 4b0e976c authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* 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
parents 19520fc1 112e7546
...@@ -30,6 +30,7 @@ extern struct platform_device jz4740_i2s_device; ...@@ -30,6 +30,7 @@ extern struct platform_device jz4740_i2s_device;
extern struct platform_device jz4740_pcm_device; extern struct platform_device jz4740_pcm_device;
extern struct platform_device jz4740_codec_device; extern struct platform_device jz4740_codec_device;
extern struct platform_device jz4740_adc_device; extern struct platform_device jz4740_adc_device;
extern struct platform_device jz4740_wdt_device;
void jz4740_serial_device_register(void); void jz4740_serial_device_register(void);
......
...@@ -289,3 +289,19 @@ void jz4740_serial_device_register(void) ...@@ -289,3 +289,19 @@ void jz4740_serial_device_register(void)
platform_device_register(&jz4740_uart_device); 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,
};
...@@ -533,6 +533,16 @@ config I6300ESB_WDT ...@@ -533,6 +533,16 @@ config I6300ESB_WDT
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called i6300esb. 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 config ITCO_WDT
tristate "Intel TCO Timer/Watchdog" tristate "Intel TCO Timer/Watchdog"
depends on (X86 || IA64) && PCI depends on (X86 || IA64) && PCI
...@@ -580,7 +590,7 @@ config IT87_WDT ...@@ -580,7 +590,7 @@ config IT87_WDT
depends on X86 && EXPERIMENTAL depends on X86 && EXPERIMENTAL
---help--- ---help---
This is the driver for the hardware watchdog on the ITE IT8702, 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 This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain freeze, and if it does, it reboots your computer after a certain
amount of time. amount of time.
...@@ -589,18 +599,20 @@ config IT87_WDT ...@@ -589,18 +599,20 @@ config IT87_WDT
be called it87_wdt. be called it87_wdt.
config HP_WATCHDOG config HP_WATCHDOG
tristate "HP Proliant iLO2+ Hardware Watchdog Timer" tristate "HP ProLiant iLO2+ Hardware Watchdog Timer"
depends on X86 depends on X86
default m
help help
A software monitoring watchdog and NMI sourcing driver. This driver A software monitoring watchdog and NMI sourcing driver. This driver
will detect lockups and provide a stack trace. This is a driver that 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 To compile this driver as a module, choose M here: the module will be
called hpwdt. called hpwdt.
config HPWDT_NMI_DECODING config HPWDT_NMI_DECODING
bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer" bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
depends on HP_WATCHDOG depends on HP_WATCHDOG
default y
help help
When an NMI occurs this feature will make the necessary BIOS calls to When an NMI occurs this feature will make the necessary BIOS calls to
log the cause of the NMI. log the cause of the NMI.
...@@ -903,6 +915,12 @@ config INDYDOG ...@@ -903,6 +915,12 @@ config INDYDOG
timer expired and no process has written to /dev/watchdog during timer expired and no process has written to /dev/watchdog during
that time. 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 config WDT_MTX1
tristate "MTX-1 Hardware Watchdog" tristate "MTX-1 Hardware Watchdog"
depends on MIPS_MTX1 depends on MIPS_MTX1
...@@ -1111,6 +1129,16 @@ config WATCHDOG_RIO ...@@ -1111,6 +1129,16 @@ config WATCHDOG_RIO
# XTENSA Architecture # 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 # ISA-based Watchdog Cards
# #
......
...@@ -102,6 +102,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o ...@@ -102,6 +102,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
# M32R Architecture # M32R Architecture
...@@ -114,6 +115,7 @@ obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o ...@@ -114,6 +115,7 @@ obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
...@@ -148,6 +150,9 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o ...@@ -148,6 +150,9 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
# XTENSA Architecture # XTENSA Architecture
# Xen
obj-$(CONFIG_XEN_WDT) += xen_wdt.o
# Architecture Independant # Architecture Independant
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
......
...@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this, ...@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
* want to register another driver on the same PCI id. * 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, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, }, { 0, },
...@@ -362,12 +362,12 @@ static int __init ali_find_watchdog(void) ...@@ -362,12 +362,12 @@ static int __init ali_find_watchdog(void)
*/ */
static const struct file_operations ali_fops = { static const struct file_operations ali_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ali_write, .write = ali_write,
.unlocked_ioctl = ali_ioctl, .unlocked_ioctl = ali_ioctl,
.open = ali_open, .open = ali_open,
.release = ali_release, .release = ali_release,
}; };
static struct miscdevice ali_miscdev = { static struct miscdevice ali_miscdev = {
......
...@@ -430,7 +430,7 @@ static int __init alim7101_wdt_init(void) ...@@ -430,7 +430,7 @@ static int __init alim7101_wdt_init(void)
module_init(alim7101_wdt_init); module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload); 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_M1533) },
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ } { }
......
...@@ -150,8 +150,8 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data, ...@@ -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 = { static const struct watchdog_info bcm47xx_wdt_info = {
.identity = DRV_NAME, .identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
}; };
......
...@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(bfin_wdt_spinlock); ...@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(bfin_wdt_spinlock);
/** /**
* bfin_wdt_keepalive - Keep the Userspace Watchdog Alive * 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) static int bfin_wdt_keepalive(void)
{ {
...@@ -337,7 +337,7 @@ static int bfin_wdt_resume(struct platform_device *pdev) ...@@ -337,7 +337,7 @@ static int bfin_wdt_resume(struct platform_device *pdev)
static const struct file_operations bfin_wdt_fops = { static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = bfin_wdt_write, .write = bfin_wdt_write,
.unlocked_ioctl = bfin_wdt_ioctl, .unlocked_ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open, .open = bfin_wdt_open,
.release = bfin_wdt_release, .release = bfin_wdt_release,
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Author: Matthew McClintock * Author: Matthew McClintock
* Maintainer: Kumar Gala <galak@kernel.crashing.org> * 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 * 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 * 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) ...@@ -221,9 +221,8 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) { if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1; booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
printk(KERN_INFO pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
"PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", period_to_sec(booke_wdt_period));
booke_wdt_period);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
...@@ -240,6 +239,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file) ...@@ -240,6 +239,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
*/ */
on_each_cpu(__booke_wdt_disable, NULL, 0); on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0; booke_wdt_enabled = 0;
pr_debug("booke_wdt: watchdog disabled\n");
#endif #endif
clear_bit(0, &wdt_is_active); clear_bit(0, &wdt_is_active);
...@@ -271,21 +271,20 @@ static int __init booke_wdt_init(void) ...@@ -271,21 +271,20 @@ static int __init booke_wdt_init(void)
{ {
int ret = 0; 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; ident.firmware_version = cur_cpu_spec->pvr_value;
ret = misc_register(&booke_wdt_miscdev); ret = misc_register(&booke_wdt_miscdev);
if (ret) { if (ret) {
printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n", pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
return ret; return ret;
} }
spin_lock(&booke_wdt_lock); spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) { if (booke_wdt_enabled == 1) {
printk(KERN_INFO pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
"PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", period_to_sec(booke_wdt_period));
booke_wdt_period);
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
* interface and Solaris-compatible ioctls as best it is * interface and Solaris-compatible ioctls as best it is
* able. * able.
* *
* NOTE: CP1400 systems appear to have a defective intr_mask * NOTE: CP1400 systems appear to have a defective intr_mask
* register on the PLD, preventing the disabling of * register on the PLD, preventing the disabling of
* timer interrupts. We use a timer to periodically * timer interrupts. We use a timer to periodically
* reset 'stopped' watchdogs on affected platforms. * reset 'stopped' watchdogs on affected platforms.
* *
* Copyright (c) 2000 Eric Brower (ebrower@usa.net) * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
* Copyright (C) 2008 David S. Miller <davem@davemloft.net> * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
...@@ -107,13 +107,13 @@ static struct cpwd *cpwd_device; ...@@ -107,13 +107,13 @@ static struct cpwd *cpwd_device;
* ------------------- * -------------------
* |- counter val -| * |- counter val -|
* ------------------- * -------------------
* dcntr - Current 16-bit downcounter value. * dcntr - Current 16-bit downcounter value.
* When downcounter reaches '0' watchdog expires. * When downcounter reaches '0' watchdog expires.
* Reading this register resets downcounter with * Reading this register resets downcounter with
* 'limit' value. * 'limit' value.
* limit - 16-bit countdown value in 1/10th second increments. * limit - 16-bit countdown value in 1/10th second increments.
* Writing this register begins countdown with input value. * Writing this register begins countdown with input value.
* Reading from this register does not affect counter. * Reading from this register does not affect counter.
* NOTES: After watchdog reset, dcntr and limit contain '1' * NOTES: After watchdog reset, dcntr and limit contain '1'
* *
* status register (byte access): * status register (byte access):
...@@ -123,7 +123,7 @@ static struct cpwd *cpwd_device; ...@@ -123,7 +123,7 @@ static struct cpwd *cpwd_device;
* |- UNUSED -| EXP | RUN | * |- UNUSED -| EXP | RUN |
* --------------------------- * ---------------------------
* status- Bit 0 - Watchdog is running * status- Bit 0 - Watchdog is running
* Bit 1 - Watchdog has expired * Bit 1 - Watchdog has expired
* *
*** PLD register block definition (struct wd_pld_regblk) *** PLD register block definition (struct wd_pld_regblk)
* *
...@@ -197,7 +197,7 @@ static u8 cpwd_readb(void __iomem *addr) ...@@ -197,7 +197,7 @@ static u8 cpwd_readb(void __iomem *addr)
* Because of the CP1400 defect this should only be * Because of the CP1400 defect this should only be
* called during initialzation or by wd_[start|stop]timer() * 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 * enable - non-zero to enable interrupts, zero to disable
*/ */
static void cpwd_toggleintr(struct cpwd *p, int index, int enable) static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
...@@ -317,13 +317,13 @@ static int cpwd_getstatus(struct cpwd *p, int index) ...@@ -317,13 +317,13 @@ static int cpwd_getstatus(struct cpwd *p, int index)
} else { } else {
/* Fudge WD_EXPIRED status for defective CP1400-- /* Fudge WD_EXPIRED status for defective CP1400--
* IF timer is running * IF timer is running
* AND brokenstop is set * AND brokenstop is set
* AND an interrupt has been serviced * AND an interrupt has been serviced
* we are WD_EXPIRED. * we are WD_EXPIRED.
* *
* IF timer is running * IF timer is running
* AND brokenstop is set * AND brokenstop is set
* AND no interrupt has been serviced * AND no interrupt has been serviced
* we are WD_FREERUN. * we are WD_FREERUN.
*/ */
if (p->broken && if (p->broken &&
...@@ -613,7 +613,7 @@ static int __devinit cpwd_probe(struct platform_device *op) ...@@ -613,7 +613,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
if (p->broken) { if (p->broken) {
init_timer(&cpwd_timer); init_timer(&cpwd_timer);
cpwd_timer.function = cpwd_brokentimer; cpwd_timer.function = cpwd_brokentimer;
cpwd_timer.data = (unsigned long) p; cpwd_timer.data = (unsigned long) p;
cpwd_timer.expires = WD_BTIMEOUT; cpwd_timer.expires = WD_BTIMEOUT;
......
...@@ -201,7 +201,7 @@ static void eurwdt_ping(void) ...@@ -201,7 +201,7 @@ static void eurwdt_ping(void)
static ssize_t eurwdt_write(struct file *file, const char __user *buf, static ssize_t eurwdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
......
...@@ -52,7 +52,7 @@ static void __iomem *pci_mem_addr; /* the PCI-memory address */ ...@@ -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_reg;
static unsigned long __iomem *hpwdt_timer_con; 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_COMPAQ, 0xB203) }, /* iLO2 */
{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */
{0}, /* terminate list */ {0}, /* terminate list */
......
...@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = { ...@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = {
/* /*
* Data for PCI driver interface * 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), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
{ 0, }, /* End of list */ { 0, }, /* End of list */
}; };
......
...@@ -247,7 +247,7 @@ static struct { ...@@ -247,7 +247,7 @@ static struct {
{NULL, 0} {NULL, 0}
}; };
#define ITCO_PCI_DEVICE(dev, data) \ #define ITCO_PCI_DEVICE(dev, data) \
.vendor = PCI_VENDOR_ID_INTEL, \ .vendor = PCI_VENDOR_ID_INTEL, \
.device = dev, \ .device = dev, \
.subvendor = PCI_ANY_ID, \ .subvendor = PCI_ANY_ID, \
...@@ -262,7 +262,7 @@ static struct { ...@@ -262,7 +262,7 @@ static struct {
* pci_driver, because the I/O Controller Hub has also other * pci_driver, because the I/O Controller Hub has also other
* functions that probably will be registered by other drivers. * 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_82801AA_0, TCO_ICH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)},
......
/*
* 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);
/*
* 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 */
...@@ -69,7 +69,7 @@ static unsigned short address; ...@@ -69,7 +69,7 @@ static unsigned short address;
#define IT8712F_DEVID 0x8712 #define IT8712F_DEVID 0x8712
#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */ #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_CONTROL 0x71 /* WDT Register: Control */
#define WDT_CONFIG 0x72 /* WDT Register: Configuration */ #define WDT_CONFIG 0x72 /* WDT Register: Configuration */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* http://www.ite.com.tw/ * http://www.ite.com.tw/
* *
* Support of the watchdog timers, which are available on * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include <asm/system.h> #include <asm/system.h>
#define WATCHDOG_VERSION "1.13" #define WATCHDOG_VERSION "1.14"
#define WATCHDOG_NAME "IT87 WDT" #define WATCHDOG_NAME "IT87 WDT"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
/* Defaults for Module Parameter */ /* Defaults for Module Parameter */
#define DEFAULT_NOGAMEPORT 0 #define DEFAULT_NOGAMEPORT 0
#define DEFAULT_EXCLUSIVE 1 #define DEFAULT_EXCLUSIVE 1
#define DEFAULT_TIMEOUT 60 #define DEFAULT_TIMEOUT 60
#define DEFAULT_TESTMODE 0 #define DEFAULT_TESTMODE 0
#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT #define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
...@@ -70,9 +70,9 @@ ...@@ -70,9 +70,9 @@
/* Configuration Registers and Functions */ /* Configuration Registers and Functions */
#define LDNREG 0x07 #define LDNREG 0x07
#define CHIPID 0x20 #define CHIPID 0x20
#define CHIPREV 0x22 #define CHIPREV 0x22
#define ACTREG 0x30 #define ACTREG 0x30
#define BASEREG 0x60 #define BASEREG 0x60
/* Chip Id numbers */ /* Chip Id numbers */
#define NO_DEV_ID 0xffff #define NO_DEV_ID 0xffff
...@@ -82,10 +82,11 @@ ...@@ -82,10 +82,11 @@
#define IT8716_ID 0x8716 #define IT8716_ID 0x8716
#define IT8718_ID 0x8718 #define IT8718_ID 0x8718
#define IT8720_ID 0x8720 #define IT8720_ID 0x8720
#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
/* GPIO Configuration Registers LDN=0x07 */ /* GPIO Configuration Registers LDN=0x07 */
#define WDTCTRL 0x71 #define WDTCTRL 0x71
#define WDTCFG 0x72 #define WDTCFG 0x72
#define WDTVALLSB 0x73 #define WDTVALLSB 0x73
#define WDTVALMSB 0x74 #define WDTVALMSB 0x74
...@@ -94,7 +95,7 @@ ...@@ -94,7 +95,7 @@
#define WDT_CIRINT 0x80 #define WDT_CIRINT 0x80
#define WDT_MOUSEINT 0x40 #define WDT_MOUSEINT 0x40
#define WDT_KYBINT 0x20 #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_FORCE 0x02
#define WDT_ZERO 0x01 #define WDT_ZERO 0x01
...@@ -102,11 +103,11 @@ ...@@ -102,11 +103,11 @@
#define WDT_TOV1 0x80 #define WDT_TOV1 0x80
#define WDT_KRST 0x40 #define WDT_KRST 0x40
#define WDT_TOVE 0x20 #define WDT_TOVE 0x20
#define WDT_PWROK 0x10 #define WDT_PWROK 0x10 /* not in it8721 */
#define WDT_INT_MASK 0x0f #define WDT_INT_MASK 0x0f
/* CIR Configuration Register LDN=0x0a */ /* CIR Configuration Register LDN=0x0a */
#define CIR_ILS 0x70 #define CIR_ILS 0x70
/* The default Base address is not always available, we use this */ /* The default Base address is not always available, we use this */
#define CIR_BASE 0x0208 #define CIR_BASE 0x0208
...@@ -134,7 +135,7 @@ ...@@ -134,7 +135,7 @@
#define WDTS_USE_GP 4 #define WDTS_USE_GP 4
#define WDTS_EXPECTED 5 #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 unsigned long wdt_status;
static DEFINE_SPINLOCK(spinlock); static DEFINE_SPINLOCK(spinlock);
...@@ -215,7 +216,7 @@ static inline void superio_outw(int val, int reg) ...@@ -215,7 +216,7 @@ static inline void superio_outw(int val, int reg)
/* Internal function, should be called after superio_select(GPIO) */ /* Internal function, should be called after superio_select(GPIO) */
static void wdt_update_timeout(void) static void wdt_update_timeout(void)
{ {
unsigned char cfg = WDT_KRST | WDT_PWROK; unsigned char cfg = WDT_KRST;
int tm = timeout; int tm = timeout;
if (testmode) if (testmode)
...@@ -226,6 +227,9 @@ static void wdt_update_timeout(void) ...@@ -226,6 +227,9 @@ static void wdt_update_timeout(void)
else else
tm /= 60; tm /= 60;
if (chip_type != IT8721_ID)
cfg |= WDT_PWROK;
superio_outb(cfg, WDTCFG); superio_outb(cfg, WDTCFG);
superio_outb(tm, WDTVALLSB); superio_outb(tm, WDTVALLSB);
if (max_units > 255) if (max_units > 255)
...@@ -555,7 +559,6 @@ static int __init it87_wdt_init(void) ...@@ -555,7 +559,6 @@ static int __init it87_wdt_init(void)
{ {
int rc = 0; int rc = 0;
int try_gameport = !nogameport; int try_gameport = !nogameport;
u16 chip_type;
u8 chip_rev; u8 chip_rev;
unsigned long flags; unsigned long flags;
...@@ -581,6 +584,7 @@ static int __init it87_wdt_init(void) ...@@ -581,6 +584,7 @@ static int __init it87_wdt_init(void)
break; break;
case IT8718_ID: case IT8718_ID:
case IT8720_ID: case IT8720_ID:
case IT8721_ID:
max_units = 65535; max_units = 65535;
try_gameport = 0; try_gameport = 0;
break; break;
......
/*
* 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");
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
/* indexes */ /* size */ /* indexes */ /* size */
#define ZFL_VERSION 0x02 /* 16 */ #define ZFL_VERSION 0x02 /* 16 */
#define CONTROL 0x10 /* 16 */ #define CONTROL 0x10 /* 16 */
#define STATUS 0x12 /* 8 */ #define STATUS 0x12 /* 8 */
#define COUNTER_1 0x0C /* 16 */ #define COUNTER_1 0x0C /* 16 */
#define COUNTER_2 0x0E /* 8 */ #define COUNTER_2 0x0E /* 8 */
......
...@@ -41,7 +41,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; ...@@ -41,7 +41,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
* to ping the watchdog. * to ping the watchdog.
*/ */
#define MAX6369_WDSET (7 << 0) #define MAX6369_WDSET (7 << 0)
#define MAX6369_WDI (1 << 3) #define MAX6369_WDI (1 << 3)
static DEFINE_SPINLOCK(io_lock); static DEFINE_SPINLOCK(io_lock);
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
* *
* Authors: Dave Updegraff <dave@cray.org> * Authors: Dave Updegraff <dave@cray.org>
* Kumar Gala <galak@kernel.crashing.org> * Kumar Gala <galak@kernel.crashing.org>
* Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org> * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
* ..and from sc520_wdt * ..and from sc520_wdt
* Copyright (c) 2008 MontaVista Software, Inc. * Copyright (c) 2008 MontaVista Software, Inc.
* Anton Vorontsov <avorontsov@ru.mvista.com> * Anton Vorontsov <avorontsov@ru.mvista.com>
* *
......
...@@ -172,7 +172,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) ...@@ -172,7 +172,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
/* /*
* Shut off the timer. * 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) if (wdt->expect_close == 42)
mpcore_wdt_stop(wdt); mpcore_wdt_stop(wdt);
......
...@@ -190,19 +190,19 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, ...@@ -190,19 +190,19 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
} }
static const struct file_operations mtx1_wdt_fops = { static const struct file_operations mtx1_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.unlocked_ioctl = mtx1_wdt_ioctl, .unlocked_ioctl = mtx1_wdt_ioctl,
.open = mtx1_wdt_open, .open = mtx1_wdt_open,
.write = mtx1_wdt_write, .write = mtx1_wdt_write,
.release = mtx1_wdt_release, .release = mtx1_wdt_release,
}; };
static struct miscdevice mtx1_wdt_misc = { static struct miscdevice mtx1_wdt_misc = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &mtx1_wdt_fops, .fops = &mtx1_wdt_fops,
}; };
......
...@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = { ...@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = {
* register a pci_driver, because someone else might one day * register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id. * 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_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
PCI_ANY_ID, PCI_ANY_ID, }, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
* months before firing. These limits work without scaling, * months before firing. These limits work without scaling,
* with the 60 second default assumed by most tools and docs. * 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_DEFAULT 60 /* 60 secs */
#define TIMER_MARGIN_MIN 1 #define TIMER_MARGIN_MIN 1
......
...@@ -514,7 +514,7 @@ static struct miscdevice pc87413_miscdev = { ...@@ -514,7 +514,7 @@ static struct miscdevice pc87413_miscdev = {
/* -- Module init functions -------------------------------------*/ /* -- 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 * 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. * resources we require and bitch if anyone beat us to them.
......
...@@ -817,7 +817,7 @@ static void __devexit pcipcwd_card_exit(struct pci_dev *pdev) ...@@ -817,7 +817,7 @@ static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
cards_found--; 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_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
PCI_ANY_ID, PCI_ANY_ID, }, PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }, /* End of list */ { 0 }, /* End of list */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Watchdog driver for PNX4008 board * Watchdog driver for PNX4008 board
* *
* Authors: Dmitry Chigirev <source@mvista.com>, * Authors: Dmitry Chigirev <source@mvista.com>,
* Vitaly Wool <vitalywool@gmail.com> * Vitaly Wool <vitalywool@gmail.com>
* Based on sa1100 driver, * Based on sa1100 driver,
* Copyright (C) 2000 Oleg Drokin <green@crimea.edu> * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
* *
......
...@@ -224,7 +224,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file) ...@@ -224,7 +224,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
{ {
/* /*
* Shut off the timer. * 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) if (expect_close == 42)
......
...@@ -114,7 +114,7 @@ static char expect_close; ...@@ -114,7 +114,7 @@ static char expect_close;
* C | 6.5s 65s 650s 1300s * C | 6.5s 65s 650s 1300s
* D | 7s 70s 700s 1400s * D | 7s 70s 700s 1400s
* E | 7.5s 75s 750s 1500s * E | 7.5s 75s 750s 1500s
* F | 8s 80s 800s 1600s * F | 8s 80s 800s 1600s
* *
* Another way to say the same things is: * Another way to say the same things is:
* For N=1, Timeout = (M+1) * 0.5s * For N=1, Timeout = (M+1) * 0.5s
......
...@@ -41,7 +41,7 @@ static DEFINE_MUTEX(wdt_lock); ...@@ -41,7 +41,7 @@ static DEFINE_MUTEX(wdt_lock);
#define IFACE_ON_COMMAND 1 #define IFACE_ON_COMMAND 1
#define REBOOT_COMMAND 2 #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) static void wdt_send_data(unsigned char command, unsigned char data)
{ {
......
...@@ -434,11 +434,11 @@ static long wb_smsc_wdt_ioctl(struct file *file, ...@@ -434,11 +434,11 @@ static long wb_smsc_wdt_ioctl(struct file *file,
} uarg; } uarg;
static const struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 0, .firmware_version = 0,
.identity = "SMsC 37B787 Watchdog", .identity = "SMsC 37B787 Watchdog",
}; };
uarg.i = (int __user *)arg; uarg.i = (int __user *)arg;
......
...@@ -151,7 +151,7 @@ static int softdog_release(struct inode *inode, struct file *file) ...@@ -151,7 +151,7 @@ static int softdog_release(struct inode *inode, struct file *file)
{ {
/* /*
* Shut off the timer. * 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) { if (expect_close == 42) {
softdog_stop(); softdog_stop();
......
...@@ -259,7 +259,7 @@ static struct miscdevice sp5100_tco_miscdev = { ...@@ -259,7 +259,7 @@ static struct miscdevice sp5100_tco_miscdev = {
* register a pci_driver, because someone else might * register a pci_driver, because someone else might
* want to register another driver on the same PCI id. * 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_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
PCI_ANY_ID, }, PCI_ANY_ID, },
{ 0, }, /* End of list */ { 0, }, /* End of list */
......
...@@ -68,7 +68,7 @@ struct platform_device *ts72xx_wdt_pdev; ...@@ -68,7 +68,7 @@ struct platform_device *ts72xx_wdt_pdev;
* to control register): * to control register):
* value description * value description
* ------------------------- * -------------------------
* 0x00 watchdog disabled * 0x00 watchdog disabled
* 0x01 250ms * 0x01 250ms
* 0x02 500ms * 0x02 500ms
* 0x03 1s * 0x03 1s
......
...@@ -87,10 +87,10 @@ static int w83697ug_select_wd_register(void) ...@@ -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); /* Enter extended function mode */
outb_p(0x87, WDT_EFER); /* Again according to manual */ 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); version = inb(WDT_EFDR);
if (version == 0x68) { /* W83697UG */ if (version == 0x68) { /* W83697UG */
printk(KERN_INFO PFX "Watchdog chip version 0x%02x = " printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
"W83697UG/UF found at 0x%04x\n", version, wdt_io); "W83697UG/UF found at 0x%04x\n", version, wdt_io);
......
...@@ -581,7 +581,7 @@ static void __exit wdt_exit(void) ...@@ -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 * 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. * resources we require and bitch if anyone beat us to them.
......
...@@ -281,7 +281,7 @@ static int wdt977_release(struct inode *inode, struct file *file) ...@@ -281,7 +281,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
{ {
/* /*
* Shut off the timer. * 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) { if (expect_close == 42) {
wdt977_stop(); wdt977_stop();
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* Jeff Garzik : PCI cleanups * Jeff Garzik : PCI cleanups
* Tigran Aivazian : Restructured wdtpci_init_one() to handle * Tigran Aivazian : Restructured wdtpci_init_one() to handle
* failures * failures
* Joel Becker : Added WDIOC_GET/SETTIMEOUT * Joel Becker : Added WDIOC_GET/SETTIMEOUT
* Zwane Mwaikambo : Magic char closing, locking changes, * Zwane Mwaikambo : Magic char closing, locking changes,
* cleanups * cleanups
* Matt Domsch : nowayout module option * Matt Domsch : nowayout module option
...@@ -727,7 +727,7 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev) ...@@ -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, .vendor = PCI_VENDOR_ID_ACCESSIO,
.device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM, .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
...@@ -764,7 +764,7 @@ static void __exit wdtpci_cleanup(void) ...@@ -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 * 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. * resources we require and bitch if anyone beat us to them.
......
/*
* 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);
...@@ -64,6 +64,39 @@ struct sched_poll { ...@@ -64,6 +64,39 @@ struct sched_poll {
}; };
DEFINE_GUEST_HANDLE_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 * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
* software to determine the appropriate action. For the most part, Xen does * software to determine the appropriate action. For the most part, Xen does
...@@ -73,5 +106,6 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_poll); ...@@ -73,5 +106,6 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ #define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ #define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */ #define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
#define SHUTDOWN_watchdog 4 /* Restart because watchdog time expired. */
#endif /* __XEN_PUBLIC_SCHED_H__ */ #endif /* __XEN_PUBLIC_SCHED_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment