Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf9c1b92 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
  [WATCHDOG] wdt_pci.c: remove #ifdef CONFIG_WDT_501_PCI
  [WATCHDOG] hpwdt: Add NMI priority option
  [WATCHDOG] OMAP fixes: enable clock in probe, trigger timer reload
  [WATCHDOG] add bcm47xx watchdog driver
  [WATCHDOG] Freescale STMP: watchdog driver
  [WATCHDOG] twl4030 watchdog driver
  [WATCHDOG] U300 COH 901 327 watchdog driver
  [WATCHDOG] Add pnx833x_wdt
parents 135aae34 9b901ee0
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -19,30 +19,41 @@ Last reviewed: 06/02/2009
 not be updated in a timely fashion and a hardware system reset (also known as
 an Automatic Server Recovery (ASR)) event will occur.

 The hpwdt driver also has three (3) module parameters. They are the following:
 The hpwdt driver also has four (4) module parameters. They are the following:

 soft_margin - allows the user to set the watchdog timer value
 allow_kdump - allows the user to save off a kernel dump image after an NMI
 nowayout    - basic watchdog parameter that does not allow the timer to
               be restarted or an impending ASR to be escaped.
 priority    - determines whether or not the hpwdt driver is first on the
               die_notify list to handle NMIs or last. The default value
               for this module parameter is 0 or LAST. If the user wants to
               enable NMI sourcing then reload the hpwdt driver with
               priority=1 (and boot with nmi_watchdog=0).

 NOTE: More information about watchdog drivers in general, including the ioctl
       interface to /dev/watchdog can be found in
       Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt.

 The NMI sourcing capability is disabled when the driver discovers that the
 nmi_watchdog is turned on (nmi_watchdog = 1). This is due to the inability to
 The priority parameter was introduced due to other kernel software that relied
 on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST)
 enables the users of NMIs for non critical events to be work as expected.

 The NMI sourcing capability is disabled by default due to the inability to
 distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the
 Linux kernel. What this means is that the hpwdt nmi handler code is called
 each time the NMI signal fires off. This could amount to several thousands of
 NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and
 confused" message in the logs or if the system gets into a hung state, then
 the user should reboot with nmi_watchdog=0.
 the hpwdt driver can be reloaded with the "priority" module parameter set
 (priority=1).

 1. If the kernel has not been booted with nmi_watchdog turned off then
    edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the
    currently booting kernel line.
 2. reboot the sever
 3. Once the system comes up perform a rmmod hpwdt
 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1

 Now, the hpwdt can successfully receive and source the NMI and provide a log
 message that details the reason for the NMI (as determined by the HP BIOS).
+12 −0
Original line number Diff line number Diff line
@@ -101,6 +101,12 @@
#define twl_has_usb()	false
#endif

#if defined(CONFIG_TWL4030_WATCHDOG) || \
	defined(CONFIG_TWL4030_WATCHDOG_MODULE)
#define twl_has_watchdog()        true
#else
#define twl_has_watchdog()        false
#endif

/* Triton Core internal information (BEGIN) */

