Commit 67b5ad9a authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
  watchdog: Add MCF548x watchdog driver.
  watchdog: add driver for the Atheros AR71XX/AR724X/AR913X SoCs
  watchdog: Add TCO support for nVidia chipsets
  watchdog: Add support for sp5100 chipset TCO
  watchdog: f71808e_wdt: add F71862FG, F71869 to Kconfig
  watchdog: iTCO_wdt: TCO Watchdog patch for Intel DH89xxCC PCH
  watchdog: iTCO_wdt: TCO Watchdog patch for Intel NM10 DeviceIDs
  watchdog: ks8695_wdt: include mach/hardware.h instead of mach/timex.h.
  watchdog: Propagate Book E WDT period changes to all cores
  watchdog: add CONFIG_WATCHDOG_NOWAYOUT support to PowerPC Book-E watchdog driver
  watchdog: alim7101_wdt: fix compiler warning on alim7101_pci_tbl
  watchdog: alim1535_wdt: fix compiler warning on ali_pci_tbl
  watchdog: Fix reboot on W83627ehf chipset.
  watchdog: Add watchdog support for W83627DHG chip
  watchdog: f71808e_wdt: Add Fintek F71869 watchdog
  watchdog: add f71862fg support
  watchdog: clean-up f71808e_wdt.c
