| =============================================== |
| 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.rst . |
| |
| 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 subsystem includes an registration deferral mechanism, |
| which allows you to register an watchdog as early as you wish during |
| the boot process. |
| |
| The watchdog device structure looks like this:: |
| |
| struct watchdog_device { |
| int id; |
| struct device *parent; |
| const struct attribute_group **groups; |
| const struct watchdog_info *info; |
| const struct watchdog_ops *ops; |
| const struct watchdog_governor *gov; |
| unsigned int bootstatus; |
| unsigned int timeout; |
| unsigned int pretimeout; |
| unsigned int min_timeout; |
| unsigned int max_timeout; |
| unsigned int min_hw_heartbeat_ms; |
| unsigned int max_hw_heartbeat_ms; |
| struct notifier_block reboot_nb; |
| struct notifier_block restart_nb; |
| void *driver_data; |
| struct watchdog_core_data *wd_data; |
| unsigned long status; |
| struct list_head deferred; |
| }; |
| |
| 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. |
| * parent: set this to the parent device (or NULL) before calling |
| watchdog_register_device. |
| * groups: List of sysfs attribute groups to create when creating the watchdog |
| 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. |
| * gov: a pointer to the assigned watchdog device pretimeout governor or NULL. |
| * timeout: the watchdog timer's timeout value (in seconds). |
| This is the time after which the system will reboot if user space does |
| not send a heartbeat request if WDOG_ACTIVE is set. |
| * pretimeout: the watchdog timer's pretimeout value (in seconds). |
| * min_timeout: the watchdog timer's minimum timeout value (in seconds). |
| If set, the minimum configurable value for 'timeout'. |
| * max_timeout: the watchdog timer's maximum timeout value (in seconds), |
| as seen from userspace. If set, the maximum configurable value for |
| 'timeout'. Not used if max_hw_heartbeat_ms is non-zero. |
| * min_hw_heartbeat_ms: Hardware limit for minimum time between heartbeats, |
| in milli-seconds. This value is normally 0; it should only be provided |
| if the hardware can not tolerate lower intervals between heartbeats. |
| * max_hw_heartbeat_ms: Maximum hardware heartbeat, in milli-seconds. |
| If set, the infrastructure will send heartbeats to the watchdog driver |
| if 'timeout' is larger than max_hw_heartbeat_ms, unless WDOG_ACTIVE |
| is set and userspace failed to send a heartbeat for at least 'timeout' |
| seconds. max_hw_heartbeat_ms must be set if a driver does not implement |
| the stop function. |
| * reboot_nb: notifier block that is registered for reboot notifications, for |
| internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core |
| will stop the watchdog on such notifications. |
| * restart_nb: notifier block that is registered for machine restart, for |
| internal use only. If a watchdog is capable of restarting the machine, it |
| should define ops->restart. Priority can be changed through |
| watchdog_set_restart_priority. |
| * 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. |
| * wd_data: a pointer to watchdog core internal data. |
| * 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, or is the nowayout bit set). |
| * deferred: entry in wtd_deferred_reg_list which is used to |
| register early initialized watchdogs. |
| |
| The list of watchdog operations is defined as:: |
| |
| struct watchdog_ops { |
| struct module *owner; |
| /* mandatory operations */ |
| int (*start)(struct watchdog_device *); |
| /* optional operations */ |
| int (*stop)(struct watchdog_device *); |
| int (*ping)(struct watchdog_device *); |
| unsigned int (*status)(struct watchdog_device *); |
| int (*set_timeout)(struct watchdog_device *, unsigned int); |
| int (*set_pretimeout)(struct watchdog_device *, unsigned int); |
| unsigned int (*get_timeleft)(struct watchdog_device *); |
| int (*restart)(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). |
| |
| 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. |
| |
| 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: |
| |
| * 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. A |
| driver supporting such hardware does not have to implement the stop routine. |
| |
| If a driver has no stop function, the watchdog core will set WDOG_HW_RUNNING |
| and start calling the driver's keepalive pings function after the watchdog |
| device is closed. |
| |
| If a watchdog driver does not implement the stop function, it must set |
| max_hw_heartbeat_ms. |
| * 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. |
| |
| WDIOF_MAGICCLOSE and WDIOF_KEEPALIVEPING are reported by the watchdog core; |
| it is not necessary to report those bits from the driver. Also, if no status |
| function is provided by the driver, the watchdog core reports the status bits |
| provided in the bootstatus variable of struct watchdog_device. |
| |
| * 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 have a 1 second resolution). |
| |
| Drivers implementing max_hw_heartbeat_ms set the hardware watchdog heartbeat |
| to the minimum of timeout and max_hw_heartbeat_ms. Those drivers set the |
| timeout value of the watchdog_device either to the requested timeout value |
| (if it is larger than max_hw_heartbeat_ms), or to the achieved timeout value. |
| (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the |
| watchdog's info structure). |
| |
| If the watchdog driver does not have to perform any action but setting the |
| watchdog_device.timeout, this callback can be omitted. |
| |
| If set_timeout is not provided but, WDIOF_SETTIMEOUT is set, the watchdog |
| infrastructure updates the timeout value of the watchdog_device internally |
| to the requested value. |
| |
| If the pretimeout feature is used (WDIOF_PRETIMEOUT), then set_timeout must |
| also take care of checking if pretimeout is still valid and set up the timer |
| accordingly. This can't be done in the core without races, so it is the |
| duty of the driver. |
| * set_pretimeout: this routine checks and changes the pretimeout value of |
| the watchdog. It is optional because not all watchdogs support pretimeout |
| notification. The timeout value is not an absolute time, but the number of |
| seconds before the actual timeout would happen. It returns 0 on success, |
| -EINVAL for "parameter out of range" and -EIO for "could not write value to |
| the watchdog". A value of 0 disables pretimeout notification. |
| |
| (Note: the WDIOF_PRETIMEOUT needs to be set in the options field of the |
| watchdog's info structure). |
| |
| If the watchdog driver does not have to perform any action but setting the |
| watchdog_device.pretimeout, this callback can be omitted. That means if |
| set_pretimeout is not provided but WDIOF_PRETIMEOUT is set, the watchdog |
| infrastructure updates the pretimeout value of the watchdog_device internally |
| to the requested value. |
| |
| * get_timeleft: this routines returns the time that's left before a reset. |
| * restart: this routine restarts the machine. It returns 0 on success or a |
| negative errno code for failure. |
| * 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 from user perspective. User space is expected to send |
| heartbeat requests to the driver while this flag is set. |
| * 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_HW_RUNNING: Set by the watchdog driver if the hardware watchdog is |
| running. The bit must be set if the watchdog timer hardware can not be |
| stopped. The bit may also be set if the watchdog timer is running after |
| booting, before the watchdog device is opened. If set, the watchdog |
| infrastructure will send keepalives to the watchdog hardware while |
| WDOG_ACTIVE is not set. |
| Note: when you register the watchdog timer device with this bit set, |
| then opening /dev/watchdog will skip the start operation but send a keepalive |
| request instead. |
| |
| 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. |
| |
| To disable the watchdog on reboot, the user must call the following helper:: |
| |
| static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd); |
| |
| To disable the watchdog when unregistering the watchdog, the user must call |
| the following helper. Note that this will only stop the watchdog if the |
| nowayout flag is not set. |
| |
| :: |
| |
| static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd); |
| |
| To change the priority of the restart handler the following helper should be |
| used:: |
| |
| void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority); |
| |
| User should follow the following guidelines for setting the priority: |
| |
| * 0: should be called in last resort, has limited restart capabilities |
| * 128: default restart handler, use if no other handler is expected to be |
| available, and/or if restart is sufficient to restart the entire system |
| * 255: highest priority, will preempt all other restart handlers |
| |
| To raise a pretimeout notification, the following function should be used:: |
| |
| void watchdog_notify_pretimeout(struct watchdog_device *wdd) |
| |
| The function can be called in the interrupt context. If watchdog pretimeout |
| governor framework (kbuild CONFIG_WATCHDOG_PRETIMEOUT_GOV symbol) is enabled, |
| an action is taken by a preconfigured pretimeout governor preassigned to |
| the watchdog device. If watchdog pretimeout governor framework is not |
| enabled, watchdog_notify_pretimeout() prints a notification message to |
| the kernel log buffer. |