| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 1 | The Linux WatchDog Timer Driver Core kernel API. | 
 | 2 | =============================================== | 
 | 3 | Last reviewed: 22-Jul-2011 | 
 | 4 |  | 
 | 5 | Wim Van Sebroeck <wim@iguana.be> | 
 | 6 |  | 
 | 7 | Introduction | 
 | 8 | ------------ | 
 | 9 | This document does not describe what a WatchDog Timer (WDT) Driver or Device is. | 
 | 10 | It also does not describe the API which can be used by user space to communicate | 
 | 11 | with a WatchDog Timer. If you want to know this then please read the following | 
 | 12 | file: Documentation/watchdog/watchdog-api.txt . | 
 | 13 |  | 
 | 14 | So what does this document describe? It describes the API that can be used by | 
 | 15 | WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core | 
 | 16 | Framework. This framework provides all interfacing towards user space so that | 
 | 17 | the same code does not have to be reproduced each time. This also means that | 
 | 18 | a watchdog timer driver then only needs to provide the different routines | 
 | 19 | (operations) that control the watchdog timer (WDT). | 
 | 20 |  | 
 | 21 | The API | 
 | 22 | ------- | 
 | 23 | Each watchdog timer driver that wants to use the WatchDog Timer Driver Core | 
 | 24 | must #include <linux/watchdog.h> (you would have to do this anyway when | 
 | 25 | writing a watchdog device driver). This include file contains following | 
 | 26 | register/unregister routines: | 
 | 27 |  | 
 | 28 | extern int watchdog_register_device(struct watchdog_device *); | 
 | 29 | extern void watchdog_unregister_device(struct watchdog_device *); | 
 | 30 |  | 
 | 31 | The watchdog_register_device routine registers a watchdog timer device. | 
 | 32 | The parameter of this routine is a pointer to a watchdog_device structure. | 
 | 33 | This routine returns zero on success and a negative errno code for failure. | 
 | 34 |  | 
 | 35 | The watchdog_unregister_device routine deregisters a registered watchdog timer | 
 | 36 | device. The parameter of this routine is the pointer to the registered | 
 | 37 | watchdog_device structure. | 
 | 38 |  | 
 | 39 | The watchdog device structure looks like this: | 
 | 40 |  | 
 | 41 | struct watchdog_device { | 
 | 42 | 	const struct watchdog_info *info; | 
 | 43 | 	const struct watchdog_ops *ops; | 
| Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 44 | 	unsigned int bootstatus; | 
| Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 45 | 	unsigned int timeout; | 
| Wim Van Sebroeck | 3f43f68 | 2011-07-22 19:00:16 +0000 | [diff] [blame] | 46 | 	unsigned int min_timeout; | 
 | 47 | 	unsigned int max_timeout; | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 48 | 	void *driver_data; | 
 | 49 | 	unsigned long status; | 
 | 50 | }; | 
 | 51 |  | 
 | 52 | It contains following fields: | 
 | 53 | * info: a pointer to a watchdog_info structure. This structure gives some | 
 | 54 |   additional information about the watchdog timer itself. (Like it's unique name) | 
 | 55 | * ops: a pointer to the list of watchdog operations that the watchdog supports. | 
| Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 56 | * timeout: the watchdog timer's timeout value (in seconds). | 
| Wim Van Sebroeck | 3f43f68 | 2011-07-22 19:00:16 +0000 | [diff] [blame] | 57 | * min_timeout: the watchdog timer's minimum timeout value (in seconds). | 
 | 58 | * max_timeout: the watchdog timer's maximum timeout value (in seconds). | 
| Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 59 | * bootstatus: status of the device after booting (reported with watchdog | 
 | 60 |   WDIOF_* status bits). | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 61 | * driver_data: a pointer to the drivers private data of a watchdog device. | 
 | 62 |   This data should only be accessed via the watchdog_set_drvadata and | 
 | 63 |   watchdog_get_drvdata routines. | 
 | 64 | * status: this field contains a number of status bits that give extra | 
| Wim Van Sebroeck | 234445b | 2011-07-22 18:57:55 +0000 | [diff] [blame] | 65 |   information about the status of the device (Like: is the watchdog timer | 
| Wim Van Sebroeck | 7e192b9 | 2011-07-22 18:59:17 +0000 | [diff] [blame] | 66 |   running/active, is the nowayout bit set, is the device opened via | 
 | 67 |   the /dev/watchdog interface or not, ...). | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 68 |  | 
 | 69 | The list of watchdog operations is defined as: | 
 | 70 |  | 
 | 71 | struct watchdog_ops { | 
 | 72 | 	struct module *owner; | 
 | 73 | 	/* mandatory operations */ | 
 | 74 | 	int (*start)(struct watchdog_device *); | 
 | 75 | 	int (*stop)(struct watchdog_device *); | 
 | 76 | 	/* optional operations */ | 
 | 77 | 	int (*ping)(struct watchdog_device *); | 
| Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 78 | 	unsigned int (*status)(struct watchdog_device *); | 
| Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 79 | 	int (*set_timeout)(struct watchdog_device *, unsigned int); | 
| Wim Van Sebroeck | 78d88fc | 2011-07-22 18:59:49 +0000 | [diff] [blame] | 80 | 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 81 | }; | 
 | 82 |  | 
 | 83 | It is important that you first define the module owner of the watchdog timer | 
 | 84 | driver's operations. This module owner will be used to lock the module when | 
 | 85 | the watchdog is active. (This to avoid a system crash when you unload the | 
 | 86 | module and /dev/watchdog is still open). | 
 | 87 | Some operations are mandatory and some are optional. The mandatory operations | 
 | 88 | are: | 
 | 89 | * start: this is a pointer to the routine that starts the watchdog timer | 
 | 90 |   device. | 
 | 91 |   The routine needs a pointer to the watchdog timer device structure as a | 
 | 92 |   parameter. It returns zero on success or a negative errno code for failure. | 
 | 93 | * stop: with this routine the watchdog timer device is being stopped. | 
 | 94 |   The routine needs a pointer to the watchdog timer device structure as a | 
 | 95 |   parameter. It returns zero on success or a negative errno code for failure. | 
 | 96 |   Some watchdog timer hardware can only be started and not be stopped. The | 
 | 97 |   driver supporting this hardware needs to make sure that a start and stop | 
 | 98 |   routine is being provided. This can be done by using a timer in the driver | 
 | 99 |   that regularly sends a keepalive ping to the watchdog timer hardware. | 
 | 100 |  | 
 | 101 | Not all watchdog timer hardware supports the same functionality. That's why | 
 | 102 | all other routines/operations are optional. They only need to be provided if | 
 | 103 | they are supported. These optional routines/operations are: | 
 | 104 | * ping: this is the routine that sends a keepalive ping to the watchdog timer | 
 | 105 |   hardware. | 
 | 106 |   The routine needs a pointer to the watchdog timer device structure as a | 
 | 107 |   parameter. It returns zero on success or a negative errno code for failure. | 
 | 108 |   Most hardware that does not support this as a separate function uses the | 
 | 109 |   start function to restart the watchdog timer hardware. And that's also what | 
 | 110 |   the watchdog timer driver core does: to send a keepalive ping to the watchdog | 
 | 111 |   timer hardware it will either use the ping operation (when available) or the | 
 | 112 |   start operation (when the ping operation is not available). | 
| Wim Van Sebroeck | c2dc00e | 2011-07-22 18:57:23 +0000 | [diff] [blame] | 113 |   (Note: the WDIOC_KEEPALIVE ioctl call will only be active when the | 
 | 114 |   WDIOF_KEEPALIVEPING bit has been set in the option field on the watchdog's | 
 | 115 |   info structure). | 
| Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 116 | * status: this routine checks the status of the watchdog timer device. The | 
 | 117 |   status of the device is reported with watchdog WDIOF_* status flags/bits. | 
| Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 118 | * set_timeout: this routine checks and changes the timeout of the watchdog | 
 | 119 |   timer device. It returns 0 on success, -EINVAL for "parameter out of range" | 
 | 120 |   and -EIO for "could not write value to the watchdog". On success the timeout | 
 | 121 |   value of the watchdog_device will be changed to the value that was just used | 
 | 122 |   to re-program the watchdog timer device. | 
 | 123 |   (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the | 
 | 124 |   watchdog's info structure). | 
| Wim Van Sebroeck | 78d88fc | 2011-07-22 18:59:49 +0000 | [diff] [blame] | 125 | * ioctl: if this routine is present then it will be called first before we do | 
 | 126 |   our own internal ioctl call handling. This routine should return -ENOIOCTLCMD | 
 | 127 |   if a command is not supported. The parameters that are passed to the ioctl | 
 | 128 |   call are: watchdog_device, cmd and arg. | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 129 |  | 
 | 130 | The status bits should (preferably) be set with the set_bit and clear_bit alike | 
 | 131 | bit-operations. The status bits that are defined are: | 
| Wim Van Sebroeck | 234445b | 2011-07-22 18:57:55 +0000 | [diff] [blame] | 132 | * WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device | 
 | 133 |   is active or not. When the watchdog is active after booting, then you should | 
 | 134 |   set this status bit (Note: when you register the watchdog timer device with | 
 | 135 |   this bit set, then opening /dev/watchdog will skip the start operation) | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 136 | * WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device | 
 | 137 |   was opened via /dev/watchdog. | 
 | 138 |   (This bit should only be used by the WatchDog Timer Driver Core). | 
| Wim Van Sebroeck | 017cf08 | 2011-07-22 18:58:54 +0000 | [diff] [blame] | 139 | * WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character | 
 | 140 |   has been sent (so that we can support the magic close feature). | 
 | 141 |   (This bit should only be used by the WatchDog Timer Driver Core). | 
| Wim Van Sebroeck | 7e192b9 | 2011-07-22 18:59:17 +0000 | [diff] [blame] | 142 | * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog. | 
 | 143 |   If this bit is set then the watchdog timer will not be able to stop. | 
| Wim Van Sebroeck | 017cf08 | 2011-07-22 18:58:54 +0000 | [diff] [blame] | 144 |  | 
| Wim Van Sebroeck | 7e192b9 | 2011-07-22 18:59:17 +0000 | [diff] [blame] | 145 | Note: The WatchDog Timer Driver Core supports the magic close feature and | 
 | 146 | the nowayout feature. To use the magic close feature you must set the | 
 | 147 | WDIOF_MAGICCLOSE bit in the options field of the watchdog's info structure. | 
 | 148 | The nowayout feature will overrule the magic close feature. | 
| Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 149 |  | 
 | 150 | To get or set driver specific data the following two helper functions should be | 
 | 151 | used: | 
 | 152 |  | 
 | 153 | static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) | 
 | 154 | static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) | 
 | 155 |  | 
 | 156 | The watchdog_set_drvdata function allows you to add driver specific data. The | 
 | 157 | arguments of this function are the watchdog device where you want to add the | 
 | 158 | driver specific data to and a pointer to the data itself. | 
 | 159 |  | 
 | 160 | The watchdog_get_drvdata function allows you to retrieve driver specific data. | 
 | 161 | The argument of this function is the watchdog device where you want to retrieve | 
 | 162 | data from. The function retruns the pointer to the driver specific data. |