@@ -526,6 +532,12 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
		usb_transceiver = child;
	}

	if (twl_has_watchdog()) {
		child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
		if (IS_ERR(child))
			return PTR_ERR(child);
	}

	if (twl_has_regulator()) {
		/*
		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+46 −13
Original line number Diff line number Diff line
@@ -240,6 +240,32 @@ config ORION_WATCHDOG
	  To compile this driver as a module, choose M here: the
	  module will be called orion_wdt.

config COH901327_WATCHDOG
	bool "ST-Ericsson COH 901 327 watchdog"
	depends on ARCH_U300
	default y if MACH_U300
	help
	  Say Y here to include Watchdog timer support for the
	  watchdog embedded into the ST-Ericsson U300 series platforms.
	  This watchdog is used to reset the system and thus cannot be
	  compiled as a module.

config TWL4030_WATCHDOG
	tristate "TWL4030 Watchdog"
	depends on TWL4030_CORE
	help
	  Support for TI TWL4030 watchdog.  Say 'Y' here to enable the
	  watchdog timer support for TWL4030 chips.

config STMP3XXX_WATCHDOG
	tristate "Freescale STMP3XXX watchdog"
	depends on ARCH_STMP3XXX
	help
	  Say Y here if to include support for the watchdog timer
	  for the Sigmatel STMP37XX/378X SoC.
	  To compile this driver as a module, choose M here: the
	  module will be called stmp3xxx_wdt.

# AVR32 Architecture

config AT32AP700X_WDT
@@ -703,6 +729,12 @@ config SBC_EPX_C3_WATCHDOG

# MIPS Architecture

config BCM47XX_WDT
	tristate "Broadcom BCM47xx Watchdog Timer"
	depends on BCM47XX
	help
	  Hardware driver for the Broadcom BCM47xx Watchog Timer.

config RC32434_WDT
	tristate "IDT RC32434 SoC Watchdog Timer"
	depends on MIKROTIK_RB532
@@ -729,6 +761,15 @@ config WDT_MTX1
	  Hardware driver for the MTX-1 boards. This is a watchdog timer that
	  will reboot the machine after a 100 seconds timer expired.

config PNX833X_WDT
	tristate "PNX833x Hardware Watchdog"
	depends on SOC_PNX8335
	help
	  Hardware driver for the PNX833x's watchdog. This is a
	  watchdog timer that will reboot the machine after a programable
	  timer has expired and no process has written to /dev/watchdog during
	  that time.

config WDT_RM9K_GPI
	tristate "RM9000/GPI hardware watchdog"
	depends on CPU_RM9000
@@ -966,24 +1007,16 @@ config WDTPCI
	---help---
	  If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.

	  To compile this driver as a module, choose M here: the
	  module will be called wdt_pci.

config WDT_501_PCI
	bool "PCI-WDT501 features"
	depends on WDTPCI
	help
	  Saying Y here and creating a character special file /dev/temperature
	  with major number 10 and minor number 131 ("man mknod") will give
	  you a thermometer inside your computer: reading from
	  /dev/temperature yields one byte, the temperature in degrees
	  Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
	  installed.
	  If you have a PCI-WDT501 watchdog board then you can enable the
	  temperature sensor by setting the type parameter to 501.

	  If you want to enable the Fan Tachometer on the PCI-WDT501, then you
	  can do this via the tachometer parameter. Only do this if you have a
	  fan tachometer actually set up.

	  To compile this driver as a module, choose M here: the
	  module will be called wdt_pci.

#
# USB-based Watchdog Cards
#
+5 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
@@ -41,6 +42,8 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o

# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -98,9 +101,11 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
# M68KNOMMU Architecture

# MIPS Architecture
obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+286 −0
Original line number Diff line number Diff line
/*
 *  Watchdog driver for Broadcom BCM47XX
 *
 *  Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
 *  Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
 *
 *  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.
 */

#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/ssb/ssb_embedded.h>
#include <asm/mach-bcm47xx/bcm47xx.h>

#define DRV_NAME		"bcm47xx_wdt"

#define WDT_DEFAULT_TIME	30	/* seconds */
#define WDT_MAX_TIME		255	/* seconds */

static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT;

module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
				__MODULE_STRING(WDT_DEFAULT_TIME) ")");

#ifdef CONFIG_WATCHDOG_NOWAYOUT
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout,
		"Watchdog cannot be stopped once started (default="
				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#endif

static unsigned long bcm47xx_wdt_busy;
static char expect_release;
static struct timer_list wdt_timer;
static atomic_t ticks;

static inline void bcm47xx_wdt_hw_start(void)
{
	/* this is 2,5s on 100Mhz clock  and 2s on 133 Mhz */
	ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
}

static inline int bcm47xx_wdt_hw_stop(void)
{
	return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
}

static void bcm47xx_timer_tick(unsigned long unused)
{
	if (!atomic_dec_and_test(&ticks)) {
		bcm47xx_wdt_hw_start();
		mod_timer(&wdt_timer, jiffies + HZ);
	} else {
		printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
	}
}

static inline void bcm47xx_wdt_pet(void)
{
	atomic_set(&ticks, wdt_time);
}

static void bcm47xx_wdt_start(void)
{
	bcm47xx_wdt_pet();
	bcm47xx_timer_tick(0);
}

static void bcm47xx_wdt_pause(void)
{
	del_timer_sync(&wdt_timer);
	bcm47xx_wdt_hw_stop();
}

static void bcm47xx_wdt_stop(void)
{
	bcm47xx_wdt_pause();
}

static int bcm47xx_wdt_settimeout(int new_time)
{
	if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
		return -EINVAL;

	wdt_time = new_time;
	return 0;
}

