Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 1 | The Linux WatchDog Timer Driver Core kernel API. |
| 2 | =============================================== |
Hans de Goede | e907df3 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 3 | Last reviewed: 22-May-2012 |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 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 { |
Alan Cox | 45f5fed | 2012-05-10 21:48:59 +0200 | [diff] [blame] | 42 | int id; |
| 43 | struct cdev cdev; |
Alan Cox | d6b469d | 2012-05-11 12:00:20 +0200 | [diff] [blame] | 44 | struct device *dev; |
| 45 | struct device *parent; |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 46 | const struct watchdog_info *info; |
| 47 | const struct watchdog_ops *ops; |
Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 48 | unsigned int bootstatus; |
Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 49 | unsigned int timeout; |
Wim Van Sebroeck | 3f43f68 | 2011-07-22 19:00:16 +0000 | [diff] [blame] | 50 | unsigned int min_timeout; |
| 51 | unsigned int max_timeout; |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 52 | void *driver_data; |
Hans de Goede | f4e9c82 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 53 | struct mutex lock; |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 54 | unsigned long status; |
| 55 | }; |
| 56 | |
| 57 | It contains following fields: |
Alan Cox | 45f5fed | 2012-05-10 21:48:59 +0200 | [diff] [blame] | 58 | * id: set by watchdog_register_device, id 0 is special. It has both a |
| 59 | /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old |
| 60 | /dev/watchdog miscdev. The id is set automatically when calling |
| 61 | watchdog_register_device. |
| 62 | * cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This |
| 63 | field is also populated by watchdog_register_device. |
Alan Cox | d6b469d | 2012-05-11 12:00:20 +0200 | [diff] [blame] | 64 | * dev: device under the watchdog class (created by watchdog_register_device). |
| 65 | * parent: set this to the parent device (or NULL) before calling |
| 66 | watchdog_register_device. |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 67 | * info: a pointer to a watchdog_info structure. This structure gives some |
| 68 | additional information about the watchdog timer itself. (Like it's unique name) |
| 69 | * 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] | 70 | * timeout: the watchdog timer's timeout value (in seconds). |
Wim Van Sebroeck | 3f43f68 | 2011-07-22 19:00:16 +0000 | [diff] [blame] | 71 | * min_timeout: the watchdog timer's minimum timeout value (in seconds). |
| 72 | * max_timeout: the watchdog timer's maximum timeout value (in seconds). |
Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 73 | * bootstatus: status of the device after booting (reported with watchdog |
| 74 | WDIOF_* status bits). |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 75 | * driver_data: a pointer to the drivers private data of a watchdog device. |
Devendra Naga | 2deca73 | 2012-05-14 14:33:37 +0530 | [diff] [blame] | 76 | This data should only be accessed via the watchdog_set_drvdata and |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 77 | watchdog_get_drvdata routines. |
Hans de Goede | f4e9c82 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 78 | * lock: Mutex for WatchDog Timer Driver Core internal use only. |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 79 | * 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] | 80 | 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] | 81 | running/active, is the nowayout bit set, is the device opened via |
| 82 | the /dev/watchdog interface or not, ...). |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 83 | |
| 84 | The list of watchdog operations is defined as: |
| 85 | |
| 86 | struct watchdog_ops { |
| 87 | struct module *owner; |
| 88 | /* mandatory operations */ |
| 89 | int (*start)(struct watchdog_device *); |
| 90 | int (*stop)(struct watchdog_device *); |
| 91 | /* optional operations */ |
| 92 | int (*ping)(struct watchdog_device *); |
Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 93 | unsigned int (*status)(struct watchdog_device *); |
Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 94 | int (*set_timeout)(struct watchdog_device *, unsigned int); |
Viresh Kumar | fd7b673 | 2012-03-16 09:14:00 +0100 | [diff] [blame] | 95 | unsigned int (*get_timeleft)(struct watchdog_device *); |
Hans de Goede | e907df3 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 96 | void (*ref)(struct watchdog_device *); |
| 97 | void (*unref)(struct watchdog_device *); |
Wim Van Sebroeck | 78d88fc | 2011-07-22 18:59:49 +0000 | [diff] [blame] | 98 | long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 99 | }; |
| 100 | |
| 101 | It is important that you first define the module owner of the watchdog timer |
| 102 | driver's operations. This module owner will be used to lock the module when |
| 103 | the watchdog is active. (This to avoid a system crash when you unload the |
| 104 | module and /dev/watchdog is still open). |
Hans de Goede | e907df3 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 105 | |
| 106 | If the watchdog_device struct is dynamically allocated, just locking the module |
| 107 | is not enough and a driver also needs to define the ref and unref operations to |
| 108 | ensure the structure holding the watchdog_device does not go away. |
| 109 | |
| 110 | The simplest (and usually sufficient) implementation of this is to: |
| 111 | 1) Add a kref struct to the same structure which is holding the watchdog_device |
| 112 | 2) Define a release callback for the kref which frees the struct holding both |
| 113 | 3) Call kref_init on this kref *before* calling watchdog_register_device() |
| 114 | 4) Define a ref operation calling kref_get on this kref |
| 115 | 5) Define a unref operation calling kref_put on this kref |
| 116 | 6) When it is time to cleanup: |
| 117 | * Do not kfree() the struct holding both, the last kref_put will do this! |
| 118 | * *After* calling watchdog_unregister_device() call kref_put on the kref |
| 119 | |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 120 | Some operations are mandatory and some are optional. The mandatory operations |
| 121 | are: |
| 122 | * start: this is a pointer to the routine that starts the watchdog timer |
| 123 | device. |
| 124 | The routine needs a pointer to the watchdog timer device structure as a |
| 125 | parameter. It returns zero on success or a negative errno code for failure. |
| 126 | * stop: with this routine the watchdog timer device is being stopped. |
| 127 | The routine needs a pointer to the watchdog timer device structure as a |
| 128 | parameter. It returns zero on success or a negative errno code for failure. |
| 129 | Some watchdog timer hardware can only be started and not be stopped. The |
| 130 | driver supporting this hardware needs to make sure that a start and stop |
| 131 | routine is being provided. This can be done by using a timer in the driver |
| 132 | that regularly sends a keepalive ping to the watchdog timer hardware. |
| 133 | |
| 134 | Not all watchdog timer hardware supports the same functionality. That's why |
| 135 | all other routines/operations are optional. They only need to be provided if |
| 136 | they are supported. These optional routines/operations are: |
| 137 | * ping: this is the routine that sends a keepalive ping to the watchdog timer |
| 138 | hardware. |
| 139 | The routine needs a pointer to the watchdog timer device structure as a |
| 140 | parameter. It returns zero on success or a negative errno code for failure. |
| 141 | Most hardware that does not support this as a separate function uses the |
| 142 | start function to restart the watchdog timer hardware. And that's also what |
| 143 | the watchdog timer driver core does: to send a keepalive ping to the watchdog |
| 144 | timer hardware it will either use the ping operation (when available) or the |
| 145 | start operation (when the ping operation is not available). |
Wim Van Sebroeck | c2dc00e | 2011-07-22 18:57:23 +0000 | [diff] [blame] | 146 | (Note: the WDIOC_KEEPALIVE ioctl call will only be active when the |
| 147 | WDIOF_KEEPALIVEPING bit has been set in the option field on the watchdog's |
| 148 | info structure). |
Wim Van Sebroeck | 2fa0356 | 2011-07-22 18:56:38 +0000 | [diff] [blame] | 149 | * status: this routine checks the status of the watchdog timer device. The |
| 150 | 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] | 151 | * set_timeout: this routine checks and changes the timeout of the watchdog |
| 152 | timer device. It returns 0 on success, -EINVAL for "parameter out of range" |
Hans de Goede | b10f7c1 | 2011-09-12 11:56:59 +0200 | [diff] [blame] | 153 | and -EIO for "could not write value to the watchdog". On success this |
| 154 | routine should set the timeout value of the watchdog_device to the |
| 155 | achieved timeout value (which may be different from the requested one |
| 156 | because the watchdog does not necessarily has a 1 second resolution). |
Wim Van Sebroeck | 014d694 | 2011-07-22 18:58:21 +0000 | [diff] [blame] | 157 | (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the |
| 158 | watchdog's info structure). |
Viresh Kumar | fd7b673 | 2012-03-16 09:14:00 +0100 | [diff] [blame] | 159 | * get_timeleft: this routines returns the time that's left before a reset. |
Hans de Goede | e907df3 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 160 | * ref: the operation that calls kref_get on the kref of a dynamically |
| 161 | allocated watchdog_device struct. |
| 162 | * unref: the operation that calls kref_put on the kref of a dynamically |
| 163 | allocated watchdog_device struct. |
Wim Van Sebroeck | 78d88fc | 2011-07-22 18:59:49 +0000 | [diff] [blame] | 164 | * ioctl: if this routine is present then it will be called first before we do |
| 165 | our own internal ioctl call handling. This routine should return -ENOIOCTLCMD |
| 166 | if a command is not supported. The parameters that are passed to the ioctl |
| 167 | call are: watchdog_device, cmd and arg. |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 168 | |
| 169 | The status bits should (preferably) be set with the set_bit and clear_bit alike |
| 170 | bit-operations. The status bits that are defined are: |
Wim Van Sebroeck | 234445b | 2011-07-22 18:57:55 +0000 | [diff] [blame] | 171 | * WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device |
| 172 | is active or not. When the watchdog is active after booting, then you should |
| 173 | set this status bit (Note: when you register the watchdog timer device with |
| 174 | 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] | 175 | * WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device |
| 176 | was opened via /dev/watchdog. |
| 177 | (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] | 178 | * WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character |
| 179 | has been sent (so that we can support the magic close feature). |
| 180 | (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] | 181 | * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog. |
| 182 | If this bit is set then the watchdog timer will not be able to stop. |
Hans de Goede | e907df3 | 2012-05-22 11:40:26 +0200 | [diff] [blame] | 183 | * WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core |
| 184 | after calling watchdog_unregister_device, and then checked before calling |
| 185 | any watchdog_ops, so that you can be sure that no operations (other then |
| 186 | unref) will get called after unregister, even if userspace still holds a |
| 187 | reference to /dev/watchdog |
Wim Van Sebroeck | 017cf08 | 2011-07-22 18:58:54 +0000 | [diff] [blame] | 188 | |
Wim Van Sebroeck | ff0b3cd | 2011-11-29 16:24:16 +0100 | [diff] [blame] | 189 | To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog |
| 190 | timer device) you can either: |
| 191 | * set it statically in your watchdog_device struct with |
| 192 | .status = WATCHDOG_NOWAYOUT_INIT_STATUS, |
| 193 | (this will set the value the same as CONFIG_WATCHDOG_NOWAYOUT) or |
| 194 | * use the following helper function: |
| 195 | static inline void watchdog_set_nowayout(struct watchdog_device *wdd, int nowayout) |
| 196 | |
Wim Van Sebroeck | 7e192b9 | 2011-07-22 18:59:17 +0000 | [diff] [blame] | 197 | Note: The WatchDog Timer Driver Core supports the magic close feature and |
| 198 | the nowayout feature. To use the magic close feature you must set the |
| 199 | WDIOF_MAGICCLOSE bit in the options field of the watchdog's info structure. |
| 200 | The nowayout feature will overrule the magic close feature. |
Wim Van Sebroeck | 4331604 | 2011-07-22 18:55:18 +0000 | [diff] [blame] | 201 | |
| 202 | To get or set driver specific data the following two helper functions should be |
| 203 | used: |
| 204 | |
| 205 | static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) |
| 206 | static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) |
| 207 | |
| 208 | The watchdog_set_drvdata function allows you to add driver specific data. The |
| 209 | arguments of this function are the watchdog device where you want to add the |
| 210 | driver specific data to and a pointer to the data itself. |
| 211 | |
| 212 | The watchdog_get_drvdata function allows you to retrieve driver specific data. |
| 213 | The argument of this function is the watchdog device where you want to retrieve |
Masanari Iida | e198652 | 2012-02-11 00:09:20 +0900 | [diff] [blame] | 214 | data from. The function returns the pointer to the driver specific data. |