diff options
Diffstat (limited to 'Documentation/watchdog')
| -rw-r--r-- | Documentation/watchdog/00-INDEX | 15 | ||||
| -rw-r--r-- | Documentation/watchdog/convert_drivers_to_kernel_api.txt | 218 | ||||
| -rw-r--r-- | Documentation/watchdog/hpwdt.txt | 2 | ||||
| -rw-r--r-- | Documentation/watchdog/src/watchdog-test.c | 20 | ||||
| -rw-r--r-- | Documentation/watchdog/watchdog-kernel-api.txt | 226 | ||||
| -rw-r--r-- | Documentation/watchdog/watchdog-parameters.txt | 20 | 
6 files changed, 474 insertions, 27 deletions
diff --git a/Documentation/watchdog/00-INDEX b/Documentation/watchdog/00-INDEX deleted file mode 100644 index ee994513a9b..00000000000 --- a/Documentation/watchdog/00-INDEX +++ /dev/null @@ -1,15 +0,0 @@ -00-INDEX -	- this file. -hpwdt.txt -	- information on the HP iLO2 NMI watchdog -pcwd-watchdog.txt -	- documentation for Berkshire Products PC Watchdog ISA cards. -src/ -	- directory holding watchdog related example programs. -watchdog-api.txt -	- description of the Linux Watchdog driver API. -watchdog-parameters.txt -	- information on driver parameters (for drivers other than -	  the ones that have driver-specific files here) -wdt.txt -	- description of the Watchdog Timer Interfaces for Linux. diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.txt b/Documentation/watchdog/convert_drivers_to_kernel_api.txt new file mode 100644 index 00000000000..271b8850dde --- /dev/null +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.txt @@ -0,0 +1,218 @@ +Converting old watchdog drivers to the watchdog framework +by Wolfram Sang <w.sang@pengutronix.de> +========================================================= + +Before the watchdog framework came into the kernel, every driver had to +implement the API on its own. Now, as the framework factored out the common +components, those drivers can be lightened making it a user of the framework. +This document shall guide you for this task. The necessary steps are described +as well as things to look out for. + + +Remove the file_operations struct +--------------------------------- + +Old drivers define their own file_operations for actions like open(), write(), +etc... These are now handled by the framework and just call the driver when +needed. So, in general, the 'file_operations' struct and assorted functions can +go. Only very few driver-specific details have to be moved to other functions. +Here is a overview of the functions and probably needed actions: + +- open: Everything dealing with resource management (file-open checks, magic +  close preparations) can simply go. Device specific stuff needs to go to the +  driver specific start-function. Note that for some drivers, the start-function +  also serves as the ping-function. If that is the case and you need start/stop +  to be balanced (clocks!), you are better off refactoring a separate start-function. + +- close: Same hints as for open apply. + +- write: Can simply go, all defined behaviour is taken care of by the framework, +  i.e. ping on write and magic char ('V') handling. + +- ioctl: While the driver is allowed to have extensions to the IOCTL interface, +  the most common ones are handled by the framework, supported by some assistance +  from the driver: + +	WDIOC_GETSUPPORT: +		Returns the mandatory watchdog_info struct from the driver + +	WDIOC_GETSTATUS: +		Needs the status-callback defined, otherwise returns 0 + +	WDIOC_GETBOOTSTATUS: +		Needs the bootstatus member properly set. Make sure it is 0 if you +		don't have further support! + +	WDIOC_SETOPTIONS: +		No preparations needed + +	WDIOC_KEEPALIVE: +		If wanted, options in watchdog_info need to have WDIOF_KEEPALIVEPING +		set + +	WDIOC_SETTIMEOUT: +		Options in watchdog_info need to have WDIOF_SETTIMEOUT set +		and a set_timeout-callback has to be defined. The core will also +		do limit-checking, if min_timeout and max_timeout in the watchdog +		device are set. All is optional. + +	WDIOC_GETTIMEOUT: +		No preparations needed + +	WDIOC_GETTIMELEFT: +		It needs get_timeleft() callback to be defined. Otherwise it +		will return EOPNOTSUPP + +  Other IOCTLs can be served using the ioctl-callback. Note that this is mainly +  intended for porting old drivers; new drivers should not invent private IOCTLs. +  Private IOCTLs are processed first. When the callback returns with +  -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error +  is directly given to the user. + +Example conversion: + +-static const struct file_operations s3c2410wdt_fops = { +-       .owner          = THIS_MODULE, +-       .llseek         = no_llseek, +-       .write          = s3c2410wdt_write, +-       .unlocked_ioctl = s3c2410wdt_ioctl, +-       .open           = s3c2410wdt_open, +-       .release        = s3c2410wdt_release, +-}; + +Check the functions for device-specific stuff and keep it for later +refactoring. The rest can go. + + +Remove the miscdevice +--------------------- + +Since the file_operations are gone now, you can also remove the 'struct +miscdevice'. The framework will create it on watchdog_dev_register() called by +watchdog_register_device(). + +-static struct miscdevice s3c2410wdt_miscdev = { +-       .minor          = WATCHDOG_MINOR, +-       .name           = "watchdog", +-       .fops           = &s3c2410wdt_fops, +-}; + + +Remove obsolete includes and defines +------------------------------------ + +Because of the simplifications, a few defines are probably unused now. Remove +them. Includes can be removed, too. For example: + +- #include <linux/fs.h> +- #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used) +- #include <linux/uaccess.h> (if no custom IOCTLs are used) + + +Add the watchdog operations +--------------------------- + +All possible callbacks are defined in 'struct watchdog_ops'. You can find it +explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and +owner must be set, the rest are optional. You will easily find corresponding +functions in the old driver. Note that you will now get a pointer to the +watchdog_device as a parameter to these functions, so you probably have to +change the function header. Other changes are most likely not needed, because +here simply happens the direct hardware access. If you have device-specific +code left from the above steps, it should be refactored into these callbacks. + +Here is a simple example: + ++static struct watchdog_ops s3c2410wdt_ops = { ++       .owner = THIS_MODULE, ++       .start = s3c2410wdt_start, ++       .stop = s3c2410wdt_stop, ++       .ping = s3c2410wdt_keepalive, ++       .set_timeout = s3c2410wdt_set_heartbeat, ++}; + +A typical function-header change looks like: + +-static void s3c2410wdt_keepalive(void) ++static int s3c2410wdt_keepalive(struct watchdog_device *wdd) + { +... ++ ++       return 0; + } + +... + +-       s3c2410wdt_keepalive(); ++       s3c2410wdt_keepalive(&s3c2410_wdd); + + +Add the watchdog device +----------------------- + +Now we need to create a 'struct watchdog_device' and populate it with the +necessary information for the framework. The struct is also explained in detail +in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory +watchdog_info struct and the newly created watchdog_ops. Often, old drivers +have their own record-keeping for things like bootstatus and timeout using +static variables. Those have to be converted to use the members in +watchdog_device. Note that the timeout values are unsigned int. Some drivers +use signed int, so this has to be converted, too. + +Here is a simple example for a watchdog device: + ++static struct watchdog_device s3c2410_wdd = { ++       .info = &s3c2410_wdt_ident, ++       .ops = &s3c2410wdt_ops, ++}; + + +Handle the 'nowayout' feature +----------------------------- + +A few drivers use nowayout statically, i.e. there is no module parameter for it +and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be +used. This needs to be converted by initializing the status variable of the +watchdog_device like this: + +        .status = WATCHDOG_NOWAYOUT_INIT_STATUS, + +Most drivers, however, also allow runtime configuration of nowayout, usually +by adding a module parameter. The conversion for this would be something like: + +	watchdog_set_nowayout(&s3c2410_wdd, nowayout); + +The module parameter itself needs to stay, everything else related to nowayout +can go, though. This will likely be some code in open(), close() or write(). + + +Register the watchdog device +---------------------------- + +Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev). +Make sure the return value gets checked and the error message, if present, +still fits. Also convert the unregister case. + +-       ret = misc_register(&s3c2410wdt_miscdev); ++       ret = watchdog_register_device(&s3c2410_wdd); + +... + +-       misc_deregister(&s3c2410wdt_miscdev); ++       watchdog_unregister_device(&s3c2410_wdd); + + +Update the Kconfig-entry +------------------------ + +The entry for the driver now needs to select WATCHDOG_CORE: + ++       select WATCHDOG_CORE + + +Create a patch and send it to upstream +-------------------------------------- + +Make sure you understood Documentation/SubmittingPatches and send your patch to +linux-watchdog@vger.kernel.org. We are looking forward to it :) + diff --git a/Documentation/watchdog/hpwdt.txt b/Documentation/watchdog/hpwdt.txt index 9c24d5ffbb0..9488078900e 100644 --- a/Documentation/watchdog/hpwdt.txt +++ b/Documentation/watchdog/hpwdt.txt @@ -8,7 +8,7 @@ Last reviewed: 06/02/2009   The HP iLO2 NMI Watchdog driver is a kernel module that provides basic   watchdog functionality and the added benefit of NMI sourcing. Both the   watchdog functionality and the NMI sourcing capability need to be enabled - by the user. Remember that the two modes are not dependant on one another. + by the user. Remember that the two modes are not dependent on one another.   A user can have the NMI sourcing without the watchdog timer and vice-versa.   Watchdog functionality is enabled like any other common watchdog driver. That diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c index 63fdc34ceb9..3da822967ee 100644 --- a/Documentation/watchdog/src/watchdog-test.c +++ b/Documentation/watchdog/src/watchdog-test.c @@ -7,6 +7,7 @@  #include <string.h>  #include <unistd.h>  #include <fcntl.h> +#include <signal.h>  #include <sys/ioctl.h>  #include <linux/types.h>  #include <linux/watchdog.h> @@ -29,6 +30,14 @@ static void keep_alive(void)   * The main program.  Run the program with "-d" to disable the card,   * or "-e" to enable the card.   */ + +static void term(int sig) +{ +    close(fd); +    fprintf(stderr, "Stopping watchdog ticks...\n"); +    exit(0); +} +  int main(int argc, char *argv[])  {      int flags; @@ -47,26 +56,31 @@ int main(int argc, char *argv[])  	    ioctl(fd, WDIOC_SETOPTIONS, &flags);  	    fprintf(stderr, "Watchdog card disabled.\n");  	    fflush(stderr); -	    exit(0); +	    goto end;  	} else if (!strncasecmp(argv[1], "-e", 2)) {  	    flags = WDIOS_ENABLECARD;  	    ioctl(fd, WDIOC_SETOPTIONS, &flags);  	    fprintf(stderr, "Watchdog card enabled.\n");  	    fflush(stderr); -	    exit(0); +	    goto end;  	} else {  	    fprintf(stderr, "-d to disable, -e to enable.\n");  	    fprintf(stderr, "run by itself to tick the card.\n");  	    fflush(stderr); -	    exit(0); +	    goto end;  	}      } else {  	fprintf(stderr, "Watchdog Ticking Away!\n");  	fflush(stderr);      } +    signal(SIGINT, term); +      while(1) {  	keep_alive();  	sleep(1);      } +end: +    close(fd); +    return 0;  } diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt new file mode 100644 index 00000000000..a0438f3957c --- /dev/null +++ b/Documentation/watchdog/watchdog-kernel-api.txt @@ -0,0 +1,226 @@ +The Linux WatchDog Timer Driver Core kernel API. +=============================================== +Last reviewed: 12-Feb-2013 + +Wim Van Sebroeck <wim@iguana.be> + +Introduction +------------ +This document does not describe what a WatchDog Timer (WDT) Driver or Device is. +It also does not describe the API which can be used by user space to communicate +with a WatchDog Timer. If you want to know this then please read the following +file: Documentation/watchdog/watchdog-api.txt . + +So what does this document describe? It describes the API that can be used by +WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core +Framework. This framework provides all interfacing towards user space so that +the same code does not have to be reproduced each time. This also means that +a watchdog timer driver then only needs to provide the different routines +(operations) that control the watchdog timer (WDT). + +The API +------- +Each watchdog timer driver that wants to use the WatchDog Timer Driver Core +must #include <linux/watchdog.h> (you would have to do this anyway when +writing a watchdog device driver). This include file contains following +register/unregister routines: + +extern int watchdog_register_device(struct watchdog_device *); +extern void watchdog_unregister_device(struct watchdog_device *); + +The watchdog_register_device routine registers a watchdog timer device. +The parameter of this routine is a pointer to a watchdog_device structure. +This routine returns zero on success and a negative errno code for failure. + +The watchdog_unregister_device routine deregisters a registered watchdog timer +device. The parameter of this routine is the pointer to the registered +watchdog_device structure. + +The watchdog device structure looks like this: + +struct watchdog_device { +	int id; +	struct cdev cdev; +	struct device *dev; +	struct device *parent; +	const struct watchdog_info *info; +	const struct watchdog_ops *ops; +	unsigned int bootstatus; +	unsigned int timeout; +	unsigned int min_timeout; +	unsigned int max_timeout; +	void *driver_data; +	struct mutex lock; +	unsigned long status; +}; + +It contains following fields: +* id: set by watchdog_register_device, id 0 is special. It has both a +  /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old +  /dev/watchdog miscdev. The id is set automatically when calling +  watchdog_register_device. +* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This +  field is also populated by watchdog_register_device. +* dev: device under the watchdog class (created by watchdog_register_device). +* parent: set this to the parent device (or NULL) before calling +  watchdog_register_device. +* info: a pointer to a watchdog_info structure. This structure gives some +  additional information about the watchdog timer itself. (Like it's unique name) +* ops: a pointer to the list of watchdog operations that the watchdog supports. +* timeout: the watchdog timer's timeout value (in seconds). +* min_timeout: the watchdog timer's minimum timeout value (in seconds). +* max_timeout: the watchdog timer's maximum timeout value (in seconds). +* bootstatus: status of the device after booting (reported with watchdog +  WDIOF_* status bits). +* driver_data: a pointer to the drivers private data of a watchdog device. +  This data should only be accessed via the watchdog_set_drvdata and +  watchdog_get_drvdata routines. +* lock: Mutex for WatchDog Timer Driver Core internal use only. +* status: this field contains a number of status bits that give extra +  information about the status of the device (Like: is the watchdog timer +  running/active, is the nowayout bit set, is the device opened via +  the /dev/watchdog interface or not, ...). + +The list of watchdog operations is defined as: + +struct watchdog_ops { +	struct module *owner; +	/* mandatory operations */ +	int (*start)(struct watchdog_device *); +	int (*stop)(struct watchdog_device *); +	/* optional operations */ +	int (*ping)(struct watchdog_device *); +	unsigned int (*status)(struct watchdog_device *); +	int (*set_timeout)(struct watchdog_device *, unsigned int); +	unsigned int (*get_timeleft)(struct watchdog_device *); +	void (*ref)(struct watchdog_device *); +	void (*unref)(struct watchdog_device *); +	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); +}; + +It is important that you first define the module owner of the watchdog timer +driver's operations. This module owner will be used to lock the module when +the watchdog is active. (This to avoid a system crash when you unload the +module and /dev/watchdog is still open). + +If the watchdog_device struct is dynamically allocated, just locking the module +is not enough and a driver also needs to define the ref and unref operations to +ensure the structure holding the watchdog_device does not go away. + +The simplest (and usually sufficient) implementation of this is to: +1) Add a kref struct to the same structure which is holding the watchdog_device +2) Define a release callback for the kref which frees the struct holding both +3) Call kref_init on this kref *before* calling watchdog_register_device() +4) Define a ref operation calling kref_get on this kref +5) Define a unref operation calling kref_put on this kref +6) When it is time to cleanup: + * Do not kfree() the struct holding both, the last kref_put will do this! + * *After* calling watchdog_unregister_device() call kref_put on the kref + +Some operations are mandatory and some are optional. The mandatory operations +are: +* start: this is a pointer to the routine that starts the watchdog timer +  device. +  The routine needs a pointer to the watchdog timer device structure as a +  parameter. It returns zero on success or a negative errno code for failure. +* stop: with this routine the watchdog timer device is being stopped. +  The routine needs a pointer to the watchdog timer device structure as a +  parameter. It returns zero on success or a negative errno code for failure. +  Some watchdog timer hardware can only be started and not be stopped. The +  driver supporting this hardware needs to make sure that a start and stop +  routine is being provided. This can be done by using a timer in the driver +  that regularly sends a keepalive ping to the watchdog timer hardware. + +Not all watchdog timer hardware supports the same functionality. That's why +all other routines/operations are optional. They only need to be provided if +they are supported. These optional routines/operations are: +* ping: this is the routine that sends a keepalive ping to the watchdog timer +  hardware. +  The routine needs a pointer to the watchdog timer device structure as a +  parameter. It returns zero on success or a negative errno code for failure. +  Most hardware that does not support this as a separate function uses the +  start function to restart the watchdog timer hardware. And that's also what +  the watchdog timer driver core does: to send a keepalive ping to the watchdog +  timer hardware it will either use the ping operation (when available) or the +  start operation (when the ping operation is not available). +  (Note: the WDIOC_KEEPALIVE ioctl call will only be active when the +  WDIOF_KEEPALIVEPING bit has been set in the option field on the watchdog's +  info structure). +* status: this routine checks the status of the watchdog timer device. The +  status of the device is reported with watchdog WDIOF_* status flags/bits. +* set_timeout: this routine checks and changes the timeout of the watchdog +  timer device. It returns 0 on success, -EINVAL for "parameter out of range" +  and -EIO for "could not write value to the watchdog". On success this +  routine should set the timeout value of the watchdog_device to the +  achieved timeout value (which may be different from the requested one +  because the watchdog does not necessarily has a 1 second resolution). +  (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the +  watchdog's info structure). +* get_timeleft: this routines returns the time that's left before a reset. +* ref: the operation that calls kref_get on the kref of a dynamically +  allocated watchdog_device struct. +* unref: the operation that calls kref_put on the kref of a dynamically +  allocated watchdog_device struct. +* ioctl: if this routine is present then it will be called first before we do +  our own internal ioctl call handling. This routine should return -ENOIOCTLCMD +  if a command is not supported. The parameters that are passed to the ioctl +  call are: watchdog_device, cmd and arg. + +The status bits should (preferably) be set with the set_bit and clear_bit alike +bit-operations. The status bits that are defined are: +* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device +  is active or not. When the watchdog is active after booting, then you should +  set this status bit (Note: when you register the watchdog timer device with +  this bit set, then opening /dev/watchdog will skip the start operation) +* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device +  was opened via /dev/watchdog. +  (This bit should only be used by the WatchDog Timer Driver Core). +* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character +  has been sent (so that we can support the magic close feature). +  (This bit should only be used by the WatchDog Timer Driver Core). +* WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog. +  If this bit is set then the watchdog timer will not be able to stop. +* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core +  after calling watchdog_unregister_device, and then checked before calling +  any watchdog_ops, so that you can be sure that no operations (other then +  unref) will get called after unregister, even if userspace still holds a +  reference to /dev/watchdog + +  To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog +  timer device) you can either: +  * set it statically in your watchdog_device struct with +	.status = WATCHDOG_NOWAYOUT_INIT_STATUS, +    (this will set the value the same as CONFIG_WATCHDOG_NOWAYOUT) or +  * use the following helper function: +  static inline void watchdog_set_nowayout(struct watchdog_device *wdd, int nowayout) + +Note: The WatchDog Timer Driver Core supports the magic close feature and +the nowayout feature. To use the magic close feature you must set the +WDIOF_MAGICCLOSE bit in the options field of the watchdog's info structure. +The nowayout feature will overrule the magic close feature. + +To get or set driver specific data the following two helper functions should be +used: + +static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) +static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) + +The watchdog_set_drvdata function allows you to add driver specific data. The +arguments of this function are the watchdog device where you want to add the +driver specific data to and a pointer to the data itself. + +The watchdog_get_drvdata function allows you to retrieve driver specific data. +The argument of this function is the watchdog device where you want to retrieve +data from. The function returns the pointer to the driver specific data. + +To initialize the timeout field, the following function can be used: + +extern int watchdog_init_timeout(struct watchdog_device *wdd, +                                  unsigned int timeout_parm, struct device *dev); + +The watchdog_init_timeout function allows you to initialize the timeout field +using the module timeout parameter or by retrieving the timeout-sec property from +the device tree (if the module timeout parameter is invalid). Best practice is +to set the default timeout value as timeout value in the watchdog_device and +then use this function to set the user "preferred" timeout value. +This routine returns zero on success and a negative errno code for failure. diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index 17ddd822b45..692791cc674 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt @@ -78,6 +78,11 @@ wd0_timeout: Default watchdog0 timeout in 1/10secs  wd1_timeout: Default watchdog1 timeout in 1/10secs  wd2_timeout: Default watchdog2 timeout in 1/10secs  ------------------------------------------------- +da9052wdt: +timeout: Watchdog timeout in seconds. 2<= timeout <=131, default=2.048s +nowayout: Watchdog cannot be stopped once started +	(default=kernel config parameter) +-------------------------------------------------  davinci_wdt:  heartbeat: Watchdog heartbeat period in seconds from 1 to 600, default 60  ------------------------------------------------- @@ -145,6 +150,8 @@ nowayout: Disable watchdog shutdown on close  -------------------------------------------------  it87_wdt:  nogameport: Forbid the activation of game port, default=0 +nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if +system resets despite watchdog daemon running, default=0  exclusive: Watchdog exclusive device open, default=1  timeout: Watchdog timeout in seconds, default=60  testmode: Watchdog test mode (1 = no reboot), default=0 @@ -189,14 +196,6 @@ reset: Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset  nowayout: Watchdog cannot be stopped once started  	(default=kernel config parameter)  ------------------------------------------------- -mpcore_wdt: -mpcore_margin: MPcore timer margin in seconds. -	(0 < mpcore_margin < 65536, default=60) -nowayout: Watchdog cannot be stopped once started -	(default=kernel config parameter) -mpcore_noboot: MPcore watchdog action, set to 1 to ignore reboots, -	0 to reboot (default=0 --------------------------------------------------  mv64x60_wdt:  nowayout: Watchdog cannot be stopped once started  	(default=kernel config parameter) @@ -328,6 +327,11 @@ soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot  stmp3xxx_wdt:  heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19  ------------------------------------------------- +tegra_wdt: +heartbeat: Watchdog heartbeats in seconds. (default = 120) +nowayout: Watchdog cannot be stopped once started +	(default=kernel config parameter) +-------------------------------------------------  ts72xx_wdt:  timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)  nowayout: Disable watchdog shutdown on close  | 
