diff options
author | Pavel Kubelun <be.dissent@gmail.com> | 2016-11-04 02:12:32 +0300 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2016-11-16 10:59:30 +0100 |
commit | 793d448a51b53d81e2dbd58a5865a204de92ad34 (patch) | |
tree | c0bc1ee32bdff6336dfa73288b5d7f2ac8564a7b /target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch | |
parent | 4a6f9fc6333d5043d4ddfd25d87be3ae17f9e794 (diff) | |
download | upstream-793d448a51b53d81e2dbd58a5865a204de92ad34.tar.gz upstream-793d448a51b53d81e2dbd58a5865a204de92ad34.tar.bz2 upstream-793d448a51b53d81e2dbd58a5865a204de92ad34.zip |
ipq806x: backport upstream wdt driver
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
Diffstat (limited to 'target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch')
-rw-r--r-- | target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch b/target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch new file mode 100644 index 0000000000..0534e78a27 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/009-1-watchdog-core-add-restart-handler-support.patch @@ -0,0 +1,205 @@ +From 2165bf524da5f5e496d1cdb8c5afae1345ecce1e Mon Sep 17 00:00:00 2001 +From: Damien Riegel <damien.riegel@savoirfairelinux.com> +Date: Mon, 16 Nov 2015 12:27:59 -0500 +Subject: 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> +--- + Documentation/watchdog/watchdog-kernel-api.txt | 19 ++++++++++ + drivers/watchdog/watchdog_core.c | 48 ++++++++++++++++++++++++++ + include/linux/watchdog.h | 6 ++++ + 3 files changed, 73 insertions(+) + +--- a/Documentation/watchdog/watchdog-kernel-api.txt ++++ b/Documentation/watchdog/watchdog-kernel-api.txt +@@ -53,6 +53,7 @@ struct watchdog_device { + unsigned int timeout; + unsigned int min_timeout; + unsigned int max_timeout; ++ struct notifier_block restart_nb; + void *driver_data; + struct mutex lock; + unsigned long status; +@@ -75,6 +76,10 @@ It contains following fields: + * timeout: the watchdog timer's timeout value (in seconds). + * min_timeout: the watchdog timer's minimum timeout value (in seconds). + * max_timeout: the watchdog timer's maximum timeout value (in seconds). ++* 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. +@@ -100,6 +105,7 @@ struct watchdog_ops { + unsigned int (*status)(struct watchdog_device *); + int (*set_timeout)(struct watchdog_device *, unsigned int); + unsigned int (*get_timeleft)(struct watchdog_device *); ++ int (*restart)(struct watchdog_device *); + void (*ref)(struct watchdog_device *); + void (*unref)(struct watchdog_device *); + long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); +@@ -164,6 +170,8 @@ they are supported. These optional routi + (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the + watchdog's info structure). + * 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. + * ref: the operation that calls kref_get on the kref of a dynamically + allocated watchdog_device struct. + * unref: the operation that calls kref_put on the kref of a dynamically +@@ -231,3 +239,14 @@ the device tree (if the module timeout p + 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 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 +--- a/drivers/watchdog/watchdog_core.c ++++ b/drivers/watchdog/watchdog_core.c +@@ -32,6 +32,7 @@ + #include <linux/types.h> /* For standard types */ + #include <linux/errno.h> /* For the -ENODEV/... values */ + #include <linux/kernel.h> /* For printk/panic/... */ ++#include <linux/reboot.h> /* For restart handler */ + #include <linux/watchdog.h> /* For watchdog specific items */ + #include <linux/init.h> /* For __init/__exit/... */ + #include <linux/idr.h> /* For ida_* macros */ +@@ -137,6 +138,41 @@ int watchdog_init_timeout(struct watchdo + } + EXPORT_SYMBOL_GPL(watchdog_init_timeout); + ++static int watchdog_restart_notifier(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct watchdog_device *wdd = container_of(nb, struct watchdog_device, ++ restart_nb); ++ ++ int ret; ++ ++ ret = wdd->ops->restart(wdd); ++ if (ret) ++ return NOTIFY_BAD; ++ ++ return NOTIFY_DONE; ++} ++ ++/** ++ * watchdog_set_restart_priority - Change priority of restart handler ++ * @wdd: watchdog device ++ * @priority: priority of the restart handler, should follow these guidelines: ++ * 0: use watchdog's restart function as last resort, has limited restart ++ * capabilies ++ * 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: preempt all other handlers ++ * ++ * If a wdd->ops->restart function is provided when watchdog_register_device is ++ * called, it will be registered as a restart handler with the priority given ++ * here. ++ */ ++void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority) ++{ ++ wdd->restart_nb.priority = priority; ++} ++EXPORT_SYMBOL_GPL(watchdog_set_restart_priority); ++ + static int __watchdog_register_device(struct watchdog_device *wdd) + { + int ret, id = -1, devno; +@@ -202,6 +238,15 @@ static int __watchdog_register_device(st + return ret; + } + ++ if (wdd->ops->restart) { ++ wdd->restart_nb.notifier_call = watchdog_restart_notifier; ++ ++ ret = register_restart_handler(&wdd->restart_nb); ++ if (ret) ++ dev_warn(wdd->dev, "Cannot register restart handler (%d)\n", ++ ret); ++ } ++ + return 0; + } + +@@ -238,6 +283,9 @@ static void __watchdog_unregister_device + if (wdd == NULL) + return; + ++ if (wdd->ops->restart) ++ unregister_restart_handler(&wdd->restart_nb); ++ + devno = wdd->cdev.dev; + ret = watchdog_dev_unregister(wdd); + if (ret) +--- a/include/linux/watchdog.h ++++ b/include/linux/watchdog.h +@@ -12,6 +12,7 @@ + #include <linux/bitops.h> + #include <linux/device.h> + #include <linux/cdev.h> ++#include <linux/notifier.h> + #include <uapi/linux/watchdog.h> + + struct watchdog_ops; +@@ -26,6 +27,7 @@ struct watchdog_device; + * @status: The routine that shows the status of the watchdog device. + * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds). + * @get_timeleft:The routine that gets the time left before a reset (in seconds). ++ * @restart: The routine for restarting the machine. + * @ref: The ref operation for dyn. allocated watchdog_device structs + * @unref: The unref operation for dyn. allocated watchdog_device structs + * @ioctl: The routines that handles extra ioctl calls. +@@ -45,6 +47,7 @@ struct watchdog_ops { + unsigned int (*status)(struct watchdog_device *); + int (*set_timeout)(struct watchdog_device *, unsigned int); + unsigned int (*get_timeleft)(struct watchdog_device *); ++ int (*restart)(struct watchdog_device *); + void (*ref)(struct watchdog_device *); + void (*unref)(struct watchdog_device *); + long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); +@@ -62,6 +65,7 @@ struct watchdog_ops { + * @timeout: The watchdog devices timeout value (in seconds). + * @min_timeout:The watchdog devices minimum timeout value (in seconds). + * @max_timeout:The watchdog devices maximum timeout value (in seconds). ++ * @restart_nb: The notifier block to register a restart function. + * @driver-data:Pointer to the drivers private data. + * @lock: Lock for watchdog core internal use only. + * @status: Field that contains the devices internal status bits. +@@ -88,6 +92,7 @@ struct watchdog_device { + unsigned int timeout; + unsigned int min_timeout; + unsigned int max_timeout; ++ struct notifier_block restart_nb; + void *driver_data; + struct mutex lock; + unsigned long status; +@@ -142,6 +147,7 @@ static inline void *watchdog_get_drvdata + } + + /* drivers/watchdog/watchdog_core.c */ ++void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority); + extern int watchdog_init_timeout(struct watchdog_device *wdd, + unsigned int timeout_parm, struct device *dev); + extern int watchdog_register_device(struct watchdog_device *); |