static int bcm47xx_wdt_open(struct inode *inode, struct file *file)
{
	if (test_and_set_bit(0, &bcm47xx_wdt_busy))
		return -EBUSY;

	bcm47xx_wdt_start();
	return nonseekable_open(inode, file);
}

static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
{
	if (expect_release == 42) {
		bcm47xx_wdt_stop();
	} else {
		printk(KERN_CRIT DRV_NAME
			": Unexpected close, not stopping watchdog!\n");
		bcm47xx_wdt_start();
	}

	clear_bit(0, &bcm47xx_wdt_busy);
	expect_release = 0;
	return 0;
}

static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
				size_t len, loff_t *ppos)
{
	if (len) {
		if (!nowayout) {
			size_t i;

			expect_release = 0;

			for (i = 0; i != len; i++) {
				char c;
				if (get_user(c, data + i))
					return -EFAULT;
				if (c == 'V')
					expect_release = 42;
			}
		}
		bcm47xx_wdt_pet();
	}
	return len;
}

static struct watchdog_info bcm47xx_wdt_info = {
	.identity 	= DRV_NAME,
	.options 	= WDIOF_SETTIMEOUT |
				WDIOF_KEEPALIVEPING |
				WDIOF_MAGICCLOSE,
};

static long bcm47xx_wdt_ioctl(struct file *file,
					unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
	int new_value, retval = -EINVAL;;

	switch (cmd) {
	case WDIOC_GETSUPPORT:
		return copy_to_user(argp, &bcm47xx_wdt_info,
				sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;

	case WDIOC_GETSTATUS:
	case WDIOC_GETBOOTSTATUS:
		return put_user(0, p);

	case WDIOC_SETOPTIONS:
		if (get_user(new_value, p))
			return -EFAULT;

		if (new_value & WDIOS_DISABLECARD) {
			bcm47xx_wdt_stop();
			retval = 0;
		}

		if (new_value & WDIOS_ENABLECARD) {
			bcm47xx_wdt_start();
			retval = 0;
		}

		return retval;

	case WDIOC_KEEPALIVE:
		bcm47xx_wdt_pet();
		return 0;

	case WDIOC_SETTIMEOUT:
		if (get_user(new_value, p))
			return -EFAULT;

		if (bcm47xx_wdt_settimeout(new_value))
			return -EINVAL;

		bcm47xx_wdt_pet();

	case WDIOC_GETTIMEOUT:
		return put_user(wdt_time, p);

	default:
		return -ENOTTY;
	}
}

static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
	unsigned long code, void *unused)
{
	if (code == SYS_DOWN || code == SYS_HALT)
		bcm47xx_wdt_stop();
	return NOTIFY_DONE;
}

static const struct file_operations bcm47xx_wdt_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.unlocked_ioctl	= bcm47xx_wdt_ioctl,
	.open		= bcm47xx_wdt_open,
	.release	= bcm47xx_wdt_release,
	.write		= bcm47xx_wdt_write,
};

static struct miscdevice bcm47xx_wdt_miscdev = {
	.minor		= WATCHDOG_MINOR,
	.name		= "watchdog",
	.fops		= &bcm47xx_wdt_fops,
};

static struct notifier_block bcm47xx_wdt_notifier = {
	.notifier_call = bcm47xx_wdt_notify_sys,
};

static int __init bcm47xx_wdt_init(void)
{
	int ret;

	if (bcm47xx_wdt_hw_stop() < 0)
		return -ENODEV;

	setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);

	if (bcm47xx_wdt_settimeout(wdt_time)) {
		bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
		printk(KERN_INFO DRV_NAME ": "
			"wdt_time value must be 0 < wdt_time < %d, using %d\n",
			(WDT_MAX_TIME + 1), wdt_time);
	}

	ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
	if (ret)
		return ret;

	ret = misc_register(&bcm47xx_wdt_miscdev);
	if (ret) {
		unregister_reboot_notifier(&bcm47xx_wdt_notifier);
		return ret;
	}

	printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
				wdt_time, nowayout ? ", nowayout" : "");
	return 0;
}

static void __exit bcm47xx_wdt_exit(void)
{
	if (!nowayout)
		bcm47xx_wdt_stop();

	misc_deregister(&bcm47xx_wdt_miscdev);

	unregister_reboot_notifier(&bcm47xx_wdt_notifier);
}

module_init(bcm47xx_wdt_init);
module_exit(bcm47xx_wdt_exit);

MODULE_AUTHOR("Aleksandar Radovanovic");
MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
Loading