|  | The Linux WatchDog Timer Driver Core kernel API. | 
|  | =============================================== | 
|  | Last reviewed: 22-May-2012 | 
|  |  | 
|  | 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. |