2005-04-16 15:20:36 -07:00
/*
2012-02-28 22:48:11 +00:00
* SoftDog : A Software Watchdog Device
2005-04-16 15:20:36 -07:00
*
2009-03-18 08:35:09 +00:00
* ( c ) Copyright 1996 Alan Cox < alan @ lxorguk . ukuu . org . uk > ,
* All Rights Reserved .
2005-04-16 15:20:36 -07: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-15 15:06:19 -08:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2016-05-25 08:37:47 +02:00
# include <linux/init.h>
# include <linux/jiffies.h>
# include <linux/kernel.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/moduleparam.h>
2016-05-25 08:37:47 +02:00
# include <linux/reboot.h>
2005-04-16 15:20:36 -07:00
# include <linux/timer.h>
2016-05-25 08:37:47 +02:00
# include <linux/types.h>
2005-04-16 15:20:36 -07:00
# include <linux/watchdog.h>
# define TIMER_MARGIN 60 /* Default is 60 seconds */
2012-02-28 22:48:11 +00:00
static unsigned int soft_margin = TIMER_MARGIN ; /* in seconds */
module_param ( soft_margin , uint , 0 ) ;
2008-05-19 14:09:06 +01:00
MODULE_PARM_DESC ( soft_margin ,
" Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default= "
__MODULE_STRING ( TIMER_MARGIN ) " ) " ) ;
2005-04-16 15:20:36 -07:00
2012-03-05 16:51:11 +01:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2008-05-19 14:09:06 +01:00
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2005-04-16 15:20:36 -07:00
2014-02-27 14:41:42 +09:00
static int soft_noboot ;
2005-04-16 15:20:36 -07:00
module_param ( soft_noboot , int , 0 ) ;
2009-04-14 20:20:07 +00:00
MODULE_PARM_DESC ( soft_noboot ,
2012-02-28 22:48:11 +00:00
" Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0) " ) ;
2005-04-16 15:20:36 -07:00
2011-03-28 14:29:19 -07: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 08:37:45 +02:00
static void softdog_fire ( unsigned long data )
2005-04-16 15:20:36 -07:00
{
2015-12-17 21:30:02 +08:00
module_put ( THIS_MODULE ) ;
2016-05-25 08:37:49 +02:00
if ( soft_noboot ) {
2012-02-15 15:06:19 -08:00
pr_crit ( " Triggered - Reboot ignored \n " ) ;
2016-05-25 08:37:49 +02:00
} else if ( soft_panic ) {
2012-02-15 15:06:19 -08:00
pr_crit ( " Initiating panic \n " ) ;
panic ( " Software Watchdog Timer expired " ) ;
2011-03-28 14:29:19 -07:00
} else {
2012-02-15 15:06:19 -08:00
pr_crit ( " Initiating system reboot \n " ) ;
2005-07-26 21:41:38 -07:00
emergency_restart ( ) ;
2012-02-15 15:06:19 -08:00
pr_crit ( " Reboot didn't ????? \n " ) ;
2005-04-16 15:20:36 -07:00
}
}
2016-05-25 08:37:46 +02:00
static struct timer_list softdog_ticktock =
TIMER_INITIALIZER ( softdog_fire , 0 , 0 ) ;
2016-10-07 15:41:38 +03:00
static struct watchdog_device softdog_dev ;
static void softdog_pretimeout ( unsigned long data )
{
watchdog_notify_pretimeout ( & softdog_dev ) ;
}
static struct timer_list softdog_preticktock =
TIMER_INITIALIZER ( softdog_pretimeout , 0 , 0 ) ;
2012-02-28 22:48:11 +00:00
static int softdog_ping ( struct watchdog_device * w )
2005-04-16 15:20:36 -07:00
{
2016-05-25 08:37:49 +02:00
if ( ! mod_timer ( & softdog_ticktock , jiffies + ( w - > timeout * HZ ) ) )
2015-12-17 21:30:02 +08:00
__module_get ( THIS_MODULE ) ;
2016-10-07 15:41:38 +03:00
2017-02-07 15:03:29 +01:00
if ( IS_ENABLED ( CONFIG_SOFT_WATCHDOG_PRETIMEOUT ) ) {
if ( w - > pretimeout )
mod_timer ( & softdog_preticktock , jiffies +
( w - > timeout - w - > pretimeout ) * HZ ) ;
else
del_timer ( & softdog_preticktock ) ;
}
2016-10-07 15:41:38 +03:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-02-28 22:48:11 +00:00
static int softdog_stop ( struct watchdog_device * w )
2005-04-16 15:20:36 -07:00
{
2016-05-25 08:37:45 +02:00
if ( del_timer ( & softdog_ticktock ) )
2015-12-17 21:30:02 +08:00
module_put ( THIS_MODULE ) ;
2017-02-07 15:03:29 +01:00
if ( IS_ENABLED ( CONFIG_SOFT_WATCHDOG_PRETIMEOUT ) )
del_timer ( & softdog_preticktock ) ;
2016-10-07 15:41:38 +03:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2012-02-28 22:48:11 +00:00
static struct watchdog_info softdog_info = {
. identity = " Software Watchdog " ,
2017-02-07 15:03:29 +01:00
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
2005-04-16 15:20:36 -07:00
} ;
2016-09-01 19:35:26 +02:00
static const struct watchdog_ops softdog_ops = {
2012-02-28 22:48:11 +00:00
. owner = THIS_MODULE ,
. start = softdog_ping ,
. stop = softdog_stop ,
} ;
static struct watchdog_device softdog_dev = {
. info = & softdog_info ,
. ops = & softdog_ops ,
. min_timeout = 1 ,
2016-05-25 08:37:44 +02:00
. max_timeout = 65535 ,
. timeout = TIMER_MARGIN ,
2005-04-16 15:20:36 -07:00
} ;
2016-05-25 08:37:45 +02:00
static int __init softdog_init ( void )
2005-04-16 15:20:36 -07:00
{
int ret ;
2016-05-25 08:37:44 +02:00
watchdog_init_timeout ( & softdog_dev , soft_margin , NULL ) ;
2012-02-28 22:48:11 +00:00
watchdog_set_nowayout ( & softdog_dev , nowayout ) ;
2015-11-20 16:54:55 -05:00
watchdog_stop_on_reboot ( & softdog_dev ) ;
2005-04-16 15:20:36 -07:00
2017-02-07 15:03:29 +01:00
if ( IS_ENABLED ( CONFIG_SOFT_WATCHDOG_PRETIMEOUT ) )
softdog_info . options | = WDIOF_PRETIMEOUT ;
2012-02-28 22:48:11 +00:00
ret = watchdog_register_device ( & softdog_dev ) ;
2015-11-20 16:54:55 -05:00
if ( ret )
2005-04-16 15:20:36 -07:00
return ret ;
2016-05-25 08:37:44 +02: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-16 15:20:36 -07:00
return 0 ;
}
2016-05-25 08:37:45 +02:00
module_init ( softdog_init ) ;
2005-04-16 15:20:36 -07:00
2016-05-25 08:37:45 +02:00
static void __exit softdog_exit ( void )
2005-04-16 15:20:36 -07:00
{
2012-02-28 22:48:11 +00:00
watchdog_unregister_device ( & softdog_dev ) ;
2005-04-16 15:20:36 -07:00
}
2016-05-25 08:37:45 +02:00
module_exit ( softdog_exit ) ;
2005-04-16 15:20:36 -07:00
MODULE_AUTHOR ( " Alan Cox " ) ;
MODULE_DESCRIPTION ( " Software Watchdog Device Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;