parents 174a86df 88cce427
......@@ -59,11 +59,13 @@
#define MCF_GPT_GMS_GPIO_INPUT (0x00000000)
#define MCF_GPT_GMS_GPIO_OUTLO (0x00000020)
#define MCF_GPT_GMS_GPIO_OUTHI (0x00000030)
#define MCF_GPT_GMS_GPIO_MASK (0x00000030)
#define MCF_GPT_GMS_TMS_DISABLE (0x00000000)
#define MCF_GPT_GMS_TMS_INCAPT (0x00000001)
#define MCF_GPT_GMS_TMS_OUTCAPT (0x00000002)
#define MCF_GPT_GMS_TMS_PWM (0x00000003)
#define MCF_GPT_GMS_TMS_GPIO (0x00000004)
#define MCF_GPT_GMS_TMS_MASK (0x00000007)
/* Bit definitions and macros for MCF_GPT_GCIR */
#define MCF_GPT_GCIR_CNT(x) (((x)&0x0000FFFF)<<0)
......
......@@ -409,15 +409,26 @@ config ALIM7101_WDT
Most people will say N.
config F71808E_WDT
tristate "Fintek F71808E, F71882FG and F71889FG Watchdog"
tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
depends on X86 && EXPERIMENTAL
help
This is the driver for the hardware watchdog on the Fintek
F71808E, F71882FG and F71889FG Super I/O controllers.
F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
You can compile this driver directly into the kernel, or use
it as a module. The module will be called f71808e_wdt.
config SP5100_TCO
tristate "AMD/ATI SP5100 TCO Timer/Watchdog"
depends on X86 && PCI
---help---
Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO
(Total Cost of Ownership) timer is a watchdog timer that will reboot
the machine after its expiration. The expiration time can be
configured with the "heartbeat" parameter.
To compile this driver as a module, choose M here: the
module will be called sp5100_tco.
config GEODE_WDT
tristate "AMD Geode CS5535/CS5536 Watchdog"
......@@ -631,6 +642,24 @@ config PC87413_WDT
Most people will say N.
config NV_TCO
tristate "nVidia TCO Timer/Watchdog"
depends on X86 && PCI
---help---
Hardware driver for the TCO timer built into the nVidia Hub family
(such as the MCP51). The TCO (Total Cost of Ownership) timer is a
watchdog timer that will reboot the machine after its second
expiration. The expiration time can be configured with the
"heartbeat" parameter.
On some motherboards the driver may fail to reset the chipset's
NO_REBOOT flag which prevents the watchdog from rebooting the
machine. If this is the case you will get a kernel message like
"failed to reset NO_REBOOT flag, reboot disabled by hardware".
To compile this driver as a module, choose M here: the
module will be called nv_tco.
config RDC321X_WDT
tristate "RDC R-321x SoC watchdog"
depends on X86_RDC321X
......@@ -722,14 +751,15 @@ config SMSC37B787_WDT
Most people will say N.
config W83627HF_WDT
tristate "W83627HF Watchdog Timer"
tristate "W83627HF/W83627DHG Watchdog Timer"
depends on X86
---help---
This is the driver for the hardware watchdog on the W83627HF chipset
as used in Advantech PC-9578 and Tyan S2721-533 motherboards
(and likely others). This watchdog simply watches your kernel to
make sure it doesn't freeze, and if it does, it reboots your computer
after a certain amount of time.
(and likely others). The driver also supports the W83627DHG chip.
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
To compile this driver as a module, choose M here: the
module will be called w83627hf_wdt.
......@@ -832,10 +862,22 @@ config SBC_EPX_C3_WATCHDOG
# M68K Architecture
# M68KNOMMU Architecture
config M548x_WATCHDOG
tristate "MCF548x watchdog support"
depends on M548x
help
To compile this driver as a module, choose M here: the
module will be called m548x_wdt.
# MIPS Architecture
config ATH79_WDT
tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog"
depends on ATH79
help
Hardware driver for the built-in watchdog timer on the Atheros
AR71XX/AR724X/AR913X SoCs.
config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
depends on BCM47XX
......
......@@ -68,6 +68,7 @@ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o
obj-$(CONFIG_GEODE_WDT) += geodewdt.o
obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o
......@@ -86,6 +87,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
obj-$(CONFIG_NV_TCO) += nv_tco.o
obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
......@@ -104,10 +106,10 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
# M32R Architecture
# M68K Architecture
# M68KNOMMU Architecture
obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o
# MIPS Architecture
obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
......
......@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
* want to register another driver on the same PCI id.
*/
static struct pci_device_id ali_pci_tbl[] = {
static struct pci_device_id ali_pci_tbl[] __used = {
{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
......
......@@ -430,7 +430,7 @@ static int __init alim7101_wdt_init(void)
module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }
......
/*
* Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer.
*
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
*
* This driver was based on: drivers/watchdog/ixp4xx_wdt.c
* Author: Deepak Saxena <dsaxena@plexity.net>
* Copyright 2004 (c) MontaVista, Software, Inc.
*
* which again was based on sa1100 driver,
* Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
*/
#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/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/mach-ath79/ath79.h>
#include <asm/mach-ath79/ar71xx_regs.h>
#define DRIVER_NAME "ath79-wdt"
#define WDT_TIMEOUT 15 /* seconds */
#define WDOG_CTRL_LAST_RESET BIT(31)
#define WDOG_CTRL_ACTION_MASK 3
#define WDOG_CTRL_ACTION_NONE 0 /* no action */
#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */
#define WDOG_CTRL_ACTION_NMI 2 /* NMI */
#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static int timeout = WDT_TIMEOUT;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
"(default=" __MODULE_STRING(WDT_TIMEOUT) "s)");
static unsigned long wdt_flags;
#define WDT_FLAGS_BUSY 0
#define WDT_FLAGS_EXPECT_CLOSE 1
static struct clk *wdt_clk;
static unsigned long wdt_freq;
static int boot_status;
static int max_timeout;
static inline void ath79_wdt_keepalive(void)
{
ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout);
}
static inline void ath79_wdt_enable(void)
{
ath79_wdt_keepalive();
ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
}
static inline void ath79_wdt_disable(void)
{
ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE);
}
static int ath79_wdt_set_timeout(int val)
{
if (val < 1 || val > max_timeout)
return -EINVAL;
timeout = val;
ath79_wdt_keepalive();
return 0;
}
static int ath79_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
return -EBUSY;
clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
ath79_wdt_enable();
return nonseekable_open(inode, file);
}
static int ath79_wdt_release(struct inode *inode, struct file *file)
{
if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
ath79_wdt_disable();
else {
pr_crit(DRIVER_NAME ": device closed unexpectedly, "
"watchdog timer will not stop!\n");
ath79_wdt_keepalive();
}
clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
return 0;
}
static ssize_t ath79_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
if (len) {
if (!nowayout) {
size_t i;
clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
set_bit(WDT_FLAGS_EXPECT_CLOSE,
&wdt_flags);
}
}
ath79_wdt_keepalive();
}
return len;
}
static const struct watchdog_info ath79_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
.firmware_version = 0,
.identity = "ATH79 watchdog",
};
static long ath79_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int err;
int t;
switch (cmd) {
case WDIOC_GETSUPPORT:
err = copy_to_user(argp, &ath79_wdt_info,
sizeof(ath79_wdt_info)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
err = put_user(0, p);
break;
case WDIOC_GETBOOTSTATUS:
err = put_user(boot_status, p);
break;
case WDIOC_KEEPALIVE:
ath79_wdt_keepalive();
err = 0;
break;
case WDIOC_SETTIMEOUT:
err = get_user(t, p);
if (err)
break;
err = ath79_wdt_set_timeout(t);
if (err)
break;
/* fallthrough */
case WDIOC_GETTIMEOUT:
err = put_user(timeout, p);
break;
default:
err = -ENOTTY;
break;
}
return err;
}
static const struct file_operations ath79_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ath79_wdt_write,
.unlocked_ioctl = ath79_wdt_ioctl,
.open = ath79_wdt_open,
.release = ath79_wdt_release,
};
static struct miscdevice ath79_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ath79_wdt_fops,
};
static int __devinit ath79_wdt_probe(struct platform_device *pdev)
{
u32 ctrl;
int err;
wdt_clk = clk_get(&pdev->dev, "wdt");
if (IS_ERR(wdt_clk))
return PTR_ERR(wdt_clk);
err = clk_enable(wdt_clk);
if (err)
goto err_clk_put;
wdt_freq = clk_get_rate(wdt_clk);
if (!wdt_freq) {
err = -EINVAL;
goto err_clk_disable;
}
max_timeout = (0xfffffffful / wdt_freq);
if (timeout < 1 || timeout > max_timeout) {
timeout = max_timeout;
dev_info(&pdev->dev,
"timeout value must be 0 < timeout < %d, using %d\n",
max_timeout, timeout);
}
ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL);
boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;
err = misc_register(&ath79_wdt_miscdev);
if (err) {
dev_err(&pdev->dev,
"unable to register misc device, err=%d\n", err);
goto err_clk_disable;
}
return 0;
err_clk_disable:
clk_disable(wdt_clk);
err_clk_put:
clk_put(wdt_clk);
return err;
}
static int __devexit ath79_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&ath79_wdt_miscdev);
clk_disable(wdt_clk);
clk_put(wdt_clk);
return 0;
}
static void ath97_wdt_shutdown(struct platform_device *pdev)
{
ath79_wdt_disable();
}
static struct platform_driver ath79_wdt_driver = {
.remove = __devexit_p(ath79_wdt_remove),
.shutdown = ath97_wdt_shutdown,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static int __init ath79_wdt_init(void)
{
return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
}
module_init(ath79_wdt_init);
static void __exit ath79_wdt_exit(void)
{
platform_driver_unregister(&ath79_wdt_driver);
}
module_exit(ath79_wdt_exit);
MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
......@@ -85,6 +85,22 @@ static unsigned int sec_to_period(unsigned int secs)
return 0;
}
static void __booke_wdt_set(void *data)
{
u32 val;
val = mfspr(SPRN_TCR);
val &= ~WDTP_MASK;
val |= WDTP(booke_wdt_period);
mtspr(SPRN_TCR, val);
}
static void booke_wdt_set(void)
{
on_each_cpu(__booke_wdt_set, NULL, 0);
}
static void __booke_wdt_ping(void *data)
{
mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
......@@ -181,8 +197,7 @@ static long booke_wdt_ioctl(struct file *file,
#else
booke_wdt_period = tmp;
#endif
mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) |
WDTP(booke_wdt_period));
booke_wdt_set();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
......@@ -193,8 +208,15 @@ static long booke_wdt_ioctl(struct file *file,
return 0;
}
/* wdt_is_active stores wether or not the /dev/watchdog device is opened */
static unsigned long wdt_is_active;
static int booke_wdt_open(struct inode *inode, struct file *file)
{
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &wdt_is_active))
return -EBUSY;
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
......@@ -210,8 +232,17 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
static int booke_wdt_release(struct inode *inode, struct file *file)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
/* Normally, the watchdog is disabled when /dev/watchdog is closed, but
* if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the
* watchdog should remain enabled. So we disable it only if
* CONFIG_WATCHDOG_NOWAYOUT is not defined.
*/
on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0;
#endif
clear_bit(0, &wdt_is_active);
return 0;
}
......
......@@ -42,18 +42,21 @@
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
#define SIO_REG_DEVREV 0x22 /* Device revision */
#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */
#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */
#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */
#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
#define SIO_F71808_ID 0x0901 /* Chipset ID */
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71808_ID 0x0901 /* Chipset ID */
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
#define F71882FG_REG_START 0x01
#define F71808FG_REG_WDO_CONF 0xf0
#define F71808FG_REG_WDT_CONF 0xf5
#define F71808FG_REG_WD_TIME 0xf6
......@@ -70,13 +73,15 @@
#define WATCHDOG_MAX_TIMEOUT (60 * 255)
#define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for
watchdog signal */
#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output
pin number 63 */
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
static const int max_timeout = WATCHDOG_MAX_TIMEOUT;
static int timeout = 60; /* default timeout in seconds */
static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <="
......@@ -89,6 +94,12 @@ MODULE_PARM_DESC(pulse_width,
"Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
module_param(f71862fg_pin, uint, 0);
MODULE_PARM_DESC(f71862fg_pin,
"Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
" (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0444);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
......@@ -98,12 +109,13 @@ module_param(start_withtimeout, uint, 0);
MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
" given initial timeout. Zero (default) disables this feature.");
enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg };
enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg };
static const char *f71808e_names[] = {
"f71808fg",
"f71858fg",
"f71862fg",
"f71869",
"f71882fg",
"f71889fg",
};
......@@ -282,6 +294,28 @@ static int watchdog_keepalive(void)
return err;
}
static int f71862fg_pin_configure(unsigned short ioaddr)
{
/* When ioaddr is non-zero the calling function has to take care of
mutex handling and superio preparation! */
if (f71862fg_pin == 63) {
if (ioaddr) {
/* SPI must be disabled first to use this pin! */
superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6);
superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4);
}
} else if (f71862fg_pin == 56) {
if (ioaddr)
superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
} else {
printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
f71862fg_pin);
return -EINVAL;
}
return 0;
}
static int watchdog_start(void)
{
/* Make sure we don't die as soon as the watchdog is enabled below */
......@@ -299,19 +333,30 @@ static int watchdog_start(void)
switch (watchdog.type) {
case f71808fg:
/* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
superio_clear_bit(watchdog.sioaddr, 0x2a, 3);
superio_clear_bit(watchdog.sioaddr, 0x2b, 3);
superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3);
superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3);
break;
case f71862fg:
err = f71862fg_pin_configure(watchdog.sioaddr);
if (err)
goto exit_superio;
break;
case f71869:
/* GPIO14 --> WDTRST# */
superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
break;
case f71882fg:
/* Set pin 56 to WDTRST# */
superio_set_bit(watchdog.sioaddr, 0x29, 1);
superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1);
break;
case f71889fg:
/* set pin 40 to WDTRST# */
superio_outb(watchdog.sioaddr, 0x2b,
superio_inb(watchdog.sioaddr, 0x2b) & 0xcf);
superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3,
superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf);
break;
default:
......@@ -711,16 +756,19 @@ static int __init f71808e_find(int sioaddr)
case SIO_F71808_ID:
watchdog.type = f71808fg;
break;
case SIO_F71862_ID:
watchdog.type = f71862fg;
err = f71862fg_pin_configure(0); /* validate module parameter */
break;
case SIO_F71869_ID:
watchdog.type = f71869;
break;
case SIO_F71882_ID:
watchdog.type = f71882fg;
break;
case SIO_F71889_ID:
watchdog.type = f71889fg;
break;
case SIO_F71862_ID:
/* These have a watchdog, though it isn't implemented (yet). */
err = -ENOSYS;
goto exit;
case SIO_F71858_ID:
/* Confirmed (by datasheet) not to have a watchdog. */
err = -ENODEV;
......
/*
* intel TCO Watchdog Driver
*
* (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
* (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -26,13 +26,15 @@
* document number 301473-002, 301474-026: 82801F (ICH6)
* document number 313082-001, 313075-006: 631xESB, 632xESB
* document number 307013-003, 307014-024: 82801G (ICH7)
* document number 322896-001, 322897-001: NM10
* document number 313056-003, 313057-017: 82801H (ICH8)
* document number 316972-004, 316973-012: 82801I (ICH9)
* document number 319973-002, 319974-002: 82801J (ICH10)
* document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
* document number 320066-003, 320257-008: EP80597 (IICH)
* document number TBD : Cougar Point (CPT)
* document number 324645-001, 324646-001: Cougar Point (CPT)
* document number TBD : Patsburg (PBG)
* document number TBD : DH89xxCC
*/
/*
......@@ -85,6 +87,7 @@ enum iTCO_chipsets {
TCO_ICH7DH, /* ICH7DH */
TCO_ICH7M, /* ICH7-M & ICH7-U */
TCO_ICH7MDH, /* ICH7-M DH */
TCO_NM10, /* NM10 */
TCO_ICH8, /* ICH8 & ICH8R */
TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */
......@@ -149,6 +152,7 @@ enum iTCO_chipsets {
TCO_CPT31, /* Cougar Point */
TCO_PBG1, /* Patsburg */
TCO_PBG2, /* Patsburg */
TCO_DH89XXCC, /* DH89xxCC */
};
static struct {
......@@ -174,6 +178,7 @@ static struct {
{"ICH7DH", 2},
{"ICH7-M or ICH7-U", 2},
{"ICH7-M DH", 2},
{"NM10", 2},
{"ICH8 or ICH8R", 2},
{"ICH8DH", 2},
{"ICH8DO", 2},
......@@ -238,6 +243,7 @@ static struct {
{"Cougar Point", 2},
{"Patsburg", 2},
{"Patsburg", 2},
{"DH89xxCC", 2},
{NULL, 0}
};
......@@ -291,6 +297,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)},
{ ITCO_PCI_DEVICE(0x27bc, TCO_NM10)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)},
......@@ -355,6 +362,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)},
{ ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)},
{ ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)},
{ ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
......
......@@ -21,7 +21,7 @@
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <mach/timex.h>
#include <mach/hardware.h>
#include <mach/regs-timer.h>
#define WDT_DEFAULT_TIME 5 /* seconds */
......
/*
* drivers/watchdog/m548x_wdt.c
*
* Watchdog driver for ColdFire MCF548x processors
* Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
*
* Adapted from the IXP4xx watchdog driver, which carries these notices:
*
* Author: Deepak Saxena <dsaxena@plexity.net>
*
* Copyright 2004 (c) MontaVista, Software, Inc.
* Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/ioport.h>
#include <linux/uaccess.h>
#include <asm/coldfire.h>
#include <asm/m548xsim.h>
#include <asm/m548xgpt.h>
static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */
static unsigned long wdt_status;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
static void wdt_enable(void)
{
unsigned int gms0;
/* preserve GPIO usage, if any */
gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
if (gms0 & MCF_GPT_GMS_TMS_GPIO)
gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
| MCF_GPT_GMS_OD);
else
gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
__raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
__raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
__raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
}
static void wdt_disable(void)
{
unsigned int gms0;
/* disable watchdog */
gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
__raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
}
static void wdt_keepalive(void)
{
unsigned int gms0;
gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
gms0 |= MCF_GPT_GMS_OCPW(0xA5);
__raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
}
static int m548x_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable();
return nonseekable_open(inode, file);
}
static ssize_t m548x_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
if (len) {
if (!nowayout) {
size_t i;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
set_bit(WDT_OK_TO_CLOSE, &wdt_status);
}
}
wdt_keepalive();
}
return len;
}
static const struct watchdog_info ident = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "Coldfire M548x Watchdog",
};
static long m548x_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
int time;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user((struct watchdog_info *)arg, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg);
break;
case WDIOC_GETBOOTSTATUS:
ret = put_user(0, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_keepalive();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
break;
if (time <= 0 || time > 30) {
ret = -EINVAL;
break;
}
heartbeat = time;
wdt_enable();
/* Fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
}
return ret;
}
static int m548x_wdt_release(struct inode *inode, struct file *file)
{
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable();
else {
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n");
wdt_keepalive();
}
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
return 0;
}
static const struct file_operations m548x_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = m548x_wdt_write,
.unlocked_ioctl = m548x_wdt_ioctl,
.open = m548x_wdt_open,
.release = m548x_wdt_release,
};
static struct miscdevice m548x_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &m548x_wdt_fops,
};
static int __init m548x_wdt_init(void)
{
if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
"Coldfire M548x Watchdog")) {
printk(KERN_WARNING
"Coldfire M548x Watchdog : I/O region busy\n");
return -EBUSY;
}
printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
return misc_register(&m548x_wdt_miscdev);
}
static void __exit m548x_wdt_exit(void)
{
misc_deregister(&m548x_wdt_miscdev);
release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
}
module_init(m548x_wdt_init);
module_exit(m548x_wdt_exit);
MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
MODULE_DESCRIPTION("Coldfire M548x Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
This diff is collapsed.
/*
* nv_tco: TCO timer driver for nVidia chipsets.
*
* (c) Copyright 2005 Google Inc., All Rights Reserved.
*
* Supported Chipsets:
* - MCP51/MCP55
*
* (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
* Reserved.
* http://www.kernelconcepts.de
*
* 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.
*
* Neither kernel concepts nor Nils Faerber admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
*
* (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
* developed for
* Jentro AG, Haar/Munich (Germany)
*
* TCO timer driver for NV chipsets
* based on softdog.c by Alan Cox <alan@redhat.com>
*/
/*
* Some address definitions for the TCO
*/
#define TCO_RLD(base) ((base) + 0x00) /* TCO Timer Reload and Current Value */
#define TCO_TMR(base) ((base) + 0x01) /* TCO Timer Initial Value */
#define TCO_STS(base) ((base) + 0x04) /* TCO Status Register */
/*
* TCO Boot Status bit: set on TCO reset, reset by software or standby
* power-good (survives reboots), unfortunately this bit is never
* set.
*/
# define TCO_STS_BOOT_STS (1 << 9)
/*
* first and 2nd timeout status bits, these also survive a warm boot,
* and they work, so we use them.
*/
# define TCO_STS_TCO_INT_STS (1 << 1)
# define TCO_STS_TCO2TO_STS (1 << 10)
# define TCO_STS_RESET (TCO_STS_BOOT_STS | TCO_STS_TCO2TO_STS | \
TCO_STS_TCO_INT_STS)
#define TCO_CNT(base) ((base) + 0x08) /* TCO Control Register */
# define TCO_CNT_TCOHALT (1 << 12)
#define MCP51_SMBUS_SETUP_B 0xe8
# define MCP51_SMBUS_SETUP_B_TCO_REBOOT (1 << 25)
/*
* The SMI_EN register is at the base io address + 0x04,
* while TCOBASE is + 0x40.
*/
#define MCP51_SMI_EN(base) ((base) - 0x40 + 0x04)
# define MCP51_SMI_EN_TCO ((1 << 4) | (1 << 5))
This diff is collapsed.
/*
* sp5100_tco: TCO timer driver for sp5100 chipsets.
*
* (c) Copyright 2009 Google Inc., All Rights Reserved.
*
* TCO timer driver for sp5100 chipsets
*/
/*
* Some address definitions for the Watchdog
*/
#define SP5100_WDT_MEM_MAP_SIZE 0x08
#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
#define SP5100_WDT_START_STOP_BIT 1
#define SP5100_WDT_TRIGGER_BIT (1 << 7)
#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
#define SP5100_PM_IOPORTS_SIZE 0x02
/* These two IO registers are hardcoded and there doesn't seem to be a way to
* read them from a register.
*/
#define SP5100_IO_PM_INDEX_REG 0xCD6
#define SP5100_IO_PM_DATA_REG 0xCD7
#define SP5100_PM_WATCHDOG_CONTROL 0x69
#define SP5100_PM_WATCHDOG_BASE0 0x6C
#define SP5100_PM_WATCHDOG_BASE1 0x6D
#define SP5100_PM_WATCHDOG_BASE2 0x6E
#define SP5100_PM_WATCHDOG_BASE3 0x6F
#define SP5100_PM_WATCHDOG_FIRED (1 << 1)
#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
#define SP5100_PM_WATCHDOG_DISABLE 1
#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
......@@ -42,7 +42,7 @@
#include <asm/system.h>
#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
......@@ -89,7 +89,7 @@ static void w83627hf_select_wd_register(void)
c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
outb_p(0x2b, WDT_EFER);
outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */
} else if (c == 0x88) { /* W83627EHF */
} else if (c == 0x88 || c == 0xa0) { /* W83627EHF / W83627DHG */
outb_p(0x2d, WDT_EFER); /* select GPIO5 */
c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */
outb_p(0x2d, WDT_EFER);
......@@ -129,6 +129,8 @@ static void w83627hf_init(void)
t = inb_p(WDT_EFDR); /* read CRF5 */
t &= ~0x0C; /* set second mode & disable keyboard
turning off watchdog */
t |= 0x02; /* enable the WDTO# output low pulse
to the KBRST# pin (PIN60) */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */
outb_p(0xF7, WDT_EFER); /* Select CRF7 */
......@@ -321,7 +323,7 @@ static int __init wdt_init(void)
{
int ret;
printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment