ipq806x: backport upstream wdt driver
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.4 / 009-1-watchdog-core-add-restart-handler-support.patch
1 From 2165bf524da5f5e496d1cdb8c5afae1345ecce1e Mon Sep 17 00:00:00 2001
2 From: Damien Riegel <damien.riegel@savoirfairelinux.com>
3 Date: Mon, 16 Nov 2015 12:27:59 -0500
4 Subject: watchdog: core: add restart handler support
5
6 Many watchdog drivers implement the same code to register a restart
7 handler. This patch provides a generic way to set such a function.
8
9 The patch adds a new restart watchdog operation. If a restart priority
10 greater than 0 is needed, the driver can call
11 watchdog_set_restart_priority to set it.
12
13 Suggested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
14 Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
15 Reviewed-by: Guenter Roeck <linux@roeck-us.net>
16 Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
17 Signed-off-by: Guenter Roeck <linux@roeck-us.net>
18 Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
19 ---
20  Documentation/watchdog/watchdog-kernel-api.txt | 19 ++++++++++
21  drivers/watchdog/watchdog_core.c               | 48 ++++++++++++++++++++++++++
22  include/linux/watchdog.h                       |  6 ++++
23  3 files changed, 73 insertions(+)
24
25 --- a/Documentation/watchdog/watchdog-kernel-api.txt
26 +++ b/Documentation/watchdog/watchdog-kernel-api.txt
27 @@ -53,6 +53,7 @@ struct watchdog_device {
28         unsigned int timeout;
29         unsigned int min_timeout;
30         unsigned int max_timeout;
31 +       struct notifier_block restart_nb;
32         void *driver_data;
33         struct mutex lock;
34         unsigned long status;
35 @@ -75,6 +76,10 @@ It contains following fields:
36  * timeout: the watchdog timer's timeout value (in seconds).
37  * min_timeout: the watchdog timer's minimum timeout value (in seconds).
38  * max_timeout: the watchdog timer's maximum timeout value (in seconds).
39 +* restart_nb: notifier block that is registered for machine restart, for
40 +  internal use only. If a watchdog is capable of restarting the machine, it
41 +  should define ops->restart. Priority can be changed through
42 +  watchdog_set_restart_priority.
43  * bootstatus: status of the device after booting (reported with watchdog
44    WDIOF_* status bits).
45  * driver_data: a pointer to the drivers private data of a watchdog device.
46 @@ -100,6 +105,7 @@ struct watchdog_ops {
47         unsigned int (*status)(struct watchdog_device *);
48         int (*set_timeout)(struct watchdog_device *, unsigned int);
49         unsigned int (*get_timeleft)(struct watchdog_device *);
50 +       int (*restart)(struct watchdog_device *);
51         void (*ref)(struct watchdog_device *);
52         void (*unref)(struct watchdog_device *);
53         long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
54 @@ -164,6 +170,8 @@ they are supported. These optional routi
55    (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
56    watchdog's info structure).
57  * get_timeleft: this routines returns the time that's left before a reset.
58 +* restart: this routine restarts the machine. It returns 0 on success or a
59 +  negative errno code for failure.
60  * ref: the operation that calls kref_get on the kref of a dynamically
61    allocated watchdog_device struct.
62  * unref: the operation that calls kref_put on the kref of a dynamically
63 @@ -231,3 +239,14 @@ the device tree (if the module timeout p
64  to set the default timeout value as timeout value in the watchdog_device and
65  then use this function to set the user "preferred" timeout value.
66  This routine returns zero on success and a negative errno code for failure.
67 +
68 +To change the priority of the restart handler the following helper should be
69 +used:
70 +
71 +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
72 +
73 +User should follow the following guidelines for setting the priority:
74 +* 0: should be called in last resort, has limited restart capabilities
75 +* 128: default restart handler, use if no other handler is expected to be
76 +  available, and/or if restart is sufficient to restart the entire system
77 +* 255: highest priority, will preempt all other restart handlers
78 --- a/drivers/watchdog/watchdog_core.c
79 +++ b/drivers/watchdog/watchdog_core.c
80 @@ -32,6 +32,7 @@
81  #include <linux/types.h>       /* For standard types */
82  #include <linux/errno.h>       /* For the -ENODEV/... values */
83  #include <linux/kernel.h>      /* For printk/panic/... */
84 +#include <linux/reboot.h>      /* For restart handler */
85  #include <linux/watchdog.h>    /* For watchdog specific items */
86  #include <linux/init.h>                /* For __init/__exit/... */
87  #include <linux/idr.h>         /* For ida_* macros */
88 @@ -137,6 +138,41 @@ int watchdog_init_timeout(struct watchdo
89  }
90  EXPORT_SYMBOL_GPL(watchdog_init_timeout);
91  
92 +static int watchdog_restart_notifier(struct notifier_block *nb,
93 +                                    unsigned long action, void *data)
94 +{
95 +       struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
96 +                                                  restart_nb);
97 +
98 +       int ret;
99 +
100 +       ret = wdd->ops->restart(wdd);
101 +       if (ret)
102 +               return NOTIFY_BAD;
103 +
104 +       return NOTIFY_DONE;
105 +}
106 +
107 +/**
108 + * watchdog_set_restart_priority - Change priority of restart handler
109 + * @wdd: watchdog device
110 + * @priority: priority of the restart handler, should follow these guidelines:
111 + *   0:   use watchdog's restart function as last resort, has limited restart
112 + *        capabilies
113 + *   128: default restart handler, use if no other handler is expected to be
114 + *        available and/or if restart is sufficient to restart the entire system
115 + *   255: preempt all other handlers
116 + *
117 + * If a wdd->ops->restart function is provided when watchdog_register_device is
118 + * called, it will be registered as a restart handler with the priority given
119 + * here.
120 + */
121 +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority)
122 +{
123 +       wdd->restart_nb.priority = priority;
124 +}
125 +EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
126 +
127  static int __watchdog_register_device(struct watchdog_device *wdd)
128  {
129         int ret, id = -1, devno;
130 @@ -202,6 +238,15 @@ static int __watchdog_register_device(st
131                 return ret;
132         }
133  
134 +       if (wdd->ops->restart) {
135 +               wdd->restart_nb.notifier_call = watchdog_restart_notifier;
136 +
137 +               ret = register_restart_handler(&wdd->restart_nb);
138 +               if (ret)
139 +                       dev_warn(wdd->dev, "Cannot register restart handler (%d)\n",
140 +                                ret);
141 +       }
142 +
143         return 0;
144  }
145  
146 @@ -238,6 +283,9 @@ static void __watchdog_unregister_device
147         if (wdd == NULL)
148                 return;
149  
150 +       if (wdd->ops->restart)
151 +               unregister_restart_handler(&wdd->restart_nb);
152 +
153         devno = wdd->cdev.dev;
154         ret = watchdog_dev_unregister(wdd);
155         if (ret)
156 --- a/include/linux/watchdog.h
157 +++ b/include/linux/watchdog.h
158 @@ -12,6 +12,7 @@
159  #include <linux/bitops.h>
160  #include <linux/device.h>
161  #include <linux/cdev.h>
162 +#include <linux/notifier.h>
163  #include <uapi/linux/watchdog.h>
164  
165  struct watchdog_ops;
166 @@ -26,6 +27,7 @@ struct watchdog_device;
167   * @status:    The routine that shows the status of the watchdog device.
168   * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds).
169   * @get_timeleft:The routine that gets the time left before a reset (in seconds).
170 + * @restart:   The routine for restarting the machine.
171   * @ref:       The ref operation for dyn. allocated watchdog_device structs
172   * @unref:     The unref operation for dyn. allocated watchdog_device structs
173   * @ioctl:     The routines that handles extra ioctl calls.
174 @@ -45,6 +47,7 @@ struct watchdog_ops {
175         unsigned int (*status)(struct watchdog_device *);
176         int (*set_timeout)(struct watchdog_device *, unsigned int);
177         unsigned int (*get_timeleft)(struct watchdog_device *);
178 +       int (*restart)(struct watchdog_device *);
179         void (*ref)(struct watchdog_device *);
180         void (*unref)(struct watchdog_device *);
181         long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
182 @@ -62,6 +65,7 @@ struct watchdog_ops {
183   * @timeout:   The watchdog devices timeout value (in seconds).
184   * @min_timeout:The watchdog devices minimum timeout value (in seconds).
185   * @max_timeout:The watchdog devices maximum timeout value (in seconds).
186 + * @restart_nb:        The notifier block to register a restart function.
187   * @driver-data:Pointer to the drivers private data.
188   * @lock:      Lock for watchdog core internal use only.
189   * @status:    Field that contains the devices internal status bits.
190 @@ -88,6 +92,7 @@ struct watchdog_device {
191         unsigned int timeout;
192         unsigned int min_timeout;
193         unsigned int max_timeout;
194 +       struct notifier_block restart_nb;
195         void *driver_data;
196         struct mutex lock;
197         unsigned long status;
198 @@ -142,6 +147,7 @@ static inline void *watchdog_get_drvdata
199  }
200  
201  /* drivers/watchdog/watchdog_core.c */
202 +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
203  extern int watchdog_init_timeout(struct watchdog_device *wdd,
204                                   unsigned int timeout_parm, struct device *dev);
205  extern int watchdog_register_device(struct watchdog_device *);