Commit b588e2bb 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: (70 commits)
  [WATCHDOG] more coding style clean-up's
  [WATCHDOG] sbc8360.c - move stop code into a function
  [WATCHDOG] Coding style - Indentation - part 2
  [WATCHDOG] Coding style - Indentation - part 1
  [WATCHDOG] mpc8xxx_wdt: add support for MPC8xx watchdogs
  [WATCHDOG] mpc8xxx_wdt: fix build
  [WATCHDOG] mpc8xxx_wdt: various renames, mostly s/mpc83xx/mpc8xxx/g
  [WATCHDOG] mpc83xx_wdt: rename to mpc8xxx_wdt
  [WATCHDOG] mpc83xx_wdt: add support for MPC86xx CPUs
  [WATCHDOG] mpc83xx_wdt: convert to the OF platform driver
  [WATCHDOG] pcwd: a couple of watchdogs escaped conversion
  [WATCHDOG] Clean-up includes
  [WATCHDOG] hpwdt.c - fix double includes
  [WATCHDOG 57/57] wdt501/pci: Clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 56/57] wdt977: clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 55/57] wdt285: switch to unlocked_ioctl and tidy up oddments of coding style
  [WATCHDOG 54/57] wdrtas: clean up, coding style, switch to unlocked_ioctl
  [WATCHDOG 53/57] wafer5823wdt: Clean up, coding style, switch to unlocked_ioctl
  [WATCHDOG 52/57] w83977f_wdt: clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 51/57] w83877f_wdt: clean up code, coding style, switch to unlocked_ioctl
  ...
