aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch
diff options
context:
space:
mode:
authorPavel Kubelun <be.dissent@gmail.com>2016-11-04 02:12:32 +0300
committerJohn Crispin <john@phrozen.org>2016-11-16 10:59:30 +0100
commit793d448a51b53d81e2dbd58a5865a204de92ad34 (patch)
treec0bc1ee32bdff6336dfa73288b5d7f2ac8564a7b /target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch
parent4a6f9fc6333d5043d4ddfd25d87be3ae17f9e794 (diff)
downloadupstream-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-2-watchdog-core-add-reboot-notifier-support.patch')
-rw-r--r--target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch160
1 files changed, 160 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch b/target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch
new file mode 100644
index 0000000000..2afa4e566b
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-2-watchdog-core-add-reboot-notifier-support.patch
@@ -0,0 +1,160 @@
+From e131319669e0ef5e6fcd75174daeffa40492135c Mon Sep 17 00:00:00 2001
+From: Damien Riegel <damien.riegel@savoirfairelinux.com>
+Date: Fri, 20 Nov 2015 16:54:51 -0500
+Subject: watchdog: core: add reboot notifier support
+
+Many watchdog drivers register a reboot notifier in order to stop the
+watchdog on system reboot. Thus we can factorize this code in the
+watchdog core.
+
+For that purpose, a new notifier block is added in watchdog_device for
+internal use only, as well as a new watchdog_stop_on_reboot helper
+function.
+
+If this helper is called, watchdog core registers the related notifier
+block and will stop the watchdog when SYS_HALT or SYS_DOWN is received.
+
+Since this operation can be critical on some platforms, abort the device
+registration if the reboot notifier registration fails.
+
+Suggested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
+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 | 8 ++++++
+ drivers/watchdog/watchdog_core.c | 37 ++++++++++++++++++++++++++
+ include/linux/watchdog.h | 9 +++++++
+ 3 files changed, 54 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 reboot_nb;
+ struct notifier_block restart_nb;
+ void *driver_data;
+ struct mutex lock;
+@@ -76,6 +77,9 @@ 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).
++* reboot_nb: notifier block that is registered for reboot notifications, for
++ internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core
++ will stop the watchdog on such notifications.
+ * 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
+@@ -240,6 +244,10 @@ to set the default timeout value as time
+ 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 disable the watchdog on reboot, the user must call the following helper:
++
++static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
++
+ To change the priority of the restart handler the following helper should be
+ used:
+
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -138,6 +138,25 @@ int watchdog_init_timeout(struct watchdo
+ }
+ EXPORT_SYMBOL_GPL(watchdog_init_timeout);
+
++static int watchdog_reboot_notifier(struct notifier_block *nb,
++ unsigned long code, void *data)
++{
++ struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
++ reboot_nb);
++
++ if (code == SYS_DOWN || code == SYS_HALT) {
++ if (watchdog_active(wdd)) {
++ int ret;
++
++ ret = wdd->ops->stop(wdd);
++ if (ret)
++ return NOTIFY_BAD;
++ }
++ }
++
++ return NOTIFY_DONE;
++}
++
+ static int watchdog_restart_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+ {
+@@ -238,6 +257,21 @@ static int __watchdog_register_device(st
+ return ret;
+ }
+
++ if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
++ wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
++
++ ret = register_reboot_notifier(&wdd->reboot_nb);
++ if (ret) {
++ dev_err(wdd->dev, "Cannot register reboot notifier (%d)\n",
++ ret);
++ watchdog_dev_unregister(wdd);
++ device_destroy(watchdog_class, devno);
++ ida_simple_remove(&watchdog_ida, wdd->id);
++ wdd->dev = NULL;
++ return ret;
++ }
++ }
++
+ if (wdd->ops->restart) {
+ wdd->restart_nb.notifier_call = watchdog_restart_notifier;
+
+@@ -286,6 +320,9 @@ static void __watchdog_unregister_device
+ if (wdd->ops->restart)
+ unregister_restart_handler(&wdd->restart_nb);
+
++ if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
++ unregister_reboot_notifier(&wdd->reboot_nb);
++
+ devno = wdd->cdev.dev;
+ ret = watchdog_dev_unregister(wdd);
+ if (ret)
+--- a/include/linux/watchdog.h
++++ b/include/linux/watchdog.h
+@@ -65,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).
++ * @reboot_nb: The notifier block to stop watchdog on reboot.
+ * @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.
+@@ -92,6 +93,7 @@ struct watchdog_device {
+ unsigned int timeout;
+ unsigned int min_timeout;
+ unsigned int max_timeout;
++ struct notifier_block reboot_nb;
+ struct notifier_block restart_nb;
+ void *driver_data;
+ struct mutex lock;
+@@ -102,6 +104,7 @@ struct watchdog_device {
+ #define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
+ #define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
+ #define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
++#define WDOG_STOP_ON_REBOOT 5 /* Should be stopped on reboot */
+ struct list_head deferred;
+ };
+
+@@ -121,6 +124,12 @@ static inline void watchdog_set_nowayout
+ set_bit(WDOG_NO_WAY_OUT, &wdd->status);
+ }
+
++/* Use the following function to stop the watchdog on reboot */
++static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
++{
++ set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
++}
++
+ /* Use the following function to check if a timeout value is invalid */
+ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
+ {