Commit c8ff99a7 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 ICH9DO into the iTCO_wdt.c driver
  [WATCHDOG] Fix booke_wdt.c on MPC85xx SMP system's
  [WATCHDOG] Add a watchdog driver based on the CS5535/CS5536 MFGPT timers
  [WATCHDOG] hpwdt: Fix NMI handling.
  [WATCHDOG] Blackfin Watchdog Driver: split platform device/driver
  [WATCHDOG] Add w83697h_wdt early_disable option
  [WATCHDOG] Make w83697h_wdt timeout option string similar to others
  [WATCHDOG] Make w83697h_wdt void-like functions void
parents 32522bfd a49056da
...@@ -295,6 +295,19 @@ config ALIM7101_WDT ...@@ -295,6 +295,19 @@ config ALIM7101_WDT
Most people will say N. Most people will say N.
config GEODE_WDT
tristate "AMD Geode CS5535/CS5536 Watchdog"
depends on MGEODE_LX
help
This driver enables a watchdog capability built into the
CS5535/CS5536 companion chips for the AMD Geode GX and LX
processors. This watchdog watches your kernel to make sure
it doesn't freeze, and if it does, it reboots your computer after
a certain amount of time.
You can compile this driver directly into the kernel, or use
it as a module. The module will be called geodewdt.
config SC520_WDT config SC520_WDT
tristate "AMD Elan SC520 processor Watchdog" tristate "AMD Elan SC520 processor Watchdog"
depends on X86 depends on X86
......
...@@ -59,6 +59,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o ...@@ -59,6 +59,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_GEODE_WDT) += geodewdt.o
obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o
......
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am") #define stampit() stamp("here i am")
#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); }) #define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define WATCHDOG_NAME "bfin-wdt" #define WATCHDOG_NAME "bfin-wdt"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
...@@ -377,20 +378,6 @@ static int bfin_wdt_resume(struct platform_device *pdev) ...@@ -377,20 +378,6 @@ static int bfin_wdt_resume(struct platform_device *pdev)
# define bfin_wdt_resume NULL # define bfin_wdt_resume NULL
#endif #endif
static struct platform_device bfin_wdt_device = {
.name = WATCHDOG_NAME,
.id = -1,
};
static struct platform_driver bfin_wdt_driver = {
.driver = {
.name = WATCHDOG_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin_wdt_suspend,
.resume = bfin_wdt_resume,
};
static const struct file_operations bfin_wdt_fops = { static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
...@@ -418,11 +405,67 @@ static struct notifier_block bfin_wdt_notifier = { ...@@ -418,11 +405,67 @@ static struct notifier_block bfin_wdt_notifier = {
}; };
/** /**
* bfin_wdt_init - Initialize module * bfin_wdt_probe - Initialize module
* *
* Registers the device and notifier handler. Actual device * Registers the misc device and notifier handler. Actual device
* initialization is handled by bfin_wdt_open(). * initialization is handled by bfin_wdt_open().
*/ */
static int __devinit bfin_wdt_probe(struct platform_device *pdev)
{
int ret;
ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) {
pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;
}
/**
* bfin_wdt_remove - Initialize module
*
* Unregisters the misc device and notifier handler. Actual device
* deinitialization is handled by bfin_wdt_close().
*/
static int __devexit bfin_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&bfin_wdt_miscdev);
unregister_reboot_notifier(&bfin_wdt_notifier);
return 0;
}
static struct platform_device *bfin_wdt_device;
static struct platform_driver bfin_wdt_driver = {
.probe = bfin_wdt_probe,
.remove = __devexit_p(bfin_wdt_remove),
.suspend = bfin_wdt_suspend,
.resume = bfin_wdt_resume,
.driver = {
.name = WATCHDOG_NAME,
.owner = THIS_MODULE,
},
};
/**
* bfin_wdt_init - Initialize module
*
* Checks the module params and registers the platform device & driver.
* Real work is in the platform probe function.
*/
static int __init bfin_wdt_init(void) static int __init bfin_wdt_init(void)
{ {
int ret; int ret;
...@@ -436,44 +479,32 @@ static int __init bfin_wdt_init(void) ...@@ -436,44 +479,32 @@ static int __init bfin_wdt_init(void)
/* Since this is an on-chip device and needs no board-specific /* Since this is an on-chip device and needs no board-specific
* resources, we'll handle all the platform device stuff here. * resources, we'll handle all the platform device stuff here.
*/ */
ret = platform_device_register(&bfin_wdt_device); ret = platform_driver_register(&bfin_wdt_driver);
if (ret)
return ret;
ret = platform_driver_probe(&bfin_wdt_driver, NULL);
if (ret)
return ret;
ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) { if (ret) {
pr_init(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); pr_init(KERN_ERR PFX "unable to register driver\n");
return ret; return ret;
} }
ret = misc_register(&bfin_wdt_miscdev); bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
if (ret) { if (IS_ERR(bfin_wdt_device)) {
pr_init(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", pr_init(KERN_ERR PFX "unable to register device\n");
WATCHDOG_MINOR, ret); platform_driver_unregister(&bfin_wdt_driver);
unregister_reboot_notifier(&bfin_wdt_notifier); return PTR_ERR(bfin_wdt_device);
return ret;
} }
pr_init(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0; return 0;
} }
/** /**
* bfin_wdt_exit - Deinitialize module * bfin_wdt_exit - Deinitialize module
* *
* Unregisters the device and notifier handler. Actual device * Back out the platform device & driver steps. Real work is in the
* deinitialization is handled by bfin_wdt_close(). * platform remove function.
*/ */
static void __exit bfin_wdt_exit(void) static void __exit bfin_wdt_exit(void)
{ {
misc_deregister(&bfin_wdt_miscdev); platform_device_unregister(bfin_wdt_device);
unregister_reboot_notifier(&bfin_wdt_notifier); platform_driver_unregister(&bfin_wdt_driver);
} }
module_init(bfin_wdt_init); module_init(bfin_wdt_init);
......
/* /*
* drivers/char/watchdog/booke_wdt.c
*
* Watchdog timer for PowerPC Book-E systems * Watchdog timer for PowerPC Book-E systems
* *
* Author: Matthew McClintock * Author: Matthew McClintock
* Maintainer: Kumar Gala <galak@kernel.crashing.org> * Maintainer: Kumar Gala <galak@kernel.crashing.org>
* *
* Copyright 2005 Freescale Semiconductor Inc. * Copyright 2005, 2008 Freescale Semiconductor Inc.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -16,6 +14,7 @@ ...@@ -16,6 +14,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/smp.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
...@@ -38,7 +37,7 @@ ...@@ -38,7 +37,7 @@
#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */ #endif /* for timing information */
u32 booke_wdt_enabled = 0; u32 booke_wdt_enabled;
u32 booke_wdt_period = WDT_PERIOD_DEFAULT; u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#ifdef CONFIG_FSL_BOOKE #ifdef CONFIG_FSL_BOOKE
...@@ -47,33 +46,31 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT; ...@@ -47,33 +46,31 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#define WDTP(x) (TCR_WP(x)) #define WDTP(x) (TCR_WP(x))
#endif #endif
/* static DEFINE_SPINLOCK(booke_wdt_lock);
* booke_wdt_ping:
*/ static void __booke_wdt_ping(void *data)
static __inline__ void booke_wdt_ping(void)
{ {
mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
} }
/* static void booke_wdt_ping(void)
* booke_wdt_enable: {
*/ on_each_cpu(__booke_wdt_ping, NULL, 0, 0);
static __inline__ void booke_wdt_enable(void) }
static void __booke_wdt_enable(void *data)
{ {
u32 val; u32 val;
/* clear status before enabling watchdog */ /* clear status before enabling watchdog */
booke_wdt_ping(); __booke_wdt_ping(NULL);
val = mfspr(SPRN_TCR); val = mfspr(SPRN_TCR);
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
mtspr(SPRN_TCR, val); mtspr(SPRN_TCR, val);
} }
/* static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
* booke_wdt_write:
*/
static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
booke_wdt_ping(); booke_wdt_ping();
...@@ -81,15 +78,11 @@ static ssize_t booke_wdt_write (struct file *file, const char __user *buf, ...@@ -81,15 +78,11 @@ static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
} }
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.firmware_version = 0, .identity = "PowerPC Book-E Watchdog",
.identity = "PowerPC Book-E Watchdog",
}; };
/* static int booke_wdt_ioctl(struct inode *inode, struct file *file,
* booke_wdt_ioctl:
*/
static int booke_wdt_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
u32 tmp = 0; u32 tmp = 0;
...@@ -97,7 +90,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, ...@@ -97,7 +90,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user ((struct watchdog_info __user *) arg, &ident, if (copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(struct watchdog_info))) sizeof(struct watchdog_info)))
return -EFAULT; return -EFAULT;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
...@@ -132,33 +125,33 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, ...@@ -132,33 +125,33 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
return 0; return 0;
} }
/*
* booke_wdt_open: static int booke_wdt_open(struct inode *inode, struct file *file)
*/
static int booke_wdt_open (struct inode *inode, struct file *file)
{ {
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 0) { if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1; booke_wdt_enabled = 1;
booke_wdt_enable(); on_each_cpu(__booke_wdt_enable, NULL, 0, 0);
printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
booke_wdt_period); "(wdt_period=%d)\n", booke_wdt_period);
} }
spin_unlock(&booke_wdt_lock);
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static const struct file_operations booke_wdt_fops = { static const struct file_operations booke_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = booke_wdt_write, .write = booke_wdt_write,
.ioctl = booke_wdt_ioctl, .ioctl = booke_wdt_ioctl,
.open = booke_wdt_open, .open = booke_wdt_open,
}; };
static struct miscdevice booke_wdt_miscdev = { static struct miscdevice booke_wdt_miscdev = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &booke_wdt_fops, .fops = &booke_wdt_fops,
}; };
static void __exit booke_wdt_exit(void) static void __exit booke_wdt_exit(void)
...@@ -166,28 +159,27 @@ static void __exit booke_wdt_exit(void) ...@@ -166,28 +159,27 @@ static void __exit booke_wdt_exit(void)
misc_deregister(&booke_wdt_miscdev); misc_deregister(&booke_wdt_miscdev);
} }
/*
* booke_wdt_init:
*/
static int __init booke_wdt_init(void) static int __init booke_wdt_init(void)
{ {
int ret = 0; int ret = 0;
printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
ident.firmware_version = cur_cpu_spec->pvr_value; ident.firmware_version = cur_cpu_spec->pvr_value;
ret = misc_register(&booke_wdt_miscdev); ret = misc_register(&booke_wdt_miscdev);
if (ret) { if (ret) {
printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
return ret; return ret;
} }
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) { if (booke_wdt_enabled == 1) {
printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
booke_wdt_period); "(wdt_period=%d)\n", booke_wdt_period);
booke_wdt_enable(); on_each_cpu(__booke_wdt_enable, NULL, 0, 0);
} }
spin_unlock(&booke_wdt_lock);
return ret; return ret;
} }
......
/* Watchdog timer for the Geode GX/LX with the CS5535/CS5536 companion chip
*
* Copyright (C) 2006-2007, Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/geode.h>
#define GEODEWDT_HZ 500
#define GEODEWDT_SCALE 6
#define GEODEWDT_MAX_SECONDS 131
#define WDT_FLAGS_OPEN 1
#define WDT_FLAGS_ORPHAN 2
#define DRV_NAME "geodewdt"
#define WATCHDOG_NAME "Geode GX/LX WDT"
#define WATCHDOG_TIMEOUT 60
static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=131, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
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 struct platform_device *geodewdt_platform_device;
static unsigned long wdt_flags;
static int wdt_timer;
static int safe_close;
static void geodewdt_ping(void)
{
/* Stop the counter */
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
/* Reset the counter */
geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
/* Enable the counter */
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
}
static void geodewdt_disable(void)
{
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
}
static int geodewdt_set_heartbeat(int val)
{
if (val < 1 || val > GEODEWDT_MAX_SECONDS)
return -EINVAL;
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ);
geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
timeout = val;
return 0;
}
static int
geodewdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags))
return -EBUSY;
if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags))
__module_get(THIS_MODULE);
geodewdt_ping();
return nonseekable_open(inode, file);
}
static int
geodewdt_release(struct inode *inode, struct file *file)
{
if (safe_close) {
geodewdt_disable();
module_put(THIS_MODULE);
}
else {
printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
geodewdt_ping();
set_bit(WDT_FLAGS_ORPHAN, &wdt_flags);
}
clear_bit(WDT_FLAGS_OPEN, &wdt_flags);
safe_close = 0;
return 0;
}
static ssize_t
geodewdt_write(struct file *file, const char __user *data, size_t len,
loff_t *ppos)
{
if(len) {
if (!nowayout) {
size_t i;
safe_close = 0;
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
safe_close = 1;
}
}
geodewdt_ping();
}
return len;
}
static int
geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int interval;
static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
switch(cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
geodewdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(interval, p))
return -EFAULT;
if (geodewdt_set_heartbeat(interval))
return -EINVAL;
/* Fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS:
{
int options, ret = -EINVAL;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
geodewdt_disable();
ret = 0;
}
if (options & WDIOS_ENABLECARD) {
geodewdt_ping();
ret = 0;
}
return ret;
}
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations geodewdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = geodewdt_write,
.ioctl = geodewdt_ioctl,
.open = geodewdt_open,
.release = geodewdt_release,
};
static struct miscdevice geodewdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &geodewdt_fops
};
static int __devinit
geodewdt_probe(struct platform_device *dev)
{
int ret, timer;
timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY,
MFGPT_DOMAIN_WORKING, THIS_MODULE);
if (timer == -1) {
printk(KERN_ERR "geodewdt: No timers were available\n");
return -ENODEV;
}
wdt_timer = timer;
/* Set up the timer */
geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP,
GEODEWDT_SCALE | (3 << 8));
/* Set up comparator 2 to reset when the event fires */
geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1);
/* Set up the initial timeout */
geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2,
timeout * GEODEWDT_HZ);
ret = misc_register(&geodewdt_miscdev);
return ret;
}
static int __devexit
geodewdt_remove(struct platform_device *dev)
{
misc_deregister(&geodewdt_miscdev);
return 0;
}
static void
geodewdt_shutdown(struct platform_device *dev)
{
geodewdt_disable();
}
static struct platform_driver geodewdt_driver = {
.probe = geodewdt_probe,
.remove = __devexit_p(geodewdt_remove),
.shutdown = geodewdt_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
},
};
static int __init
geodewdt_init(void)
{
int ret;
ret = platform_driver_register(&geodewdt_driver);
if (ret)
return ret;
geodewdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
if (IS_ERR(geodewdt_platform_device)) {
ret = PTR_ERR(geodewdt_platform_device);
goto err;
}
return 0;
err:
platform_driver_unregister(&geodewdt_driver);
return ret;
}
static void __exit
geodewdt_exit(void)
{
platform_device_unregister(geodewdt_platform_device);
platform_driver_unregister(&geodewdt_driver);
}
module_init(geodewdt_init);
module_exit(geodewdt_exit);
MODULE_AUTHOR("Advanced Micro Devices, Inc");
MODULE_DESCRIPTION("Geode GX/LX Watchdog Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
...@@ -418,23 +418,20 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, ...@@ -418,23 +418,20 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
static unsigned long rom_pl; static unsigned long rom_pl;
static int die_nmi_called; static int die_nmi_called;
if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) if (ulReason == DIE_NMI || ulReason == DIE_NMI_IPI) {
return NOTIFY_OK; spin_lock_irqsave(&rom_lock, rom_pl);
if (!die_nmi_called)
spin_lock_irqsave(&rom_lock, rom_pl); asminline_call(&cmn_regs, cru_rom_addr);
if (!die_nmi_called) die_nmi_called = 1;
asminline_call(&cmn_regs, cru_rom_addr); spin_unlock_irqrestore(&rom_lock, rom_pl);
die_nmi_called = 1; if (cmn_regs.u1.ral != 0) {
spin_unlock_irqrestore(&rom_lock, rom_pl); panic("An NMI occurred, please see the Integrated "
if (cmn_regs.u1.ral == 0) { "Management Log for details.\n");
printk(KERN_WARNING "hpwdt: An NMI occurred, " }
"but unable to determine source.\n");
} else {
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
} }
return NOTIFY_STOP; die_nmi_called = 0;
return NOTIFY_DONE;
} }
/* /*
......
...@@ -41,9 +41,10 @@ ...@@ -41,9 +41,10 @@
* 82801HH (ICH8DH) : document number 313056-003, 313057-009, * 82801HH (ICH8DH) : document number 313056-003, 313057-009,
* 82801HO (ICH8DO) : document number 313056-003, 313057-009, * 82801HO (ICH8DO) : document number 313056-003, 313057-009,
* 82801HEM (ICH8M-E) : document number 313056-003, 313057-009, * 82801HEM (ICH8M-E) : document number 313056-003, 313057-009,
* 82801IB (ICH9) : document number 316972-001, 316973-001, * 82801IB (ICH9) : document number 316972-001, 316973-006,
* 82801IR (ICH9R) : document number 316972-001, 316973-001, * 82801IR (ICH9R) : document number 316972-001, 316973-006,
* 82801IH (ICH9DH) : document number 316972-001, 316973-001, * 82801IH (ICH9DH) : document number 316972-001, 316973-006,
* 82801IO (ICH9DO) : document number 316972-001, 316973-006,
* 6300ESB (6300ESB) : document number 300641-003, 300884-010, * 6300ESB (6300ESB) : document number 300641-003, 300884-010,
* 631xESB (631xESB) : document number 313082-001, 313075-005, * 631xESB (631xESB) : document number 313082-001, 313075-005,
* 632xESB (632xESB) : document number 313082-001, 313075-005 * 632xESB (632xESB) : document number 313082-001, 313075-005
...@@ -55,8 +56,8 @@ ...@@ -55,8 +56,8 @@
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_wdt" #define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.02" #define DRV_VERSION "1.03"
#define DRV_RELDATE "26-Jul-2007" #define DRV_RELDATE "30-Apr-2008"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
/* Includes */ /* Includes */
...@@ -104,6 +105,7 @@ enum iTCO_chipsets { ...@@ -104,6 +105,7 @@ enum iTCO_chipsets {
TCO_ICH9, /* ICH9 */ TCO_ICH9, /* ICH9 */
TCO_ICH9R, /* ICH9R */ TCO_ICH9R, /* ICH9R */
TCO_ICH9DH, /* ICH9DH */ TCO_ICH9DH, /* ICH9DH */
TCO_ICH9DO, /* ICH9DO */
TCO_631XESB, /* 631xESB/632xESB */ TCO_631XESB, /* 631xESB/632xESB */
}; };
...@@ -136,6 +138,7 @@ static struct { ...@@ -136,6 +138,7 @@ static struct {
{"ICH9", 2}, {"ICH9", 2},
{"ICH9R", 2}, {"ICH9R", 2},
{"ICH9DH", 2}, {"ICH9DH", 2},
{"ICH9DO", 2},
{"631xESB/632xESB", 2}, {"631xESB/632xESB", 2},
{NULL,0} {NULL,0}
}; };
...@@ -181,6 +184,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { ...@@ -181,6 +184,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )}, { ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )},
{ ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )}, { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO )},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define WATCHDOG_NAME "w83697hf/hg WDT" #define WATCHDOG_NAME "w83697hf/hg WDT"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
#define WATCHDOG_EARLY_DISABLE 1 /* Disable until userland kicks in */
static unsigned long wdt_is_open; static unsigned long wdt_is_open;
static char expect_close; static char expect_close;
...@@ -56,12 +57,16 @@ MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect) ...@@ -56,12 +57,16 @@ MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static int early_disable = WATCHDOG_EARLY_DISABLE;
module_param(early_disable, int, 0);
MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")");
/* /*
* Kernel methods. * Kernel methods.
*/ */
...@@ -140,7 +145,7 @@ w83697hf_init(void) ...@@ -140,7 +145,7 @@ w83697hf_init(void)
w83697hf_deselect_wdt(); w83697hf_deselect_wdt();
} }
static int static void
wdt_ping(void) wdt_ping(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
...@@ -150,10 +155,9 @@ wdt_ping(void) ...@@ -150,10 +155,9 @@ wdt_ping(void)
w83697hf_deselect_wdt(); w83697hf_deselect_wdt();
spin_unlock(&io_lock); spin_unlock(&io_lock);
return 0;
} }
static int static void
wdt_enable(void) wdt_enable(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
...@@ -164,10 +168,9 @@ wdt_enable(void) ...@@ -164,10 +168,9 @@ wdt_enable(void)
w83697hf_deselect_wdt(); w83697hf_deselect_wdt();
spin_unlock(&io_lock); spin_unlock(&io_lock);
return 0;
} }
static int static void
wdt_disable(void) wdt_disable(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
...@@ -178,7 +181,22 @@ wdt_disable(void) ...@@ -178,7 +181,22 @@ wdt_disable(void)
w83697hf_deselect_wdt(); w83697hf_deselect_wdt();
spin_unlock(&io_lock); spin_unlock(&io_lock);
return 0; }
static unsigned char
wdt_running(void)
{
unsigned char t;
spin_lock(&io_lock);
w83697hf_select_wdt();
t = w83697hf_get_reg(0xF4); /* Read timer */
w83697hf_deselect_wdt();
spin_unlock(&io_lock);
return t;
} }
static int static int
...@@ -397,7 +415,11 @@ wdt_init(void) ...@@ -397,7 +415,11 @@ wdt_init(void)
} }
w83697hf_init(); w83697hf_init();
wdt_disable(); /* Disable watchdog until first use */ if (early_disable) {
if (wdt_running())
printk (KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n");
wdt_disable();
}
if (wdt_set_heartbeat(timeout)) { if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_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