// SPDX-License-Identifier: GPL-2.0-or-later /* * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x * * Based on acquirewdt.c by Alan Cox. * * The author does NOT admit liability nor provide warranty for * any of this software. This material is provided "AS-IS" in * the hope that it may be useful for others. * * (c) Copyright 2000 Jakob Oestergaard <[email protected]> * * 12/4 - 2000 [Initial revision] * 25/4 - 2000 Added /dev/watchdog support * 09/5 - 2001 [[email protected]] fixed fop_write to "return 1" * on success * 12/4 - 2002 [[email protected]] eliminate fop_read * fix possible wdt_is_open race * add CONFIG_WATCHDOG_NOWAYOUT support * remove lock_kernel/unlock_kernel pairs * added KERN_* to printk's * got rid of extraneous comments * changed watchdog_info to correctly reflect what * the driver offers * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, * WDIOC_SETTIMEOUT, WDIOC_GETTIMEOUT, and * WDIOC_SETOPTIONS ioctls * 09/8 - 2003 [[email protected]] cleanup of trailing spaces * use module_param * made timeout (the emulated heartbeat) a * module_param * made the keepalive ping an internal subroutine * made wdt_stop and wdt_start module params * added extra printk's for startup problems * added MODULE_AUTHOR and MODULE_DESCRIPTION info * * This WDT driver is different from the other Linux WDT * drivers in the following ways: * *) The driver will ping the watchdog by itself, because this * particular WDT has a very short timeout (one second) and it * would be insane to count on any userspace daemon always * getting scheduled within that time frame. */ #define pr_fmt(fmt) … #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/timer.h> #include <linux/jiffies.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/fs.h> #include <linux/ioport.h> #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> #include <linux/io.h> #include <linux/uaccess.h> #define OUR_NAME … #define PFX … /* * You must set these - The driver cannot probe for the settings */ static int wdt_stop = …; module_param(wdt_stop, int, 0); MODULE_PARM_DESC(…) …; static int wdt_start = …; module_param(wdt_start, int, 0); MODULE_PARM_DESC(…) …; /* * The 60xx board can use watchdog timeout values from one second * to several minutes. The default is one second, so if we reset * the watchdog every ~250ms we should be safe. */ #define WDT_INTERVAL … /* * We must not require too good response from the userspace daemon. * Here we require the userspace daemon to send us a heartbeat * char to /dev/watchdog every 30 seconds. * If the daemon pulses us every 25 seconds, we can still afford * a 5 second scheduling delay on the (high priority) daemon. That * should be sufficient for a box under any load. */ #define WATCHDOG_TIMEOUT … static int timeout = …; /* in seconds, multiplied by HZ to get seconds to wait for a ping */ module_param(timeout, int, 0); MODULE_PARM_DESC(…) …; static bool nowayout = … WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(…) …; static void wdt_timer_ping(struct timer_list *); static DEFINE_TIMER(timer, wdt_timer_ping); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; /* * Whack the dog */ static void wdt_timer_ping(struct timer_list *unused) { … } /* * Utility routines */ static void wdt_startup(void) { … } static void wdt_turnoff(void) { … } static void wdt_keepalive(void) { … } /* * /dev/watchdog handling */ static ssize_t fop_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { … } static int fop_open(struct inode *inode, struct file *file) { … } static int fop_close(struct inode *inode, struct file *file) { … } static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } static const struct file_operations wdt_fops = …; static struct miscdevice wdt_miscdev = …; /* * Notifier for system down */ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { … } /* * The WDT needs to learn about soft shutdowns in order to * turn the timebomb registers off. */ static struct notifier_block wdt_notifier = …; static void __exit sbc60xxwdt_unload(void) { … } static int __init sbc60xxwdt_init(void) { … } module_init(…) …; module_exit(sbc60xxwdt_unload); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;