aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 20:09:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 20:09:29 -0400
commit4b0e976c663e808822adf51274f948e8a4986f06 (patch)
tree64ee15cbaafc283248dfac5dc7bccbc65b9159e0 /drivers
parent19520fc1ee36164808e6f084bd95e8178e2db231 (diff)
parent112e75466f63997d0f4c3c13ecf999e36aea692f (diff)
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/Kconfig34
-rw-r--r--drivers/watchdog/Makefile5
-rw-r--r--drivers/watchdog/alim1535_wdt.c10
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c4
-rw-r--r--drivers/watchdog/bfin_wdt.c4
-rw-r--r--drivers/watchdog/booke_wdt.c19
-rw-r--r--drivers/watchdog/cpwd.c36
-rw-r--r--drivers/watchdog/eurotechwdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/i6300esb.c2
-rw-r--r--drivers/watchdog/iTCO_wdt.c4
-rw-r--r--drivers/watchdog/intel_scu_watchdog.c572
-rw-r--r--drivers/watchdog/intel_scu_watchdog.h66
-rw-r--r--drivers/watchdog/it8712f_wdt.c2
-rw-r--r--drivers/watchdog/it87_wdt.c28
-rw-r--r--drivers/watchdog/jz4740_wdt.c322
-rw-r--r--drivers/watchdog/machzwd.c2
-rw-r--r--drivers/watchdog/max63xx_wdt.c2
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c6
-rw-r--r--drivers/watchdog/mpcore_wdt.c2
-rw-r--r--drivers/watchdog/mtx-1_wdt.c14
-rw-r--r--drivers/watchdog/nv_tco.c2
-rw-r--r--drivers/watchdog/omap_wdt.h2
-rw-r--r--drivers/watchdog/pc87413_wdt.c2
-rw-r--r--drivers/watchdog/pcwd_pci.c2
-rw-r--r--drivers/watchdog/pnx4008_wdt.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c2
-rw-r--r--drivers/watchdog/sbc8360.c2
-rw-r--r--drivers/watchdog/sbc_fitpc2_wdt.c2
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c4
-rw-r--r--drivers/watchdog/softdog.c2
-rw-r--r--drivers/watchdog/sp5100_tco.c2
-rw-r--r--drivers/watchdog/ts72xx_wdt.c2
-rw-r--r--drivers/watchdog/w83697ug_wdt.c4
-rw-r--r--drivers/watchdog/wdt.c2
-rw-r--r--drivers/watchdog/wdt977.c2
-rw-r--r--drivers/watchdog/wdt_pci.c6
-rw-r--r--drivers/watchdog/xen_wdt.c359
39 files changed, 1447 insertions, 92 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 908160e938dc..b69d71482554 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -533,6 +533,16 @@ config I6300ESB_WDT
533 To compile this driver as a module, choose M here: the 533 To compile this driver as a module, choose M here: the
534 module will be called i6300esb. 534 module will be called i6300esb.
535 535
536config INTEL_SCU_WATCHDOG
537 bool "Intel SCU Watchdog for Mobile Platforms"
538 depends on WATCHDOG
539 depends on INTEL_SCU_IPC
540 ---help---
541 Hardware driver for the watchdog time built into the Intel SCU
542 for Intel Mobile Platforms.
543
544 To compile this driver as a module, choose M here.
545
536config ITCO_WDT 546config ITCO_WDT
537 tristate "Intel TCO Timer/Watchdog" 547 tristate "Intel TCO Timer/Watchdog"
538 depends on (X86 || IA64) && PCI 548 depends on (X86 || IA64) && PCI
@@ -580,7 +590,7 @@ config IT87_WDT
580 depends on X86 && EXPERIMENTAL 590 depends on X86 && EXPERIMENTAL
581 ---help--- 591 ---help---
582 This is the driver for the hardware watchdog on the ITE IT8702, 592 This is the driver for the hardware watchdog on the ITE IT8702,
583 IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips. 593 IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
584 This watchdog simply watches your kernel to make sure it doesn't 594 This watchdog simply watches your kernel to make sure it doesn't
585 freeze, and if it does, it reboots your computer after a certain 595 freeze, and if it does, it reboots your computer after a certain
586 amount of time. 596 amount of time.
@@ -589,18 +599,20 @@ config IT87_WDT
589 be called it87_wdt. 599 be called it87_wdt.
590 600
591config HP_WATCHDOG 601config HP_WATCHDOG
592 tristate "HP Proliant iLO2+ Hardware Watchdog Timer" 602 tristate "HP ProLiant iLO2+ Hardware Watchdog Timer"
593 depends on X86 603 depends on X86
604 default m
594 help 605 help
595 A software monitoring watchdog and NMI sourcing driver. This driver 606 A software monitoring watchdog and NMI sourcing driver. This driver
596 will detect lockups and provide a stack trace. This is a driver that 607 will detect lockups and provide a stack trace. This is a driver that
597 will only load on a HP ProLiant system with a minimum of iLO2 support. 608 will only load on an HP ProLiant system with a minimum of iLO2 support.
598 To compile this driver as a module, choose M here: the module will be 609 To compile this driver as a module, choose M here: the module will be
599 called hpwdt. 610 called hpwdt.
600 611
601config HPWDT_NMI_DECODING 612config HPWDT_NMI_DECODING
602 bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer" 613 bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
603 depends on HP_WATCHDOG 614 depends on HP_WATCHDOG
615 default y
604 help 616 help
605 When an NMI occurs this feature will make the necessary BIOS calls to 617 When an NMI occurs this feature will make the necessary BIOS calls to
606 log the cause of the NMI. 618 log the cause of the NMI.
@@ -903,6 +915,12 @@ config INDYDOG
903 timer expired and no process has written to /dev/watchdog during 915 timer expired and no process has written to /dev/watchdog during
904 that time. 916 that time.
905 917
918config JZ4740_WDT
919 tristate "Ingenic jz4740 SoC hardware watchdog"
920 depends on MACH_JZ4740
921 help
922 Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
923
906config WDT_MTX1 924config WDT_MTX1
907 tristate "MTX-1 Hardware Watchdog" 925 tristate "MTX-1 Hardware Watchdog"
908 depends on MIPS_MTX1 926 depends on MIPS_MTX1
@@ -1111,6 +1129,16 @@ config WATCHDOG_RIO
1111 1129
1112# XTENSA Architecture 1130# XTENSA Architecture
1113 1131
1132# Xen Architecture
1133
1134config XEN_WDT
1135 tristate "Xen Watchdog support"
1136 depends on XEN
1137 help
1138 Say Y here to support the hypervisor watchdog capability provided
1139 by Xen 4.0 and newer. The watchdog timeout period is normally one
1140 minute but can be changed with a boot-time parameter.
1141
1114# 1142#
1115# ISA-based Watchdog Cards 1143# ISA-based Watchdog Cards
1116# 1144#
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 20e44c4782b3..d520bf9c3355 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
102obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 102obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
103obj-$(CONFIG_MACHZ_WDT) += machzwd.o 103obj-$(CONFIG_MACHZ_WDT) += machzwd.o
104obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o 104obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
105obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
105 106
106# M32R Architecture 107# M32R Architecture
107 108
@@ -114,6 +115,7 @@ obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
114obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o 115obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
115obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o 116obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
116obj-$(CONFIG_INDYDOG) += indydog.o 117obj-$(CONFIG_INDYDOG) += indydog.o
118obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
117obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o 119obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
118obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o 120obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
119obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o 121obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
@@ -148,6 +150,9 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
148 150
149# XTENSA Architecture 151# XTENSA Architecture
150 152
153# Xen
154obj-$(CONFIG_XEN_WDT) += xen_wdt.o
155
151# Architecture Independant 156# Architecture Independant
152obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o 157obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
153obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o 158obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index fa4d36033552..f16dcbd475fb 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
301 * want to register another driver on the same PCI id. 301 * want to register another driver on the same PCI id.
302 */ 302 */
303 303
304static struct pci_device_id ali_pci_tbl[] __used = { 304static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = {
305 { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, 305 { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
306 { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, 306 { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
307 { 0, }, 307 { 0, },
@@ -362,12 +362,12 @@ static int __init ali_find_watchdog(void)
362 */ 362 */
363 363
364static const struct file_operations ali_fops = { 364static const struct file_operations ali_fops = {
365 .owner = THIS_MODULE, 365 .owner = THIS_MODULE,
366 .llseek = no_llseek, 366 .llseek = no_llseek,
367 .write = ali_write, 367 .write = ali_write,
368 .unlocked_ioctl = ali_ioctl, 368 .unlocked_ioctl = ali_ioctl,
369 .open = ali_open, 369 .open = ali_open,
370 .release = ali_release, 370 .release = ali_release,
371}; 371};
372 372
373static struct miscdevice ali_miscdev = { 373static struct miscdevice ali_miscdev = {
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 4b7a2b4138ed..46f4b85b46de 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -430,7 +430,7 @@ err_out:
430module_init(alim7101_wdt_init); 430module_init(alim7101_wdt_init);
431module_exit(alim7101_wdt_unload); 431module_exit(alim7101_wdt_unload);
432 432
433static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = { 433static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = {
434 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, 434 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
435 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, 435 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
436 { } 436 { }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 5f245522397b..bd44417c84d4 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -150,8 +150,8 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
150} 150}
151 151
152static const struct watchdog_info bcm47xx_wdt_info = { 152static const struct watchdog_info bcm47xx_wdt_info = {
153 .identity = DRV_NAME, 153 .identity = DRV_NAME,
154 .options = WDIOF_SETTIMEOUT | 154 .options = WDIOF_SETTIMEOUT |
155 WDIOF_KEEPALIVEPING | 155 WDIOF_KEEPALIVEPING |
156 WDIOF_MAGICCLOSE, 156 WDIOF_MAGICCLOSE,
157}; 157};
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 9042a95fc98c..b9fa9b71583a 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(bfin_wdt_spinlock);
63/** 63/**
64 * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive 64 * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
65 * 65 *
66 * The Userspace watchdog got a KeepAlive: schedule the next timeout. 66 * The Userspace watchdog got a KeepAlive: schedule the next timeout.
67 */ 67 */
68static int bfin_wdt_keepalive(void) 68static int bfin_wdt_keepalive(void)
69{ 69{
@@ -337,7 +337,7 @@ static int bfin_wdt_resume(struct platform_device *pdev)
337static const struct file_operations bfin_wdt_fops = { 337static const struct file_operations bfin_wdt_fops = {
338 .owner = THIS_MODULE, 338 .owner = THIS_MODULE,
339 .llseek = no_llseek, 339 .llseek = no_llseek,
340 .write = bfin_wdt_write, 340 .write = bfin_wdt_write,
341 .unlocked_ioctl = bfin_wdt_ioctl, 341 .unlocked_ioctl = bfin_wdt_ioctl,
342 .open = bfin_wdt_open, 342 .open = bfin_wdt_open,
343 .release = bfin_wdt_release, 343 .release = bfin_wdt_release,
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 7e7ec9c35b6a..337265b47305 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
4 * Author: Matthew McClintock 4 * Author: Matthew McClintock
5 * Maintainer: Kumar Gala <galak@kernel.crashing.org> 5 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
6 * 6 *
7 * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc. 7 * Copyright 2005, 2008, 2010-2011 Freescale Semiconductor Inc.
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify it 9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the 10 * 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 if (booke_wdt_enabled == 0) { 221 if (booke_wdt_enabled == 0) {
222 booke_wdt_enabled = 1; 222 booke_wdt_enabled = 1;
223 on_each_cpu(__booke_wdt_enable, NULL, 0); 223 on_each_cpu(__booke_wdt_enable, NULL, 0);
224 printk(KERN_INFO 224 pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
225 "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", 225 period_to_sec(booke_wdt_period));
226 booke_wdt_period);
227 } 226 }
228 spin_unlock(&booke_wdt_lock); 227 spin_unlock(&booke_wdt_lock);
229 228
@@ -240,6 +239,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
240 */ 239 */
241 on_each_cpu(__booke_wdt_disable, NULL, 0); 240 on_each_cpu(__booke_wdt_disable, NULL, 0);
242 booke_wdt_enabled = 0; 241 booke_wdt_enabled = 0;
242 pr_debug("booke_wdt: watchdog disabled\n");
243#endif 243#endif
244 244
245 clear_bit(0, &wdt_is_active); 245 clear_bit(0, &wdt_is_active);
@@ -271,21 +271,20 @@ static int __init booke_wdt_init(void)
271{ 271{
272 int ret = 0; 272 int ret = 0;
273 273
274 printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); 274 pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
275 ident.firmware_version = cur_cpu_spec->pvr_value; 275 ident.firmware_version = cur_cpu_spec->pvr_value;
276 276
277 ret = misc_register(&booke_wdt_miscdev); 277 ret = misc_register(&booke_wdt_miscdev);
278 if (ret) { 278 if (ret) {
279 printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n", 279 pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
280 WATCHDOG_MINOR, ret); 280 WATCHDOG_MINOR, ret);
281 return ret; 281 return ret;
282 } 282 }
283 283
284 spin_lock(&booke_wdt_lock); 284 spin_lock(&booke_wdt_lock);
285 if (booke_wdt_enabled == 1) { 285 if (booke_wdt_enabled == 1) {
286 printk(KERN_INFO 286 pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
287 "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", 287 period_to_sec(booke_wdt_period));
288 booke_wdt_period);
289 on_each_cpu(__booke_wdt_enable, NULL, 0); 288 on_each_cpu(__booke_wdt_enable, NULL, 0);
290 } 289 }
291 spin_unlock(&booke_wdt_lock); 290 spin_unlock(&booke_wdt_lock);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 65911678453d..1e013e8457b7 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -5,10 +5,10 @@
5 * interface and Solaris-compatible ioctls as best it is 5 * interface and Solaris-compatible ioctls as best it is
6 * able. 6 * able.
7 * 7 *
8 * NOTE: CP1400 systems appear to have a defective intr_mask 8 * NOTE: CP1400 systems appear to have a defective intr_mask
9 * register on the PLD, preventing the disabling of 9 * register on the PLD, preventing the disabling of
10 * timer interrupts. We use a timer to periodically 10 * timer interrupts. We use a timer to periodically
11 * reset 'stopped' watchdogs on affected platforms. 11 * reset 'stopped' watchdogs on affected platforms.
12 * 12 *
13 * Copyright (c) 2000 Eric Brower (ebrower@usa.net) 13 * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
14 * Copyright (C) 2008 David S. Miller <davem@davemloft.net> 14 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
@@ -107,13 +107,13 @@ static struct cpwd *cpwd_device;
107 * ------------------- 107 * -------------------
108 * |- counter val -| 108 * |- counter val -|
109 * ------------------- 109 * -------------------
110 * dcntr - Current 16-bit downcounter value. 110 * dcntr - Current 16-bit downcounter value.
111 * When downcounter reaches '0' watchdog expires. 111 * When downcounter reaches '0' watchdog expires.
112 * Reading this register resets downcounter with 112 * Reading this register resets downcounter with
113 * 'limit' value. 113 * 'limit' value.
114 * limit - 16-bit countdown value in 1/10th second increments. 114 * limit - 16-bit countdown value in 1/10th second increments.
115 * Writing this register begins countdown with input value. 115 * Writing this register begins countdown with input value.
116 * Reading from this register does not affect counter. 116 * Reading from this register does not affect counter.
117 * NOTES: After watchdog reset, dcntr and limit contain '1' 117 * NOTES: After watchdog reset, dcntr and limit contain '1'
118 * 118 *
119 * status register (byte access): 119 * status register (byte access):
@@ -123,7 +123,7 @@ static struct cpwd *cpwd_device;
123 * |- UNUSED -| EXP | RUN | 123 * |- UNUSED -| EXP | RUN |
124 * --------------------------- 124 * ---------------------------
125 * status- Bit 0 - Watchdog is running 125 * status- Bit 0 - Watchdog is running
126 * Bit 1 - Watchdog has expired 126 * Bit 1 - Watchdog has expired
127 * 127 *
128 *** PLD register block definition (struct wd_pld_regblk) 128 *** PLD register block definition (struct wd_pld_regblk)
129 * 129 *
@@ -197,7 +197,7 @@ static u8 cpwd_readb(void __iomem *addr)
197 * Because of the CP1400 defect this should only be 197 * Because of the CP1400 defect this should only be
198 * called during initialzation or by wd_[start|stop]timer() 198 * called during initialzation or by wd_[start|stop]timer()
199 * 199 *
200 * index - sub-device index, or -1 for 'all' 200 * index - sub-device index, or -1 for 'all'
201 * enable - non-zero to enable interrupts, zero to disable 201 * enable - non-zero to enable interrupts, zero to disable
202 */ 202 */
203static void cpwd_toggleintr(struct cpwd *p, int index, int enable) 203static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
@@ -317,13 +317,13 @@ static int cpwd_getstatus(struct cpwd *p, int index)
317 } else { 317 } else {
318 /* Fudge WD_EXPIRED status for defective CP1400-- 318 /* Fudge WD_EXPIRED status for defective CP1400--
319 * IF timer is running 319 * IF timer is running
320 * AND brokenstop is set 320 * AND brokenstop is set
321 * AND an interrupt has been serviced 321 * AND an interrupt has been serviced
322 * we are WD_EXPIRED. 322 * we are WD_EXPIRED.
323 * 323 *
324 * IF timer is running 324 * IF timer is running
325 * AND brokenstop is set 325 * AND brokenstop is set
326 * AND no interrupt has been serviced 326 * AND no interrupt has been serviced
327 * we are WD_FREERUN. 327 * we are WD_FREERUN.
328 */ 328 */
329 if (p->broken && 329 if (p->broken &&
@@ -613,7 +613,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
613 613
614 if (p->broken) { 614 if (p->broken) {
615 init_timer(&cpwd_timer); 615 init_timer(&cpwd_timer);
616 cpwd_timer.function = cpwd_brokentimer; 616 cpwd_timer.function = cpwd_brokentimer;
617 cpwd_timer.data = (unsigned long) p; 617 cpwd_timer.data = (unsigned long) p;
618 cpwd_timer.expires = WD_BTIMEOUT; 618 cpwd_timer.expires = WD_BTIMEOUT;
619 619
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 3f3dc093ad68..f1d1da662fbe 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -201,7 +201,7 @@ static void eurwdt_ping(void)
201static ssize_t eurwdt_write(struct file *file, const char __user *buf, 201static ssize_t eurwdt_write(struct file *file, const char __user *buf,
202size_t count, loff_t *ppos) 202size_t count, loff_t *ppos)
203{ 203{
204 if (count) { 204 if (count) {
205 if (!nowayout) { 205 if (!nowayout) {
206 size_t i; 206 size_t i;
207 207
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 204a5603c4ae..8cb26855bfed 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -52,7 +52,7 @@ static void __iomem *pci_mem_addr; /* the PCI-memory address */
52static unsigned long __iomem *hpwdt_timer_reg; 52static unsigned long __iomem *hpwdt_timer_reg;
53static unsigned long __iomem *hpwdt_timer_con; 53static unsigned long __iomem *hpwdt_timer_con;
54 54
55static struct pci_device_id hpwdt_devices[] = { 55static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = {
56 { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ 56 { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */
57 { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ 57 { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */
58 {0}, /* terminate list */ 58 {0}, /* terminate list */
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index bb9750a03942..db45091ef434 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = {
334/* 334/*
335 * Data for PCI driver interface 335 * Data for PCI driver interface
336 */ 336 */
337static struct pci_device_id esb_pci_tbl[] = { 337static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = {
338 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, 338 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
339 { 0, }, /* End of list */ 339 { 0, }, /* End of list */
340}; 340};
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 2c6c2b4ad8bf..35a0d12dad73 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -247,7 +247,7 @@ static struct {
247 {NULL, 0} 247 {NULL, 0}
248}; 248};
249 249
250#define ITCO_PCI_DEVICE(dev, data) \ 250#define ITCO_PCI_DEVICE(dev, data) \
251 .vendor = PCI_VENDOR_ID_INTEL, \ 251 .vendor = PCI_VENDOR_ID_INTEL, \
252 .device = dev, \ 252 .device = dev, \
253 .subvendor = PCI_ANY_ID, \ 253 .subvendor = PCI_ANY_ID, \
@@ -262,7 +262,7 @@ static struct {
262 * pci_driver, because the I/O Controller Hub has also other 262 * pci_driver, because the I/O Controller Hub has also other
263 * functions that probably will be registered by other drivers. 263 * functions that probably will be registered by other drivers.
264 */ 264 */
265static struct pci_device_id iTCO_wdt_pci_tbl[] = { 265static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
266 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)}, 266 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)},
267 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)}, 267 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)},
268 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)}, 268 { 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
index 000000000000..919bdd16136f
--- /dev/null
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -0,0 +1,572 @@
1/*
2 * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
3 * for Intel part #(s):
4 * - AF82MP20 PCH
5 *
6 * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General
10 * Public License as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied
14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 * The full GNU General Public License is included in this
21 * distribution in the file called COPYING.
22 *
23 */
24
25#include <linux/compiler.h>
26#include <linux/module.h>
27#include <linux/kernel.h>
28#include <linux/moduleparam.h>
29#include <linux/types.h>
30#include <linux/miscdevice.h>
31#include <linux/watchdog.h>
32#include <linux/fs.h>
33#include <linux/notifier.h>
34#include <linux/reboot.h>
35#include <linux/init.h>
36#include <linux/jiffies.h>
37#include <linux/uaccess.h>
38#include <linux/slab.h>
39#include <linux/io.h>
40#include <linux/interrupt.h>
41#include <linux/delay.h>
42#include <linux/sched.h>
43#include <linux/signal.h>
44#include <linux/sfi.h>
45#include <linux/types.h>
46#include <asm/irq.h>
47#include <asm/atomic.h>
48#include <asm/intel_scu_ipc.h>
49#include <asm/apb_timer.h>
50#include <asm/mrst.h>
51
52#include "intel_scu_watchdog.h"
53
54/* Bounds number of times we will retry loading time count */
55/* This retry is a work around for a silicon bug. */
56#define MAX_RETRY 16
57
58#define IPC_SET_WATCHDOG_TIMER 0xF8
59
60static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
61module_param(timer_margin, int, 0);
62MODULE_PARM_DESC(timer_margin,
63 "Watchdog timer margin"
64 "Time between interrupt and resetting the system"
65 "The range is from 1 to 160"
66 "This is the time for all keep alives to arrive");
67
68static int timer_set = DEFAULT_TIME;
69module_param(timer_set, int, 0);
70MODULE_PARM_DESC(timer_set,
71 "Default Watchdog timer setting"
72 "Complete cycle time"
73 "The range is from 1 to 170"
74 "This is the time for all keep alives to arrive");
75
76/* After watchdog device is closed, check force_boot. If:
77 * force_boot == 0, then force boot on next watchdog interrupt after close,
78 * force_boot == 1, then force boot immediately when device is closed.
79 */
80static int force_boot;
81module_param(force_boot, int, 0);
82MODULE_PARM_DESC(force_boot,
83 "A value of 1 means that the driver will reboot"
84 "the system immediately if the /dev/watchdog device is closed"
85 "A value of 0 means that when /dev/watchdog device is closed"
86 "the watchdog timer will be refreshed for one more interval"
87 "of length: timer_set. At the end of this interval, the"
88 "watchdog timer will reset the system."
89 );
90
91/* there is only one device in the system now; this can be made into
92 * an array in the future if we have more than one device */
93
94static struct intel_scu_watchdog_dev watchdog_device;
95
96/* Forces restart, if force_reboot is set */
97static void watchdog_fire(void)
98{
99 if (force_boot) {
100 printk(KERN_CRIT PFX "Initiating system reboot.\n");
101 emergency_restart();
102 printk(KERN_CRIT PFX "Reboot didn't ?????\n");
103 }
104
105 else {
106 printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
107 printk(KERN_CRIT PFX
108 "System will reset when watchdog timer times out!\n");
109 }
110}
111
112static int check_timer_margin(int new_margin)
113{
114 if ((new_margin < MIN_TIME_CYCLE) ||
115 (new_margin > MAX_TIME - timer_set)) {
116 pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
117 new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
118 return -EINVAL;
119 }
120 return 0;
121}
122
123/*
124 * IPC operations
125 */
126static int watchdog_set_ipc(int soft_threshold, int threshold)
127{
128 u32 *ipc_wbuf;
129 u8 cbuf[16] = { '\0' };
130 int ipc_ret = 0;
131
132 ipc_wbuf = (u32 *)&cbuf;
133 ipc_wbuf[0] = soft_threshold;
134 ipc_wbuf[1] = threshold;
135
136 ipc_ret = intel_scu_ipc_command(
137 IPC_SET_WATCHDOG_TIMER,
138 0,
139 ipc_wbuf,
140 2,
141 NULL,
142 0);
143
144 if (ipc_ret != 0)
145 pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
146
147 return ipc_ret;
148};
149
150/*
151 * Intel_SCU operations
152 */
153
154/* timer interrupt handler */
155static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
156{
157 int int_status;
158 int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
159
160 pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
161
162 if (int_status != 0)
163 return IRQ_NONE;
164
165 /* has the timer been started? If not, then this is spurious */
166 if (watchdog_device.timer_started == 0) {
167 pr_debug("Watchdog timer: spurious interrupt received\n");
168 return IRQ_HANDLED;
169 }
170
171 /* temporarily disable the timer */
172 iowrite32(0x00000002, watchdog_device.timer_control_addr);
173
174 /* set the timer to the threshold */
175 iowrite32(watchdog_device.threshold,
176 watchdog_device.timer_load_count_addr);
177
178 /* allow the timer to run */
179 iowrite32(0x00000003, watchdog_device.timer_control_addr);
180
181 return IRQ_HANDLED;
182}
183
184static int intel_scu_keepalive(void)
185{
186
187 /* read eoi register - clears interrupt */
188 ioread32(watchdog_device.timer_clear_interrupt_addr);
189
190 /* temporarily disable the timer */
191 iowrite32(0x00000002, watchdog_device.timer_control_addr);
192
193 /* set the timer to the soft_threshold */
194 iowrite32(watchdog_device.soft_threshold,
195 watchdog_device.timer_load_count_addr);
196
197 /* allow the timer to run */
198 iowrite32(0x00000003, watchdog_device.timer_control_addr);
199
200 return 0;
201}
202
203static int intel_scu_stop(void)
204{
205 iowrite32(0, watchdog_device.timer_control_addr);
206 return 0;
207}
208
209static int intel_scu_set_heartbeat(u32 t)
210{
211 int ipc_ret;
212 int retry_count;
213 u32 soft_value;
214 u32 hw_pre_value;
215 u32 hw_value;
216
217 watchdog_device.timer_set = t;
218 watchdog_device.threshold =
219 timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
220 watchdog_device.soft_threshold =
221 (watchdog_device.timer_set - timer_margin)
222 * watchdog_device.timer_tbl_ptr->freq_hz;
223
224 pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
225 watchdog_device.timer_tbl_ptr->freq_hz);
226 pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
227 watchdog_device.timer_set);
228 pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
229 timer_margin);
230 pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
231 watchdog_device.threshold);
232 pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
233 watchdog_device.soft_threshold);
234
235 /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
236 /* watchdog timing come out right. */
237 watchdog_device.threshold =
238 watchdog_device.threshold / FREQ_ADJUSTMENT;
239 watchdog_device.soft_threshold =
240 watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
241
242 /* temporarily disable the timer */
243 iowrite32(0x00000002, watchdog_device.timer_control_addr);
244
245 /* send the threshold and soft_threshold via IPC to the processor */
246 ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
247 watchdog_device.threshold);
248
249 if (ipc_ret != 0) {
250 /* Make sure the watchdog timer is stopped */
251 intel_scu_stop();
252 return ipc_ret;
253 }
254
255 /* Soft Threshold set loop. Early versions of silicon did */
256 /* not always set this count correctly. This loop checks */
257 /* the value and retries if it was not set correctly. */
258
259 retry_count = 0;
260 soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
261 do {
262
263 /* Make sure timer is stopped */
264 intel_scu_stop();
265
266 if (MAX_RETRY < retry_count++) {
267 /* Unable to set timer value */
268 pr_err("Watchdog timer: Unable to set timer\n");
269 return -ENODEV;
270 }
271
272 /* set the timer to the soft threshold */
273 iowrite32(watchdog_device.soft_threshold,
274 watchdog_device.timer_load_count_addr);
275
276 /* read count value before starting timer */
277 hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
278 hw_pre_value = hw_pre_value & 0xFFFF0000;
279
280 /* Start the timer */
281 iowrite32(0x00000003, watchdog_device.timer_control_addr);
282
283 /* read the value the time loaded into its count reg */
284 hw_value = ioread32(watchdog_device.timer_load_count_addr);
285 hw_value = hw_value & 0xFFFF0000;
286
287
288 } while (soft_value != hw_value);
289
290 watchdog_device.timer_started = 1;
291
292 return 0;
293}
294
295/*
296 * /dev/watchdog handling
297 */
298
299static int intel_scu_open(struct inode *inode, struct file *file)
300{
301
302 /* Set flag to indicate that watchdog device is open */
303 if (test_and_set_bit(0, &watchdog_device.driver_open))
304 return -EBUSY;
305
306 /* Check for reopen of driver. Reopens are not allowed */
307 if (watchdog_device.driver_closed)
308 return -EPERM;
309
310 return nonseekable_open(inode, file);
311}
312
313static int intel_scu_release(struct inode *inode, struct file *file)
314{
315 /*
316 * This watchdog should not be closed, after the timer
317 * is started with the WDIPC_SETTIMEOUT ioctl
318 * If force_boot is set watchdog_fire() will cause an
319 * immediate reset. If force_boot is not set, the watchdog
320 * timer is refreshed for one more interval. At the end
321 * of that interval, the watchdog timer will reset the system.
322 */
323
324 if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
325 pr_debug("Watchdog timer: intel_scu_release, without open\n");
326 return -ENOTTY;
327 }
328
329 if (!watchdog_device.timer_started) {
330 /* Just close, since timer has not been started */
331 pr_debug("Watchdog timer: closed, without starting timer\n");
332 return 0;
333 }
334
335 printk(KERN_CRIT PFX
336 "Unexpected close of /dev/watchdog!\n");
337
338 /* Since the timer was started, prevent future reopens */
339 watchdog_device.driver_closed = 1;
340
341 /* Refresh the timer for one more interval */
342 intel_scu_keepalive();
343
344 /* Reboot system (if force_boot is set) */
345 watchdog_fire();
346
347 /* We should only reach this point if force_boot is not set */
348 return 0;
349}
350
351static ssize_t intel_scu_write(struct file *file,
352 char const *data,
353 size_t len,
354 loff_t *ppos)
355{
356
357 if (watchdog_device.timer_started)
358 /* Watchdog already started, keep it alive */
359 intel_scu_keepalive();
360 else
361 /* Start watchdog with timer value set by init */
362 intel_scu_set_heartbeat(watchdog_device.timer_set);
363
364 return len;
365}
366
367static long intel_scu_ioctl(struct file *file,
368 unsigned int cmd,
369 unsigned long arg)
370{
371 void __user *argp = (void __user *)arg;
372 u32 __user *p = argp;
373 u32 new_margin;
374
375
376 static const struct watchdog_info ident = {
377 .options = WDIOF_SETTIMEOUT
378 | WDIOF_KEEPALIVEPING,
379 .firmware_version = 0, /* @todo Get from SCU via
380 ipc_get_scu_fw_version()? */
381 .identity = "Intel_SCU IOH Watchdog" /* len < 32 */
382 };
383
384 switch (cmd) {
385 case WDIOC_GETSUPPORT:
386 return copy_to_user(argp,
387 &ident,
388 sizeof(ident)) ? -EFAULT : 0;
389 case WDIOC_GETSTATUS:
390 case WDIOC_GETBOOTSTATUS:
391 return put_user(0, p);
392 case WDIOC_KEEPALIVE:
393 intel_scu_keepalive();
394
395 return 0;
396 case WDIOC_SETTIMEOUT:
397 if (get_user(new_margin, p))
398 return -EFAULT;
399
400 if (check_timer_margin(new_margin))
401 return -EINVAL;
402
403 if (intel_scu_set_heartbeat(new_margin))
404 return -EINVAL;
405 return 0;
406 case WDIOC_GETTIMEOUT:
407 return put_user(watchdog_device.soft_threshold, p);
408
409 default:
410 return -ENOTTY;
411 }
412}
413
414/*
415 * Notifier for system down
416 */
417static int intel_scu_notify_sys(struct notifier_block *this,
418 unsigned long code,
419 void *another_unused)
420{
421 if (code == SYS_DOWN || code == SYS_HALT)
422 /* Turn off the watchdog timer. */
423 intel_scu_stop();
424 return NOTIFY_DONE;
425}
426
427/*
428 * Kernel Interfaces
429 */
430static const struct file_operations intel_scu_fops = {
431 .owner = THIS_MODULE,
432 .llseek = no_llseek,
433 .write = intel_scu_write,
434 .unlocked_ioctl = intel_scu_ioctl,
435 .open = intel_scu_open,
436 .release = intel_scu_release,
437};
438
439static int __init intel_scu_watchdog_init(void)
440{
441 int ret;
442 u32 __iomem *tmp_addr;
443
444 /*
445 * We don't really need to check this as the SFI timer get will fail
446 * but if we do so we can exit with a clearer reason and no noise.
447 *
448 * If it isn't an intel MID device then it doesn't have this watchdog
449 */
450 if (!mrst_identify_cpu())
451 return -ENODEV;
452
453 /* Check boot parameters to verify that their initial values */
454 /* are in range. */
455 /* Check value of timer_set boot parameter */
456 if ((timer_set < MIN_TIME_CYCLE) ||
457 (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
458 pr_err("Watchdog timer: value of timer_set %x (hex) "
459 "is out of range from %x to %x (hex)\n",
460 timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
461 return -EINVAL;
462 }
463
464 /* Check value of timer_margin boot parameter */
465 if (check_timer_margin(timer_margin))
466 return -EINVAL;
467
468 watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
469
470 if (watchdog_device.timer_tbl_ptr == NULL) {
471 pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
472 return -ENODEV;
473 }
474 /* make sure the timer exists */
475 if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
476 pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
477 sfi_mtimer_num);
478 return -ENODEV;
479 }
480
481 if (watchdog_device.timer_tbl_ptr->irq == 0) {
482 pr_debug("Watchdog timer: timer %d invalid irq\n",
483 sfi_mtimer_num);
484 return -ENODEV;
485 }
486
487 tmp_addr = ioremap_nocache(watchdog_device.timer_tbl_ptr->phys_addr,
488 20);
489
490 if (tmp_addr == NULL) {
491 pr_debug("Watchdog timer: timer unable to ioremap\n");
492 return -ENOMEM;
493 }
494
495 watchdog_device.timer_load_count_addr = tmp_addr++;
496 watchdog_device.timer_current_value_addr = tmp_addr++;
497 watchdog_device.timer_control_addr = tmp_addr++;
498 watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
499 watchdog_device.timer_interrupt_status_addr = tmp_addr++;
500
501 /* Set the default time values in device structure */
502
503 watchdog_device.timer_set = timer_set;
504 watchdog_device.threshold =
505 timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
506 watchdog_device.soft_threshold =
507 (watchdog_device.timer_set - timer_margin)
508 * watchdog_device.timer_tbl_ptr->freq_hz;
509
510
511 watchdog_device.intel_scu_notifier.notifier_call =
512 intel_scu_notify_sys;
513
514 ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
515 if (ret) {
516 pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
517 goto register_reboot_error;
518 }
519
520 watchdog_device.miscdev.minor = WATCHDOG_MINOR;
521 watchdog_device.miscdev.name = "watchdog";
522 watchdog_device.miscdev.fops = &intel_scu_fops;
523
524 ret = misc_register(&watchdog_device.miscdev);
525 if (ret) {
526 pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
527 WATCHDOG_MINOR, ret);
528 goto misc_register_error;
529 }
530
531 ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
532 watchdog_timer_interrupt,
533 IRQF_SHARED, "watchdog",
534 &watchdog_device.timer_load_count_addr);
535 if (ret) {
536 pr_err("Watchdog timer: error requesting irq %d\n", ret);
537 goto request_irq_error;
538 }
539 /* Make sure timer is disabled before returning */
540 intel_scu_stop();
541 return 0;
542
543/* error cleanup */
544
545request_irq_error:
546 misc_deregister(&watchdog_device.miscdev);
547misc_register_error:
548 unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
549register_reboot_error:
550 intel_scu_stop();
551 iounmap(watchdog_device.timer_load_count_addr);
552 return ret;
553}
554
555static void __exit intel_scu_watchdog_exit(void)
556{
557
558 misc_deregister(&watchdog_device.miscdev);
559 unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
560 /* disable the timer */
561 iowrite32(0x00000002, watchdog_device.timer_control_addr);
562 iounmap(watchdog_device.timer_load_count_addr);
563}
564
565late_initcall(intel_scu_watchdog_init);
566module_exit(intel_scu_watchdog_exit);
567
568MODULE_AUTHOR("Intel Corporation");
569MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
570MODULE_LICENSE("GPL");
571MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
572MODULE_VERSION(WDT_VER);
diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h
new file mode 100644
index 000000000000..d2b074a82db6
--- /dev/null
+++ b/drivers/watchdog/intel_scu_watchdog.h
@@ -0,0 +1,66 @@
1/*
2 * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
3 * for Intel part #(s):
4 * - AF82MP20 PCH
5 *
6 * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General
10 * Public License as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied
14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 * The full GNU General Public License is included in this
21 * distribution in the file called COPYING.
22 *
23 */
24
25#ifndef __INTEL_SCU_WATCHDOG_H
26#define __INTEL_SCU_WATCHDOG_H
27
28#define PFX "Intel_SCU: "
29#define WDT_VER "0.3"
30
31/* minimum time between interrupts */
32#define MIN_TIME_CYCLE 1
33
34/* Time from warning to reboot is 2 seconds */
35#define DEFAULT_SOFT_TO_HARD_MARGIN 2
36
37#define MAX_TIME 170
38
39#define DEFAULT_TIME 5
40
41#define MAX_SOFT_TO_HARD_MARGIN (MAX_TIME-MIN_TIME_CYCLE)
42
43/* Ajustment to clock tick frequency to make timing come out right */
44#define FREQ_ADJUSTMENT 8
45
46struct intel_scu_watchdog_dev {
47 ulong driver_open;
48 ulong driver_closed;
49 u32 timer_started;
50 u32 timer_set;
51 u32 threshold;
52 u32 soft_threshold;
53 u32 __iomem *timer_load_count_addr;
54 u32 __iomem *timer_current_value_addr;
55 u32 __iomem *timer_control_addr;
56 u32 __iomem *timer_clear_interrupt_addr;
57 u32 __iomem *timer_interrupt_status_addr;
58 struct sfi_timer_table_entry *timer_tbl_ptr;
59 struct notifier_block intel_scu_notifier;
60 struct miscdevice miscdev;
61};
62
63extern int sfi_mtimer_num;
64
65/* extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); */
66#endif /* __INTEL_SCU_WATCHDOG_H */
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index b32c6c045b1a..6143f52ba6b8 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -69,7 +69,7 @@ static unsigned short address;
69#define IT8712F_DEVID 0x8712 69#define IT8712F_DEVID 0x8712
70 70
71#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */ 71#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */
72#define LDN_GAME 0x09 /* Game Port */ 72#define LDN_GAME 0x09 /* Game Port */
73 73
74#define WDT_CONTROL 0x71 /* WDT Register: Control */ 74#define WDT_CONTROL 0x71 /* WDT Register: Control */
75#define WDT_CONFIG 0x72 /* WDT Register: Configuration */ 75#define WDT_CONFIG 0x72 /* WDT Register: Configuration */
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index dad29245a6a7..b1bc72f9a209 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,7 +12,7 @@
12 * http://www.ite.com.tw/ 12 * http://www.ite.com.tw/
13 * 13 *
14 * Support of the watchdog timers, which are available on 14 * Support of the watchdog timers, which are available on
15 * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. 15 * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
16 * 16 *
17 * This program is free software; you can redistribute it and/or 17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License 18 * modify it under the terms of the GNU General Public License
@@ -45,7 +45,7 @@
45 45
46#include <asm/system.h> 46#include <asm/system.h>
47 47
48#define WATCHDOG_VERSION "1.13" 48#define WATCHDOG_VERSION "1.14"
49#define WATCHDOG_NAME "IT87 WDT" 49#define WATCHDOG_NAME "IT87 WDT"
50#define PFX WATCHDOG_NAME ": " 50#define PFX WATCHDOG_NAME ": "
51#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" 51#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
@@ -54,7 +54,7 @@
54/* Defaults for Module Parameter */ 54/* Defaults for Module Parameter */
55#define DEFAULT_NOGAMEPORT 0 55#define DEFAULT_NOGAMEPORT 0
56#define DEFAULT_EXCLUSIVE 1 56#define DEFAULT_EXCLUSIVE 1
57#define DEFAULT_TIMEOUT 60 57#define DEFAULT_TIMEOUT 60
58#define DEFAULT_TESTMODE 0 58#define DEFAULT_TESTMODE 0
59#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT 59#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
60 60
@@ -70,9 +70,9 @@
70/* Configuration Registers and Functions */ 70/* Configuration Registers and Functions */
71#define LDNREG 0x07 71#define LDNREG 0x07
72#define CHIPID 0x20 72#define CHIPID 0x20
73#define CHIPREV 0x22 73#define CHIPREV 0x22
74#define ACTREG 0x30 74#define ACTREG 0x30
75#define BASEREG 0x60 75#define BASEREG 0x60
76 76
77/* Chip Id numbers */ 77/* Chip Id numbers */
78#define NO_DEV_ID 0xffff 78#define NO_DEV_ID 0xffff
@@ -82,10 +82,11 @@
82#define IT8716_ID 0x8716 82#define IT8716_ID 0x8716
83#define IT8718_ID 0x8718 83#define IT8718_ID 0x8718
84#define IT8720_ID 0x8720 84#define IT8720_ID 0x8720
85#define IT8721_ID 0x8721
85#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ 86#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
86 87
87/* GPIO Configuration Registers LDN=0x07 */ 88/* GPIO Configuration Registers LDN=0x07 */
88#define WDTCTRL 0x71 89#define WDTCTRL 0x71
89#define WDTCFG 0x72 90#define WDTCFG 0x72
90#define WDTVALLSB 0x73 91#define WDTVALLSB 0x73
91#define WDTVALMSB 0x74 92#define WDTVALMSB 0x74
@@ -94,7 +95,7 @@
94#define WDT_CIRINT 0x80 95#define WDT_CIRINT 0x80
95#define WDT_MOUSEINT 0x40 96#define WDT_MOUSEINT 0x40
96#define WDT_KYBINT 0x20 97#define WDT_KYBINT 0x20
97#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ 98#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721 */
98#define WDT_FORCE 0x02 99#define WDT_FORCE 0x02
99#define WDT_ZERO 0x01 100#define WDT_ZERO 0x01
100 101
@@ -102,11 +103,11 @@
102#define WDT_TOV1 0x80 103#define WDT_TOV1 0x80
103#define WDT_KRST 0x40 104#define WDT_KRST 0x40
104#define WDT_TOVE 0x20 105#define WDT_TOVE 0x20
105#define WDT_PWROK 0x10 106#define WDT_PWROK 0x10 /* not in it8721 */
106#define WDT_INT_MASK 0x0f 107#define WDT_INT_MASK 0x0f
107 108
108/* CIR Configuration Register LDN=0x0a */ 109/* CIR Configuration Register LDN=0x0a */
109#define CIR_ILS 0x70 110#define CIR_ILS 0x70
110 111
111/* The default Base address is not always available, we use this */ 112/* The default Base address is not always available, we use this */
112#define CIR_BASE 0x0208 113#define CIR_BASE 0x0208
@@ -134,7 +135,7 @@
134#define WDTS_USE_GP 4 135#define WDTS_USE_GP 4
135#define WDTS_EXPECTED 5 136#define WDTS_EXPECTED 5
136 137
137static unsigned int base, gpact, ciract, max_units; 138static unsigned int base, gpact, ciract, max_units, chip_type;
138static unsigned long wdt_status; 139static unsigned long wdt_status;
139static DEFINE_SPINLOCK(spinlock); 140static DEFINE_SPINLOCK(spinlock);
140 141
@@ -215,7 +216,7 @@ static inline void superio_outw(int val, int reg)
215/* Internal function, should be called after superio_select(GPIO) */ 216/* Internal function, should be called after superio_select(GPIO) */
216static void wdt_update_timeout(void) 217static void wdt_update_timeout(void)
217{ 218{
218 unsigned char cfg = WDT_KRST | WDT_PWROK; 219 unsigned char cfg = WDT_KRST;
219 int tm = timeout; 220 int tm = timeout;
220 221
221 if (testmode) 222 if (testmode)
@@ -226,6 +227,9 @@ static void wdt_update_timeout(void)
226 else 227 else
227 tm /= 60; 228 tm /= 60;
228 229
230 if (chip_type != IT8721_ID)
231 cfg |= WDT_PWROK;
232
229 superio_outb(cfg, WDTCFG); 233 superio_outb(cfg, WDTCFG);
230 superio_outb(tm, WDTVALLSB); 234 superio_outb(tm, WDTVALLSB);
231 if (max_units > 255) 235 if (max_units > 255)
@@ -555,7 +559,6 @@ static int __init it87_wdt_init(void)
555{ 559{
556 int rc = 0; 560 int rc = 0;
557 int try_gameport = !nogameport; 561 int try_gameport = !nogameport;
558 u16 chip_type;
559 u8 chip_rev; 562 u8 chip_rev;
560 unsigned long flags; 563 unsigned long flags;
561 564
@@ -581,6 +584,7 @@ static int __init it87_wdt_init(void)
581 break; 584 break;
582 case IT8718_ID: 585 case IT8718_ID:
583 case IT8720_ID: 586 case IT8720_ID:
587 case IT8721_ID:
584 max_units = 65535; 588 max_units = 65535;
585 try_gameport = 0; 589 try_gameport = 0;
586 break; 590 break;
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
new file mode 100644
index 000000000000..684ba01fb540
--- /dev/null
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -0,0 +1,322 @@
1/*
2 * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net>
3 * JZ4740 Watchdog driver
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/fs.h>
21#include <linux/miscdevice.h>
22#include <linux/watchdog.h>
23#include <linux/init.h>
24#include <linux/bitops.h>
25#include <linux/platform_device.h>
26#include <linux/spinlock.h>
27#include <linux/uaccess.h>
28#include <linux/io.h>
29#include <linux/device.h>
30#include <linux/clk.h>
31#include <linux/slab.h>
32
33#include <asm/mach-jz4740/timer.h>
34
35#define JZ_REG_WDT_TIMER_DATA 0x0
36#define JZ_REG_WDT_COUNTER_ENABLE 0x4
37#define JZ_REG_WDT_TIMER_COUNTER 0x8
38#define JZ_REG_WDT_TIMER_CONTROL 0xC
39
40#define JZ_WDT_CLOCK_PCLK 0x1
41#define JZ_WDT_CLOCK_RTC 0x2
42#define JZ_WDT_CLOCK_EXT 0x4
43
44#define WDT_IN_USE 0
45#define WDT_OK_TO_CLOSE 1
46
47#define JZ_WDT_CLOCK_DIV_SHIFT 3
48
49#define JZ_WDT_CLOCK_DIV_1 (0 << JZ_WDT_CLOCK_DIV_SHIFT)
50#define JZ_WDT_CLOCK_DIV_4 (1 << JZ_WDT_CLOCK_DIV_SHIFT)
51#define JZ_WDT_CLOCK_DIV_16 (2 << JZ_WDT_CLOCK_DIV_SHIFT)
52#define JZ_WDT_CLOCK_DIV_64 (3 << JZ_WDT_CLOCK_DIV_SHIFT)
53#define JZ_WDT_CLOCK_DIV_256 (4 << JZ_WDT_CLOCK_DIV_SHIFT)
54#define JZ_WDT_CLOCK_DIV_1024 (5 << JZ_WDT_CLOCK_DIV_SHIFT)
55
56#define DEFAULT_HEARTBEAT 5
57#define MAX_HEARTBEAT 2048
58
59static struct {
60 void __iomem *base;
61 struct resource *mem;
62 struct clk *rtc_clk;
63 unsigned long status;
64} jz4740_wdt;
65
66static int heartbeat = DEFAULT_HEARTBEAT;
67
68
69static void jz4740_wdt_service(void)
70{
71 writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
72}
73
74static void jz4740_wdt_set_heartbeat(int new_heartbeat)
75{
76 unsigned int rtc_clk_rate;
77 unsigned int timeout_value;
78 unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
79
80 heartbeat = new_heartbeat;
81
82 rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
83
84 timeout_value = rtc_clk_rate * heartbeat;
85 while (timeout_value > 0xffff) {
86 if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
87 /* Requested timeout too high;
88 * use highest possible value. */
89 timeout_value = 0xffff;
90 break;
91 }
92 timeout_value >>= 2;
93 clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
94 }
95
96 writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
97 writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
98
99 writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
100 writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
101 writew(clock_div | JZ_WDT_CLOCK_RTC,
102 jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
103
104 writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
105}
106
107static void jz4740_wdt_enable(void)
108{
109 jz4740_timer_enable_watchdog();
110 jz4740_wdt_set_heartbeat(heartbeat);
111}
112
113static void jz4740_wdt_disable(void)
114{
115 jz4740_timer_disable_watchdog();
116 writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
117}
118
119static int jz4740_wdt_open(struct inode *inode, struct file *file)
120{
121 if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
122 return -EBUSY;
123
124 jz4740_wdt_enable();
125
126 return nonseekable_open(inode, file);
127}
128
129static ssize_t jz4740_wdt_write(struct file *file, const char *data,
130 size_t len, loff_t *ppos)
131{
132 if (len) {
133 size_t i;
134
135 clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
136 for (i = 0; i != len; i++) {
137 char c;
138
139 if (get_user(c, data + i))
140 return -EFAULT;
141
142 if (c == 'V')
143 set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
144 }
145 jz4740_wdt_service();
146 }
147
148 return len;
149}
150
151static const struct watchdog_info ident = {
152 .options = WDIOF_KEEPALIVEPING,
153 .identity = "jz4740 Watchdog",
154};
155
156static long jz4740_wdt_ioctl(struct file *file,
157 unsigned int cmd, unsigned long arg)
158{
159 int ret = -ENOTTY;
160 int heartbeat_seconds;
161
162 switch (cmd) {
163 case WDIOC_GETSUPPORT:
164 ret = copy_to_user((struct watchdog_info *)arg, &ident,
165 sizeof(ident)) ? -EFAULT : 0;
166 break;
167
168 case WDIOC_GETSTATUS:
169 case WDIOC_GETBOOTSTATUS:
170 ret = put_user(0, (int *)arg);
171 break;
172
173 case WDIOC_KEEPALIVE:
174 jz4740_wdt_service();
175 return 0;
176
177 case WDIOC_SETTIMEOUT:
178 if (get_user(heartbeat_seconds, (int __user *)arg))
179 return -EFAULT;
180
181 jz4740_wdt_set_heartbeat(heartbeat_seconds);
182 return 0;
183
184 case WDIOC_GETTIMEOUT:
185 return put_user(heartbeat, (int *)arg);
186
187 default:
188 break;
189 }
190
191 return ret;
192}
193
194static int jz4740_wdt_release(struct inode *inode, struct file *file)
195{
196 jz4740_wdt_service();
197
198 if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
199 jz4740_wdt_disable();
200
201 clear_bit(WDT_IN_USE, &jz4740_wdt.status);
202 return 0;
203}
204
205static const struct file_operations jz4740_wdt_fops = {
206 .owner = THIS_MODULE,
207 .llseek = no_llseek,
208 .write = jz4740_wdt_write,
209 .unlocked_ioctl = jz4740_wdt_ioctl,
210 .open = jz4740_wdt_open,
211 .release = jz4740_wdt_release,
212};
213
214static struct miscdevice jz4740_wdt_miscdev = {
215 .minor = WATCHDOG_MINOR,
216 .name = "watchdog",
217 .fops = &jz4740_wdt_fops,
218};
219
220static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
221{
222 int ret = 0, size;
223 struct resource *res;
224 struct device *dev = &pdev->dev;
225
226 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
227 if (res == NULL) {
228 dev_err(dev, "failed to get memory region resource\n");
229 return -ENXIO;
230 }
231
232 size = resource_size(res);
233 jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
234 if (jz4740_wdt.mem == NULL) {
235 dev_err(dev, "failed to get memory region\n");
236 return -EBUSY;
237 }
238
239 jz4740_wdt.base = ioremap_nocache(res->start, size);
240 if (jz4740_wdt.base == NULL) {
241 dev_err(dev, "failed to map memory region\n");
242 ret = -EBUSY;
243 goto err_release_region;
244 }
245
246 jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
247 if (IS_ERR(jz4740_wdt.rtc_clk)) {
248 dev_err(dev, "cannot find RTC clock\n");
249 ret = PTR_ERR(jz4740_wdt.rtc_clk);
250 goto err_iounmap;
251 }
252
253 ret = misc_register(&jz4740_wdt_miscdev);
254 if (ret < 0) {
255 dev_err(dev, "cannot register misc device\n");
256 goto err_disable_clk;
257 }
258
259 return 0;
260
261err_disable_clk:
262 clk_put(jz4740_wdt.rtc_clk);
263err_iounmap:
264 iounmap(jz4740_wdt.base);
265err_release_region:
266 release_mem_region(jz4740_wdt.mem->start,
267 resource_size(jz4740_wdt.mem));
268 return ret;
269}
270
271
272static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
273{
274 jz4740_wdt_disable();
275 misc_deregister(&jz4740_wdt_miscdev);
276 clk_put(jz4740_wdt.rtc_clk);
277
278 iounmap(jz4740_wdt.base);
279 jz4740_wdt.base = NULL;
280
281 release_mem_region(jz4740_wdt.mem->start,
282 resource_size(jz4740_wdt.mem));
283 jz4740_wdt.mem = NULL;
284
285 return 0;
286}
287
288
289static struct platform_driver jz4740_wdt_driver = {
290 .probe = jz4740_wdt_probe,
291 .remove = __devexit_p(jz4740_wdt_remove),
292 .driver = {
293 .name = "jz4740-wdt",
294 .owner = THIS_MODULE,
295 },
296};
297
298
299static int __init jz4740_wdt_init(void)
300{
301 return platform_driver_register(&jz4740_wdt_driver);
302}
303module_init(jz4740_wdt_init);
304
305static void __exit jz4740_wdt_exit(void)
306{
307 platform_driver_unregister(&jz4740_wdt_driver);
308}
309module_exit(jz4740_wdt_exit);
310
311MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
312MODULE_DESCRIPTION("jz4740 Watchdog Driver");
313
314module_param(heartbeat, int, 0);
315MODULE_PARM_DESC(heartbeat,
316 "Watchdog heartbeat period in seconds from 1 to "
317 __MODULE_STRING(MAX_HEARTBEAT) ", default "
318 __MODULE_STRING(DEFAULT_HEARTBEAT));
319
320MODULE_LICENSE("GPL");
321MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
322MODULE_ALIAS("platform:jz4740-wdt");
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 928035069396..1332b838cc58 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -54,7 +54,7 @@
54 54
55/* indexes */ /* size */ 55/* indexes */ /* size */
56#define ZFL_VERSION 0x02 /* 16 */ 56#define ZFL_VERSION 0x02 /* 16 */
57#define CONTROL 0x10 /* 16 */ 57#define CONTROL 0x10 /* 16 */
58#define STATUS 0x12 /* 8 */ 58#define STATUS 0x12 /* 8 */
59#define COUNTER_1 0x0C /* 16 */ 59#define COUNTER_1 0x0C /* 16 */
60#define COUNTER_2 0x0E /* 8 */ 60#define COUNTER_2 0x0E /* 8 */
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index 3053ff05ca41..7a82ce5a6337 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -41,7 +41,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
41 * to ping the watchdog. 41 * to ping the watchdog.
42 */ 42 */
43#define MAX6369_WDSET (7 << 0) 43#define MAX6369_WDSET (7 << 0)
44#define MAX6369_WDI (1 << 3) 44#define MAX6369_WDI (1 << 3)
45 45
46static DEFINE_SPINLOCK(io_lock); 46static DEFINE_SPINLOCK(io_lock);
47 47
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index ea438ad53055..6709d723e017 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -2,9 +2,9 @@
2 * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface 2 * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
3 * 3 *
4 * Authors: Dave Updegraff <dave@cray.org> 4 * Authors: Dave Updegraff <dave@cray.org>
5 * Kumar Gala <galak@kernel.crashing.org> 5 * Kumar Gala <galak@kernel.crashing.org>
6 * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org> 6 * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
7 * ..and from sc520_wdt 7 * ..and from sc520_wdt
8 * Copyright (c) 2008 MontaVista Software, Inc. 8 * Copyright (c) 2008 MontaVista Software, Inc.
9 * Anton Vorontsov <avorontsov@ru.mvista.com> 9 * Anton Vorontsov <avorontsov@ru.mvista.com>
10 * 10 *
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index b8ec7aca3c8e..2b4af222b5f2 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -172,7 +172,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
172 172
173 /* 173 /*
174 * Shut off the timer. 174 * Shut off the timer.
175 * Lock it in if it's a module and we set nowayout 175 * Lock it in if it's a module and we set nowayout
176 */ 176 */
177 if (wdt->expect_close == 42) 177 if (wdt->expect_close == 42)
178 mpcore_wdt_stop(wdt); 178 mpcore_wdt_stop(wdt);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 08e8a6ab74e1..5ec5ac1f7878 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -190,19 +190,19 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
190} 190}
191 191
192static const struct file_operations mtx1_wdt_fops = { 192static const struct file_operations mtx1_wdt_fops = {
193 .owner = THIS_MODULE, 193 .owner = THIS_MODULE,
194 .llseek = no_llseek, 194 .llseek = no_llseek,
195 .unlocked_ioctl = mtx1_wdt_ioctl, 195 .unlocked_ioctl = mtx1_wdt_ioctl,
196 .open = mtx1_wdt_open, 196 .open = mtx1_wdt_open,
197 .write = mtx1_wdt_write, 197 .write = mtx1_wdt_write,
198 .release = mtx1_wdt_release, 198 .release = mtx1_wdt_release,
199}; 199};
200 200
201 201
202static struct miscdevice mtx1_wdt_misc = { 202static struct miscdevice mtx1_wdt_misc = {
203 .minor = WATCHDOG_MINOR, 203 .minor = WATCHDOG_MINOR,
204 .name = "watchdog", 204 .name = "watchdog",
205 .fops = &mtx1_wdt_fops, 205 .fops = &mtx1_wdt_fops,
206}; 206};
207 207
208 208
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
index 1a50aa7079bf..267377a5a83e 100644
--- a/drivers/watchdog/nv_tco.c
+++ b/drivers/watchdog/nv_tco.c
@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = {
289 * register a pci_driver, because someone else might one day 289 * register a pci_driver, because someone else might one day
290 * want to register another driver on the same PCI id. 290 * want to register another driver on the same PCI id.
291 */ 291 */
292static struct pci_device_id tco_pci_tbl[] = { 292static DEFINE_PCI_DEVICE_TABLE(tco_pci_tbl) = {
293 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, 293 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
294 PCI_ANY_ID, PCI_ANY_ID, }, 294 PCI_ANY_ID, PCI_ANY_ID, },
295 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, 295 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index fc02ec6a0386..09b774cf75b9 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -44,7 +44,7 @@
44 * months before firing. These limits work without scaling, 44 * months before firing. These limits work without scaling,
45 * with the 60 second default assumed by most tools and docs. 45 * with the 60 second default assumed by most tools and docs.
46 */ 46 */
47#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */ 47#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
48#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */ 48#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
49#define TIMER_MARGIN_MIN 1 49#define TIMER_MARGIN_MIN 1
50 50
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 3a56bc360924..139d773300c6 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -514,7 +514,7 @@ static struct miscdevice pc87413_miscdev = {
514/* -- Module init functions -------------------------------------*/ 514/* -- Module init functions -------------------------------------*/
515 515
516/** 516/**
517 * pc87413_init: module's "constructor" 517 * pc87413_init: module's "constructor"
518 * 518 *
519 * Set up the WDT watchdog board. All we have to do is grab the 519 * Set up the WDT watchdog board. All we have to do is grab the
520 * resources we require and bitch if anyone beat us to them. 520 * resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index 64374d636f09..b8d14f88f0b5 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -817,7 +817,7 @@ static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
817 cards_found--; 817 cards_found--;
818} 818}
819 819
820static struct pci_device_id pcipcwd_pci_tbl[] = { 820static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = {
821 { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD, 821 { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
822 PCI_ANY_ID, PCI_ANY_ID, }, 822 PCI_ANY_ID, PCI_ANY_ID, },
823 { 0 }, /* End of list */ 823 { 0 }, /* End of list */
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index bf5b97c546eb..c7cf4cbf8ab3 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -4,7 +4,7 @@
4 * Watchdog driver for PNX4008 board 4 * Watchdog driver for PNX4008 board
5 * 5 *
6 * Authors: Dmitry Chigirev <source@mvista.com>, 6 * Authors: Dmitry Chigirev <source@mvista.com>,
7 * Vitaly Wool <vitalywool@gmail.com> 7 * Vitaly Wool <vitalywool@gmail.com>
8 * Based on sa1100 driver, 8 * Based on sa1100 driver,
9 * Copyright (C) 2000 Oleg Drokin <green@crimea.edu> 9 * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
10 * 10 *
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index ae53662c29bc..25b39bf35925 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -224,7 +224,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
224{ 224{
225 /* 225 /*
226 * Shut off the timer. 226 * Shut off the timer.
227 * Lock it in if it's a module and we set nowayout 227 * Lock it in if it's a module and we set nowayout
228 */ 228 */
229 229
230 if (expect_close == 42) 230 if (expect_close == 42)
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 68e2e2d6f73d..514ec23050f7 100644
--- a/drivers/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -114,7 +114,7 @@ static char expect_close;
114 * C | 6.5s 65s 650s 1300s 114 * C | 6.5s 65s 650s 1300s
115 * D | 7s 70s 700s 1400s 115 * D | 7s 70s 700s 1400s
116 * E | 7.5s 75s 750s 1500s 116 * E | 7.5s 75s 750s 1500s
117 * F | 8s 80s 800s 1600s 117 * F | 8s 80s 800s 1600s
118 * 118 *
119 * Another way to say the same things is: 119 * Another way to say the same things is:
120 * For N=1, Timeout = (M+1) * 0.5s 120 * For N=1, Timeout = (M+1) * 0.5s
diff --git a/drivers/watchdog/sbc_fitpc2_wdt.c b/drivers/watchdog/sbc_fitpc2_wdt.c
index 79906255eeb6..d5d399464599 100644
--- a/drivers/watchdog/sbc_fitpc2_wdt.c
+++ b/drivers/watchdog/sbc_fitpc2_wdt.c
@@ -41,7 +41,7 @@ static DEFINE_MUTEX(wdt_lock);
41#define IFACE_ON_COMMAND 1 41#define IFACE_ON_COMMAND 1
42#define REBOOT_COMMAND 2 42#define REBOOT_COMMAND 2
43 43
44#define WATCHDOG_NAME "SBC-FITPC2 Watchdog" 44#define WATCHDOG_NAME "SBC-FITPC2 Watchdog"
45 45
46static void wdt_send_data(unsigned char command, unsigned char data) 46static void wdt_send_data(unsigned char command, unsigned char data)
47{ 47{
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index 8a1f0bc3e271..df88cfa05f35 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -434,11 +434,11 @@ static long wb_smsc_wdt_ioctl(struct file *file,
434 } uarg; 434 } uarg;
435 435
436 static const struct watchdog_info ident = { 436 static const struct watchdog_info ident = {
437 .options = WDIOF_KEEPALIVEPING | 437 .options = WDIOF_KEEPALIVEPING |
438 WDIOF_SETTIMEOUT | 438 WDIOF_SETTIMEOUT |
439 WDIOF_MAGICCLOSE, 439 WDIOF_MAGICCLOSE,
440 .firmware_version = 0, 440 .firmware_version = 0,
441 .identity = "SMsC 37B787 Watchdog", 441 .identity = "SMsC 37B787 Watchdog",
442 }; 442 };
443 443
444 uarg.i = (int __user *)arg; 444 uarg.i = (int __user *)arg;
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 833f49f43d43..100b114e3c3c 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -151,7 +151,7 @@ static int softdog_release(struct inode *inode, struct file *file)
151{ 151{
152 /* 152 /*
153 * Shut off the timer. 153 * Shut off the timer.
154 * Lock it in if it's a module and we set nowayout 154 * Lock it in if it's a module and we set nowayout
155 */ 155 */
156 if (expect_close == 42) { 156 if (expect_close == 42) {
157 softdog_stop(); 157 softdog_stop();
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 808372883e88..1bc493848ed4 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -259,7 +259,7 @@ static struct miscdevice sp5100_tco_miscdev = {
259 * register a pci_driver, because someone else might 259 * register a pci_driver, because someone else might
260 * want to register another driver on the same PCI id. 260 * want to register another driver on the same PCI id.
261 */ 261 */
262static struct pci_device_id sp5100_tco_pci_tbl[] = { 262static DEFINE_PCI_DEVICE_TABLE(sp5100_tco_pci_tbl) = {
263 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, 263 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
264 PCI_ANY_ID, }, 264 PCI_ANY_ID, },
265 { 0, }, /* End of list */ 265 { 0, }, /* End of list */
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 18cdeb4c4258..5a90a4a871dd 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -68,7 +68,7 @@ struct platform_device *ts72xx_wdt_pdev;
68 * to control register): 68 * to control register):
69 * value description 69 * value description
70 * ------------------------- 70 * -------------------------
71 * 0x00 watchdog disabled 71 * 0x00 watchdog disabled
72 * 0x01 250ms 72 * 0x01 250ms
73 * 0x02 500ms 73 * 0x02 500ms
74 * 0x03 1s 74 * 0x03 1s
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
index df2a64dc9672..be9c4d839e15 100644
--- a/drivers/watchdog/w83697ug_wdt.c
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -87,10 +87,10 @@ static int w83697ug_select_wd_register(void)
87 outb_p(0x87, WDT_EFER); /* Enter extended function mode */ 87 outb_p(0x87, WDT_EFER); /* Enter extended function mode */
88 outb_p(0x87, WDT_EFER); /* Again according to manual */ 88 outb_p(0x87, WDT_EFER); /* Again according to manual */
89 89
90 outb(0x20, WDT_EFER); /* check chip version */ 90 outb(0x20, WDT_EFER); /* check chip version */
91 version = inb(WDT_EFDR); 91 version = inb(WDT_EFDR);
92 92
93 if (version == 0x68) { /* W83697UG */ 93 if (version == 0x68) { /* W83697UG */
94 printk(KERN_INFO PFX "Watchdog chip version 0x%02x = " 94 printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
95 "W83697UG/UF found at 0x%04x\n", version, wdt_io); 95 "W83697UG/UF found at 0x%04x\n", version, wdt_io);
96 96
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 552a4381e78f..bb03e151a1d0 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -581,7 +581,7 @@ static void __exit wdt_exit(void)
581} 581}
582 582
583/** 583/**
584 * wdt_init: 584 * wdt_init:
585 * 585 *
586 * Set up the WDT watchdog board. All we have to do is grab the 586 * Set up the WDT watchdog board. All we have to do is grab the
587 * resources we require and bitch if anyone beat us to them. 587 * resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 5c2521fc836c..a2f01c9f5c34 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -281,7 +281,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
281{ 281{
282 /* 282 /*
283 * Shut off the timer. 283 * Shut off the timer.
284 * Lock it in if it's a module and we set nowayout 284 * Lock it in if it's a module and we set nowayout
285 */ 285 */
286 if (expect_close == 42) { 286 if (expect_close == 42) {
287 wdt977_stop(); 287 wdt977_stop();
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 6130c88fa5ac..172dad6c7693 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -31,7 +31,7 @@
31 * Jeff Garzik : PCI cleanups 31 * Jeff Garzik : PCI cleanups
32 * Tigran Aivazian : Restructured wdtpci_init_one() to handle 32 * Tigran Aivazian : Restructured wdtpci_init_one() to handle
33 * failures 33 * failures
34 * Joel Becker : Added WDIOC_GET/SETTIMEOUT 34 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
35 * Zwane Mwaikambo : Magic char closing, locking changes, 35 * Zwane Mwaikambo : Magic char closing, locking changes,
36 * cleanups 36 * cleanups
37 * Matt Domsch : nowayout module option 37 * Matt Domsch : nowayout module option
@@ -727,7 +727,7 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
727} 727}
728 728
729 729
730static struct pci_device_id wdtpci_pci_tbl[] = { 730static DEFINE_PCI_DEVICE_TABLE(wdtpci_pci_tbl) = {
731 { 731 {
732 .vendor = PCI_VENDOR_ID_ACCESSIO, 732 .vendor = PCI_VENDOR_ID_ACCESSIO,
733 .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM, 733 .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
@@ -764,7 +764,7 @@ static void __exit wdtpci_cleanup(void)
764 764
765 765
766/** 766/**
767 * wdtpci_init: 767 * wdtpci_init:
768 * 768 *
769 * Set up the WDT watchdog board. All we have to do is grab the 769 * Set up the WDT watchdog board. All we have to do is grab the
770 * resources we require and bitch if anyone beat us to them. 770 * 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
index 000000000000..49bd9d395562
--- /dev/null
+++ b/drivers/watchdog/xen_wdt.c
@@ -0,0 +1,359 @@
1/*
2 * Xen Watchdog Driver
3 *
4 * (c) Copyright 2010 Novell, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#define DRV_NAME "wdt"
13#define DRV_VERSION "0.01"
14#define PFX DRV_NAME ": "
15
16#include <linux/bug.h>
17#include <linux/errno.h>
18#include <linux/fs.h>
19#include <linux/hrtimer.h>
20#include <linux/kernel.h>
21#include <linux/ktime.h>
22#include <linux/init.h>
23#include <linux/miscdevice.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/platform_device.h>
27#include <linux/spinlock.h>
28#include <linux/uaccess.h>
29#include <linux/watchdog.h>
30#include <xen/xen.h>
31#include <asm/xen/hypercall.h>
32#include <xen/interface/sched.h>
33
34static struct platform_device *platform_device;
35static DEFINE_SPINLOCK(wdt_lock);
36static struct sched_watchdog wdt;
37static __kernel_time_t wdt_expires;
38static bool is_active, expect_release;
39
40#define WATCHDOG_TIMEOUT 60 /* in seconds */
41static unsigned int timeout = WATCHDOG_TIMEOUT;
42module_param(timeout, uint, S_IRUGO);
43MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
44 "(default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
45
46static bool nowayout = WATCHDOG_NOWAYOUT;
47module_param(nowayout, bool, S_IRUGO);
48MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
49 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
50
51static inline __kernel_time_t set_timeout(void)
52{
53 wdt.timeout = timeout;
54 return ktime_to_timespec(ktime_get()).tv_sec + timeout;
55}
56
57static int xen_wdt_start(void)
58{
59 __kernel_time_t expires;
60 int err;
61
62 spin_lock(&wdt_lock);
63
64 expires = set_timeout();
65 if (!wdt.id)
66 err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
67 else
68 err = -EBUSY;
69 if (err > 0) {
70 wdt.id = err;
71 wdt_expires = expires;
72 err = 0;
73 } else
74 BUG_ON(!err);
75
76 spin_unlock(&wdt_lock);
77
78 return err;
79}
80
81static int xen_wdt_stop(void)
82{
83 int err = 0;
84
85 spin_lock(&wdt_lock);
86
87 wdt.timeout = 0;
88 if (wdt.id)
89 err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
90 if (!err)
91 wdt.id = 0;
92
93 spin_unlock(&wdt_lock);
94
95 return err;
96}
97
98static int xen_wdt_kick(void)
99{
100 __kernel_time_t expires;
101 int err;
102
103 spin_lock(&wdt_lock);
104
105 expires = set_timeout();
106 if (wdt.id)
107 err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
108 else
109 err = -ENXIO;
110 if (!err)
111 wdt_expires = expires;
112
113 spin_unlock(&wdt_lock);
114
115 return err;
116}
117
118static int xen_wdt_open(struct inode *inode, struct file *file)
119{
120 int err;
121
122 /* /dev/watchdog can only be opened once */
123 if (xchg(&is_active, true))
124 return -EBUSY;
125
126 err = xen_wdt_start();
127 if (err == -EBUSY)
128 err = xen_wdt_kick();
129 return err ?: nonseekable_open(inode, file);
130}
131
132static int xen_wdt_release(struct inode *inode, struct file *file)
133{
134 if (expect_release)
135 xen_wdt_stop();
136 else {
137 printk(KERN_CRIT PFX
138 "unexpected close, not stopping watchdog!\n");
139 xen_wdt_kick();
140 }
141 is_active = false;
142 expect_release = false;
143 return 0;
144}
145
146static ssize_t xen_wdt_write(struct file *file, const char __user *data,
147 size_t len, loff_t *ppos)
148{
149 /* See if we got the magic character 'V' and reload the timer */
150 if (len) {
151 if (!nowayout) {
152 size_t i;
153
154 /* in case it was set long ago */
155 expect_release = false;
156
157 /* scan to see whether or not we got the magic
158 character */
159 for (i = 0; i != len; i++) {
160 char c;
161 if (get_user(c, data + i))
162 return -EFAULT;
163 if (c == 'V')
164 expect_release = true;
165 }
166 }
167
168 /* someone wrote to us, we should reload the timer */
169 xen_wdt_kick();
170 }
171 return len;
172}
173
174static long xen_wdt_ioctl(struct file *file, unsigned int cmd,
175 unsigned long arg)
176{
177 int new_options, retval = -EINVAL;
178 int new_timeout;
179 int __user *argp = (void __user *)arg;
180 static const struct watchdog_info ident = {
181 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
182 .firmware_version = 0,
183 .identity = DRV_NAME,
184 };
185
186 switch (cmd) {
187 case WDIOC_GETSUPPORT:
188 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
189
190 case WDIOC_GETSTATUS:
191 case WDIOC_GETBOOTSTATUS:
192 return put_user(0, argp);
193
194 case WDIOC_SETOPTIONS:
195 if (get_user(new_options, argp))
196 return -EFAULT;
197
198 if (new_options & WDIOS_DISABLECARD)
199 retval = xen_wdt_stop();
200 if (new_options & WDIOS_ENABLECARD) {
201 retval = xen_wdt_start();
202 if (retval == -EBUSY)
203 retval = xen_wdt_kick();
204 }
205 return retval;
206
207 case WDIOC_KEEPALIVE:
208 xen_wdt_kick();
209 return 0;
210
211 case WDIOC_SETTIMEOUT:
212 if (get_user(new_timeout, argp))
213 return -EFAULT;
214 if (!new_timeout)
215 return -EINVAL;
216 timeout = new_timeout;
217 xen_wdt_kick();
218 /* fall through */
219 case WDIOC_GETTIMEOUT:
220 return put_user(timeout, argp);
221
222 case WDIOC_GETTIMELEFT:
223 retval = wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
224 return put_user(retval, argp);
225 }
226
227 return -ENOTTY;
228}
229
230static const struct file_operations xen_wdt_fops = {
231 .owner = THIS_MODULE,
232 .llseek = no_llseek,
233 .write = xen_wdt_write,
234 .unlocked_ioctl = xen_wdt_ioctl,
235 .open = xen_wdt_open,
236 .release = xen_wdt_release,
237};
238
239static struct miscdevice xen_wdt_miscdev = {
240 .minor = WATCHDOG_MINOR,
241 .name = "watchdog",
242 .fops = &xen_wdt_fops,
243};
244
245static int __devinit xen_wdt_probe(struct platform_device *dev)
246{
247 struct sched_watchdog wd = { .id = ~0 };
248 int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);
249
250 switch (ret) {
251 case -EINVAL:
252 if (!timeout) {
253 timeout = WATCHDOG_TIMEOUT;
254 printk(KERN_INFO PFX
255 "timeout value invalid, using %d\n", timeout);
256 }
257
258 ret = misc_register(&xen_wdt_miscdev);
259 if (ret) {
260 printk(KERN_ERR PFX
261 "cannot register miscdev on minor=%d (%d)\n",
262 WATCHDOG_MINOR, ret);
263 break;
264 }
265
266 printk(KERN_INFO PFX
267 "initialized (timeout=%ds, nowayout=%d)\n",
268 timeout, nowayout);
269 break;
270
271 case -ENOSYS:
272 printk(KERN_INFO PFX "not supported\n");
273 ret = -ENODEV;
274 break;
275
276 default:
277 printk(KERN_INFO PFX "bogus return value %d\n", ret);
278 break;
279 }
280
281 return ret;
282}
283
284static int __devexit xen_wdt_remove(struct platform_device *dev)
285{
286 /* Stop the timer before we leave */
287 if (!nowayout)
288 xen_wdt_stop();
289
290 misc_deregister(&xen_wdt_miscdev);
291
292 return 0;
293}
294
295static void xen_wdt_shutdown(struct platform_device *dev)
296{
297 xen_wdt_stop();
298}
299
300static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
301{
302 return xen_wdt_stop();
303}
304
305static int xen_wdt_resume(struct platform_device *dev)
306{
307 return xen_wdt_start();
308}
309
310static struct platform_driver xen_wdt_driver = {
311 .probe = xen_wdt_probe,
312 .remove = __devexit_p(xen_wdt_remove),
313 .shutdown = xen_wdt_shutdown,
314 .suspend = xen_wdt_suspend,
315 .resume = xen_wdt_resume,
316 .driver = {
317 .owner = THIS_MODULE,
318 .name = DRV_NAME,
319 },
320};
321
322static int __init xen_wdt_init_module(void)
323{
324 int err;
325
326 if (!xen_domain())
327 return -ENODEV;
328
329 printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
330
331 err = platform_driver_register(&xen_wdt_driver);
332 if (err)
333 return err;
334
335 platform_device = platform_device_register_simple(DRV_NAME,
336 -1, NULL, 0);
337 if (IS_ERR(platform_device)) {
338 err = PTR_ERR(platform_device);
339 platform_driver_unregister(&xen_wdt_driver);
340 }
341
342 return err;
343}
344
345static void __exit xen_wdt_cleanup_module(void)
346{
347 platform_device_unregister(platform_device);
348 platform_driver_unregister(&xen_wdt_driver);
349 printk(KERN_INFO PFX "module unloaded\n");
350}
351
352module_init(xen_wdt_init_module);
353module_exit(xen_wdt_cleanup_module);
354
355MODULE_AUTHOR("Jan Beulich <jbeulich@novell.com>");
356MODULE_DESCRIPTION("Xen WatchDog Timer Driver");
357MODULE_VERSION(DRV_VERSION);
358MODULE_LICENSE("GPL");
359MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);