2005-04-17 02:20:36 +04:00
/*
2012-02-29 02:48:11 +04:00
* SoftDog : A Software Watchdog Device
2005-04-17 02:20:36 +04:00
*
2009-03-18 11:35:09 +03:00
* ( c ) Copyright 1996 Alan Cox < alan @ lxorguk . ukuu . org . uk > ,
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* Neither Alan Cox nor CymruNet Ltd . admit liability nor provide
* warranty for any of this software . This material is provided
* " AS-IS " and at no charge .
*
* ( c ) Copyright 1995 Alan Cox < alan @ lxorguk . ukuu . org . uk >
*
* Software only watchdog driver . Unlike its big brother the WDT501P
* driver this won ' t always recover a failed machine .
*/
2012-02-16 03:06:19 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/types.h>
# include <linux/timer.h>
# include <linux/watchdog.h>
# include <linux/reboot.h>
# include <linux/init.h>
2005-10-31 02:03:48 +03:00
# include <linux/jiffies.h>
2011-03-29 01:29:19 +04:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
# define TIMER_MARGIN 60 /* Default is 60 seconds */
2012-02-29 02:48:11 +04:00
static unsigned int soft_margin = TIMER_MARGIN ; /* in seconds */
module_param ( soft_margin , uint , 0 ) ;
2008-05-19 17:09:06 +04:00
MODULE_PARM_DESC ( soft_margin ,
" Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default= "
__MODULE_STRING ( TIMER_MARGIN ) " ) " ) ;
2005-04-17 02:20:36 +04:00
2012-03-05 19:51:11 +04:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2008-05-19 17:09:06 +04:00
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2005-04-17 02:20:36 +04:00
2014-02-27 09:41:42 +04:00
static int soft_noboot ;
2005-04-17 02:20:36 +04:00
module_param ( soft_noboot , int , 0 ) ;
2009-04-15 00:20:07 +04:00
MODULE_PARM_DESC ( soft_noboot ,
2012-02-29 02:48:11 +04:00
" Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0) " ) ;
2005-04-17 02:20:36 +04:00
2011-03-29 01:29:19 +04:00
static int soft_panic ;
module_param ( soft_panic , int , 0 ) ;
MODULE_PARM_DESC ( soft_panic ,
" Softdog action, set to 1 to panic, 0 to reboot (default=0) " ) ;
2016-05-25 09:37:45 +03:00
static void softdog_fire ( unsigned long ) ;
2005-04-17 02:20:36 +04:00
2016-05-25 09:37:45 +03:00
static struct timer_list softdog_ticktock =
TIMER_INITIALIZER ( softdog_fire , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
2016-05-25 09:37:45 +03:00
static void softdog_fire ( unsigned long data )
2005-04-17 02:20:36 +04:00
{
2015-12-17 16:30:02 +03:00
module_put ( THIS_MODULE ) ;
2005-04-17 02:20:36 +04:00
if ( soft_noboot )
2012-02-16 03:06:19 +04:00
pr_crit ( " Triggered - Reboot ignored \n " ) ;
2011-03-29 01:29:19 +04:00
else if ( soft_panic ) {
2012-02-16 03:06:19 +04:00
pr_crit ( " Initiating panic \n " ) ;
panic ( " Software Watchdog Timer expired " ) ;
2011-03-29 01:29:19 +04:00
} else {
2012-02-16 03:06:19 +04:00
pr_crit ( " Initiating system reboot \n " ) ;
2005-07-27 08:41:38 +04:00
emergency_restart ( ) ;
2012-02-16 03:06:19 +04:00
pr_crit ( " Reboot didn't ????? \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
2012-02-29 02:48:11 +04:00
static int softdog_ping ( struct watchdog_device * w )
2005-04-17 02:20:36 +04:00
{
2016-05-25 09:37:45 +03:00
if ( ! mod_timer ( & softdog_ticktock , jiffies + ( w - > timeout * HZ ) ) )
2015-12-17 16:30:02 +03:00
__module_get ( THIS_MODULE ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-02-29 02:48:11 +04:00
static int softdog_stop ( struct watchdog_device * w )
2005-04-17 02:20:36 +04:00
{
2016-05-25 09:37:45 +03:00
if ( del_timer ( & softdog_ticktock ) )
2015-12-17 16:30:02 +03:00
module_put ( THIS_MODULE ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-02-29 02:48:11 +04:00
static int softdog_set_timeout ( struct watchdog_device * w , unsigned int t )
2005-04-17 02:20:36 +04:00
{
2012-02-29 02:48:11 +04:00
w - > timeout = t ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-02-29 02:48:11 +04:00
static struct watchdog_info softdog_info = {
. identity = " Software Watchdog " ,
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-29 02:48:11 +04:00
static struct watchdog_ops softdog_ops = {
. owner = THIS_MODULE ,
. start = softdog_ping ,
. stop = softdog_stop ,
. set_timeout = softdog_set_timeout ,
} ;
static struct watchdog_device softdog_dev = {
. info = & softdog_info ,
. ops = & softdog_ops ,
. min_timeout = 1 ,
2016-05-25 09:37:44 +03:00
. max_timeout = 65535 ,
. timeout = TIMER_MARGIN ,
2005-04-17 02:20:36 +04:00
} ;
2016-05-25 09:37:45 +03:00
static int __init softdog_init ( void )
2005-04-17 02:20:36 +04:00
{
int ret ;
2016-05-25 09:37:44 +03:00
watchdog_init_timeout ( & softdog_dev , soft_margin , NULL ) ;
2012-02-29 02:48:11 +04:00
watchdog_set_nowayout ( & softdog_dev , nowayout ) ;
2015-11-21 00:54:55 +03:00
watchdog_stop_on_reboot ( & softdog_dev ) ;
2005-04-17 02:20:36 +04:00
2012-02-29 02:48:11 +04:00
ret = watchdog_register_device ( & softdog_dev ) ;
2015-11-21 00:54:55 +03:00
if ( ret )
2005-04-17 02:20:36 +04:00
return ret ;
2016-05-25 09:37:44 +03:00
pr_info ( " initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d) \n " ,
soft_noboot , softdog_dev . timeout , soft_panic , nowayout ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2016-05-25 09:37:45 +03:00
module_init ( softdog_init ) ;
2005-04-17 02:20:36 +04:00
2016-05-25 09:37:45 +03:00
static void __exit softdog_exit ( void )
2005-04-17 02:20:36 +04:00
{
2012-02-29 02:48:11 +04:00
watchdog_unregister_device ( & softdog_dev ) ;
2005-04-17 02:20:36 +04:00
}
2016-05-25 09:37:45 +03:00
module_exit ( softdog_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Alan Cox " ) ;
MODULE_DESCRIPTION ( " Software Watchdog Device Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;