/*
- * IndyDog 0.2 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.
*
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <asm/sgi/sgimc.h>
+#define PFX "indydog: "
+#define WATCHDOG_HEARTBEAT 60
+
static unsigned long indydog_alive;
static struct sgimc_misc_ctrl *mcmisc_regs;
static char expect_close;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
-static void indydog_ping()
+static void indydog_start(void)
{
- mcmisc_regs->watchdogt = 0;
+ u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+ mc_ctrl0 |= SGIMC_CCTRL0_WDOG;
+ mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+ printk(KERN_INFO PFX "Started watchdog timer.\n");
}
+static void indydog_stop(void)
+{
+ u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+ mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+ mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+ printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void indydog_ping(void)
+{
+ mcmisc_regs->watchdogt = 0;
+}
/*
* Allow only one person to hold it open
static int indydog_open(struct inode *inode, struct file *file)
{
- u32 mc_ctrl0;
-
if( test_and_set_bit(0,&indydog_alive) )
return -EBUSY;
/*
* Activate timer
*/
- mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
-
- mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG;
- mcmisc_regs->cpuctrl0 = mc_ctrl0;
+ indydog_start();
indydog_ping();
- printk("Started watchdog timer.\n");
return 0;
}
*/
if (expect_close == 42) {
- u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
- mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
- mcmisc_regs->cpuctrl0 = mc_ctrl0;
- printk("Stopped watchdog timer.\n");
+ indydog_stop();
} else {
- printk(KERN_CRIT "WDT device closed unexpectedly. WDT will not stop!\n");
+ printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
+ indydog_ping();
}
clear_bit(0,&indydog_alive);
expect_close = 0;
static int indydog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ int options, retval = -EINVAL;
static struct watchdog_info ident = {
- .options = WDIOF_MAGICCLOSE,
- .identity = "Hardware Watchdog for SGI IP22",
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = "Hardware Watchdog for SGI IP22",
};
switch (cmd) {
case WDIOC_KEEPALIVE:
indydog_ping();
return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+ case WDIOC_SETOPTIONS:
+ {
+ if (get_user(options, (int *)arg))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD)
+ {
+ indydog_stop();
+ retval = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD)
+ {
+ indydog_start();
+ retval = 0;
+ }
+
+ return retval;
+ }
}
}
+static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT) {
+ /* Turn the WDT off */
+ indydog_stop();
+ }
+
+ return NOTIFY_DONE;
+}
+
static struct file_operations indydog_fops = {
.owner = THIS_MODULE,
.write = indydog_write,
.fops = &indydog_fops,
};
-static char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n";
+static struct notifier_block indydog_notifier = {
+ .notifier_call = indydog_notify_sys,
+};
+
+static char banner[] __initdata = KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
static int __init watchdog_init(void)
{
int ret;
- ret = misc_register(&indydog_miscdev);
+ mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
+
+ ret = register_reboot_notifier(&indydog_notifier);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ ret);
+ return ret;
+ }
- if (ret)
+ ret = misc_register(&indydog_miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ unregister_reboot_notifier(&indydog_notifier);
return ret;
+ }
printk(banner);
static void __exit watchdog_exit(void)
{
misc_deregister(&indydog_miscdev);
+ unregister_reboot_notifier(&indydog_notifier);
}
module_init(watchdog_init);
module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);