parents 3df302ff 7944d3a5
...@@ -695,9 +695,17 @@ config 8xx_WDT ...@@ -695,9 +695,17 @@ config 8xx_WDT
tristate "MPC8xx Watchdog Timer" tristate "MPC8xx Watchdog Timer"
depends on 8xx depends on 8xx
config 83xx_WDT config 8xxx_WDT
tristate "MPC83xx Watchdog Timer" tristate "MPC8xxx Platform Watchdog Timer"
depends on PPC_83xx depends on PPC_8xx || PPC_83xx || PPC_86xx
help
This driver is for a SoC level watchdog that exists on some
Freescale PowerPC processors. So far this driver supports:
- MPC8xx watchdogs
- MPC83xx watchdogs
- MPC86xx watchdogs
For BookE processors (MPC85xx) use the BOOKE_WDT driver instead.
config MV64X60_WDT config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer" tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
......
...@@ -103,7 +103,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o ...@@ -103,7 +103,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
# POWERPC Architecture # POWERPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
......
...@@ -58,39 +58,45 @@ ...@@ -58,39 +58,45 @@
#include <linux/types.h> /* For standard types (like size_t) */ #include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/kernel.h> /* For printk/panic/... */ #include <linux/kernel.h> /* For printk/panic/... */
#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV
(WATCHDOG_MINOR) */
#include <linux/watchdog.h> /* For the watchdog specific items */ #include <linux/watchdog.h> /* For the watchdog specific items */
#include <linux/fs.h> /* For file operations */ #include <linux/fs.h> /* For file operations */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <linux/platform_device.h> /* For platform_driver framework */ #include <linux/platform_device.h> /* For platform_driver framework */
#include <linux/init.h> /* For __init/__exit/... */ #include <linux/init.h> /* For __init/__exit/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/io.h> /* For inb/outb/... */
#include <asm/io.h> /* For inb/outb/... */
/* Module information */ /* Module information */
#define DRV_NAME "acquirewdt" #define DRV_NAME "acquirewdt"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Acquire WDT" #define WATCHDOG_NAME "Acquire WDT"
#define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */ /* There is no way to see what the correct time-out period is */
#define WATCHDOG_HEARTBEAT 0
/* internal variables */ /* internal variables */
static struct platform_device *acq_platform_device; /* the watchdog platform device */ /* the watchdog platform device */
static struct platform_device *acq_platform_device;
static unsigned long acq_is_open; static unsigned long acq_is_open;
static char expect_close; static char expect_close;
/* module parameters */ /* module parameters */
static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */ /* You must set this - there is no sane way to probe for this board. */
static int wdt_stop = 0x43;
module_param(wdt_stop, int, 0); module_param(wdt_stop, int, 0);
MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)"); MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */ /* You must set this - there is no sane way to probe for this board. */
static int wdt_start = 0x443;
module_param(wdt_start, int, 0); module_param(wdt_start, int, 0);
MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)"); MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
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) ")");
/* /*
* Watchdog Operations * Watchdog Operations
...@@ -112,18 +118,18 @@ static void acq_stop(void) ...@@ -112,18 +118,18 @@ static void acq_stop(void)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) static ssize_t acq_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) { if (count) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the magic character
* five months ago... */ five months ago... */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the
/* scan to see whether or not we got the magic character */ magic character */
for (i = 0; i != count; i++) { for (i = 0; i != count; i++) {
char c; char c;
if (get_user(c, buf + i)) if (get_user(c, buf + i))
...@@ -132,28 +138,25 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count ...@@ -132,28 +138,25 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count
expect_close = 42; expect_close = 42;
} }
} }
/* Well, anyhow someone wrote to us, we should
/* Well, anyhow someone wrote to us, we should return that favour */ return that favour */
acq_keepalive(); acq_keepalive();
} }
return count; return count;
} }
static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = static struct watchdog_info ident = {
{
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = WATCHDOG_NAME, .identity = WATCHDOG_NAME,
}; };
switch(cmd) switch (cmd) {
{
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
...@@ -161,32 +164,26 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -161,32 +164,26 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE:
acq_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_HEARTBEAT, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
if (get_user(options, p)) if (get_user(options, p))
return -EFAULT; return -EFAULT;
if (options & WDIOS_DISABLECARD) {
if (options & WDIOS_DISABLECARD)
{
acq_stop(); acq_stop();
retval = 0; retval = 0;
} }
if (options & WDIOS_ENABLECARD) {
if (options & WDIOS_ENABLECARD)
{
acq_keepalive(); acq_keepalive();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
case WDIOC_KEEPALIVE:
acq_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_HEARTBEAT, p);
default: default:
return -ENOTTY; return -ENOTTY;
...@@ -211,7 +208,8 @@ static int acq_close(struct inode *inode, struct file *file) ...@@ -211,7 +208,8 @@ static int acq_close(struct inode *inode, struct file *file)
if (expect_close == 42) { if (expect_close == 42) {
acq_stop(); acq_stop();
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
acq_keepalive(); acq_keepalive();
} }
clear_bit(0, &acq_is_open); clear_bit(0, &acq_is_open);
...@@ -227,7 +225,7 @@ static const struct file_operations acq_fops = { ...@@ -227,7 +225,7 @@ static const struct file_operations acq_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = acq_write, .write = acq_write,
.ioctl = acq_ioctl, .unlocked_ioctl = acq_ioctl,
.open = acq_open, .open = acq_open,
.release = acq_close, .release = acq_close,
}; };
...@@ -248,32 +246,29 @@ static int __devinit acq_probe(struct platform_device *dev) ...@@ -248,32 +246,29 @@ static int __devinit acq_probe(struct platform_device *dev)
if (wdt_stop != wdt_start) { if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
wdt_stop); "I/O address 0x%04x already in use\n", wdt_stop);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
} }
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start); wdt_start);
ret = -EIO; ret = -EIO;
goto unreg_stop; goto unreg_stop;
} }
ret = misc_register(&acq_miscdev); ret = misc_register(&acq_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
goto unreg_regions; goto unreg_regions;
} }
printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
nowayout);
return 0; return 0;
unreg_regions: unreg_regions:
release_region(wdt_start, 1); release_region(wdt_start, 1);
unreg_stop: unreg_stop:
...@@ -286,9 +281,9 @@ static int __devinit acq_probe(struct platform_device *dev) ...@@ -286,9 +281,9 @@ static int __devinit acq_probe(struct platform_device *dev)
static int __devexit acq_remove(struct platform_device *dev) static int __devexit acq_remove(struct platform_device *dev)
{ {
misc_deregister(&acq_miscdev); misc_deregister(&acq_miscdev);
release_region(wdt_start,1); release_region(wdt_start, 1);
if(wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop,1); release_region(wdt_stop, 1);
return 0; return 0;
} }
...@@ -313,18 +308,19 @@ static int __init acq_init(void) ...@@ -313,18 +308,19 @@ static int __init acq_init(void)
{ {
int err; int err;
printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n"); printk(KERN_INFO
"WDT driver for Acquire single board computer initialising.\n");
err = platform_driver_register(&acquirewdt_driver); err = platform_driver_register(&acquirewdt_driver);
if (err) if (err)
return err; return err;
acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); acq_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(acq_platform_device)) { if (IS_ERR(acq_platform_device)) {
err = PTR_ERR(acq_platform_device); err = PTR_ERR(acq_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
} }
return 0; return 0;
unreg_platform_driver: unreg_platform_driver:
......
...@@ -37,9 +37,9 @@ ...@@ -37,9 +37,9 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define DRV_NAME "advantechwdt" #define DRV_NAME "advantechwdt"
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
#define WATCHDOG_NAME "Advantech WDT" #define WATCHDOG_NAME "Advantech WDT"
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static struct platform_device *advwdt_platform_device; /* the watchdog platform device */ /* the watchdog platform device */
static struct platform_device *advwdt_platform_device;
static unsigned long advwdt_is_open; static unsigned long advwdt_is_open;
static char adv_expect_close; static char adv_expect_close;
...@@ -72,35 +73,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)"); ...@@ -72,35 +73,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
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 <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=63, 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) ")");
/* /*
* Watchdog Operations * Watchdog Operations
*/ */
static void static void advwdt_ping(void)
advwdt_ping(void)
{ {
/* Write a watchdog value */ /* Write a watchdog value */
outb_p(timeout, wdt_start); outb_p(timeout, wdt_start);
} }
static void static void advwdt_disable(void)
advwdt_disable(void)
{ {
inb_p(wdt_stop); inb_p(wdt_stop);
} }
static int static int advwdt_set_heartbeat(int t)
advwdt_set_heartbeat(int t)
{ {
if ((t < 1) || (t > 63)) if (t < 1 || t > 63)
return -EINVAL; return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
} }
...@@ -109,8 +110,8 @@ advwdt_set_heartbeat(int t) ...@@ -109,8 +110,8 @@ advwdt_set_heartbeat(int t)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t static ssize_t advwdt_write(struct file *file, const char __user *buf,
advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -120,7 +121,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp ...@@ -120,7 +121,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp
for (i = 0; i != count; i++) { for (i = 0; i != count; i++) {
char c; char c;
if (get_user(c, buf+i)) if (get_user(c, buf + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
adv_expect_close = 42; adv_expect_close = 42;
...@@ -131,9 +132,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp ...@@ -131,9 +132,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp
return count; return count;
} }
static int static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
int new_timeout; int new_timeout;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -154,49 +153,42 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -154,49 +153,42 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE:
advwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
advwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
if (get_user(options, p)) if (get_user(options, p))
return -EFAULT; return -EFAULT;
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
advwdt_disable(); advwdt_disable();
retval = 0; retval = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
advwdt_ping(); advwdt_ping();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
case WDIOC_KEEPALIVE:
advwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
advwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int static int advwdt_open(struct inode *inode, struct file *file)
advwdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &advwdt_is_open)) if (test_and_set_bit(0, &advwdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -208,13 +200,13 @@ advwdt_open(struct inode *inode, struct file *file) ...@@ -208,13 +200,13 @@ advwdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int static int advwdt_close(struct inode *inode, struct file *file)
advwdt_close(struct inode *inode, struct file *file)
{ {
if (adv_expect_close == 42) { if (adv_expect_close == 42) {
advwdt_disable(); advwdt_disable();
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
advwdt_ping(); advwdt_ping();
} }
clear_bit(0, &advwdt_is_open); clear_bit(0, &advwdt_is_open);
...@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = { ...@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = advwdt_write, .write = advwdt_write,
.ioctl = advwdt_ioctl, .unlocked_ioctl = advwdt_ioctl,
.open = advwdt_open, .open = advwdt_open,
.release = advwdt_close, .release = advwdt_close,
}; };
...@@ -245,14 +237,14 @@ static struct miscdevice advwdt_miscdev = { ...@@ -245,14 +237,14 @@ static struct miscdevice advwdt_miscdev = {
* Init & exit routines * Init & exit routines
*/ */
static int __devinit static int __devinit advwdt_probe(struct platform_device *dev)
advwdt_probe(struct platform_device *dev)
{ {
int ret; int ret;
if (wdt_stop != wdt_start) { if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_stop); wdt_stop);
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -260,7 +252,8 @@ advwdt_probe(struct platform_device *dev) ...@@ -260,7 +252,8 @@ advwdt_probe(struct platform_device *dev)
} }
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_start); wdt_start);
ret = -EIO; ret = -EIO;
goto unreg_stop; goto unreg_stop;
...@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev) ...@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev)
/* Check that the heartbeat value is within it's range ; if not reset to the default */ /* Check that the heartbeat value is within it's range ; if not reset to the default */
if (advwdt_set_heartbeat(timeout)) { if (advwdt_set_heartbeat(timeout)) {
advwdt_set_heartbeat(WATCHDOG_TIMEOUT); advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1<=x<=63, using %d\n", timeout);
} }
ret = misc_register(&advwdt_miscdev); ret = misc_register(&advwdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
goto unreg_regions; goto unreg_regions;
} }
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
out: out:
return ret; return ret;
unreg_regions: unreg_regions:
...@@ -293,19 +285,17 @@ advwdt_probe(struct platform_device *dev) ...@@ -293,19 +285,17 @@ advwdt_probe(struct platform_device *dev)
goto out; goto out;
} }
static int __devexit static int __devexit advwdt_remove(struct platform_device *dev)
advwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&advwdt_miscdev); misc_deregister(&advwdt_miscdev);
release_region(wdt_start,1); release_region(wdt_start, 1);
if(wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop,1); release_region(wdt_stop, 1);
return 0; return 0;
} }
static void static void advwdt_shutdown(struct platform_device *dev)
advwdt_shutdown(struct platform_device *dev)
{ {
/* Turn the WDT off if we have a soft shutdown */ /* Turn the WDT off if we have a soft shutdown */
advwdt_disable(); advwdt_disable();
...@@ -321,18 +311,19 @@ static struct platform_driver advwdt_driver = { ...@@ -321,18 +311,19 @@ static struct platform_driver advwdt_driver = {
}, },
}; };
static int __init static int __init advwdt_init(void)
advwdt_init(void)
{ {
int err; int err;
printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); printk(KERN_INFO
"WDT driver for Advantech single board computer initialising.\n");
err = platform_driver_register(&advwdt_driver); err = platform_driver_register(&advwdt_driver);
if (err) if (err)
return err; return err;
advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); advwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(advwdt_platform_device)) { if (IS_ERR(advwdt_platform_device)) {
err = PTR_ERR(advwdt_platform_device); err = PTR_ERR(advwdt_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
...@@ -345,8 +336,7 @@ advwdt_init(void) ...@@ -345,8 +336,7 @@ advwdt_init(void)
return err; return err;
} }
static void __exit static void __exit advwdt_exit(void)
advwdt_exit(void)
{ {
platform_device_unregister(advwdt_platform_device); platform_device_unregister(advwdt_platform_device);
platform_driver_unregister(&advwdt_driver); platform_driver_unregister(&advwdt_driver);
......
...@@ -18,9 +18,8 @@ ...@@ -18,9 +18,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h> #include <linux/io.h>
#include <asm/io.h>
#define WATCHDOG_NAME "ALi_M1535" #define WATCHDOG_NAME "ALi_M1535"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
...@@ -36,11 +35,15 @@ static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */ ...@@ -36,11 +35,15 @@ static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */
/* module parameters */ /* module parameters */
static int timeout = WATCHDOG_TIMEOUT; static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (0 < timeout < 18000, 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) ")");
/* /*
* ali_start - start watchdog countdown * ali_start - start watchdog countdown
...@@ -103,15 +106,16 @@ static void ali_keepalive(void) ...@@ -103,15 +106,16 @@ static void ali_keepalive(void)
static int ali_settimer(int t) static int ali_settimer(int t)
{ {
if(t < 0) if (t < 0)
return -EINVAL; return -EINVAL;
else if(t < 60) else if (t < 60)
ali_timeout_bits = t|(1<<6); ali_timeout_bits = t|(1<<6);
else if(t < 3600) else if (t < 3600)
ali_timeout_bits = (t/60)|(1<<7); ali_timeout_bits = (t/60)|(1<<7);
else if(t < 18000) else if (t < 18000)
ali_timeout_bits = (t/300)|(1<<6)|(1<<7); ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
else return -EINVAL; else
return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
...@@ -134,21 +138,22 @@ static int ali_settimer(int t) ...@@ -134,21 +138,22 @@ static int ali_settimer(int t)
*/ */
static ssize_t ali_write(struct file *file, const char __user *data, static ssize_t ali_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the
* five months ago... */ magic character five months ago... */
ali_expect_release = 0; ali_expect_release = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got
the magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if(get_user(c, data+i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
ali_expect_release = 42; ali_expect_release = 42;
...@@ -163,7 +168,6 @@ static ssize_t ali_write(struct file *file, const char __user *data, ...@@ -163,7 +168,6 @@ static ssize_t ali_write(struct file *file, const char __user *data,
/* /*
* ali_ioctl - handle watchdog ioctls * ali_ioctl - handle watchdog ioctls
* @inode: VFS inode
* @file: VFS file pointer * @file: VFS file pointer
* @cmd: ioctl number * @cmd: ioctl number
* @arg: arguments to the ioctl * @arg: arguments to the ioctl
...@@ -172,8 +176,7 @@ static ssize_t ali_write(struct file *file, const char __user *data, ...@@ -172,8 +176,7 @@ static ssize_t ali_write(struct file *file, const char __user *data,
* we want an extension to enable irq ack monitoring and the like * we want an extension to enable irq ack monitoring and the like
*/ */
static int ali_ioctl(struct inode *inode, struct file *file, static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -187,54 +190,42 @@ static int ali_ioctl(struct inode *inode, struct file *file, ...@@ -187,54 +190,42 @@ static int ali_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
sizeof (ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE:
ali_keepalive();
return 0;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
if (get_user (new_options, p)) if (get_user(new_options, p))
return -EFAULT; return -EFAULT;
if (new_options & WDIOS_DISABLECARD) { if (new_options & WDIOS_DISABLECARD) {
ali_stop(); ali_stop();
retval = 0; retval = 0;
} }
if (new_options & WDIOS_ENABLECARD) { if (new_options & WDIOS_ENABLECARD) {
ali_start(); ali_start();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
case WDIOC_KEEPALIVE:
ali_keepalive();
return 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
{ {
int new_timeout; int new_timeout;
if (get_user(new_timeout, p)) if (get_user(new_timeout, p))
return -EFAULT; return -EFAULT;
if (ali_settimer(new_timeout)) if (ali_settimer(new_timeout))
return -EINVAL; return -EINVAL;
ali_keepalive(); ali_keepalive();
/* Fall */ /* Fall */
} }
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(timeout, p); return put_user(timeout, p);
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -274,10 +265,11 @@ static int ali_release(struct inode *inode, struct file *file) ...@@ -274,10 +265,11 @@ static int ali_release(struct inode *inode, struct file *file)
/* /*
* Shut off the timer. * Shut off the timer.
*/ */
if (ali_expect_release == 42) { if (ali_expect_release == 42)
ali_stop(); ali_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
ali_keepalive(); ali_keepalive();
} }
clear_bit(0, &ali_is_open); clear_bit(0, &ali_is_open);
...@@ -292,13 +284,11 @@ static int ali_release(struct inode *inode, struct file *file) ...@@ -292,13 +284,11 @@ static int ali_release(struct inode *inode, struct file *file)
*/ */
static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int ali_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */ ali_stop(); /* Turn the WDT off */
ali_stop();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -340,10 +330,10 @@ static int __init ali_find_watchdog(void) ...@@ -340,10 +330,10 @@ static int __init ali_find_watchdog(void)
/* Check for the a 7101 PMU */ /* Check for the a 7101 PMU */
pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL); pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
if(pdev == NULL) if (pdev == NULL)
return -ENODEV; return -ENODEV;
if(pci_enable_device(pdev)) { if (pci_enable_device(pdev)) {
pci_dev_put(pdev); pci_dev_put(pdev);
return -EIO; return -EIO;
} }
...@@ -355,9 +345,12 @@ static int __init ali_find_watchdog(void) ...@@ -355,9 +345,12 @@ static int __init ali_find_watchdog(void)
*/ */
pci_read_config_dword(pdev, 0xCC, &wdog); pci_read_config_dword(pdev, 0xCC, &wdog);
wdog &= ~0x3F; /* Timer bits */ /* Timer bits */
wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */ wdog &= ~0x3F;
wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */ /* Issued events */
wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));
/* No monitor bits */
wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));
pci_write_config_dword(pdev, 0xCC, wdog); pci_write_config_dword(pdev, 0xCC, wdog);
...@@ -372,7 +365,7 @@ static const struct file_operations ali_fops = { ...@@ -372,7 +365,7 @@ static const struct file_operations ali_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ali_write, .write = ali_write,
.ioctl = ali_ioctl, .unlocked_ioctl = ali_ioctl,
.open = ali_open, .open = ali_open,
.release = ali_release, .release = ali_release,
}; };
...@@ -399,14 +392,15 @@ static int __init watchdog_init(void) ...@@ -399,14 +392,15 @@ static int __init watchdog_init(void)
int ret; int ret;
/* Check whether or not the hardware watchdog is there */ /* Check whether or not the hardware watchdog is there */
if (ali_find_watchdog() != 0) { if (ali_find_watchdog() != 0)
return -ENODEV; return -ENODEV;
}
/* Check that the timeout value is within it's range ; if not reset to the default */ /* Check that the timeout value is within it's range;
if not reset to the default */
if (timeout < 1 || timeout >= 18000) { if (timeout < 1 || timeout >= 18000) {
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n", printk(KERN_INFO PFX
"timeout value must be 0 < timeout < 18000, using %d\n",
timeout); timeout);
} }
...@@ -415,14 +409,15 @@ static int __init watchdog_init(void) ...@@ -415,14 +409,15 @@ static int __init watchdog_init(void)
ret = register_reboot_notifier(&ali_notifier); ret = register_reboot_notifier(&ali_notifier);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
goto out; goto out;
} }
ret = misc_register(&ali_miscdev); ret = misc_register(&ali_miscdev);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
goto unreg_reboot; goto unreg_reboot;
} }
......
This diff is collapsed.
...@@ -213,7 +213,7 @@ static int ar7_wdt_notify_sys(struct notifier_block *this, ...@@ -213,7 +213,7 @@ static int ar7_wdt_notify_sys(struct notifier_block *this,
} }
static struct notifier_block ar7_wdt_notifier = { static struct notifier_block ar7_wdt_notifier = {
.notifier_call = ar7_wdt_notify_sys .notifier_call = ar7_wdt_notify_sys,
}; };
static ssize_t ar7_wdt_write(struct file *file, const char *data, static ssize_t ar7_wdt_write(struct file *file, const char *data,
...@@ -230,7 +230,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data, ...@@ -230,7 +230,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data,
expect_close = 0; expect_close = 0;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_close = 1; expect_close = 1;
...@@ -251,8 +251,6 @@ static long ar7_wdt_ioctl(struct file *file, ...@@ -251,8 +251,6 @@ static long ar7_wdt_ioctl(struct file *file,
int new_margin; int new_margin;
switch (cmd) { switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg, &ident, if (copy_to_user((struct watchdog_info *)arg, &ident,
sizeof(ident))) sizeof(ident)))
...@@ -281,6 +279,8 @@ static long ar7_wdt_ioctl(struct file *file, ...@@ -281,6 +279,8 @@ static long ar7_wdt_ioctl(struct file *file,
if (put_user(margin, (int *)arg)) if (put_user(margin, (int *)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
default:
return -ENOTTY;
} }
} }
......
...@@ -212,7 +212,7 @@ static struct watchdog_info at32_wdt_info = { ...@@ -212,7 +212,7 @@ static struct watchdog_info at32_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int at32_wdt_ioctl(struct inode *inode, struct file *file, static long at32_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -221,27 +221,10 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -221,27 +221,10 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
int __user *p = argp; int __user *p = argp;
switch (cmd) { switch (cmd) {
case WDIOC_KEEPALIVE:
at32_wdt_pat();
ret = 0;
break;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
ret = copy_to_user(argp, &at32_wdt_info, ret = copy_to_user(argp, &at32_wdt_info,
sizeof(at32_wdt_info)) ? -EFAULT : 0; sizeof(at32_wdt_info)) ? -EFAULT : 0;
break; break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret)
break;
ret = at32_wdt_settimeout(time);
if (ret)
break;
/* Enable new time value */
at32_wdt_start();
/* fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(wdt->timeout, p);
break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
ret = put_user(0, p); ret = put_user(0, p);
break; break;
...@@ -258,6 +241,23 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -258,6 +241,23 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
at32_wdt_start(); at32_wdt_start();
ret = 0; ret = 0;
break; break;
case WDIOC_KEEPALIVE:
at32_wdt_pat();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret)
break;
ret = at32_wdt_settimeout(time);
if (ret)
break;
/* Enable new time value */
at32_wdt_start();
/* fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(wdt->timeout, p);
break;
} }
return ret; return ret;
...@@ -283,7 +283,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data, ...@@ -283,7 +283,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data,
*/ */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_release = 42; expect_release = 42;
...@@ -298,7 +298,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data, ...@@ -298,7 +298,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data,
static const struct file_operations at32_wdt_fops = { static const struct file_operations at32_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = at32_wdt_ioctl, .unlocked_ioctl = at32_wdt_ioctl,
.open = at32_wdt_open, .open = at32_wdt_open,
.release = at32_wdt_close, .release = at32_wdt_close,
.write = at32_wdt_write, .write = at32_wdt_write,
...@@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev) ...@@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev)
wdt = NULL; wdt = NULL;
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
} }
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/arch/at91_st.h> #include <asm/arch/at91_st.h>
...@@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME; ...@@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0); module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT #ifdef CONFIG_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) ")");
#endif #endif
...@@ -46,7 +49,7 @@ static unsigned long at91wdt_busy; ...@@ -46,7 +49,7 @@ static unsigned long at91wdt_busy;
/* /*
* Disable the watchdog. * Disable the watchdog.
*/ */
static void inline at91_wdt_stop(void) static inline void at91_wdt_stop(void)
{ {
at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
} }
...@@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void) ...@@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void)
/* /*
* Enable and reset the watchdog. * Enable and reset the watchdog.
*/ */
static void inline at91_wdt_start(void) static inline void at91_wdt_start(void)
{ {
at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
(((65536 * wdt_time) >> 8) & AT91_ST_WDV));
at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
} }
/* /*
* Reload the watchdog timer. (ie, pat the watchdog) * Reload the watchdog timer. (ie, pat the watchdog)
*/ */
static void inline at91_wdt_reload(void) static inline void at91_wdt_reload(void)
{ {
at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
} }
...@@ -89,8 +93,9 @@ static int at91_wdt_open(struct inode *inode, struct file *file) ...@@ -89,8 +93,9 @@ static int at91_wdt_open(struct inode *inode, struct file *file)
*/ */
static int at91_wdt_close(struct inode *inode, struct file *file) static int at91_wdt_close(struct inode *inode, struct file *file)
{ {
/* Disable the watchdog when file is closed */
if (!nowayout) if (!nowayout)
at91_wdt_stop(); /* Disable the watchdog when file is closed */ at91_wdt_stop();
clear_bit(0, &at91wdt_busy); clear_bit(0, &at91wdt_busy);
return 0; return 0;
...@@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time) ...@@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
return -EINVAL; return -EINVAL;
/* Set new watchdog time. It will be used when at91_wdt_start() is called. */ /* Set new watchdog time. It will be used when
at91_wdt_start() is called. */
wdt_time = new_time; wdt_time = new_time;
return 0; return 0;
} }
...@@ -123,51 +129,42 @@ static struct watchdog_info at91_wdt_info = { ...@@ -123,51 +129,42 @@ static struct watchdog_info at91_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int at91_wdt_ioctl(struct inode *inode, struct file *file, static long at91_wdt_ioct(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_value; int new_value;
switch(cmd) { switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &at91_wdt_info,
sizeof(at91_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)
at91_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
at91_wdt_start();
return 0;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
at91_wdt_reload(); /* pat the watchdog */ at91_wdt_reload(); /* pat the watchdog */
return 0; return 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_value, p)) if (get_user(new_value, p))
return -EFAULT; return -EFAULT;
if (at91_wdt_settimeout(new_value)) if (at91_wdt_settimeout(new_value))
return -EINVAL; return -EINVAL;
/* Enable new time value */ /* Enable new time value */
at91_wdt_start(); at91_wdt_start();
/* Return current value */ /* Return current value */
return put_user(wdt_time, p); return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p); return put_user(wdt_time, p);
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)
at91_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
at91_wdt_start();
return 0;
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -176,7 +173,8 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -176,7 +173,8 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
/* /*
* Pat the watchdog whenever device is written to. * Pat the watchdog whenever device is written to.
*/ */
static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t at91_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
at91_wdt_reload(); /* pat the watchdog */ at91_wdt_reload(); /* pat the watchdog */
return len; return len;
...@@ -187,7 +185,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l ...@@ -187,7 +185,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l
static const struct file_operations at91wdt_fops = { static const struct file_operations at91wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = at91_wdt_ioctl, .unlocked_ioctl = at91_wdt_ioctl,
.open = at91_wdt_open, .open = at91_wdt_open,
.release = at91_wdt_close, .release = at91_wdt_close,
.write = at91_wdt_write, .write = at91_wdt_write,
...@@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev) ...@@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev)
if (res) if (res)
return res; return res;
printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n",
wdt_time, nowayout ? ", nowayout" : "");
return 0; return 0;
} }
...@@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = { ...@@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = {
static int __init at91_wdt_init(void) static int __init at91_wdt_init(void)
{ {
/* Check that the heartbeat value is within range; if not reset to the default */ /* Check that the heartbeat value is within range;
if not reset to the default */
if (at91_wdt_settimeout(wdt_time)) { if (at91_wdt_settimeout(wdt_time)) {
at91_wdt_settimeout(WDT_DEFAULT_TIME); at91_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/uaccess.h>
#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")
...@@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t) ...@@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t)
int run = bfin_wdt_running(); int run = bfin_wdt_running();
bfin_wdt_stop(); bfin_wdt_stop();
bfin_write_WDOG_CNT(cnt); bfin_write_WDOG_CNT(cnt);
if (run) bfin_wdt_start(); if (run)
bfin_wdt_start();
} }
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
...@@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file) ...@@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
{ {
stampit(); stampit();
if (expect_close == 42) { if (expect_close == 42)
bfin_wdt_stop(); bfin_wdt_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
bfin_wdt_keepalive(); bfin_wdt_keepalive();
} }
expect_close = 0; expect_close = 0;
clear_bit(0, &open_check); clear_bit(0, &open_check);
return 0; return 0;
} }
...@@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, ...@@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
/** /**
* bfin_wdt_ioctl - Query Device * bfin_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device * @file: file handle of device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument * @arg: argument
...@@ -249,7 +248,7 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, ...@@ -249,7 +248,7 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
* Query basic information from the device or ping it, as outlined by the * Query basic information from the device or ping it, as outlined by the
* watchdog API. * watchdog API.
*/ */
static int bfin_wdt_ioctl(struct inode *inode, struct file *file, static long bfin_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -258,36 +257,14 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -258,36 +257,14 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
stampit(); stampit();
switch (cmd) { switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info))) if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
return -EFAULT; return -EFAULT;
else else
return 0; return 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p); return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
case WDIOC_KEEPALIVE:
bfin_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT: {
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (bfin_wdt_set_timeout(new_timeout))
return -EINVAL;
}
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS: { case WDIOC_SETOPTIONS: {
unsigned long flags; unsigned long flags;
int options, ret = -EINVAL; int options, ret = -EINVAL;
...@@ -296,21 +273,33 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -296,21 +273,33 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
return -EFAULT; return -EFAULT;
spin_lock_irqsave(&bfin_wdt_spinlock, flags); spin_lock_irqsave(&bfin_wdt_spinlock, flags);
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
bfin_wdt_stop(); bfin_wdt_stop();
ret = 0; ret = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
bfin_wdt_start(); bfin_wdt_start();
ret = 0; ret = 0;
} }
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret; return ret;
} }
case WDIOC_KEEPALIVE:
bfin_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT: {
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (bfin_wdt_set_timeout(new_timeout))
return -EINVAL;
}
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
} }
} }
...@@ -323,8 +312,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -323,8 +312,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
* Handles specific events, such as turning off the watchdog during a * Handles specific events, such as turning off the watchdog during a
* shutdown event. * shutdown event.
*/ */
static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, static int bfin_wdt_notify_sys(struct notifier_block *this,
void *unused) unsigned long code, void *unused)
{ {
stampit(); stampit();
...@@ -382,7 +371,7 @@ static const struct file_operations bfin_wdt_fops = { ...@@ -382,7 +371,7 @@ static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = bfin_wdt_write, .write = bfin_wdt_write,
.ioctl = bfin_wdt_ioctl, .unlocked_ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open, .open = bfin_wdt_open,
.release = bfin_wdt_release, .release = bfin_wdt_release,
}; };
...@@ -416,13 +405,15 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev) ...@@ -416,13 +405,15 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
ret = register_reboot_notifier(&bfin_wdt_notifier); ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) { if (ret) {
pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); pr_devinit(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
return ret; return ret;
} }
ret = misc_register(&bfin_wdt_miscdev); ret = misc_register(&bfin_wdt_miscdev);
if (ret) { if (ret) {
pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", pr_devinit(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier); unregister_reboot_notifier(&bfin_wdt_notifier);
return ret; return ret;
...@@ -516,7 +507,11 @@ MODULE_LICENSE("GPL"); ...@@ -516,7 +507,11 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(timeout, uint, 0); module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
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) ")");
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/reg_booke.h> #include <asm/reg_booke.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot. /* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
*/ */
#ifdef CONFIG_FSL_BOOKE #ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
#else #else
#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 */
...@@ -82,7 +82,7 @@ static struct watchdog_info ident = { ...@@ -82,7 +82,7 @@ static struct watchdog_info ident = {
.identity = "PowerPC Book-E Watchdog", .identity = "PowerPC Book-E Watchdog",
}; };
static int booke_wdt_ioctl(struct inode *inode, struct file *file, static long booke_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
u32 tmp = 0; u32 tmp = 0;
...@@ -90,8 +90,7 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -90,8 +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(arg, &ident, sizeof(struct watchdog_info)))
sizeof(struct watchdog_info)))
return -EFAULT; return -EFAULT;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
return put_user(ident.options, p); return put_user(ident.options, p);
...@@ -100,16 +99,6 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -100,16 +99,6 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file,
tmp = mfspr(SPRN_TSR) & TSR_WRS(3); tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
/* returns 1 if last reset was caused by the WDT */ /* returns 1 if last reset was caused by the WDT */
return (tmp ? 1 : 0); return (tmp ? 1 : 0);
case WDIOC_KEEPALIVE:
booke_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(booke_wdt_period, p))
return -EFAULT;
mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (get_user(tmp, p)) if (get_user(tmp, p))
return -EINVAL; return -EINVAL;
...@@ -119,6 +108,17 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -119,6 +108,17 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file,
} else } else
return -EINVAL; return -EINVAL;
return 0; return 0;
case WDIOC_KEEPALIVE:
booke_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(booke_wdt_period, p))
return -EFAULT;
mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP(0)) |
WDTP(booke_wdt_period));
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file) ...@@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) { if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1; booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " printk(KERN_INFO
"(wdt_period=%d)\n", booke_wdt_period); "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
...@@ -144,7 +145,7 @@ static const struct file_operations booke_wdt_fops = { ...@@ -144,7 +145,7 @@ 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, .unlocked_ioctl = booke_wdt_ioctl,
.open = booke_wdt_open, .open = booke_wdt_open,
}; };
...@@ -175,8 +176,9 @@ static int __init booke_wdt_init(void) ...@@ -175,8 +176,9 @@ static int __init booke_wdt_init(void)
spin_lock(&booke_wdt_lock); spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) { if (booke_wdt_enabled == 1) {
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " printk(KERN_INFO
"(wdt_period=%d)\n", booke_wdt_period); "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
......
...@@ -30,16 +30,16 @@ ...@@ -30,16 +30,16 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
/* adjustable parameters */ /* adjustable parameters */
static int verbose = 0; static int verbose;
static int port = 0x91; static int port = 0x91;
static int ticks = 10000; static int ticks = 10000;
static spinlock_t cpu5wdt_lock;
#define PFX "cpu5wdt: " #define PFX "cpu5wdt: "
...@@ -70,12 +70,13 @@ static struct { ...@@ -70,12 +70,13 @@ static struct {
static void cpu5wdt_trigger(unsigned long unused) static void cpu5wdt_trigger(unsigned long unused)
{ {
if ( verbose > 2 ) if (verbose > 2)
printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks); printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
if( cpu5wdt_device.running ) if (cpu5wdt_device.running)
ticks--; ticks--;
spin_lock(&cpu5wdt_lock);
/* keep watchdog alive */ /* keep watchdog alive */
outb(1, port + CPU5WDT_TRIGGER_REG); outb(1, port + CPU5WDT_TRIGGER_REG);
...@@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused) ...@@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused)
/* ticks doesn't matter anyway */ /* ticks doesn't matter anyway */
complete(&cpu5wdt_device.stop); complete(&cpu5wdt_device.stop);
} }
spin_unlock(&cpu5wdt_lock);
} }
...@@ -93,14 +95,17 @@ static void cpu5wdt_reset(void) ...@@ -93,14 +95,17 @@ static void cpu5wdt_reset(void)
{ {
ticks = cpu5wdt_device.default_ticks; ticks = cpu5wdt_device.default_ticks;
if ( verbose ) if (verbose)
printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks); printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
} }
static void cpu5wdt_start(void) static void cpu5wdt_start(void)
{ {
if ( !cpu5wdt_device.queue ) { unsigned long flags;
spin_lock_irqsave(&cpu5wdt_lock, flags);
if (!cpu5wdt_device.queue) {
cpu5wdt_device.queue = 1; cpu5wdt_device.queue = 1;
outb(0, port + CPU5WDT_TIME_A_REG); outb(0, port + CPU5WDT_TIME_A_REG);
outb(0, port + CPU5WDT_TIME_B_REG); outb(0, port + CPU5WDT_TIME_B_REG);
...@@ -111,18 +116,20 @@ static void cpu5wdt_start(void) ...@@ -111,18 +116,20 @@ static void cpu5wdt_start(void)
} }
/* if process dies, counter is not decremented */ /* if process dies, counter is not decremented */
cpu5wdt_device.running++; cpu5wdt_device.running++;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
} }
static int cpu5wdt_stop(void) static int cpu5wdt_stop(void)
{ {
if ( cpu5wdt_device.running ) unsigned long flags;
cpu5wdt_device.running = 0;
spin_lock_irqsave(&cpu5wdt_lock, flags);
if (cpu5wdt_device.running)
cpu5wdt_device.running = 0;
ticks = cpu5wdt_device.default_ticks; ticks = cpu5wdt_device.default_ticks;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
if ( verbose ) if (verbose)
printk(KERN_CRIT PFX "stop not possible\n"); printk(KERN_CRIT PFX "stop not possible\n");
return -EIO; return -EIO;
} }
...@@ -130,9 +137,8 @@ static int cpu5wdt_stop(void) ...@@ -130,9 +137,8 @@ static int cpu5wdt_stop(void)
static int cpu5wdt_open(struct inode *inode, struct file *file) static int cpu5wdt_open(struct inode *inode, struct file *file)
{ {
if ( test_and_set_bit(0, &cpu5wdt_device.inuse) ) if (test_and_set_bit(0, &cpu5wdt_device.inuse))
return -EBUSY; return -EBUSY;
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -142,46 +148,38 @@ static int cpu5wdt_release(struct inode *inode, struct file *file) ...@@ -142,46 +148,38 @@ static int cpu5wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long cpu5wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp;
unsigned int value; unsigned int value;
static struct watchdog_info ident = static struct watchdog_info ident = {
{
.options = WDIOF_CARDRESET, .options = WDIOF_CARDRESET,
.identity = "CPU5 WDT", .identity = "CPU5 WDT",
}; };
switch(cmd) { switch (cmd) {
case WDIOC_KEEPALIVE: case WDIOC_GETSUPPORT:
cpu5wdt_reset(); if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
value = inb(port + CPU5WDT_STATUS_REG); value = inb(port + CPU5WDT_STATUS_REG);
value = (value >> 2) & 1; value = (value >> 2) & 1;
if ( copy_to_user(argp, &value, sizeof(int)) ) return put_user(value, p);
return -EFAULT;
break;
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) ) return put_user(0, p);
return -EFAULT;
break;
case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT;
break;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if ( copy_from_user(&value, argp, sizeof(int)) ) if (get_user(value, p))
return -EFAULT; return -EFAULT;
switch(value) { if (value & WDIOS_ENABLECARD)
case WDIOS_ENABLECARD:
cpu5wdt_start(); cpu5wdt_start();
if (value & WDIOS_DISABLECARD)
cpu5wdt_stop();
break; break;
case WDIOS_DISABLECARD: case WDIOC_KEEPALIVE:
return cpu5wdt_stop(); cpu5wdt_reset();
default:
return -EINVAL;
}
break; break;
default: default:
return -ENOTTY; return -ENOTTY;
...@@ -189,20 +187,19 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm ...@@ -189,20 +187,19 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
return 0; return 0;
} }
static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) static ssize_t cpu5wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
if ( !count ) if (!count)
return -EIO; return -EIO;
cpu5wdt_reset(); cpu5wdt_reset();
return count; return count;
} }
static const struct file_operations cpu5wdt_fops = { static const struct file_operations cpu5wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = cpu5wdt_ioctl, .unlocked_ioctl = cpu5wdt_ioctl,
.open = cpu5wdt_open, .open = cpu5wdt_open,
.write = cpu5wdt_write, .write = cpu5wdt_write,
.release = cpu5wdt_release, .release = cpu5wdt_release,
...@@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void) ...@@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void)
unsigned int val; unsigned int val;
int err; int err;
if ( verbose ) if (verbose)
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose); printk(KERN_DEBUG PFX
"port=0x%x, verbose=%i\n", port, verbose);
if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) { init_completion(&cpu5wdt_device.stop);
spin_lock_init(&cpu5wdt_lock);
cpu5wdt_device.queue = 0;
setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
if (!request_region(port, CPU5WDT_EXTENT, PFX)) {
printk(KERN_ERR PFX "request_region failed\n"); printk(KERN_ERR PFX "request_region failed\n");
err = -EBUSY; err = -EBUSY;
goto no_port; goto no_port;
} }
if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
printk(KERN_ERR PFX "misc_register failed\n");
goto no_misc;
}
/* watchdog reboot? */ /* watchdog reboot? */
val = inb(port + CPU5WDT_STATUS_REG); val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1; val = (val >> 2) & 1;
if ( !val ) if (!val)
printk(KERN_INFO PFX "sorry, was my fault\n"); printk(KERN_INFO PFX "sorry, was my fault\n");
init_completion(&cpu5wdt_device.stop); err = misc_register(&cpu5wdt_misc);
cpu5wdt_device.queue = 0; if (err < 0) {
printk(KERN_ERR PFX "misc_register failed\n");
clear_bit(0, &cpu5wdt_device.inuse); goto no_misc;
}
setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
printk(KERN_INFO PFX "init success\n"); printk(KERN_INFO PFX "init success\n");
return 0; return 0;
no_misc: no_misc:
...@@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void) ...@@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void)
static void __devexit cpu5wdt_exit(void) static void __devexit cpu5wdt_exit(void)
{ {
if ( cpu5wdt_device.queue ) { if (cpu5wdt_device.queue) {
cpu5wdt_device.queue = 0; cpu5wdt_device.queue = 0;
wait_for_completion(&cpu5wdt_device.stop); wait_for_completion(&cpu5wdt_device.stop);
} }
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define MODULE_NAME "DAVINCI-WDT: " #define MODULE_NAME "DAVINCI-WDT: "
...@@ -143,9 +143,8 @@ static struct watchdog_info ident = { ...@@ -143,9 +143,8 @@ static struct watchdog_info ident = {
.identity = "DaVinci Watchdog", .identity = "DaVinci Watchdog",
}; };
static int static long davinci_wdt_ioctl(struct file *file,
davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -160,14 +159,14 @@ davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -160,14 +159,14 @@ davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(0, (int *)arg); ret = put_user(0, (int *)arg);
break; break;
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
wdt_service(); wdt_service();
ret = 0; ret = 0;
break; break;
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
} }
return ret; return ret;
} }
...@@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = { ...@@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = davinci_wdt_write, .write = davinci_wdt_write,
.ioctl = davinci_wdt_ioctl, .unlocked_ioctl = davinci_wdt_ioctl,
.open = davinci_wdt_open, .open = davinci_wdt_open,
.release = davinci_wdt_release, .release = davinci_wdt_release,
}; };
......
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
#define WDT_VERSION "0.3" #define WDT_VERSION "0.3"
#define PFX "ep93xx_wdt: " #define PFX "ep93xx_wdt: "
...@@ -136,9 +136,8 @@ static struct watchdog_info ident = { ...@@ -136,9 +136,8 @@ static struct watchdog_info ident = {
.identity = "EP93xx Watchdog", .identity = "EP93xx Watchdog",
}; };
static int static long ep93xx_wdt_ioctl(struct file *file,
ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -156,15 +155,15 @@ ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -156,15 +155,15 @@ ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(boot_status, (int __user *)arg); ret = put_user(boot_status, (int __user *)arg);
break; break;
case WDIOC_GETTIMEOUT:
/* actually, it is 0.250 seconds.... */
ret = put_user(1, (int __user *)arg);
break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
wdt_keepalive(); wdt_keepalive();
ret = 0; ret = 0;
break; break;
case WDIOC_GETTIMEOUT:
/* actually, it is 0.250 seconds.... */
ret = put_user(1, (int __user *)arg);
break;
} }
return ret; return ret;
} }
...@@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) ...@@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_shutdown(); wdt_shutdown();
else else
printk(KERN_CRIT PFX "Device closed unexpectedly - " printk(KERN_CRIT PFX
"timer will not stop\n"); "Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -186,7 +185,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) ...@@ -186,7 +185,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
static const struct file_operations ep93xx_wdt_fops = { static const struct file_operations ep93xx_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = ep93xx_wdt_write, .write = ep93xx_wdt_write,
.ioctl = ep93xx_wdt_ioctl, .unlocked_ioctl = ep93xx_wdt_ioctl,
.open = ep93xx_wdt_open, .open = ep93xx_wdt_open,
.release = ep93xx_wdt_release, .release = ep93xx_wdt_release,
}; };
...@@ -243,7 +242,9 @@ module_param(nowayout, int, 0); ...@@ -243,7 +242,9 @@ module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
"Alessandro Zummo <a.zummo@towertech.it>"); "Alessandro Zummo <a.zummo@towertech.it>");
......
...@@ -56,14 +56,15 @@ ...@@ -56,14 +56,15 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
static unsigned long eurwdt_is_open; static unsigned long eurwdt_is_open;
static int eurwdt_timeout; static int eurwdt_timeout;
static char eur_expect_close; static char eur_expect_close;
static spinlock_t eurwdt_lock;
/* /*
* You must set these - there is no sane way to probe for this board. * You must set these - there is no sane way to probe for this board.
...@@ -78,7 +79,9 @@ static char *ev = "int"; ...@@ -78,7 +79,9 @@ static char *ev = "int";
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) ")");
/* /*
* Some symbolic names * Some symbolic names
...@@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void) ...@@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void)
{ {
eurwdt_disable_timer(); eurwdt_disable_timer();
eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */
eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT); eurwdt_write_reg(WDT_OUTPIN_CFG,
!strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT);
/* Setting interrupt line */ /* Setting interrupt line */
if (irq == 2 || irq > 15 || irq < 0) { if (irq == 2 || irq > 15 || irq < 0) {
...@@ -206,21 +210,21 @@ size_t count, loff_t *ppos) ...@@ -206,21 +210,21 @@ size_t count, loff_t *ppos)
for (i = 0; i != count; i++) { for (i = 0; i != count; i++) {
char c; char c;
if(get_user(c, buf+i)) if (get_user(c, buf + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
eur_expect_close = 42; eur_expect_close = 42;
} }
} }
spin_lock(&eurwdt_lock);
eurwdt_ping(); /* the default timeout */ eurwdt_ping(); /* the default timeout */
spin_unlock(&eurwdt_lock);
} }
return count; return count;
} }
/** /**
* eurwdt_ioctl: * eurwdt_ioctl:
* @inode: inode of the device
* @file: file handle to the device * @file: file handle to the device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument pointer * @arg: argument pointer
...@@ -229,13 +233,14 @@ size_t count, loff_t *ppos) ...@@ -229,13 +233,14 @@ size_t count, loff_t *ppos)
* according to their available features. * according to their available features.
*/ */
static int eurwdt_ioctl(struct inode *inode, struct file *file, static long eurwdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "WDT Eurotech CPU-1220/1410", .identity = "WDT Eurotech CPU-1220/1410",
}; };
...@@ -243,10 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -243,10 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
int time; int time;
int options, retval = -EINVAL; int options, retval = -EINVAL;
switch(cmd) { switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
...@@ -254,8 +256,26 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -254,8 +256,26 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(options, p))
return -EFAULT;
spin_lock(&eurwdt_lock);
if (options & WDIOS_DISABLECARD) {
eurwdt_disable_timer();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
eurwdt_activate_timer();
eurwdt_ping();
retval = 0;
}
spin_unlock(&eurwdt_lock);
return retval;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
spin_lock(&eurwdt_lock);
eurwdt_ping(); eurwdt_ping();
spin_unlock(&eurwdt_lock);
return 0; return 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
...@@ -266,26 +286,17 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -266,26 +286,17 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
if (time < 0 || time > 255) if (time < 0 || time > 255)
return -EINVAL; return -EINVAL;
spin_lock(&eurwdt_lock);
eurwdt_timeout = time; eurwdt_timeout = time;
eurwdt_set_timeout(time); eurwdt_set_timeout(time);
spin_unlock(&eurwdt_lock);
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(eurwdt_timeout, p); return put_user(eurwdt_timeout, p);
case WDIOC_SETOPTIONS: default:
if (get_user(options, p)) return -ENOTTY;
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
eurwdt_disable_timer();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
eurwdt_activate_timer();
eurwdt_ping();
retval = 0;
}
return retval;
} }
} }
...@@ -322,10 +333,11 @@ static int eurwdt_open(struct inode *inode, struct file *file) ...@@ -322,10 +333,11 @@ static int eurwdt_open(struct inode *inode, struct file *file)
static int eurwdt_release(struct inode *inode, struct file *file) static int eurwdt_release(struct inode *inode, struct file *file)
{ {
if (eur_expect_close == 42) { if (eur_expect_close == 42)
eurwdt_disable_timer(); eurwdt_disable_timer();
} else { else {
printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT
"eurwdt: Unexpected close, not stopping watchdog!\n");
eurwdt_ping(); eurwdt_ping();
} }
clear_bit(0, &eurwdt_is_open); clear_bit(0, &eurwdt_is_open);
...@@ -348,10 +360,8 @@ static int eurwdt_release(struct inode *inode, struct file *file) ...@@ -348,10 +360,8 @@ static int eurwdt_release(struct inode *inode, struct file *file)
static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the card off */ eurwdt_disable_timer(); /* Turn the card off */
eurwdt_disable_timer();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -365,7 +375,7 @@ static const struct file_operations eurwdt_fops = { ...@@ -365,7 +375,7 @@ static const struct file_operations eurwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = eurwdt_write, .write = eurwdt_write,
.ioctl = eurwdt_ioctl, .unlocked_ioctl = eurwdt_ioctl,
.open = eurwdt_open, .open = eurwdt_open,
.release = eurwdt_release, .release = eurwdt_release,
}; };
...@@ -419,7 +429,7 @@ static int __init eurwdt_init(void) ...@@ -419,7 +429,7 @@ static int __init eurwdt_init(void)
int ret; int ret;
ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
if(ret) { if (ret) {
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
goto out; goto out;
} }
...@@ -432,10 +442,13 @@ static int __init eurwdt_init(void) ...@@ -432,10 +442,13 @@ static int __init eurwdt_init(void)
ret = register_reboot_notifier(&eurwdt_notifier); ret = register_reboot_notifier(&eurwdt_notifier);
if (ret) { if (ret) {
printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret); printk(KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)\n", ret);
goto outreg; goto outreg;
} }
spin_lock_init(&eurwdt_lock);
ret = misc_register(&eurwdt_miscdev); ret = misc_register(&eurwdt_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/geode.h> #include <asm/geode.h>
#define GEODEWDT_HZ 500 #define GEODEWDT_HZ 500
...@@ -77,8 +77,7 @@ static int geodewdt_set_heartbeat(int val) ...@@ -77,8 +77,7 @@ static int geodewdt_set_heartbeat(int val)
return 0; return 0;
} }
static int static int geodewdt_open(struct inode *inode, struct file *file)
geodewdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags)) if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags))
return -EBUSY; return -EBUSY;
...@@ -90,14 +89,12 @@ geodewdt_open(struct inode *inode, struct file *file) ...@@ -90,14 +89,12 @@ geodewdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int static int geodewdt_release(struct inode *inode, struct file *file)
geodewdt_release(struct inode *inode, struct file *file)
{ {
if (safe_close) { if (safe_close) {
geodewdt_disable(); geodewdt_disable();
module_put(THIS_MODULE); module_put(THIS_MODULE);
} } else {
else {
printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n"); printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
geodewdt_ping(); geodewdt_ping();
...@@ -109,11 +106,10 @@ geodewdt_release(struct inode *inode, struct file *file) ...@@ -109,11 +106,10 @@ geodewdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t static ssize_t geodewdt_write(struct file *file, const char __user *data,
geodewdt_write(struct file *file, const char __user *data, size_t len, size_t len, loff_t *ppos)
loff_t *ppos)
{ {
if(len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
safe_close = 0; safe_close = 0;
...@@ -134,9 +130,8 @@ geodewdt_write(struct file *file, const char __user *data, size_t len, ...@@ -134,9 +130,8 @@ geodewdt_write(struct file *file, const char __user *data, size_t len,
return len; return len;
} }
static int static int geodewdt_ioctl(struct inode *inode, struct file *file,
geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -149,7 +144,7 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -149,7 +144,7 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
.identity = WATCHDOG_NAME, .identity = WATCHDOG_NAME,
}; };
switch(cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0; sizeof(ident)) ? -EFAULT : 0;
...@@ -159,22 +154,6 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -159,22 +154,6 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); 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: case WDIOC_SETOPTIONS:
{ {
int options, ret = -EINVAL; int options, ret = -EINVAL;
...@@ -194,6 +173,20 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -194,6 +173,20 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return ret; return ret;
} }
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);
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -213,11 +206,10 @@ static const struct file_operations geodewdt_fops = { ...@@ -213,11 +206,10 @@ static const struct file_operations geodewdt_fops = {
static struct miscdevice geodewdt_miscdev = { static struct miscdevice geodewdt_miscdev = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &geodewdt_fops .fops = &geodewdt_fops,
}; };
static int __devinit static int __devinit geodewdt_probe(struct platform_device *dev)
geodewdt_probe(struct platform_device *dev)
{ {
int ret, timer; int ret, timer;
...@@ -248,15 +240,13 @@ geodewdt_probe(struct platform_device *dev) ...@@ -248,15 +240,13 @@ geodewdt_probe(struct platform_device *dev)
return ret; return ret;
} }
static int __devexit static int __devexit geodewdt_remove(struct platform_device *dev)
geodewdt_remove(struct platform_device *dev)
{ {
misc_deregister(&geodewdt_miscdev); misc_deregister(&geodewdt_miscdev);
return 0; return 0;
} }
static void static void geodewdt_shutdown(struct platform_device *dev)
geodewdt_shutdown(struct platform_device *dev)
{ {
geodewdt_disable(); geodewdt_disable();
} }
...@@ -271,8 +261,7 @@ static struct platform_driver geodewdt_driver = { ...@@ -271,8 +261,7 @@ static struct platform_driver geodewdt_driver = {
}, },
}; };
static int __init static int __init geodewdt_init(void)
geodewdt_init(void)
{ {
int ret; int ret;
...@@ -292,8 +281,7 @@ geodewdt_init(void) ...@@ -292,8 +281,7 @@ geodewdt_init(void)
return ret; return ret;
} }
static void __exit static void __exit geodewdt_exit(void)
geodewdt_exit(void)
{ {
platform_device_unregister(geodewdt_platform_device); platform_device_unregister(geodewdt_platform_device);
platform_driver_unregister(&geodewdt_driver); platform_driver_unregister(&geodewdt_driver);
......
...@@ -39,9 +39,7 @@ ...@@ -39,9 +39,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/dmi.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/kdebug.h>
#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */
#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 #define CRU_BIOS_SIGNATURE_VALUE 0x55524324
...@@ -407,7 +405,7 @@ static int __devinit detect_cru_service(void) ...@@ -407,7 +405,7 @@ static int __devinit detect_cru_service(void)
dmi_walk(dmi_find_cru); dmi_walk(dmi_find_cru);
/* if cru_rom_addr has been set then we found a CRU service */ /* if cru_rom_addr has been set then we found a CRU service */
return ((cru_rom_addr != NULL)? 0: -ENODEV); return ((cru_rom_addr != NULL) ? 0: -ENODEV);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
...@@ -535,7 +533,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data, ...@@ -535,7 +533,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data,
/* scan to see whether or not we got the magic char. */ /* scan to see whether or not we got the magic char. */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_release = 42; expect_release = 42;
......
This diff is collapsed.
/* iTCO Vendor Specific Support hooks */
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
extern void iTCO_vendor_pre_stop(unsigned long);
extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
#define iTCO_vendor_pre_stop(acpibase) {}
#define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {}
#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
#define iTCO_vendor_check_noreboot_on() 1
/* 1=check noreboot; 0=don't check */
#endif
...@@ -31,8 +31,9 @@ ...@@ -31,8 +31,9 @@
#include <linux/kernel.h> /* For printk/panic/... */ #include <linux/kernel.h> /* For printk/panic/... */
#include <linux/init.h> /* For __init/__exit/... */ #include <linux/init.h> /* For __init/__exit/... */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <linux/io.h> /* For inb/outb/... */
#include <asm/io.h> /* For inb/outb/... */ #include "iTCO_vendor.h"
/* iTCO defines */ /* iTCO defines */
#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */
...@@ -40,10 +41,12 @@ ...@@ -40,10 +41,12 @@
#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
/* List of vendor support modes */ /* List of vendor support modes */
#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ #define SUPERMICRO_OLD_BOARD 1
/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
#define SUPERMICRO_NEW_BOARD 2
static int vendorsupport = 0; static int vendorsupport;
module_param(vendorsupport, int, 0); module_param(vendorsupport, int, 0);
MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
...@@ -167,10 +170,11 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase) ...@@ -167,10 +170,11 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase)
static void supermicro_new_unlock_watchdog(void) static void supermicro_new_unlock_watchdog(void)
{ {
outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ /* Write 0x87 to port 0x2e twice */
outb(SM_WATCHPAGE, SM_REGINDEX); outb(SM_WATCHPAGE, SM_REGINDEX);
outb(SM_WATCHPAGE, SM_REGINDEX);
outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ /* Switch to watchdog control page */
outb(SM_CTLPAGESW, SM_REGINDEX);
outb(SM_CTLPAGE, SM_DATAIO); outb(SM_CTLPAGE, SM_DATAIO);
} }
...@@ -192,7 +196,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat) ...@@ -192,7 +196,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat)
outb(val, SM_DATAIO); outb(val, SM_DATAIO);
/* Write heartbeat interval to WDOG */ /* Write heartbeat interval to WDOG */
outb (SM_WATCHTIMER, SM_REGINDEX); outb(SM_WATCHTIMER, SM_REGINDEX);
outb((heartbeat & 255), SM_DATAIO); outb((heartbeat & 255), SM_DATAIO);
/* Make sure keyboard/mouse interrupts don't interfere */ /* Make sure keyboard/mouse interrupts don't interfere */
...@@ -277,7 +281,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); ...@@ -277,7 +281,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
int iTCO_vendor_check_noreboot_on(void) int iTCO_vendor_check_noreboot_on(void)
{ {
switch(vendorsupport) { switch (vendorsupport) {
case SUPERMICRO_OLD_BOARD: case SUPERMICRO_OLD_BOARD:
return 0; return 0;
default: default:
...@@ -288,13 +292,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); ...@@ -288,13 +292,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
static int __init iTCO_vendor_init_module(void) static int __init iTCO_vendor_init_module(void)
{ {
printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
return 0; return 0;
} }
static void __exit iTCO_vendor_exit_module(void) static void __exit iTCO_vendor_exit_module(void)
{ {
printk (KERN_INFO PFX "Module Unloaded\n"); printk(KERN_INFO PFX "Module Unloaded\n");
} }
module_init(iTCO_vendor_init_module); module_init(iTCO_vendor_init_module);
......
This diff is collapsed.
...@@ -41,9 +41,9 @@ ...@@ -41,9 +41,9 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
static struct platform_device *ibwdt_platform_device; static struct platform_device *ibwdt_platform_device;
...@@ -120,15 +120,16 @@ static int wd_margin = WD_TIMO; ...@@ -120,15 +120,16 @@ static int wd_margin = WD_TIMO;
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) ")");
/* /*
* Watchdog Operations * Watchdog Operations
*/ */
static void static void ibwdt_ping(void)
ibwdt_ping(void)
{ {
spin_lock(&ibwdt_lock); spin_lock(&ibwdt_lock);
...@@ -138,16 +139,14 @@ ibwdt_ping(void) ...@@ -138,16 +139,14 @@ ibwdt_ping(void)
spin_unlock(&ibwdt_lock); spin_unlock(&ibwdt_lock);
} }
static void static void ibwdt_disable(void)
ibwdt_disable(void)
{ {
spin_lock(&ibwdt_lock); spin_lock(&ibwdt_lock);
outb_p(0, WDT_STOP); outb_p(0, WDT_STOP);
spin_unlock(&ibwdt_lock); spin_unlock(&ibwdt_lock);
} }
static int static int ibwdt_set_heartbeat(int t)
ibwdt_set_heartbeat(int t)
{ {
int i; int i;
...@@ -165,8 +164,8 @@ ibwdt_set_heartbeat(int t) ...@@ -165,8 +164,8 @@ ibwdt_set_heartbeat(int t)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t static ssize_t ibwdt_write(struct file *file, const char __user *buf,
ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -188,16 +187,15 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo ...@@ -188,16 +187,15 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo
return count; return count;
} }
static int static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
int new_margin; int new_margin;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "IB700 WDT", .identity = "IB700 WDT",
}; };
...@@ -212,21 +210,6 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -212,21 +210,6 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE:
ibwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
ibwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
...@@ -238,14 +221,26 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -238,14 +221,26 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ibwdt_disable(); ibwdt_disable();
retval = 0; retval = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
ibwdt_ping(); ibwdt_ping();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
case WDIOC_KEEPALIVE:
ibwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
ibwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p);
default: default:
return -ENOTTY; return -ENOTTY;
...@@ -253,12 +248,10 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -253,12 +248,10 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return 0; return 0;
} }
static int static int ibwdt_open(struct inode *inode, struct file *file)
ibwdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &ibwdt_is_open)) { if (test_and_set_bit(0, &ibwdt_is_open))
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
...@@ -267,13 +260,13 @@ ibwdt_open(struct inode *inode, struct file *file) ...@@ -267,13 +260,13 @@ ibwdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int static int ibwdt_close(struct inode *inode, struct file *file)
ibwdt_close(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42) {
ibwdt_disable(); ibwdt_disable();
} else { } else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); printk(KERN_CRIT PFX
"WDT device closed unexpectedly. WDT will not stop!\n");
ibwdt_ping(); ibwdt_ping();
} }
clear_bit(0, &ibwdt_is_open); clear_bit(0, &ibwdt_is_open);
...@@ -289,7 +282,7 @@ static const struct file_operations ibwdt_fops = { ...@@ -289,7 +282,7 @@ static const struct file_operations ibwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ibwdt_write, .write = ibwdt_write,
.ioctl = ibwdt_ioctl, .unlocked_ioctl = ibwdt_ioctl,
.open = ibwdt_open, .open = ibwdt_open,
.release = ibwdt_close, .release = ibwdt_close,
}; };
...@@ -310,21 +303,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev) ...@@ -310,21 +303,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
#if WDT_START != WDT_STOP #if WDT_START != WDT_STOP
if (!request_region(WDT_STOP, 1, "IB700 WDT")) { if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP); printk(KERN_ERR PFX "STOP method I/O %X is not available.\n",
WDT_STOP);
res = -EIO; res = -EIO;
goto out_nostopreg; goto out_nostopreg;
} }
#endif #endif
if (!request_region(WDT_START, 1, "IB700 WDT")) { if (!request_region(WDT_START, 1, "IB700 WDT")) {
printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START); printk(KERN_ERR PFX "START method I/O %X is not available.\n",
WDT_START);
res = -EIO; res = -EIO;
goto out_nostartreg; goto out_nostartreg;
} }
res = misc_register(&ibwdt_miscdev); res = misc_register(&ibwdt_miscdev);
if (res) { if (res) {
printk (KERN_ERR PFX "failed to register misc device\n"); printk(KERN_ERR PFX "failed to register misc device\n");
goto out_nomisc; goto out_nomisc;
} }
return 0; return 0;
...@@ -342,9 +337,9 @@ static int __devinit ibwdt_probe(struct platform_device *dev) ...@@ -342,9 +337,9 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
static int __devexit ibwdt_remove(struct platform_device *dev) static int __devexit ibwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&ibwdt_miscdev); misc_deregister(&ibwdt_miscdev);
release_region(WDT_START,1); release_region(WDT_START, 1);
#if WDT_START != WDT_STOP #if WDT_START != WDT_STOP
release_region(WDT_STOP,1); release_region(WDT_STOP, 1);
#endif #endif
return 0; return 0;
} }
...@@ -369,13 +364,15 @@ static int __init ibwdt_init(void) ...@@ -369,13 +364,15 @@ static int __init ibwdt_init(void)
{ {
int err; int err;
printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n"); printk(KERN_INFO PFX
"WDT driver for IB700 single board computer initialising.\n");
err = platform_driver_register(&ibwdt_driver); err = platform_driver_register(&ibwdt_driver);
if (err) if (err)
return err; return err;
ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(ibwdt_platform_device)) { if (IS_ERR(ibwdt_platform_device)) {
err = PTR_ERR(ibwdt_platform_device); err = PTR_ERR(ibwdt_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
......
...@@ -19,9 +19,8 @@ ...@@ -19,9 +19,8 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/io.h>
#include <asm/io.h> #include <linux/uaccess.h>
#include <asm/uaccess.h>
enum { enum {
...@@ -70,10 +69,13 @@ static char asr_expect_close; ...@@ -70,10 +69,13 @@ static char asr_expect_close;
static unsigned int asr_type, asr_base, asr_length; static unsigned int asr_type, asr_base, asr_length;
static unsigned int asr_read_addr, asr_write_addr; static unsigned int asr_read_addr, asr_write_addr;
static unsigned char asr_toggle_mask, asr_disable_mask; static unsigned char asr_toggle_mask, asr_disable_mask;
static spinlock_t asr_lock;
static void asr_toggle(void) static void __asr_toggle(void)
{ {
unsigned char reg = inb(asr_read_addr); unsigned char reg;
reg = inb(asr_read_addr);
outb(reg & ~asr_toggle_mask, asr_write_addr); outb(reg & ~asr_toggle_mask, asr_write_addr);
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
...@@ -83,12 +85,21 @@ static void asr_toggle(void) ...@@ -83,12 +85,21 @@ static void asr_toggle(void)
outb(reg & ~asr_toggle_mask, asr_write_addr); outb(reg & ~asr_toggle_mask, asr_write_addr);
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
}
static void asr_toggle(void)
{
spin_lock(&asr_lock);
__asr_toggle();
spin_unlock(&asr_lock);
} }
static void asr_enable(void) static void asr_enable(void)
{ {
unsigned char reg; unsigned char reg;
spin_lock(&asr_lock);
if (asr_type == ASMTYPE_TOPAZ) { if (asr_type == ASMTYPE_TOPAZ) {
/* asr_write_addr == asr_read_addr */ /* asr_write_addr == asr_read_addr */
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
...@@ -99,17 +110,21 @@ static void asr_enable(void) ...@@ -99,17 +110,21 @@ static void asr_enable(void)
* First make sure the hardware timer is reset by toggling * First make sure the hardware timer is reset by toggling
* ASR hardware timer line. * ASR hardware timer line.
*/ */
asr_toggle(); __asr_toggle();
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
outb(reg & ~asr_disable_mask, asr_write_addr); outb(reg & ~asr_disable_mask, asr_write_addr);
} }
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
} }
static void asr_disable(void) static void asr_disable(void)
{ {
unsigned char reg = inb(asr_read_addr); unsigned char reg;
spin_lock(&asr_lock);
reg = inb(asr_read_addr);
if (asr_type == ASMTYPE_TOPAZ) if (asr_type == ASMTYPE_TOPAZ)
/* asr_write_addr == asr_read_addr */ /* asr_write_addr == asr_read_addr */
...@@ -122,6 +137,7 @@ static void asr_disable(void) ...@@ -122,6 +137,7 @@ static void asr_disable(void)
outb(reg | asr_disable_mask, asr_write_addr); outb(reg | asr_disable_mask, asr_write_addr);
} }
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
} }
static int __init asr_get_base_address(void) static int __init asr_get_base_address(void)
...@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void) ...@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void)
switch (asr_type) { switch (asr_type) {
case ASMTYPE_TOPAZ: case ASMTYPE_TOPAZ:
/* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ /* SELECT SuperIO CHIP FOR QUERYING
(WRITE 0x07 TO BOTH 0x2E and 0x2F) */
outb(0x07, 0x2e); outb(0x07, 0x2e);
outb(0x07, 0x2f); outb(0x07, 0x2f);
...@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void) ...@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void)
case ASMTYPE_JASPER: case ASMTYPE_JASPER:
type = "Jaspers "; type = "Jaspers ";
#if 0
/* FIXME: need to use pci_config_lock here, but it's not exported */ u32 r;
/* Suggested fix */
pdev = pci_get_bus_and_slot(0, DEVFN(0x1f, 0));
if (pdev == NULL)
return -ENODEV;
pci_read_config_dword(pdev, 0x58, &r);
asr_base = r & 0xFFFE;
pci_dev_put(pdev);
#else
/* FIXME: need to use pci_config_lock here,
but it's not exported */
/* spin_lock_irqsave(&pci_config_lock, flags);*/ /* spin_lock_irqsave(&pci_config_lock, flags);*/
/* Select the SuperIO chip in the PCI I/O port register */ /* Select the SuperIO chip in the PCI I/O port register */
outl(0x8000f858, 0xcf8); outl(0x8000f858, 0xcf8);
/* BUS 0, Slot 1F, fnc 0, offset 58 */
/* /*
* Read the base address for the SuperIO chip. * Read the base address for the SuperIO chip.
* Only the lower 16 bits are valid, but the address is word * Only the lower 16 bits are valid, but the address is word
...@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void) ...@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void)
asr_base = inl(0xcfc) & 0xfffe; asr_base = inl(0xcfc) & 0xfffe;
/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ /* spin_unlock_irqrestore(&pci_config_lock, flags);*/
#endif
asr_read_addr = asr_write_addr = asr_read_addr = asr_write_addr =
asr_base + JASPER_ASR_REG_OFFSET; asr_base + JASPER_ASR_REG_OFFSET;
asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
...@@ -241,13 +270,12 @@ static ssize_t asr_write(struct file *file, const char __user *buf, ...@@ -241,13 +270,12 @@ static ssize_t asr_write(struct file *file, const char __user *buf,
return count; return count;
} }
static int asr_ioctl(struct inode *inode, struct file *file, static long asr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
static const struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.identity = "IBM ASR" .identity = "IBM ASR",
}; };
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -255,52 +283,44 @@ static int asr_ioctl(struct inode *inode, struct file *file, ...@@ -255,52 +283,44 @@ static int asr_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_SETOPTIONS:
case WDIOC_KEEPALIVE: {
asr_toggle();
return 0;
/*
* The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
* and WDIOC_GETTIMEOUT always returns 256.
*/
case WDIOC_GETTIMEOUT:
heartbeat = 256;
return put_user(heartbeat, p);
case WDIOC_SETOPTIONS: {
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
if (get_user(new_options, p)) if (get_user(new_options, p))
return -EFAULT; return -EFAULT;
if (new_options & WDIOS_DISABLECARD) { if (new_options & WDIOS_DISABLECARD) {
asr_disable(); asr_disable();
retval = 0; retval = 0;
} }
if (new_options & WDIOS_ENABLECARD) { if (new_options & WDIOS_ENABLECARD) {
asr_enable(); asr_enable();
asr_toggle(); asr_toggle();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
} case WDIOC_KEEPALIVE:
asr_toggle();
return 0;
/*
* The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
* and WDIOC_GETTIMEOUT always returns 256.
*/
case WDIOC_GETTIMEOUT:
heartbeat = 256;
return put_user(heartbeat, p);
default:
return -ENOTTY; return -ENOTTY;
}
} }
static int asr_open(struct inode *inode, struct file *file) static int asr_open(struct inode *inode, struct file *file)
{ {
if(test_and_set_bit(0, &asr_is_open)) if (test_and_set_bit(0, &asr_is_open))
return -EBUSY; return -EBUSY;
asr_toggle(); asr_toggle();
...@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file) ...@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file)
if (asr_expect_close == 42) if (asr_expect_close == 42)
asr_disable(); asr_disable();
else { else {
printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"unexpected close, not stopping watchdog!\n");
asr_toggle(); asr_toggle();
} }
clear_bit(0, &asr_is_open); clear_bit(0, &asr_is_open);
...@@ -326,7 +347,7 @@ static const struct file_operations asr_fops = { ...@@ -326,7 +347,7 @@ static const struct file_operations asr_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = asr_write, .write = asr_write,
.ioctl = asr_ioctl, .unlocked_ioctl = asr_ioctl,
.open = asr_open, .open = asr_open,
.release = asr_release, .release = asr_release,
}; };
...@@ -367,6 +388,8 @@ static int __init ibmasr_init(void) ...@@ -367,6 +388,8 @@ static int __init ibmasr_init(void)
if (!asr_type) if (!asr_type)
return -ENODEV; return -ENODEV;
spin_lock_init(&asr_lock);
rc = asr_get_base_address(); rc = asr_get_base_address();
if (rc) if (rc)
return rc; return rc;
...@@ -395,7 +418,9 @@ module_init(ibmasr_init); ...@@ -395,7 +418,9 @@ module_init(ibmasr_init);
module_exit(ibmasr_exit); module_exit(ibmasr_exit);
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) ")");
MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
MODULE_AUTHOR("Andrey Panin"); MODULE_AUTHOR("Andrey Panin");
......
/* /*
* IndyDog 0.3 A Hardware Watchdog Device for SGI IP22 * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
* *
* (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved. * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>,
* All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -22,32 +23,42 @@ ...@@ -22,32 +23,42 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/sgi/mc.h> #include <asm/sgi/mc.h>
#define PFX "indydog: " #define PFX "indydog: "
static int indydog_alive; static unsigned long indydog_alive;
static spinlock_t indydog_lock;
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default 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 void indydog_start(void) static void indydog_start(void)
{ {
u32 mc_ctrl0 = sgimc->cpuctrl0; u32 mc_ctrl0;
spin_lock(&indydog_lock);
mc_ctrl0 = sgimc->cpuctrl0;
mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG; mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
sgimc->cpuctrl0 = mc_ctrl0; sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
} }
static void indydog_stop(void) static void indydog_stop(void)
{ {
u32 mc_ctrl0 = sgimc->cpuctrl0; u32 mc_ctrl0;
spin_lock(&indydog_lock);
mc_ctrl0 = sgimc->cpuctrl0;
mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
sgimc->cpuctrl0 = mc_ctrl0; sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
printk(KERN_INFO PFX "Stopped watchdog timer.\n"); printk(KERN_INFO PFX "Stopped watchdog timer.\n");
} }
...@@ -62,7 +73,7 @@ static void indydog_ping(void) ...@@ -62,7 +73,7 @@ static void indydog_ping(void)
*/ */
static int indydog_open(struct inode *inode, struct file *file) static int indydog_open(struct inode *inode, struct file *file)
{ {
if (indydog_alive) if (test_and_set_bit(0, &indydog_alive))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
...@@ -84,23 +95,21 @@ static int indydog_release(struct inode *inode, struct file *file) ...@@ -84,23 +95,21 @@ static int indydog_release(struct inode *inode, struct file *file)
* Lock it in if it's a module and we defined ...NOWAYOUT */ * Lock it in if it's a module and we defined ...NOWAYOUT */
if (!nowayout) if (!nowayout)
indydog_stop(); /* Turn the WDT off */ indydog_stop(); /* Turn the WDT off */
clear_bit(0, &indydog_alive);
indydog_alive = 0;
return 0; return 0;
} }
static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t indydog_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
/* Refresh the timer. */ /* Refresh the timer. */
if (len) { if (len)
indydog_ping(); indydog_ping();
}
return len; return len;
} }
static int indydog_ioctl(struct inode *inode, struct file *file, static long indydog_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
static struct watchdog_info ident = { static struct watchdog_info ident = {
...@@ -111,8 +120,6 @@ static int indydog_ioctl(struct inode *inode, struct file *file, ...@@ -111,8 +120,6 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
}; };
switch (cmd) { switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg, if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident))) &ident, sizeof(ident)))
...@@ -120,33 +127,33 @@ static int indydog_ioctl(struct inode *inode, struct file *file, ...@@ -120,33 +127,33 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
return 0; return 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0,(int *)arg); return put_user(0, (int *)arg);
case WDIOC_KEEPALIVE:
indydog_ping();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT,(int *)arg);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
if (get_user(options, (int *)arg)) if (get_user(options, (int *)arg))
return -EFAULT; return -EFAULT;
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
indydog_stop(); indydog_stop();
retval = 0; retval = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
indydog_start(); indydog_start();
retval = 0; retval = 0;
} }
return retval; return retval;
} }
case WDIOC_KEEPALIVE:
indydog_ping();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT, (int *)arg);
default:
return -ENOTTY;
} }
} }
static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int indydog_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
indydog_stop(); /* Turn the WDT off */ indydog_stop(); /* Turn the WDT off */
...@@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = { ...@@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = indydog_write, .write = indydog_write,
.ioctl = indydog_ioctl, .unlocked_ioctl = indydog_ioctl,
.open = indydog_open, .open = indydog_open,
.release = indydog_release, .release = indydog_release,
}; };
...@@ -180,16 +187,19 @@ static int __init watchdog_init(void) ...@@ -180,16 +187,19 @@ static int __init watchdog_init(void)
{ {
int ret; int ret;
spin_lock_init(&indydog_lock);
ret = register_reboot_notifier(&indydog_notifier); ret = register_reboot_notifier(&indydog_notifier);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
return ret; return ret;
} }
ret = misc_register(&indydog_miscdev); ret = misc_register(&indydog_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&indydog_notifier); unregister_reboot_notifier(&indydog_notifier);
return ret; return ret;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned long wdt_status; static unsigned long wdt_status;
static unsigned long boot_status; static unsigned long boot_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
...@@ -68,8 +69,10 @@ static void wdt_enable(void) ...@@ -68,8 +69,10 @@ static void wdt_enable(void)
/* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
* Takes approx. 10.7s to timeout * Takes approx. 10.7s to timeout
*/ */
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_EN_ARM); write_wdtcr(IOP_WDTCR_EN_ARM);
write_wdtcr(IOP_WDTCR_EN); write_wdtcr(IOP_WDTCR_EN);
spin_unlock(&wdt_lock);
} }
/* returns 0 if the timer was successfully disabled */ /* returns 0 if the timer was successfully disabled */
...@@ -77,9 +80,11 @@ static int wdt_disable(void) ...@@ -77,9 +80,11 @@ static int wdt_disable(void)
{ {
/* Stop Counting */ /* Stop Counting */
if (wdt_supports_disable()) { if (wdt_supports_disable()) {
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_DIS_ARM); write_wdtcr(IOP_WDTCR_DIS_ARM);
write_wdtcr(IOP_WDTCR_DIS); write_wdtcr(IOP_WDTCR_DIS);
clear_bit(WDT_ENABLED, &wdt_status); clear_bit(WDT_ENABLED, &wdt_status);
spin_unlock(&wdt_lock);
printk(KERN_INFO "WATCHDOG: Disabled\n"); printk(KERN_INFO "WATCHDOG: Disabled\n");
return 0; return 0;
} else } else
...@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file) ...@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file)
return -EBUSY; return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable(); wdt_enable();
set_bit(WDT_ENABLED, &wdt_status); set_bit(WDT_ENABLED, &wdt_status);
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static ssize_t static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len,
iop_wdt_write(struct file *file, const char *data, size_t len,
loff_t *ppos) loff_t *ppos)
{ {
if (len) { if (len) {
...@@ -121,46 +122,35 @@ iop_wdt_write(struct file *file, const char *data, size_t len, ...@@ -121,46 +122,35 @@ iop_wdt_write(struct file *file, const char *data, size_t len,
} }
wdt_enable(); wdt_enable();
} }
return len; return len;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "iop watchdog", .identity = "iop watchdog",
}; };
static int static long iop_wdt_ioctl(struct file *file,
iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int options; int options;
int ret = -ENOTTY; int ret = -ENOTTY;
int __user *argp = (int __user *)arg;
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user if (copy_to_user(argp, &ident, sizeof ident))
((struct watchdog_info *)arg, &ident, sizeof ident))
ret = -EFAULT; ret = -EFAULT;
else else
ret = 0; ret = 0;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg); ret = put_user(0, argp);
break; break;
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
ret = put_user(boot_status, (int *)arg); ret = put_user(boot_status, argp);
break;
case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break; break;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
...@@ -177,14 +167,21 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -177,14 +167,21 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
} else } else
ret = 0; ret = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
wdt_enable(); wdt_enable();
ret = 0; ret = 0;
} }
break; break;
}
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), argp);
break;
}
return ret; return ret;
} }
...@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = { ...@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = iop_wdt_write, .write = iop_wdt_write,
.ioctl = iop_wdt_ioctl, .unlocked_ioctl = iop_wdt_ioctl,
.open = iop_wdt_open, .open = iop_wdt_open,
.release = iop_wdt_release, .release = iop_wdt_release,
}; };
...@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void) ...@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void)
{ {
int ret; int ret;
ret = misc_register(&iop_wdt_miscdev); spin_lock_init(&wdt_lock);
if (ret == 0)
printk("iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
/* check if the reset was caused by the watchdog timer */ /* check if the reset was caused by the watchdog timer */
boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
...@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void) ...@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void)
*/ */
write_wdtsr(IOP13XX_WDTCR_IB_RESET); write_wdtsr(IOP13XX_WDTCR_IB_RESET);
/* Register after we have the device set up so we cannot race
with an open */
ret = misc_register(&iop_wdt_miscdev);
if (ret == 0)
printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
return ret; return ret;
} }
......
...@@ -221,7 +221,7 @@ static ssize_t it8712f_wdt_write(struct file *file, const char __user *data, ...@@ -221,7 +221,7 @@ static ssize_t it8712f_wdt_write(struct file *file, const char __user *data,
expect_close = 0; expect_close = 0;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_close = 42; expect_close = 42;
...@@ -244,8 +244,6 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -244,8 +244,6 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
int value; int value;
switch (cmd) { switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
...@@ -284,6 +282,8 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -284,6 +282,8 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
if (put_user(margin, p)) if (put_user(margin, p))
return -EFAULT; return -EFAULT;
return 0; return 0;
default:
return -ENOTTY;
} }
} }
......
...@@ -25,42 +25,45 @@ ...@@ -25,42 +25,45 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */ static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status; static unsigned long wdt_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
static unsigned long wdt_tick_rate; static unsigned long wdt_tick_rate;
static void static void wdt_enable(void)
wdt_enable(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE); ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE); ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE); ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
spin_unlock(&wdt_lock);
} }
static void static void wdt_disable(void)
wdt_disable(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CTL, 0); ixp2000_reg_write(IXP2000_T4_CTL, 0);
spin_unlock(&wdt_lock);
} }
static void static void wdt_keepalive(void)
wdt_keepalive(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
spin_unlock(&wdt_lock);
} }
static int static int ixp2000_wdt_open(struct inode *inode, struct file *file)
ixp2000_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(WDT_IN_USE, &wdt_status)) if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY; return -EBUSY;
...@@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file) ...@@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static ssize_t static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
...@@ -103,8 +106,7 @@ static struct watchdog_info ident = { ...@@ -103,8 +106,7 @@ static struct watchdog_info ident = {
.identity = "IXP2000 Watchdog", .identity = "IXP2000 Watchdog",
}; };
static int static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -124,6 +126,11 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -124,6 +126,11 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(0, (int *)arg); ret = put_user(0, (int *)arg);
break; break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg); ret = get_user(time, (int *)arg);
if (ret) if (ret)
...@@ -141,26 +148,18 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -141,26 +148,18 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg); ret = put_user(heartbeat, (int *)arg);
break; break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
} }
return ret; return ret;
} }
static int static int ixp2000_wdt_release(struct inode *inode, struct file *file)
ixp2000_wdt_release(struct inode *inode, struct file *file)
{ {
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable(); wdt_disable();
} else { else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n"); "timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -168,18 +167,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file) ...@@ -168,18 +167,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
} }
static const struct file_operations ixp2000_wdt_fops = static const struct file_operations ixp2000_wdt_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ixp2000_wdt_write, .write = ixp2000_wdt_write,
.ioctl = ixp2000_wdt_ioctl, .unlocked_ioctl = ixp2000_wdt_ioctl,
.open = ixp2000_wdt_open, .open = ixp2000_wdt_open,
.release = ixp2000_wdt_release, .release = ixp2000_wdt_release,
}; };
static struct miscdevice ixp2000_wdt_miscdev = static struct miscdevice ixp2000_wdt_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &ixp2000_wdt_fops, .fops = &ixp2000_wdt_fops,
...@@ -191,9 +188,8 @@ static int __init ixp2000_wdt_init(void) ...@@ -191,9 +188,8 @@ static int __init ixp2000_wdt_init(void)
printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
return -EIO; return -EIO;
} }
wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
spin_lock_init(&wdt_lock);
return misc_register(&ixp2000_wdt_miscdev); return misc_register(&ixp2000_wdt_miscdev);
} }
......
...@@ -22,48 +22,48 @@ ...@@ -22,48 +22,48 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = 60; /* (secs) Default is 1 minute */ static int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status; static unsigned long wdt_status;
static unsigned long boot_status; static unsigned long boot_status;
static spin_lock_t wdt_lock;
#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
static void static void wdt_enable(void)
wdt_enable(void)
{ {
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY; *IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0; *IXP4XX_OSWE = 0;
*IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
*IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
*IXP4XX_OSWK = 0; *IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
} }
static void static void wdt_disable(void)
wdt_disable(void)
{ {
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY; *IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0; *IXP4XX_OSWE = 0;
*IXP4XX_OSWK = 0; *IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
} }
static int static int ixp4xx_wdt_open(struct inode *inode, struct file *file)
ixp4xx_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(WDT_IN_USE, &wdt_status)) if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY; return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable(); wdt_enable();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) ...@@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
} }
wdt_enable(); wdt_enable();
} }
return len; return len;
} }
...@@ -98,8 +97,7 @@ static struct watchdog_info ident = { ...@@ -98,8 +97,7 @@ static struct watchdog_info ident = {
}; };
static int static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd,
ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -119,6 +117,11 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -119,6 +117,11 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(boot_status, (int *)arg); ret = put_user(boot_status, (int *)arg);
break; break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg); ret = get_user(time, (int *)arg);
if (ret) if (ret)
...@@ -136,25 +139,17 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -136,25 +139,17 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg); ret = put_user(heartbeat, (int *)arg);
break; break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
} }
return ret; return ret;
} }
static int static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
ixp4xx_wdt_release(struct inode *inode, struct file *file)
{ {
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable(); wdt_disable();
} else { else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n"); "timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -162,18 +157,16 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) ...@@ -162,18 +157,16 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file)
} }
static const struct file_operations ixp4xx_wdt_fops = static const struct file_operations ixp4xx_wdt_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ixp4xx_wdt_write, .write = ixp4xx_wdt_write,
.ioctl = ixp4xx_wdt_ioctl, .unlocked_ioctl = ixp4xx_wdt_ioctl,
.open = ixp4xx_wdt_open, .open = ixp4xx_wdt_open,
.release = ixp4xx_wdt_release, .release = ixp4xx_wdt_release,
}; };
static struct miscdevice ixp4xx_wdt_miscdev = static struct miscdevice ixp4xx_wdt_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &ixp4xx_wdt_fops, .fops = &ixp4xx_wdt_fops,
...@@ -186,19 +179,18 @@ static int __init ixp4xx_wdt_init(void) ...@@ -186,19 +179,18 @@ static int __init ixp4xx_wdt_init(void)
asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
printk("IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected - " printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
"watchdog disabled\n"); " - watchdog disabled\n");
return -ENODEV; return -ENODEV;
} }
spin_lock_init(&wdt_lock);
ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0)
printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
WDIOF_CARDRESET : 0; WDIOF_CARDRESET : 0;
ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0)
printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n",
heartbeat);
return ret; return ret;
} }
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/arch/regs-timer.h> #include <asm/arch/regs-timer.h>
...@@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME; ...@@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0); module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT #ifdef CONFIG_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) ")");
#endif #endif
static unsigned long ks8695wdt_busy; static unsigned long ks8695wdt_busy;
static spinlock_t ks8695_lock;
/* ......................................................................... */ /* ......................................................................... */
/* /*
* Disable the watchdog. * Disable the watchdog.
*/ */
static void inline ks8695_wdt_stop(void) static inline void ks8695_wdt_stop(void)
{ {
unsigned long tmcon; unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable timer0 */ /* disable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
* Enable and reset the watchdog. * Enable and reset the watchdog.
*/ */
static void inline ks8695_wdt_start(void) static inline void ks8695_wdt_start(void)
{ {
unsigned long tmcon; unsigned long tmcon;
unsigned long tval = wdt_time * CLOCK_TICK_RATE; unsigned long tval = wdt_time * CLOCK_TICK_RATE;
spin_lock(&ks8695_lock);
/* disable timer0 */ /* disable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
...@@ -73,19 +79,22 @@ static void inline ks8695_wdt_start(void) ...@@ -73,19 +79,22 @@ static void inline ks8695_wdt_start(void)
/* re-enable timer0 */ /* re-enable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
* Reload the watchdog timer. (ie, pat the watchdog) * Reload the watchdog timer. (ie, pat the watchdog)
*/ */
static void inline ks8695_wdt_reload(void) static inline void ks8695_wdt_reload(void)
{ {
unsigned long tmcon; unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable, then re-enable timer0 */ /* disable, then re-enable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
...@@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time) ...@@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
return -EINVAL; return -EINVAL;
/* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */ /* Set new watchdog time. It will be used when
ks8695_wdt_start() is called. */
wdt_time = new_time; wdt_time = new_time;
return 0; return 0;
} }
...@@ -128,9 +138,9 @@ static int ks8695_wdt_open(struct inode *inode, struct file *file) ...@@ -128,9 +138,9 @@ static int ks8695_wdt_open(struct inode *inode, struct file *file)
*/ */
static int ks8695_wdt_close(struct inode *inode, struct file *file) static int ks8695_wdt_close(struct inode *inode, struct file *file)
{ {
/* Disable the watchdog when file is closed */
if (!nowayout) if (!nowayout)
ks8695_wdt_stop(); /* Disable the watchdog when file is closed */ ks8695_wdt_stop();
clear_bit(0, &ks8695wdt_busy); clear_bit(0, &ks8695wdt_busy);
return 0; return 0;
} }
...@@ -143,51 +153,42 @@ static struct watchdog_info ks8695_wdt_info = { ...@@ -143,51 +153,42 @@ static struct watchdog_info ks8695_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, static long ks8695_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_value; int new_value;
switch(cmd) { switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ks8695_wdt_info,
sizeof(ks8695_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)
ks8695_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
ks8695_wdt_start();
return 0;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
ks8695_wdt_reload(); /* pat the watchdog */ ks8695_wdt_reload(); /* pat the watchdog */
return 0; return 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_value, p)) if (get_user(new_value, p))
return -EFAULT; return -EFAULT;
if (ks8695_wdt_settimeout(new_value)) if (ks8695_wdt_settimeout(new_value))
return -EINVAL; return -EINVAL;
/* Enable new time value */ /* Enable new time value */
ks8695_wdt_start(); ks8695_wdt_start();
/* Return current value */ /* Return current value */
return put_user(wdt_time, p); return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p); return put_user(wdt_time, p);
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)
ks8695_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
ks8695_wdt_start();
return 0;
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -196,7 +197,8 @@ static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -196,7 +197,8 @@ static int ks8695_wdt_ioctl(struct inode *inode, struct file *file,
/* /*
* Pat the watchdog whenever device is written to. * Pat the watchdog whenever device is written to.
*/ */
static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t ks8695_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
ks8695_wdt_reload(); /* pat the watchdog */ ks8695_wdt_reload(); /* pat the watchdog */
return len; return len;
...@@ -207,7 +209,7 @@ static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, ...@@ -207,7 +209,7 @@ static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len,
static const struct file_operations ks8695wdt_fops = { static const struct file_operations ks8695wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = ks8695_wdt_ioctl, .unlocked_ioctl = ks8695_wdt_ioctl,
.open = ks8695_wdt_open, .open = ks8695_wdt_open,
.release = ks8695_wdt_close, .release = ks8695_wdt_close,
.write = ks8695_wdt_write, .write = ks8695_wdt_write,
...@@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev) ...@@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev)
if (res) if (res)
return res; return res;
printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n",
wdt_time, nowayout ? ", nowayout" : "");
return 0; return 0;
} }
...@@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = { ...@@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = {
static int __init ks8695_wdt_init(void) static int __init ks8695_wdt_init(void)
{ {
/* Check that the heartbeat value is within range; if not reset to the default */ spin_lock_init(&ks8695_lock);
/* Check that the heartbeat value is within range;
if not reset to the default */
if (ks8695_wdt_settimeout(wdt_time)) { if (ks8695_wdt_settimeout(wdt_time)) {
ks8695_wdt_settimeout(WDT_DEFAULT_TIME); ks8695_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME); pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n",
wdt_time, WDT_MAX_TIME);
} }
return platform_driver_register(&ks8695wdt_driver); return platform_driver_register(&ks8695wdt_driver);
} }
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* ports */ /* ports */
...@@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ...@@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
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) ")");
#define PFX "machzwd" #define PFX "machzwd"
...@@ -114,7 +116,7 @@ static struct watchdog_info zf_info = { ...@@ -114,7 +116,7 @@ static struct watchdog_info zf_info = {
* 3 = GEN_SCI * 3 = GEN_SCI
* defaults to GEN_RESET (0) * defaults to GEN_RESET (0)
*/ */
static int action = 0; static int action;
module_param(action, int, 0); module_param(action, int, 0);
MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
...@@ -123,10 +125,9 @@ static void zf_ping(unsigned long data); ...@@ -123,10 +125,9 @@ static void zf_ping(unsigned long data);
static int zf_action = GEN_RESET; static int zf_action = GEN_RESET;
static unsigned long zf_is_open; static unsigned long zf_is_open;
static char zf_expect_close; static char zf_expect_close;
static DEFINE_SPINLOCK(zf_lock);
static DEFINE_SPINLOCK(zf_port_lock); static DEFINE_SPINLOCK(zf_port_lock);
static DEFINE_TIMER(zf_timer, zf_ping, 0, 0); static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
static unsigned long next_heartbeat = 0; static unsigned long next_heartbeat;
/* timeout for user land heart beat (10 seconds) */ /* timeout for user land heart beat (10 seconds) */
...@@ -171,7 +172,7 @@ static inline void zf_set_control(unsigned short new) ...@@ -171,7 +172,7 @@ static inline void zf_set_control(unsigned short new)
static inline void zf_set_timer(unsigned short new, unsigned char n) static inline void zf_set_timer(unsigned short new, unsigned char n)
{ {
switch(n){ switch (n) {
case WD1: case WD1:
zf_writew(COUNTER_1, new); zf_writew(COUNTER_1, new);
case WD2: case WD2:
...@@ -241,10 +242,8 @@ static void zf_ping(unsigned long data) ...@@ -241,10 +242,8 @@ static void zf_ping(unsigned long data)
zf_writeb(COUNTER_2, 0xff); zf_writeb(COUNTER_2, 0xff);
if(time_before(jiffies, next_heartbeat)){ if (time_before(jiffies, next_heartbeat)) {
dprintk("time_before: %ld\n", next_heartbeat - jiffies); dprintk("time_before: %ld\n", next_heartbeat - jiffies);
/* /*
* reset event is activated by transition from 0 to 1 on * reset event is activated by transition from 0 to 1 on
* RESET_WD1 bit and we assume that it is already zero... * RESET_WD1 bit and we assume that it is already zero...
...@@ -261,24 +260,21 @@ static void zf_ping(unsigned long data) ...@@ -261,24 +260,21 @@ static void zf_ping(unsigned long data)
spin_unlock_irqrestore(&zf_port_lock, flags); spin_unlock_irqrestore(&zf_port_lock, flags);
mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
}else{ } else
printk(KERN_CRIT PFX ": I will reset your machine\n"); printk(KERN_CRIT PFX ": I will reset your machine\n");
}
} }
static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
/* See if we got the magic character */ /* See if we got the magic character */
if(count){ if (count) {
/* /*
* no need to check for close confirmation * no need to check for close confirmation
* no way to disable watchdog ;) * no way to disable watchdog ;)
*/ */
if (!nowayout) { if (!nowayout) {
size_t ofs; size_t ofs;
/* /*
* note: just in case someone wrote the magic character * note: just in case someone wrote the magic character
* five months ago... * five months ago...
...@@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, ...@@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
zf_expect_close = 0; zf_expect_close = 0;
/* now scan */ /* now scan */
for (ofs = 0; ofs != count; ofs++){ for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if (get_user(c, buf + ofs)) if (get_user(c, buf + ofs))
return -EFAULT; return -EFAULT;
if (c == 'V'){ if (c == 'V') {
zf_expect_close = 42; zf_expect_close = 42;
dprintk("zf_expect_close = 42\n"); dprintk("zf_expect_close = 42\n");
} }
...@@ -303,14 +299,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, ...@@ -303,14 +299,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
*/ */
next_heartbeat = jiffies + ZF_USER_TIMEO; next_heartbeat = jiffies + ZF_USER_TIMEO;
dprintk("user ping at %ld\n", jiffies); dprintk("user ping at %ld\n", jiffies);
} }
return count; return count;
} }
static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -319,55 +312,38 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -319,55 +312,38 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (copy_to_user(argp, &zf_info, sizeof(zf_info))) if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
zf_ping(0); zf_ping(0);
break; break;
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int zf_open(struct inode *inode, struct file *file) static int zf_open(struct inode *inode, struct file *file)
{ {
spin_lock(&zf_lock); if (test_and_set_bit(0, &zf_is_open))
if(test_and_set_bit(0, &zf_is_open)) {
spin_unlock(&zf_lock);
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
spin_unlock(&zf_lock);
zf_timer_on(); zf_timer_on();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int zf_close(struct inode *inode, struct file *file) static int zf_close(struct inode *inode, struct file *file)
{ {
if(zf_expect_close == 42){ if (zf_expect_close == 42)
zf_timer_off(); zf_timer_off();
} else { else {
del_timer(&zf_timer); del_timer(&zf_timer);
printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
} }
spin_lock(&zf_lock);
clear_bit(0, &zf_is_open); clear_bit(0, &zf_is_open);
spin_unlock(&zf_lock);
zf_expect_close = 0; zf_expect_close = 0;
return 0; return 0;
} }
...@@ -378,21 +354,16 @@ static int zf_close(struct inode *inode, struct file *file) ...@@ -378,21 +354,16 @@ static int zf_close(struct inode *inode, struct file *file)
static int zf_notify_sys(struct notifier_block *this, unsigned long code, static int zf_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code == SYS_DOWN || code == SYS_HALT){ if (code == SYS_DOWN || code == SYS_HALT)
zf_timer_off(); zf_timer_off();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static const struct file_operations zf_fops = { static const struct file_operations zf_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = zf_write, .write = zf_write,
.ioctl = zf_ioctl, .unlocked_ioctl = zf_ioctl,
.open = zf_open, .open = zf_open,
.release = zf_close, .release = zf_close,
}; };
...@@ -423,22 +394,23 @@ static int __init zf_init(void) ...@@ -423,22 +394,23 @@ static int __init zf_init(void)
{ {
int ret; int ret;
printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); printk(KERN_INFO PFX
": MachZ ZF-Logic Watchdog driver initializing.\n");
ret = zf_get_ZFL_version(); ret = zf_get_ZFL_version();
if ((!ret) || (ret == 0xffff)) { if (!ret || ret == 0xffff) {
printk(KERN_WARNING PFX ": no ZF-Logic found\n"); printk(KERN_WARNING PFX ": no ZF-Logic found\n");
return -ENODEV; return -ENODEV;
} }
if((action <= 3) && (action >= 0)){ if (action <= 3 && action >= 0)
zf_action = zf_action>>action; zf_action = zf_action >> action;
} else else
action = 0; action = 0;
zf_show_action(action); zf_show_action(action);
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
printk(KERN_ERR "cannot reserve I/O ports at %d\n", printk(KERN_ERR "cannot reserve I/O ports at %d\n",
ZF_IOBASE); ZF_IOBASE);
ret = -EBUSY; ret = -EBUSY;
...@@ -446,14 +418,14 @@ static int __init zf_init(void) ...@@ -446,14 +418,14 @@ static int __init zf_init(void)
} }
ret = register_reboot_notifier(&zf_notifier); ret = register_reboot_notifier(&zf_notifier);
if(ret){ if (ret) {
printk(KERN_ERR "can't register reboot notifier (err=%d)\n", printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
ret); ret);
goto no_reboot; goto no_reboot;
} }
ret = misc_register(&zf_miscdev); ret = misc_register(&zf_miscdev);
if (ret){ if (ret) {
printk(KERN_ERR "can't misc_register on minor=%d\n", printk(KERN_ERR "can't misc_register on minor=%d\n",
WATCHDOG_MINOR); WATCHDOG_MINOR);
goto no_misc; goto no_misc;
......
This diff is collapsed.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
...@@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt) ...@@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
/* set timeout, with maximum prescaler */ /* set timeout, with maximum prescaler */
out_be32(&wdt->regs->count, 0x0 | wdt->count); out_be32(&wdt->regs->count, 0x0 | wdt->count);
/* enable watchdog */ /* enable watchdog */
out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER); out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT |
GPT_MODE_MS_TIMER);
spin_unlock(&wdt->io_lock); spin_unlock(&wdt->io_lock);
return 0; return 0;
...@@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt) ...@@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
{ {
spin_lock(&wdt->io_lock); spin_lock(&wdt->io_lock);
/* writing A5 to OCPW resets the watchdog */ /* writing A5 to OCPW resets the watchdog */
out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode))); out_be32(&wdt->regs->mode, 0xA5000000 |
(0xffffff & in_be32(&wdt->regs->mode)));
spin_unlock(&wdt->io_lock); spin_unlock(&wdt->io_lock);
return 0; return 0;
} }
...@@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = { ...@@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "mpc5200 watchdog on GPT0", .identity = "mpc5200 watchdog on GPT0",
}; };
static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, static long mpc5200_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
struct mpc5200_wdt *wdt = file->private_data; struct mpc5200_wdt *wdt = file->private_data;
int __user *data = (int __user *)arg; int __user *data = (int __user *)arg;
...@@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
} }
return ret; return ret;
} }
static int mpc5200_wdt_open(struct inode *inode, struct file *file) static int mpc5200_wdt_open(struct inode *inode, struct file *file)
{ {
/* /dev/watchdog can only be opened once */ /* /dev/watchdog can only be opened once */
...@@ -161,13 +164,14 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file) ...@@ -161,13 +164,14 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
static const struct file_operations mpc5200_wdt_fops = { static const struct file_operations mpc5200_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = mpc5200_wdt_write, .write = mpc5200_wdt_write,
.ioctl = mpc5200_wdt_ioctl, .unlocked_ioctl = mpc5200_wdt_ioctl,
.open = mpc5200_wdt_open, .open = mpc5200_wdt_open,
.release = mpc5200_wdt_release, .release = mpc5200_wdt_release,
}; };
/* module operations */ /* module operations */
static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match) static int mpc5200_wdt_probe(struct of_device *op,
const struct of_device_id *match)
{ {
struct mpc5200_wdt *wdt; struct mpc5200_wdt *wdt;
int err; int err;
...@@ -215,9 +219,9 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma ...@@ -215,9 +219,9 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma
return 0; return 0;
iounmap(wdt->regs); iounmap(wdt->regs);
out_release: out_release:
release_mem_region(wdt->mem.start, size); release_mem_region(wdt->mem.start, size);
out_free: out_free:
kfree(wdt); kfree(wdt);
return err; return err;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -22,10 +22,9 @@ ...@@ -22,10 +22,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mv643xx.h> #include <linux/mv643xx.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#define MV64x60_WDT_WDC_OFFSET 0 #define MV64x60_WDT_WDC_OFFSET 0
...@@ -61,7 +60,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock); ...@@ -61,7 +60,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
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 mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
{ {
...@@ -150,7 +151,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file) ...@@ -150,7 +151,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
} }
static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
...@@ -160,7 +161,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, ...@@ -160,7 +161,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if(get_user(c, data + i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_close = 42; expect_close = 42;
...@@ -172,7 +173,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, ...@@ -172,7 +173,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
return len; return len;
} }
static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, static long mv64x60_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int timeout; int timeout;
...@@ -240,7 +241,7 @@ static const struct file_operations mv64x60_wdt_fops = { ...@@ -240,7 +241,7 @@ static const struct file_operations mv64x60_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mv64x60_wdt_write, .write = mv64x60_wdt_write,
.ioctl = mv64x60_wdt_ioctl, .unlocked_ioctl = mv64x60_wdt_ioctl,
.open = mv64x60_wdt_open, .open = mv64x60_wdt_open,
.release = mv64x60_wdt_release, .release = mv64x60_wdt_release,
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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