aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Riegel <damien.riegel@savoirfairelinux.com>2015-11-16 12:27:59 -0500
committerWim Van Sebroeck <wim@iguana.be>2015-12-13 09:27:10 -0500
commit2165bf524da5f5e496d1cdb8c5afae1345ecce1e (patch)
tree75a24ea774d08021e1c45e201ffc9f7a164ca661
parent1f32f83e5d81c1e99a1c16366e71d5867cd1e364 (diff)
watchdog: core: add restart handler support
Many watchdog drivers implement the same code to register a restart handler. This patch provides a generic way to set such a function. The patch adds a new restart watchdog operation. If a restart priority greater than 0 is needed, the driver can call watchdog_set_restart_priority to set it. Suggested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt19
-rw-r--r--drivers/watchdog/watchdog_core.c48
-rw-r--r--include/linux/watchdog.h6
3 files changed, 73 insertions, 0 deletions
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index d8b0d3367706..dbc6a65f0bd1 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -53,6 +53,7 @@ struct watchdog_device {
53 unsigned int timeout; 53 unsigned int timeout;
54 unsigned int min_timeout; 54 unsigned int min_timeout;
55 unsigned int max_timeout; 55 unsigned int max_timeout;
56 struct notifier_block restart_nb;
56 void *driver_data; 57 void *driver_data;
57 struct mutex lock; 58 struct mutex lock;
58 unsigned long status; 59 unsigned long status;
@@ -75,6 +76,10 @@ It contains following fields:
75* timeout: the watchdog timer's timeout value (in seconds). 76* timeout: the watchdog timer's timeout value (in seconds).
76* min_timeout: the watchdog timer's minimum timeout value (in seconds). 77* min_timeout: the watchdog timer's minimum timeout value (in seconds).
77* max_timeout: the watchdog timer's maximum timeout value (in seconds). 78* max_timeout: the watchdog timer's maximum timeout value (in seconds).
79* restart_nb: notifier block that is registered for machine restart, for
80 internal use only. If a watchdog is capable of restarting the machine, it
81 should define ops->restart. Priority can be changed through
82 watchdog_set_restart_priority.
78* bootstatus: status of the device after booting (reported with watchdog 83* bootstatus: status of the device after booting (reported with watchdog
79 WDIOF_* status bits). 84 WDIOF_* status bits).
80* driver_data: a pointer to the drivers private data of a watchdog device. 85* driver_data: a pointer to the drivers private data of a watchdog device.
@@ -100,6 +105,7 @@ struct watchdog_ops {
100 unsigned int (*status)(struct watchdog_device *); 105 unsigned int (*status)(struct watchdog_device *);
101 int (*set_timeout)(struct watchdog_device *, unsigned int); 106 int (*set_timeout)(struct watchdog_device *, unsigned int);
102 unsigned int (*get_timeleft)(struct watchdog_device *); 107 unsigned int (*get_timeleft)(struct watchdog_device *);
108 int (*restart)(struct watchdog_device *);
103 void (*ref)(struct watchdog_device *); 109 void (*ref)(struct watchdog_device *);
104 void (*unref)(struct watchdog_device *); 110 void (*unref)(struct watchdog_device *);
105 long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); 111 long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
@@ -164,6 +170,8 @@ they are supported. These optional routines/operations are:
164 (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the 170 (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
165 watchdog's info structure). 171 watchdog's info structure).
166* get_timeleft: this routines returns the time that's left before a reset. 172* get_timeleft: this routines returns the time that's left before a reset.
173* restart: this routine restarts the machine. It returns 0 on success or a
174 negative errno code for failure.
167* ref: the operation that calls kref_get on the kref of a dynamically 175* ref: the operation that calls kref_get on the kref of a dynamically
168 allocated watchdog_device struct. 176 allocated watchdog_device struct.
169* unref: the operation that calls kref_put on the kref of a dynamically 177* unref: the operation that calls kref_put on the kref of a dynamically
@@ -231,3 +239,14 @@ the device tree (if the module timeout parameter is invalid). Best practice is
231to set the default timeout value as timeout value in the watchdog_device and 239to set the default timeout value as timeout value in the watchdog_device and
232then use this function to set the user "preferred" timeout value. 240then use this function to set the user "preferred" timeout value.
233This routine returns zero on success and a negative errno code for failure. 241This routine returns zero on success and a negative errno code for failure.
242
243To change the priority of the restart handler the following helper should be
244used:
245
246void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
247
248User should follow the following guidelines for setting the priority:
249* 0: should be called in last resort, has limited restart capabilities
250* 128: default restart handler, use if no other handler is expected to be
251 available, and/or if restart is sufficient to restart the entire system
252* 255: highest priority, will preempt all other restart handlers
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 873f13972cf4..88a34efac400 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -32,6 +32,7 @@
32#include <linux/types.h> /* For standard types */ 32#include <linux/types.h> /* For standard types */
33#include <linux/errno.h> /* For the -ENODEV/... values */ 33#include <linux/errno.h> /* For the -ENODEV/... values */
34#include <linux/kernel.h> /* For printk/panic/... */ 34#include <linux/kernel.h> /* For printk/panic/... */
35#include <linux/reboot.h> /* For restart handler */
35#include <linux/watchdog.h> /* For watchdog specific items */ 36#include <linux/watchdog.h> /* For watchdog specific items */
36#include <linux/init.h> /* For __init/__exit/... */ 37#include <linux/init.h> /* For __init/__exit/... */
37#include <linux/idr.h> /* For ida_* macros */ 38#include <linux/idr.h> /* For ida_* macros */
@@ -137,6 +138,41 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
137} 138}
138EXPORT_SYMBOL_GPL(watchdog_init_timeout); 139EXPORT_SYMBOL_GPL(watchdog_init_timeout);
139 140
141static int watchdog_restart_notifier(struct notifier_block *nb,
142 unsigned long action, void *data)
143{
144 struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
145 restart_nb);
146
147 int ret;
148
149 ret = wdd->ops->restart(wdd);
150 if (ret)
151 return NOTIFY_BAD;
152
153 return NOTIFY_DONE;
154}
155
156/**
157 * watchdog_set_restart_priority - Change priority of restart handler
158 * @wdd: watchdog device
159 * @priority: priority of the restart handler, should follow these guidelines:
160 * 0: use watchdog's restart function as last resort, has limited restart
161 * capabilies
162 * 128: default restart handler, use if no other handler is expected to be
163 * available and/or if restart is sufficient to restart the entire system
164 * 255: preempt all other handlers
165 *
166 * If a wdd->ops->restart function is provided when watchdog_register_device is
167 * called, it will be registered as a restart handler with the priority given
168 * here.
169 */
170void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority)
171{
172 wdd->restart_nb.priority = priority;
173}
174EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
175
140static int __watchdog_register_device(struct watchdog_device *wdd) 176static int __watchdog_register_device(struct watchdog_device *wdd)
141{ 177{
142 int ret, id = -1, devno; 178 int ret, id = -1, devno;
@@ -202,6 +238,15 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
202 return ret; 238 return ret;
203 } 239 }
204 240
241 if (wdd->ops->restart) {
242 wdd->restart_nb.notifier_call = watchdog_restart_notifier;
243
244 ret = register_restart_handler(&wdd->restart_nb);
245 if (ret)
246 dev_warn(wdd->dev, "Cannot register restart handler (%d)\n",
247 ret);
248 }
249
205 return 0; 250 return 0;
206} 251}
207 252
@@ -238,6 +283,9 @@ static void __watchdog_unregister_device(struct watchdog_device *wdd)
238 if (wdd == NULL) 283 if (wdd == NULL)
239 return; 284 return;
240 285
286 if (wdd->ops->restart)
287 unregister_restart_handler(&wdd->restart_nb);
288
241 devno = wdd->cdev.dev; 289 devno = wdd->cdev.dev;
242 ret = watchdog_dev_unregister(wdd); 290 ret = watchdog_dev_unregister(wdd);
243 if (ret) 291 if (ret)
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 027b1f43f12d..5b52c834f7aa 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -12,6 +12,7 @@
12#include <linux/bitops.h> 12#include <linux/bitops.h>
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/cdev.h> 14#include <linux/cdev.h>
15#include <linux/notifier.h>
15#include <uapi/linux/watchdog.h> 16#include <uapi/linux/watchdog.h>
16 17
17struct watchdog_ops; 18struct watchdog_ops;
@@ -26,6 +27,7 @@ struct watchdog_device;
26 * @status: The routine that shows the status of the watchdog device. 27 * @status: The routine that shows the status of the watchdog device.
27 * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds). 28 * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds).
28 * @get_timeleft:The routine that gets the time left before a reset (in seconds). 29 * @get_timeleft:The routine that gets the time left before a reset (in seconds).
30 * @restart: The routine for restarting the machine.
29 * @ref: The ref operation for dyn. allocated watchdog_device structs 31 * @ref: The ref operation for dyn. allocated watchdog_device structs
30 * @unref: The unref operation for dyn. allocated watchdog_device structs 32 * @unref: The unref operation for dyn. allocated watchdog_device structs
31 * @ioctl: The routines that handles extra ioctl calls. 33 * @ioctl: The routines that handles extra ioctl calls.
@@ -45,6 +47,7 @@ struct watchdog_ops {
45 unsigned int (*status)(struct watchdog_device *); 47 unsigned int (*status)(struct watchdog_device *);
46 int (*set_timeout)(struct watchdog_device *, unsigned int); 48 int (*set_timeout)(struct watchdog_device *, unsigned int);
47 unsigned int (*get_timeleft)(struct watchdog_device *); 49 unsigned int (*get_timeleft)(struct watchdog_device *);
50 int (*restart)(struct watchdog_device *);
48 void (*ref)(struct watchdog_device *); 51 void (*ref)(struct watchdog_device *);
49 void (*unref)(struct watchdog_device *); 52 void (*unref)(struct watchdog_device *);
50 long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); 53 long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
@@ -62,6 +65,7 @@ struct watchdog_ops {
62 * @timeout: The watchdog devices timeout value (in seconds). 65 * @timeout: The watchdog devices timeout value (in seconds).
63 * @min_timeout:The watchdog devices minimum timeout value (in seconds). 66 * @min_timeout:The watchdog devices minimum timeout value (in seconds).
64 * @max_timeout:The watchdog devices maximum timeout value (in seconds). 67 * @max_timeout:The watchdog devices maximum timeout value (in seconds).
68 * @restart_nb: The notifier block to register a restart function.
65 * @driver-data:Pointer to the drivers private data. 69 * @driver-data:Pointer to the drivers private data.
66 * @lock: Lock for watchdog core internal use only. 70 * @lock: Lock for watchdog core internal use only.
67 * @status: Field that contains the devices internal status bits. 71 * @status: Field that contains the devices internal status bits.
@@ -88,6 +92,7 @@ struct watchdog_device {
88 unsigned int timeout; 92 unsigned int timeout;
89 unsigned int min_timeout; 93 unsigned int min_timeout;
90 unsigned int max_timeout; 94 unsigned int max_timeout;
95 struct notifier_block restart_nb;
91 void *driver_data; 96 void *driver_data;
92 struct mutex lock; 97 struct mutex lock;
93 unsigned long status; 98 unsigned long status;
@@ -142,6 +147,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
142} 147}
143 148
144/* drivers/watchdog/watchdog_core.c */ 149/* drivers/watchdog/watchdog_core.c */
150void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
145extern int watchdog_init_timeout(struct watchdog_device *wdd, 151extern int watchdog_init_timeout(struct watchdog_device *wdd,
146 unsigned int timeout_parm, struct device *dev); 152 unsigned int timeout_parm, struct device *dev);
147extern int watchdog_register_device(struct watchdog_device *); 153extern int watchdog_register_device(struct watchdog_device *);