[source] ipq806x: backport upstream wdt driver

LEDE Commits lede-commits at lists.infradead.org
Wed Nov 16 02:11:04 PST 2016


blogic pushed a commit to source.git, branch master:
https://git.lede-project.org/793d448a51b53d81e2dbd58a5865a204de92ad34

commit 793d448a51b53d81e2dbd58a5865a204de92ad34
Author: Pavel Kubelun <be.dissent at gmail.com>
AuthorDate: Fri Nov 4 02:12:32 2016 +0300

    ipq806x: backport upstream wdt driver
    
    Signed-off-by: Pavel Kubelun <be.dissent at gmail.com>
---
 target/linux/ipq806x/config-4.4                    |   1 +
 ...watchdog-core-add-restart-handler-support.patch | 205 +++++
 ...watchdog-core-add-reboot-notifier-support.patch | 160 ++++
 ...t-class-watchdog_class-instead-of-pointer.patch | 111 +++
 ...ad-device-status-through-sysfs-attributes.patch | 260 ++++++
 ...-Create-watchdog-device-in-watchdog_dev-c.patch | 261 ++++++
 ...tain-variables-based-on-variable-lifetime.patch | 969 +++++++++++++++++++++
 ...tchdog-device-from-struct-watchdog_device.patch | 117 +++
 .../009-8-watchdog-kill-unref-ref-ops.patch        |  26 +
 .../010-1-qcom-wdt-use-core-restart-handler.patch  | 113 +++
 ...-Do-not-set-dev-in-struct-watchdog_device.patch |  25 +
 ...ta-parameters-to-restart-handler-callback.patch |  51 ++
 .../010-4-watchdog-qcom-Report-reboot-reason.patch |  46 +
 ...or-standalone-watchdog-not-in-timer-block.patch | 162 ++++
 ...figure-BARK-time-in-addition-to-BITE-time.patch |  60 ++
 ...om-set-WDT_BARK_TIME-register-offset-to-o.patch |  38 -
 16 files changed, 2567 insertions(+), 38 deletions(-)

diff --git a/target/linux/ipq806x/config-4.4 b/target/linux/ipq806x/config-4.4
index e67d0f1..252e53a 100644
--- a/target/linux/ipq806x/config-4.4
+++ b/target/linux/ipq806x/config-4.4
@@ -412,6 +412,7 @@ CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_VFP=y
 CONFIG_VFPv3=y
 CONFIG_WATCHDOG_CORE=y
+# CONFIG_WATCHDOG_SYSFS is not set
 # CONFIG_WL_TI is not set
 CONFIG_XPS=y
 CONFIG_XZ_DEC_ARM=y
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 0000000..0534e78
--- /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 at 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 at savoirfairelinux.com>
+Signed-off-by: Damien Riegel <damien.riegel at savoirfairelinux.com>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Reviewed-by: Vivien Didelot <vivien.didelot at savoirfairelinux.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at 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 *);
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 0000000..2afa4e5
--- /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 at 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 at savoirfairelinux.com>
+Signed-off-by: Damien Riegel <damien.riegel at savoirfairelinux.com>
+Reviewed-by: Vivien Didelot <vivien.didelot at savoirfairelinux.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at 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)
+ {
diff --git a/target/linux/ipq806x/patches-4.4/009-3-watchdog-Use-static-struct-class-watchdog_class-instead-of-pointer.patch b/target/linux/ipq806x/patches-4.4/009-3-watchdog-Use-static-struct-class-watchdog_class-instead-of-pointer.patch
new file mode 100644
index 0000000..1906a1f
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-3-watchdog-Use-static-struct-class-watchdog_class-instead-of-pointer.patch
@@ -0,0 +1,111 @@
+From 906d7a5cfeda508e7361f021605579a00cd82815 Mon Sep 17 00:00:00 2001
+From: Pratyush Anand <panand at redhat.com>
+Date: Thu, 17 Dec 2015 17:53:58 +0530
+Subject: watchdog: Use static struct class watchdog_class in stead of pointer
+
+We need few sysfs attributes to know different status of a watchdog device.
+To do that, we need to associate .dev_groups with watchdog_class. So
+convert it from pointer to static.
+Putting this static struct in watchdog_dev.c, so that static device
+attributes defined in that file can be attached to it.
+
+Signed-off-by: Pratyush Anand <panand at redhat.com>
+Suggested-by: Guenter Roeck <linux at roeck-us.net>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/watchdog_core.c | 15 ++-------------
+ drivers/watchdog/watchdog_core.h |  2 +-
+ drivers/watchdog/watchdog_dev.c  | 26 ++++++++++++++++++++++----
+ 3 files changed, 25 insertions(+), 18 deletions(-)
+
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -370,19 +370,9 @@ static int __init watchdog_deferred_regi
+ 
+ static int __init watchdog_init(void)
+ {
+-	int err;
+-
+-	watchdog_class = class_create(THIS_MODULE, "watchdog");
+-	if (IS_ERR(watchdog_class)) {
+-		pr_err("couldn't create class\n");
++	watchdog_class = watchdog_dev_init();
++	if (IS_ERR(watchdog_class))
+ 		return PTR_ERR(watchdog_class);
+-	}
+-
+-	err = watchdog_dev_init();
+-	if (err < 0) {
+-		class_destroy(watchdog_class);
+-		return err;
+-	}
+ 
+ 	watchdog_deferred_registration();
+ 	return 0;
+@@ -391,7 +381,6 @@ static int __init watchdog_init(void)
+ static void __exit watchdog_exit(void)
+ {
+ 	watchdog_dev_exit();
+-	class_destroy(watchdog_class);
+ 	ida_destroy(&watchdog_ida);
+ }
+ 
+--- a/drivers/watchdog/watchdog_core.h
++++ b/drivers/watchdog/watchdog_core.h
+@@ -33,5 +33,5 @@
+  */
+ extern int watchdog_dev_register(struct watchdog_device *);
+ extern int watchdog_dev_unregister(struct watchdog_device *);
+-extern int __init watchdog_dev_init(void);
++extern struct class * __init watchdog_dev_init(void);
+ extern void __exit watchdog_dev_exit(void);
+--- a/drivers/watchdog/watchdog_dev.c
++++ b/drivers/watchdog/watchdog_dev.c
+@@ -581,18 +581,35 @@ int watchdog_dev_unregister(struct watch
+ 	return 0;
+ }
+ 
++static struct class watchdog_class = {
++	.name =		"watchdog",
++	.owner =	THIS_MODULE,
++};
++
+ /*
+  *	watchdog_dev_init: init dev part of watchdog core
+  *
+  *	Allocate a range of chardev nodes to use for watchdog devices
+  */
+ 
+-int __init watchdog_dev_init(void)
++struct class * __init watchdog_dev_init(void)
+ {
+-	int err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
+-	if (err < 0)
++	int err;
++
++	err = class_register(&watchdog_class);
++	if (err < 0) {
++		pr_err("couldn't register class\n");
++		return ERR_PTR(err);
++	}
++
++	err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
++	if (err < 0) {
+ 		pr_err("watchdog: unable to allocate char dev region\n");
+-	return err;
++		class_unregister(&watchdog_class);
++		return ERR_PTR(err);
++	}
++
++	return &watchdog_class;
+ }
+ 
+ /*
+@@ -604,4 +621,5 @@ int __init watchdog_dev_init(void)
+ void __exit watchdog_dev_exit(void)
+ {
+ 	unregister_chrdev_region(watchdog_devt, MAX_DOGS);
++	class_unregister(&watchdog_class);
+ }
diff --git a/target/linux/ipq806x/patches-4.4/009-4-watchdog-Read-device-status-through-sysfs-attributes.patch b/target/linux/ipq806x/patches-4.4/009-4-watchdog-Read-device-status-through-sysfs-attributes.patch
new file mode 100644
index 0000000..fd4b38a
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-4-watchdog-Read-device-status-through-sysfs-attributes.patch
@@ -0,0 +1,260 @@
+From 33b711269ade3f6bc9d9d15e4343e6fa922d999b Mon Sep 17 00:00:00 2001
+From: Pratyush Anand <panand at redhat.com>
+Date: Thu, 17 Dec 2015 17:53:59 +0530
+Subject: watchdog: Read device status through sysfs attributes
+
+This patch adds following attributes to watchdog device's sysfs interface
+to read its different status.
+
+* state - reads whether device is active or not
+* identity - reads Watchdog device's identity string.
+* timeout - reads current timeout.
+* timeleft - reads timeleft before watchdog generates a reset
+* bootstatus - reads status of the watchdog device at boot
+* status - reads watchdog device's  internal status bits
+* nowayout - reads whether nowayout feature was set or not
+
+Testing with iTCO_wdt:
+ # cd /sys/class/watchdog/watchdog1/
+ # ls
+bootstatus  dev  device  identity  nowayout  power  state
+subsystem  timeleft  timeout  uevent
+ # cat identity
+iTCO_wdt
+ # cat timeout
+30
+ # cat state
+inactive
+ # echo > /dev/watchdog1
+ # cat timeleft
+26
+ # cat state
+active
+ # cat bootstatus
+0
+ # cat nowayout
+0
+
+Signed-off-by: Pratyush Anand <panand at redhat.com>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ Documentation/ABI/testing/sysfs-class-watchdog |  51 +++++++++++
+ drivers/watchdog/Kconfig                       |   7 ++
+ drivers/watchdog/watchdog_core.c               |   2 +-
+ drivers/watchdog/watchdog_dev.c                | 114 +++++++++++++++++++++++++
+ 4 files changed, 173 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-class-watchdog
+
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-watchdog
+@@ -0,0 +1,51 @@
++What:		/sys/class/watchdog/watchdogn/bootstatus
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It contains status of the watchdog
++		device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
++		ioctl interface.
++
++What:		/sys/class/watchdog/watchdogn/identity
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It contains identity string of
++		watchdog device.
++
++What:		/sys/class/watchdog/watchdogn/nowayout
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. While reading, it gives '1' if that
++		device supports nowayout feature else, it gives '0'.
++
++What:		/sys/class/watchdog/watchdogn/state
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It gives active/inactive status of
++		watchdog device.
++
++What:		/sys/class/watchdog/watchdogn/status
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It contains watchdog device's
++		internal status bits. It is equivalent to WDIOC_GETSTATUS
++		of ioctl interface.
++
++What:		/sys/class/watchdog/watchdogn/timeleft
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It contains value of time left for
++		reset generation. It is equivalent to WDIOC_GETTIMELEFT of
++		ioctl interface.
++
++What:		/sys/class/watchdog/watchdogn/timeout
++Date:		August 2015
++Contact:	Wim Van Sebroeck <wim at iguana.be>
++Description:
++		It is a read only file. It is read to know about current
++		value of timeout programmed.
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -46,6 +46,13 @@ config WATCHDOG_NOWAYOUT
+ 	  get killed. If you say Y here, the watchdog cannot be stopped once
+ 	  it has been started.
+ 
++config WATCHDOG_SYSFS
++	bool "Read different watchdog information through sysfs"
++	default n
++	help
++	  Say Y here if you want to enable watchdog device status read through
++	  sysfs attributes.
++
+ #
+ # General Watchdog drivers
+ #
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -249,7 +249,7 @@ static int __watchdog_register_device(st
+ 
+ 	devno = wdd->cdev.dev;
+ 	wdd->dev = device_create(watchdog_class, wdd->parent, devno,
+-					NULL, "watchdog%d", wdd->id);
++					wdd, "watchdog%d", wdd->id);
+ 	if (IS_ERR(wdd->dev)) {
+ 		watchdog_dev_unregister(wdd);
+ 		ida_simple_remove(&watchdog_ida, id);
+--- a/drivers/watchdog/watchdog_dev.c
++++ b/drivers/watchdog/watchdog_dev.c
+@@ -247,6 +247,119 @@ out_timeleft:
+ 	return err;
+ }
+ 
++#ifdef CONFIG_WATCHDOG_SYSFS
++static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++
++	return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
++}
++static DEVICE_ATTR_RO(nowayout);
++
++static ssize_t status_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++	ssize_t status;
++	unsigned int val;
++
++	status = watchdog_get_status(wdd, &val);
++	if (!status)
++		status = sprintf(buf, "%u\n", val);
++
++	return status;
++}
++static DEVICE_ATTR_RO(status);
++
++static ssize_t bootstatus_show(struct device *dev,
++				struct device_attribute *attr, char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++
++	return sprintf(buf, "%u\n", wdd->bootstatus);
++}
++static DEVICE_ATTR_RO(bootstatus);
++
++static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++	ssize_t status;
++	unsigned int val;
++
++	status = watchdog_get_timeleft(wdd, &val);
++	if (!status)
++		status = sprintf(buf, "%u\n", val);
++
++	return status;
++}
++static DEVICE_ATTR_RO(timeleft);
++
++static ssize_t timeout_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++
++	return sprintf(buf, "%u\n", wdd->timeout);
++}
++static DEVICE_ATTR_RO(timeout);
++
++static ssize_t identity_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++
++	return sprintf(buf, "%s\n", wdd->info->identity);
++}
++static DEVICE_ATTR_RO(identity);
++
++static ssize_t state_show(struct device *dev, struct device_attribute *attr,
++				char *buf)
++{
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++
++	if (watchdog_active(wdd))
++		return sprintf(buf, "active\n");
++
++	return sprintf(buf, "inactive\n");
++}
++static DEVICE_ATTR_RO(state);
++
++static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
++				int n)
++{
++	struct device *dev = container_of(kobj, struct device, kobj);
++	struct watchdog_device *wdd = dev_get_drvdata(dev);
++	umode_t mode = attr->mode;
++
++	if (attr == &dev_attr_status.attr && !wdd->ops->status)
++		mode = 0;
++	else if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft)
++		mode = 0;
++
++	return mode;
++}
++static struct attribute *wdt_attrs[] = {
++	&dev_attr_state.attr,
++	&dev_attr_identity.attr,
++	&dev_attr_timeout.attr,
++	&dev_attr_timeleft.attr,
++	&dev_attr_bootstatus.attr,
++	&dev_attr_status.attr,
++	&dev_attr_nowayout.attr,
++	NULL,
++};
++
++static const struct attribute_group wdt_group = {
++	.attrs = wdt_attrs,
++	.is_visible = wdt_is_visible,
++};
++__ATTRIBUTE_GROUPS(wdt);
++#else
++#define wdt_groups	NULL
++#endif
++
+ /*
+  *	watchdog_ioctl_op: call the watchdog drivers ioctl op if defined
+  *	@wdd: the watchdog device to do the ioctl on
+@@ -584,6 +697,7 @@ int watchdog_dev_unregister(struct watch
+ static struct class watchdog_class = {
+ 	.name =		"watchdog",
+ 	.owner =	THIS_MODULE,
++	.dev_groups =	wdt_groups,
+ };
+ 
+ /*
diff --git a/target/linux/ipq806x/patches-4.4/009-5-watchdog-Create-watchdog-device-in-watchdog_dev-c.patch b/target/linux/ipq806x/patches-4.4/009-5-watchdog-Create-watchdog-device-in-watchdog_dev-c.patch
new file mode 100644
index 0000000..059ebdd
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-5-watchdog-Create-watchdog-device-in-watchdog_dev-c.patch
@@ -0,0 +1,261 @@
+From 32ecc6392654a0db34b310e8924b5b2c3b8bf503 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux at roeck-us.net>
+Date: Fri, 25 Dec 2015 16:01:40 -0800
+Subject: watchdog: Create watchdog device in watchdog_dev.c
+
+The watchdog character device is currently created in watchdog_dev.c,
+and the watchdog device in watchdog_core.c. This results in
+cross-dependencies, since device creation needs to know the watchdog
+character device number as well as the watchdog class, both of which
+reside in watchdog_dev.c.
+
+Create the watchdog device in watchdog_dev.c to simplify the code.
+
+Inspired by earlier patch set from Damien Riegel.
+
+Cc: Damien Riegel <damien.riegel at savoirfairelinux.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/watchdog_core.c | 33 ++++--------------
+ drivers/watchdog/watchdog_core.h |  4 +--
+ drivers/watchdog/watchdog_dev.c  | 73 +++++++++++++++++++++++++++++++++-------
+ 3 files changed, 69 insertions(+), 41 deletions(-)
+
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -42,7 +42,6 @@
+ #include "watchdog_core.h"	/* For watchdog_dev_register/... */
+ 
+ static DEFINE_IDA(watchdog_ida);
+-static struct class *watchdog_class;
+ 
+ /*
+  * Deferred Registration infrastructure.
+@@ -194,7 +193,7 @@ EXPORT_SYMBOL_GPL(watchdog_set_restart_p
+ 
+ static int __watchdog_register_device(struct watchdog_device *wdd)
+ {
+-	int ret, id = -1, devno;
++	int ret, id = -1;
+ 
+ 	if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
+ 		return -EINVAL;
+@@ -247,16 +246,6 @@ static int __watchdog_register_device(st
+ 		}
+ 	}
+ 
+-	devno = wdd->cdev.dev;
+-	wdd->dev = device_create(watchdog_class, wdd->parent, devno,
+-					wdd, "watchdog%d", wdd->id);
+-	if (IS_ERR(wdd->dev)) {
+-		watchdog_dev_unregister(wdd);
+-		ida_simple_remove(&watchdog_ida, id);
+-		ret = PTR_ERR(wdd->dev);
+-		return ret;
+-	}
+-
+ 	if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
+ 		wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
+ 
+@@ -265,9 +254,7 @@ static int __watchdog_register_device(st
+ 			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;
+ 		}
+ 	}
+@@ -311,9 +298,6 @@ EXPORT_SYMBOL_GPL(watchdog_register_devi
+ 
+ static void __watchdog_unregister_device(struct watchdog_device *wdd)
+ {
+-	int ret;
+-	int devno;
+-
+ 	if (wdd == NULL)
+ 		return;
+ 
+@@ -323,13 +307,8 @@ static void __watchdog_unregister_device
+ 	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)
+-		pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
+-	device_destroy(watchdog_class, devno);
++	watchdog_dev_unregister(wdd);
+ 	ida_simple_remove(&watchdog_ida, wdd->id);
+-	wdd->dev = NULL;
+ }
+ 
+ /**
+@@ -370,9 +349,11 @@ static int __init watchdog_deferred_regi
+ 
+ static int __init watchdog_init(void)
+ {
+-	watchdog_class = watchdog_dev_init();
+-	if (IS_ERR(watchdog_class))
+-		return PTR_ERR(watchdog_class);
++	int err;
++
++	err = watchdog_dev_init();
++	if (err < 0)
++		return err;
+ 
+ 	watchdog_deferred_registration();
+ 	return 0;
+--- a/drivers/watchdog/watchdog_core.h
++++ b/drivers/watchdog/watchdog_core.h
+@@ -32,6 +32,6 @@
+  *	Functions/procedures to be called by the core
+  */
+ extern int watchdog_dev_register(struct watchdog_device *);
+-extern int watchdog_dev_unregister(struct watchdog_device *);
+-extern struct class * __init watchdog_dev_init(void);
++extern void watchdog_dev_unregister(struct watchdog_device *);
++extern int __init watchdog_dev_init(void);
+ extern void __exit watchdog_dev_exit(void);
+--- a/drivers/watchdog/watchdog_dev.c
++++ b/drivers/watchdog/watchdog_dev.c
+@@ -628,17 +628,18 @@ static struct miscdevice watchdog_miscde
+ };
+ 
+ /*
+- *	watchdog_dev_register: register a watchdog device
++ *	watchdog_cdev_register: register watchdog character device
+  *	@wdd: watchdog device
++ *	@devno: character device number
+  *
+- *	Register a watchdog device including handling the legacy
++ *	Register a watchdog character device including handling the legacy
+  *	/dev/watchdog node. /dev/watchdog is actually a miscdevice and
+  *	thus we set it up like that.
+  */
+ 
+-int watchdog_dev_register(struct watchdog_device *wdd)
++static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
+ {
+-	int err, devno;
++	int err;
+ 
+ 	if (wdd->id == 0) {
+ 		old_wdd = wdd;
+@@ -656,7 +657,6 @@ int watchdog_dev_register(struct watchdo
+ 	}
+ 
+ 	/* Fill in the data structures */
+-	devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
+ 	cdev_init(&wdd->cdev, &watchdog_fops);
+ 	wdd->cdev.owner = wdd->ops->owner;
+ 
+@@ -674,13 +674,14 @@ int watchdog_dev_register(struct watchdo
+ }
+ 
+ /*
+- *	watchdog_dev_unregister: unregister a watchdog device
++ *	watchdog_cdev_unregister: unregister watchdog character device
+  *	@watchdog: watchdog device
+  *
+- *	Unregister the watchdog and if needed the legacy /dev/watchdog device.
++ *	Unregister watchdog character device and if needed the legacy
++ *	/dev/watchdog device.
+  */
+ 
+-int watchdog_dev_unregister(struct watchdog_device *wdd)
++static void watchdog_cdev_unregister(struct watchdog_device *wdd)
+ {
+ 	mutex_lock(&wdd->lock);
+ 	set_bit(WDOG_UNREGISTERED, &wdd->status);
+@@ -691,7 +692,6 @@ int watchdog_dev_unregister(struct watch
+ 		misc_deregister(&watchdog_miscdev);
+ 		old_wdd = NULL;
+ 	}
+-	return 0;
+ }
+ 
+ static struct class watchdog_class = {
+@@ -701,29 +701,76 @@ static struct class watchdog_class = {
+ };
+ 
+ /*
++ *	watchdog_dev_register: register a watchdog device
++ *	@wdd: watchdog device
++ *
++ *	Register a watchdog device including handling the legacy
++ *	/dev/watchdog node. /dev/watchdog is actually a miscdevice and
++ *	thus we set it up like that.
++ */
++
++int watchdog_dev_register(struct watchdog_device *wdd)
++{
++	struct device *dev;
++	dev_t devno;
++	int ret;
++
++	devno = MKDEV(MAJOR(watchdog_devt), wdd->id);
++
++	ret = watchdog_cdev_register(wdd, devno);
++	if (ret)
++		return ret;
++
++	dev = device_create(&watchdog_class, wdd->parent, devno, wdd,
++			    "watchdog%d", wdd->id);
++	if (IS_ERR(dev)) {
++		watchdog_cdev_unregister(wdd);
++		return PTR_ERR(dev);
++	}
++	wdd->dev = dev;
++
++	return ret;
++}
++
++/*
++ *	watchdog_dev_unregister: unregister a watchdog device
++ *	@watchdog: watchdog device
++ *
++ *	Unregister watchdog device and if needed the legacy
++ *	/dev/watchdog device.
++ */
++
++void watchdog_dev_unregister(struct watchdog_device *wdd)
++{
++	watchdog_cdev_unregister(wdd);
++	device_destroy(&watchdog_class, wdd->dev->devt);
++	wdd->dev = NULL;
++}
++
++/*
+  *	watchdog_dev_init: init dev part of watchdog core
+  *
+  *	Allocate a range of chardev nodes to use for watchdog devices
+  */
+ 
+-struct class * __init watchdog_dev_init(void)
++int __init watchdog_dev_init(void)
+ {
+ 	int err;
+ 
+ 	err = class_register(&watchdog_class);
+ 	if (err < 0) {
+ 		pr_err("couldn't register class\n");
+-		return ERR_PTR(err);
++		return err;
+ 	}
+ 
+ 	err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
+ 	if (err < 0) {
+ 		pr_err("watchdog: unable to allocate char dev region\n");
+ 		class_unregister(&watchdog_class);
+-		return ERR_PTR(err);
++		return err;
+ 	}
+ 
+-	return &watchdog_class;
++	return 0;
+ }
+ 
+ /*
diff --git a/target/linux/ipq806x/patches-4.4/009-6-watchdog-Separate-and-maintain-variables-based-on-variable-lifetime.patch b/target/linux/ipq806x/patches-4.4/009-6-watchdog-Separate-and-maintain-variables-based-on-variable-lifetime.patch
new file mode 100644
index 0000000..214dabf
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-6-watchdog-Separate-and-maintain-variables-based-on-variable-lifetime.patch
@@ -0,0 +1,969 @@
+From b4ffb1909843b28f3b1b60197d517b123b7a9b66 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux at roeck-us.net>
+Date: Fri, 25 Dec 2015 16:01:42 -0800
+Subject: watchdog: Separate and maintain variables based on variable lifetime
+
+All variables required by the watchdog core to manage a watchdog are
+currently stored in struct watchdog_device. The lifetime of those
+variables is determined by the watchdog driver. However, the lifetime
+of variables used by the watchdog core differs from the lifetime of
+struct watchdog_device. To remedy this situation, watchdog drivers
+can implement ref and unref callbacks, to be used by the watchdog
+core to lock struct watchdog_device in memory.
+
+While this solves the immediate problem, it depends on watchdog drivers
+to actually implement the ref/unref callbacks. This is error prone,
+often not implemented in the first place, or not implemented correctly.
+
+To solve the problem without requiring driver support, split the variables
+in struct watchdog_device into two data structures - one for variables
+associated with the watchdog driver, one for variables associated with
+the watchdog core. With this approach, the watchdog core can keep track
+of its variable lifetime and no longer depends on ref/unref callbacks
+in the driver. As a side effect, some of the variables originally in
+struct watchdog_driver are now private to the watchdog core and no longer
+visible in watchdog drivers.
+
+As a side effect of the changes made, an ioctl will now always fail
+with -ENODEV after a watchdog device was unregistered with the character
+device still open. Previously, it would only fail with -ENODEV in some
+situations. Also, ioctl operations are now atomic from driver perspective.
+With this change, it is now guaranteed that the driver will not unregister
+a watchdog between a timeout change and the subsequent ping.
+
+The 'ref' and 'unref' callbacks in struct watchdog_driver are no longer
+used and marked as deprecated.
+
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ Documentation/watchdog/watchdog-kernel-api.txt |  45 +--
+ drivers/watchdog/watchdog_core.c               |   2 -
+ drivers/watchdog/watchdog_dev.c                | 383 +++++++++++++------------
+ include/linux/watchdog.h                       |  22 +-
+ 4 files changed, 218 insertions(+), 234 deletions(-)
+
+--- a/Documentation/watchdog/watchdog-kernel-api.txt
++++ b/Documentation/watchdog/watchdog-kernel-api.txt
+@@ -44,7 +44,6 @@ The watchdog device structure looks like
+ 
+ struct watchdog_device {
+ 	int id;
+-	struct cdev cdev;
+ 	struct device *dev;
+ 	struct device *parent;
+ 	const struct watchdog_info *info;
+@@ -56,7 +55,7 @@ struct watchdog_device {
+ 	struct notifier_block reboot_nb;
+ 	struct notifier_block restart_nb;
+ 	void *driver_data;
+-	struct mutex lock;
++	struct watchdog_core_data *wd_data;
+ 	unsigned long status;
+ 	struct list_head deferred;
+ };
+@@ -66,8 +65,6 @@ It contains following fields:
+   /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
+   /dev/watchdog miscdev. The id is set automatically when calling
+   watchdog_register_device.
+-* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This
+-  field is also populated by watchdog_register_device.
+ * dev: device under the watchdog class (created by watchdog_register_device).
+ * parent: set this to the parent device (or NULL) before calling
+   watchdog_register_device.
+@@ -89,11 +86,10 @@ It contains following fields:
+ * driver_data: a pointer to the drivers private data of a watchdog device.
+   This data should only be accessed via the watchdog_set_drvdata and
+   watchdog_get_drvdata routines.
+-* lock: Mutex for WatchDog Timer Driver Core internal use only.
++* wd_data: a pointer to watchdog core internal data.
+ * status: this field contains a number of status bits that give extra
+   information about the status of the device (Like: is the watchdog timer
+-  running/active, is the nowayout bit set, is the device opened via
+-  the /dev/watchdog interface or not, ...).
++  running/active, or is the nowayout bit set).
+ * deferred: entry in wtd_deferred_reg_list which is used to
+   register early initialized watchdogs.
+ 
+@@ -110,8 +106,8 @@ struct watchdog_ops {
+ 	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 *);
++	void (*ref)(struct watchdog_device *) __deprecated;
++	void (*unref)(struct watchdog_device *) __deprecated;
+ 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+ };
+ 
+@@ -120,20 +116,6 @@ driver's operations. This module owner w
+ the watchdog is active. (This to avoid a system crash when you unload the
+ module and /dev/watchdog is still open).
+ 
+-If the watchdog_device struct is dynamically allocated, just locking the module
+-is not enough and a driver also needs to define the ref and unref operations to
+-ensure the structure holding the watchdog_device does not go away.
+-
+-The simplest (and usually sufficient) implementation of this is to:
+-1) Add a kref struct to the same structure which is holding the watchdog_device
+-2) Define a release callback for the kref which frees the struct holding both
+-3) Call kref_init on this kref *before* calling watchdog_register_device()
+-4) Define a ref operation calling kref_get on this kref
+-5) Define a unref operation calling kref_put on this kref
+-6) When it is time to cleanup:
+- * Do not kfree() the struct holding both, the last kref_put will do this!
+- * *After* calling watchdog_unregister_device() call kref_put on the kref
+-
+ Some operations are mandatory and some are optional. The mandatory operations
+ are:
+ * start: this is a pointer to the routine that starts the watchdog timer
+@@ -176,34 +158,21 @@ they are supported. These optional routi
+ * 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
+-  allocated watchdog_device struct.
+ * ioctl: if this routine is present then it will be called first before we do
+   our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
+   if a command is not supported. The parameters that are passed to the ioctl
+   call are: watchdog_device, cmd and arg.
+ 
++The 'ref' and 'unref' operations are no longer used and deprecated.
++
+ The status bits should (preferably) be set with the set_bit and clear_bit alike
+ bit-operations. The status bits that are defined are:
+ * WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
+   is active or not. When the watchdog is active after booting, then you should
+   set this status bit (Note: when you register the watchdog timer device with
+   this bit set, then opening /dev/watchdog will skip the start operation)
+-* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
+-  was opened via /dev/watchdog.
+-  (This bit should only be used by the WatchDog Timer Driver Core).
+-* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
+-  has been sent (so that we can support the magic close feature).
+-  (This bit should only be used by the WatchDog Timer Driver Core).
+ * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
+   If this bit is set then the watchdog timer will not be able to stop.
+-* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core
+-  after calling watchdog_unregister_device, and then checked before calling
+-  any watchdog_ops, so that you can be sure that no operations (other then
+-  unref) will get called after unregister, even if userspace still holds a
+-  reference to /dev/watchdog
+ 
+   To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog
+   timer device) you can either:
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -210,8 +210,6 @@ static int __watchdog_register_device(st
+ 	 * corrupted in a later stage then we expect a kernel panic!
+ 	 */
+ 
+-	mutex_init(&wdd->lock);
+-
+ 	/* Use alias for watchdog id if possible */
+ 	if (wdd->parent) {
+ 		ret = of_alias_get_id(wdd->parent->of_node, "watchdog");
+--- a/drivers/watchdog/watchdog_dev.c
++++ b/drivers/watchdog/watchdog_dev.c
+@@ -32,27 +32,51 @@
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ 
+-#include <linux/module.h>	/* For module stuff/... */
+-#include <linux/types.h>	/* For standard types (like size_t) */
++#include <linux/cdev.h>		/* For character device */
+ #include <linux/errno.h>	/* For the -ENODEV/... values */
+-#include <linux/kernel.h>	/* For printk/panic/... */
+ #include <linux/fs.h>		/* For file operations */
+-#include <linux/watchdog.h>	/* For watchdog specific items */
+-#include <linux/miscdevice.h>	/* For handling misc devices */
+ #include <linux/init.h>		/* For __init/__exit/... */
++#include <linux/kernel.h>	/* For printk/panic/... */
++#include <linux/kref.h>		/* For data references */
++#include <linux/miscdevice.h>	/* For handling misc devices */
++#include <linux/module.h>	/* For module stuff/... */
++#include <linux/mutex.h>	/* For mutexes */
++#include <linux/slab.h>		/* For memory functions */
++#include <linux/types.h>	/* For standard types (like size_t) */
++#include <linux/watchdog.h>	/* For watchdog specific items */
+ #include <linux/uaccess.h>	/* For copy_to_user/put_user/... */
+ 
+ #include "watchdog_core.h"
+ 
++/*
++ * struct watchdog_core_data - watchdog core internal data
++ * @kref:	Reference count.
++ * @cdev:	The watchdog's Character device.
++ * @wdd:	Pointer to watchdog device.
++ * @lock:	Lock for watchdog core.
++ * @status:	Watchdog core internal status bits.
++ */
++struct watchdog_core_data {
++	struct kref kref;
++	struct cdev cdev;
++	struct watchdog_device *wdd;
++	struct mutex lock;
++	unsigned long status;		/* Internal status bits */
++#define _WDOG_DEV_OPEN		0	/* Opened ? */
++#define _WDOG_ALLOW_RELEASE	1	/* Did we receive the magic char ? */
++};
++
+ /* the dev_t structure to store the dynamically allocated watchdog devices */
+ static dev_t watchdog_devt;
+-/* the watchdog device behind /dev/watchdog */
+-static struct watchdog_device *old_wdd;
++/* Reference to watchdog device behind /dev/watchdog */
++static struct watchdog_core_data *old_wd_data;
+ 
+ /*
+  *	watchdog_ping: ping the watchdog.
+  *	@wdd: the watchdog device to ping
+  *
++ *	The caller must hold wd_data->lock.
++ *
+  *	If the watchdog has no own ping operation then it needs to be
+  *	restarted via the start operation. This wrapper function does
+  *	exactly that.
+@@ -61,25 +85,16 @@ static struct watchdog_device *old_wdd;
+ 
+ static int watchdog_ping(struct watchdog_device *wdd)
+ {
+-	int err = 0;
+-
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_ping;
+-	}
++	int err;
+ 
+ 	if (!watchdog_active(wdd))
+-		goto out_ping;
++		return 0;
+ 
+ 	if (wdd->ops->ping)
+ 		err = wdd->ops->ping(wdd);	/* ping the watchdog */
+ 	else
+ 		err = wdd->ops->start(wdd);	/* restart watchdog */
+ 
+-out_ping:
+-	mutex_unlock(&wdd->lock);
+ 	return err;
+ }
+ 
+@@ -87,6 +102,8 @@ out_ping:
+  *	watchdog_start: wrapper to start the watchdog.
+  *	@wdd: the watchdog device to start
+  *
++ *	The caller must hold wd_data->lock.
++ *
+  *	Start the watchdog if it is not active and mark it active.
+  *	This function returns zero on success or a negative errno code for
+  *	failure.
+@@ -94,24 +111,15 @@ out_ping:
+ 
+ static int watchdog_start(struct watchdog_device *wdd)
+ {
+-	int err = 0;
+-
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_start;
+-	}
++	int err;
+ 
+ 	if (watchdog_active(wdd))
+-		goto out_start;
++		return 0;
+ 
+ 	err = wdd->ops->start(wdd);
+ 	if (err == 0)
+ 		set_bit(WDOG_ACTIVE, &wdd->status);
+ 
+-out_start:
+-	mutex_unlock(&wdd->lock);
+ 	return err;
+ }
+ 
+@@ -119,6 +127,8 @@ out_start:
+  *	watchdog_stop: wrapper to stop the watchdog.
+  *	@wdd: the watchdog device to stop
+  *
++ *	The caller must hold wd_data->lock.
++ *
+  *	Stop the watchdog if it is still active and unmark it active.
+  *	This function returns zero on success or a negative errno code for
+  *	failure.
+@@ -127,93 +137,58 @@ out_start:
+ 
+ static int watchdog_stop(struct watchdog_device *wdd)
+ {
+-	int err = 0;
+-
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_stop;
+-	}
++	int err;
+ 
+ 	if (!watchdog_active(wdd))
+-		goto out_stop;
++		return 0;
+ 
+ 	if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+ 		dev_info(wdd->dev, "nowayout prevents watchdog being stopped!\n");
+-		err = -EBUSY;
+-		goto out_stop;
++		return -EBUSY;
+ 	}
+ 
+ 	err = wdd->ops->stop(wdd);
+ 	if (err == 0)
+ 		clear_bit(WDOG_ACTIVE, &wdd->status);
+ 
+-out_stop:
+-	mutex_unlock(&wdd->lock);
+ 	return err;
+ }
+ 
+ /*
+  *	watchdog_get_status: wrapper to get the watchdog status
+  *	@wdd: the watchdog device to get the status from
+- *	@status: the status of the watchdog device
++ *
++ *	The caller must hold wd_data->lock.
+  *
+  *	Get the watchdog's status flags.
+  */
+ 
+-static int watchdog_get_status(struct watchdog_device *wdd,
+-							unsigned int *status)
++static unsigned int watchdog_get_status(struct watchdog_device *wdd)
+ {
+-	int err = 0;
+-
+-	*status = 0;
+ 	if (!wdd->ops->status)
+-		return -EOPNOTSUPP;
+-
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_status;
+-	}
+-
+-	*status = wdd->ops->status(wdd);
++		return 0;
+ 
+-out_status:
+-	mutex_unlock(&wdd->lock);
+-	return err;
++	return wdd->ops->status(wdd);
+ }
+ 
+ /*
+  *	watchdog_set_timeout: set the watchdog timer timeout
+  *	@wdd: the watchdog device to set the timeout for
+  *	@timeout: timeout to set in seconds
++ *
++ *	The caller must hold wd_data->lock.
+  */
+ 
+ static int watchdog_set_timeout(struct watchdog_device *wdd,
+ 							unsigned int timeout)
+ {
+-	int err;
+-
+ 	if (!wdd->ops->set_timeout || !(wdd->info->options & WDIOF_SETTIMEOUT))
+ 		return -EOPNOTSUPP;
+ 
+ 	if (watchdog_timeout_invalid(wdd, timeout))
+ 		return -EINVAL;
+ 
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_timeout;
+-	}
+-
+-	err = wdd->ops->set_timeout(wdd, timeout);
+-
+-out_timeout:
+-	mutex_unlock(&wdd->lock);
+-	return err;
++	return wdd->ops->set_timeout(wdd, timeout);
+ }
+ 
+ /*
+@@ -221,30 +196,22 @@ out_timeout:
+  *	@wdd: the watchdog device to get the remaining time from
+  *	@timeleft: the time that's left
+  *
++ *	The caller must hold wd_data->lock.
++ *
+  *	Get the time before a watchdog will reboot (if not pinged).
+  */
+ 
+ static int watchdog_get_timeleft(struct watchdog_device *wdd,
+ 							unsigned int *timeleft)
+ {
+-	int err = 0;
+-
+ 	*timeleft = 0;
++
+ 	if (!wdd->ops->get_timeleft)
+ 		return -EOPNOTSUPP;
+ 
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_timeleft;
+-	}
+-
+ 	*timeleft = wdd->ops->get_timeleft(wdd);
+ 
+-out_timeleft:
+-	mutex_unlock(&wdd->lock);
+-	return err;
++	return 0;
+ }
+ 
+ #ifdef CONFIG_WATCHDOG_SYSFS
+@@ -261,14 +228,14 @@ static ssize_t status_show(struct device
+ 				char *buf)
+ {
+ 	struct watchdog_device *wdd = dev_get_drvdata(dev);
+-	ssize_t status;
+-	unsigned int val;
++	struct watchdog_core_data *wd_data = wdd->wd_data;
++	unsigned int status;
+ 
+-	status = watchdog_get_status(wdd, &val);
+-	if (!status)
+-		status = sprintf(buf, "%u\n", val);
++	mutex_lock(&wd_data->lock);
++	status = watchdog_get_status(wdd);
++	mutex_unlock(&wd_data->lock);
+ 
+-	return status;
++	return sprintf(buf, "%u\n", status);
+ }
+ static DEVICE_ATTR_RO(status);
+ 
+@@ -285,10 +252,13 @@ static ssize_t timeleft_show(struct devi
+ 				char *buf)
+ {
+ 	struct watchdog_device *wdd = dev_get_drvdata(dev);
++	struct watchdog_core_data *wd_data = wdd->wd_data;
+ 	ssize_t status;
+ 	unsigned int val;
+ 
++	mutex_lock(&wd_data->lock);
+ 	status = watchdog_get_timeleft(wdd, &val);
++	mutex_unlock(&wd_data->lock);
+ 	if (!status)
+ 		status = sprintf(buf, "%u\n", val);
+ 
+@@ -365,28 +335,17 @@ __ATTRIBUTE_GROUPS(wdt);
+  *	@wdd: the watchdog device to do the ioctl on
+  *	@cmd: watchdog command
+  *	@arg: argument pointer
++ *
++ *	The caller must hold wd_data->lock.
+  */
+ 
+ static int watchdog_ioctl_op(struct watchdog_device *wdd, unsigned int cmd,
+ 							unsigned long arg)
+ {
+-	int err;
+-
+ 	if (!wdd->ops->ioctl)
+ 		return -ENOIOCTLCMD;
+ 
+-	mutex_lock(&wdd->lock);
+-
+-	if (test_bit(WDOG_UNREGISTERED, &wdd->status)) {
+-		err = -ENODEV;
+-		goto out_ioctl;
+-	}
+-
+-	err = wdd->ops->ioctl(wdd, cmd, arg);
+-
+-out_ioctl:
+-	mutex_unlock(&wdd->lock);
+-	return err;
++	return wdd->ops->ioctl(wdd, cmd, arg);
+ }
+ 
+ /*
+@@ -404,10 +363,11 @@ out_ioctl:
+ static ssize_t watchdog_write(struct file *file, const char __user *data,
+ 						size_t len, loff_t *ppos)
+ {
+-	struct watchdog_device *wdd = file->private_data;
++	struct watchdog_core_data *wd_data = file->private_data;
++	struct watchdog_device *wdd;
++	int err;
+ 	size_t i;
+ 	char c;
+-	int err;
+ 
+ 	if (len == 0)
+ 		return 0;
+@@ -416,18 +376,25 @@ static ssize_t watchdog_write(struct fil
+ 	 * Note: just in case someone wrote the magic character
+ 	 * five months ago...
+ 	 */
+-	clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
++	clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
+ 
+ 	/* scan to see whether or not we got the magic character */
+ 	for (i = 0; i != len; i++) {
+ 		if (get_user(c, data + i))
+ 			return -EFAULT;
+ 		if (c == 'V')
+-			set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
++			set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
+ 	}
+ 
+ 	/* someone wrote to us, so we send the watchdog a keepalive ping */
+-	err = watchdog_ping(wdd);
++
++	err = -ENODEV;
++	mutex_lock(&wd_data->lock);
++	wdd = wd_data->wdd;
++	if (wdd)
++		err = watchdog_ping(wdd);
++	mutex_unlock(&wd_data->lock);
++
+ 	if (err < 0)
+ 		return err;
+ 
+@@ -447,71 +414,94 @@ static ssize_t watchdog_write(struct fil
+ static long watchdog_ioctl(struct file *file, unsigned int cmd,
+ 							unsigned long arg)
+ {
+-	struct watchdog_device *wdd = file->private_data;
++	struct watchdog_core_data *wd_data = file->private_data;
+ 	void __user *argp = (void __user *)arg;
++	struct watchdog_device *wdd;
+ 	int __user *p = argp;
+ 	unsigned int val;
+ 	int err;
+ 
++	mutex_lock(&wd_data->lock);
++
++	wdd = wd_data->wdd;
++	if (!wdd) {
++		err = -ENODEV;
++		goto out_ioctl;
++	}
++
+ 	err = watchdog_ioctl_op(wdd, cmd, arg);
+ 	if (err != -ENOIOCTLCMD)
+-		return err;
++		goto out_ioctl;
+ 
+ 	switch (cmd) {
+ 	case WDIOC_GETSUPPORT:
+-		return copy_to_user(argp, wdd->info,
++		err = copy_to_user(argp, wdd->info,
+ 			sizeof(struct watchdog_info)) ? -EFAULT : 0;
++		break;
+ 	case WDIOC_GETSTATUS:
+-		err = watchdog_get_status(wdd, &val);
+-		if (err == -ENODEV)
+-			return err;
+-		return put_user(val, p);
++		val = watchdog_get_status(wdd);
++		err = put_user(val, p);
++		break;
+ 	case WDIOC_GETBOOTSTATUS:
+-		return put_user(wdd->bootstatus, p);
++		err = put_user(wdd->bootstatus, p);
++		break;
+ 	case WDIOC_SETOPTIONS:
+-		if (get_user(val, p))
+-			return -EFAULT;
++		if (get_user(val, p)) {
++			err = -EFAULT;
++			break;
++		}
+ 		if (val & WDIOS_DISABLECARD) {
+ 			err = watchdog_stop(wdd);
+ 			if (err < 0)
+-				return err;
++				break;
+ 		}
+-		if (val & WDIOS_ENABLECARD) {
++		if (val & WDIOS_ENABLECARD)
+ 			err = watchdog_start(wdd);
+-			if (err < 0)
+-				return err;
+-		}
+-		return 0;
++		break;
+ 	case WDIOC_KEEPALIVE:
+-		if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
+-			return -EOPNOTSUPP;
+-		return watchdog_ping(wdd);
++		if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) {
++			err = -EOPNOTSUPP;
++			break;
++		}
++		err = watchdog_ping(wdd);
++		break;
+ 	case WDIOC_SETTIMEOUT:
+-		if (get_user(val, p))
+-			return -EFAULT;
++		if (get_user(val, p)) {
++			err = -EFAULT;
++			break;
++		}
+ 		err = watchdog_set_timeout(wdd, val);
+ 		if (err < 0)
+-			return err;
++			break;
+ 		/* If the watchdog is active then we send a keepalive ping
+ 		 * to make sure that the watchdog keep's running (and if
+ 		 * possible that it takes the new timeout) */
+ 		err = watchdog_ping(wdd);
+ 		if (err < 0)
+-			return err;
++			break;
+ 		/* Fall */
+ 	case WDIOC_GETTIMEOUT:
+ 		/* timeout == 0 means that we don't know the timeout */
+-		if (wdd->timeout == 0)
+-			return -EOPNOTSUPP;
+-		return put_user(wdd->timeout, p);
++		if (wdd->timeout == 0) {
++			err = -EOPNOTSUPP;
++			break;
++		}
++		err = put_user(wdd->timeout, p);
++		break;
+ 	case WDIOC_GETTIMELEFT:
+ 		err = watchdog_get_timeleft(wdd, &val);
+-		if (err)
+-			return err;
+-		return put_user(val, p);
++		if (err < 0)
++			break;
++		err = put_user(val, p);
++		break;
+ 	default:
+-		return -ENOTTY;
++		err = -ENOTTY;
++		break;
+ 	}
++
++out_ioctl:
++	mutex_unlock(&wd_data->lock);
++	return err;
+ }
+ 
+ /*
+@@ -526,45 +516,59 @@ static long watchdog_ioctl(struct file *
+ 
+ static int watchdog_open(struct inode *inode, struct file *file)
+ {
+-	int err = -EBUSY;
++	struct watchdog_core_data *wd_data;
+ 	struct watchdog_device *wdd;
++	int err;
+ 
+ 	/* Get the corresponding watchdog device */
+ 	if (imajor(inode) == MISC_MAJOR)
+-		wdd = old_wdd;
++		wd_data = old_wd_data;
+ 	else
+-		wdd = container_of(inode->i_cdev, struct watchdog_device, cdev);
++		wd_data = container_of(inode->i_cdev, struct watchdog_core_data,
++				       cdev);
+ 
+ 	/* the watchdog is single open! */
+-	if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
++	if (test_and_set_bit(_WDOG_DEV_OPEN, &wd_data->status))
+ 		return -EBUSY;
+ 
++	wdd = wd_data->wdd;
++
+ 	/*
+ 	 * If the /dev/watchdog device is open, we don't want the module
+ 	 * to be unloaded.
+ 	 */
+-	if (!try_module_get(wdd->ops->owner))
+-		goto out;
++	if (!try_module_get(wdd->ops->owner)) {
++		err = -EBUSY;
++		goto out_clear;
++	}
+ 
+ 	err = watchdog_start(wdd);
+ 	if (err < 0)
+ 		goto out_mod;
+ 
+-	file->private_data = wdd;
++	file->private_data = wd_data;
+ 
+-	if (wdd->ops->ref)
+-		wdd->ops->ref(wdd);
++	kref_get(&wd_data->kref);
+ 
+ 	/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
+ 	return nonseekable_open(inode, file);
+ 
+ out_mod:
+-	module_put(wdd->ops->owner);
+-out:
+-	clear_bit(WDOG_DEV_OPEN, &wdd->status);
++	module_put(wd_data->wdd->ops->owner);
++out_clear:
++	clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
+ 	return err;
+ }
+ 
++static void watchdog_core_data_release(struct kref *kref)
++{
++	struct watchdog_core_data *wd_data;
++
++	wd_data = container_of(kref, struct watchdog_core_data, kref);
++
++	kfree(wd_data);
++}
++
+ /*
+  *	watchdog_release: release the watchdog device.
+  *	@inode: inode of device
+@@ -577,9 +581,16 @@ out:
+ 
+ static int watchdog_release(struct inode *inode, struct file *file)
+ {
+-	struct watchdog_device *wdd = file->private_data;
++	struct watchdog_core_data *wd_data = file->private_data;
++	struct watchdog_device *wdd;
+ 	int err = -EBUSY;
+ 
++	mutex_lock(&wd_data->lock);
++
++	wdd = wd_data->wdd;
++	if (!wdd)
++		goto done;
++
+ 	/*
+ 	 * We only stop the watchdog if we received the magic character
+ 	 * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
+@@ -587,29 +598,24 @@ static int watchdog_release(struct inode
+ 	 */
+ 	if (!test_bit(WDOG_ACTIVE, &wdd->status))
+ 		err = 0;
+-	else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
++	else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
+ 		 !(wdd->info->options & WDIOF_MAGICCLOSE))
+ 		err = watchdog_stop(wdd);
+ 
+ 	/* If the watchdog was not stopped, send a keepalive ping */
+ 	if (err < 0) {
+-		mutex_lock(&wdd->lock);
+-		if (!test_bit(WDOG_UNREGISTERED, &wdd->status))
+-			dev_crit(wdd->dev, "watchdog did not stop!\n");
+-		mutex_unlock(&wdd->lock);
++		dev_crit(wdd->dev, "watchdog did not stop!\n");
+ 		watchdog_ping(wdd);
+ 	}
+ 
+-	/* Allow the owner module to be unloaded again */
+-	module_put(wdd->ops->owner);
+-
+ 	/* make sure that /dev/watchdog can be re-opened */
+-	clear_bit(WDOG_DEV_OPEN, &wdd->status);
+-
+-	/* Note wdd may be gone after this, do not use after this! */
+-	if (wdd->ops->unref)
+-		wdd->ops->unref(wdd);
++	clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
+ 
++done:
++	mutex_unlock(&wd_data->lock);
++	/* Allow the owner module to be unloaded again */
++	module_put(wd_data->cdev.owner);
++	kref_put(&wd_data->kref, watchdog_core_data_release);
+ 	return 0;
+ }
+ 
+@@ -639,10 +645,20 @@ static struct miscdevice watchdog_miscde
+ 
+ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
+ {
++	struct watchdog_core_data *wd_data;
+ 	int err;
+ 
++	wd_data = kzalloc(sizeof(struct watchdog_core_data), GFP_KERNEL);
++	if (!wd_data)
++		return -ENOMEM;
++	kref_init(&wd_data->kref);
++	mutex_init(&wd_data->lock);
++
++	wd_data->wdd = wdd;
++	wdd->wd_data = wd_data;
++
+ 	if (wdd->id == 0) {
+-		old_wdd = wdd;
++		old_wd_data = wd_data;
+ 		watchdog_miscdev.parent = wdd->parent;
+ 		err = misc_register(&watchdog_miscdev);
+ 		if (err != 0) {
+@@ -651,23 +667,25 @@ static int watchdog_cdev_register(struct
+ 			if (err == -EBUSY)
+ 				pr_err("%s: a legacy watchdog module is probably present.\n",
+ 					wdd->info->identity);
+-			old_wdd = NULL;
++			old_wd_data = NULL;
++			kfree(wd_data);
+ 			return err;
+ 		}
+ 	}
+ 
+ 	/* Fill in the data structures */
+-	cdev_init(&wdd->cdev, &watchdog_fops);
+-	wdd->cdev.owner = wdd->ops->owner;
++	cdev_init(&wd_data->cdev, &watchdog_fops);
++	wd_data->cdev.owner = wdd->ops->owner;
+ 
+ 	/* Add the device */
+-	err  = cdev_add(&wdd->cdev, devno, 1);
++	err = cdev_add(&wd_data->cdev, devno, 1);
+ 	if (err) {
+ 		pr_err("watchdog%d unable to add device %d:%d\n",
+ 			wdd->id,  MAJOR(watchdog_devt), wdd->id);
+ 		if (wdd->id == 0) {
+ 			misc_deregister(&watchdog_miscdev);
+-			old_wdd = NULL;
++			old_wd_data = NULL;
++			kref_put(&wd_data->kref, watchdog_core_data_release);
+ 		}
+ 	}
+ 	return err;
+@@ -683,15 +701,20 @@ static int watchdog_cdev_register(struct
+ 
+ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
+ {
+-	mutex_lock(&wdd->lock);
+-	set_bit(WDOG_UNREGISTERED, &wdd->status);
+-	mutex_unlock(&wdd->lock);
++	struct watchdog_core_data *wd_data = wdd->wd_data;
+ 
+-	cdev_del(&wdd->cdev);
++	cdev_del(&wd_data->cdev);
+ 	if (wdd->id == 0) {
+ 		misc_deregister(&watchdog_miscdev);
+-		old_wdd = NULL;
++		old_wd_data = NULL;
+ 	}
++
++	mutex_lock(&wd_data->lock);
++	wd_data->wdd = NULL;
++	wdd->wd_data = NULL;
++	mutex_unlock(&wd_data->lock);
++
++	kref_put(&wd_data->kref, watchdog_core_data_release);
+ }
+ 
+ static struct class watchdog_class = {
+@@ -742,9 +765,9 @@ int watchdog_dev_register(struct watchdo
+ 
+ void watchdog_dev_unregister(struct watchdog_device *wdd)
+ {
+-	watchdog_cdev_unregister(wdd);
+ 	device_destroy(&watchdog_class, wdd->dev->devt);
+ 	wdd->dev = NULL;
++	watchdog_cdev_unregister(wdd);
+ }
+ 
+ /*
+--- a/include/linux/watchdog.h
++++ b/include/linux/watchdog.h
+@@ -17,6 +17,7 @@
+ 
+ struct watchdog_ops;
+ struct watchdog_device;
++struct watchdog_core_data;
+ 
+ /** struct watchdog_ops - The watchdog-devices operations
+  *
+@@ -28,8 +29,6 @@ struct 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.
+  *
+  * The watchdog_ops structure contains a list of low-level operations
+@@ -48,15 +47,14 @@ struct watchdog_ops {
+ 	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 *);
++	void (*ref)(struct watchdog_device *) __deprecated;
++	void (*unref)(struct watchdog_device *) __deprecated;
+ 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+ };
+ 
+ /** struct watchdog_device - The structure that defines a watchdog device
+  *
+  * @id:		The watchdog's ID. (Allocated by watchdog_register_device)
+- * @cdev:	The watchdog's Character device.
+  * @dev:	The device for our watchdog
+  * @parent:	The parent bus device
+  * @info:	Pointer to a watchdog_info structure.
+@@ -67,8 +65,8 @@ struct watchdog_ops {
+  * @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.
++ * @driver_data:Pointer to the drivers private data.
++ * @wd_data:	Pointer to watchdog core internal data.
+  * @status:	Field that contains the devices internal status bits.
+  * @deferred: entry in wtd_deferred_reg_list which is used to
+  *			   register early initialized watchdogs.
+@@ -84,7 +82,6 @@ struct watchdog_ops {
+  */
+ struct watchdog_device {
+ 	int id;
+-	struct cdev cdev;
+ 	struct device *dev;
+ 	struct device *parent;
+ 	const struct watchdog_info *info;
+@@ -96,15 +93,12 @@ struct watchdog_device {
+ 	struct notifier_block reboot_nb;
+ 	struct notifier_block restart_nb;
+ 	void *driver_data;
+-	struct mutex lock;
++	struct watchdog_core_data *wd_data;
+ 	unsigned long status;
+ /* Bit numbers for status flags */
+ #define WDOG_ACTIVE		0	/* Is the watchdog running/active */
+-#define WDOG_DEV_OPEN		1	/* Opened via /dev/watchdog ? */
+-#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 */
++#define WDOG_NO_WAY_OUT		1	/* Is 'nowayout' feature set ? */
++#define WDOG_STOP_ON_REBOOT	2	/* Should be stopped on reboot */
+ 	struct list_head deferred;
+ };
+ 
diff --git a/target/linux/ipq806x/patches-4.4/009-7-watchdog-Drop-pointer-to-watchdog-device-from-struct-watchdog_device.patch b/target/linux/ipq806x/patches-4.4/009-7-watchdog-Drop-pointer-to-watchdog-device-from-struct-watchdog_device.patch
new file mode 100644
index 0000000..9640cd4
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-7-watchdog-Drop-pointer-to-watchdog-device-from-struct-watchdog_device.patch
@@ -0,0 +1,117 @@
+From 0254e953537c92df3e7d0176f401a211e944fd61 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux at roeck-us.net>
+Date: Sun, 3 Jan 2016 15:11:58 -0800
+Subject: watchdog: Drop pointer to watchdog device from struct watchdog_device
+
+The lifetime of the watchdog device pointer is different from the lifetime
+of its character device. Remove it entirely to avoid race conditions.
+
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ Documentation/watchdog/watchdog-kernel-api.txt | 2 --
+ drivers/watchdog/watchdog_core.c               | 8 ++++----
+ drivers/watchdog/watchdog_dev.c                | 9 ++++-----
+ include/linux/watchdog.h                       | 2 --
+ 4 files changed, 8 insertions(+), 13 deletions(-)
+
+--- a/Documentation/watchdog/watchdog-kernel-api.txt
++++ b/Documentation/watchdog/watchdog-kernel-api.txt
+@@ -44,7 +44,6 @@ The watchdog device structure looks like
+ 
+ struct watchdog_device {
+ 	int id;
+-	struct device *dev;
+ 	struct device *parent;
+ 	const struct watchdog_info *info;
+ 	const struct watchdog_ops *ops;
+@@ -65,7 +64,6 @@ It contains following fields:
+   /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
+   /dev/watchdog miscdev. The id is set automatically when calling
+   watchdog_register_device.
+-* dev: device under the watchdog class (created by watchdog_register_device).
+ * parent: set this to the parent device (or NULL) before calling
+   watchdog_register_device.
+ * info: a pointer to a watchdog_info structure. This structure gives some
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -249,8 +249,8 @@ static int __watchdog_register_device(st
+ 
+ 		ret = register_reboot_notifier(&wdd->reboot_nb);
+ 		if (ret) {
+-			dev_err(wdd->dev, "Cannot register reboot notifier (%d)\n",
+-				ret);
++			pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
++			       wdd->id, ret);
+ 			watchdog_dev_unregister(wdd);
+ 			ida_simple_remove(&watchdog_ida, wdd->id);
+ 			return ret;
+@@ -262,8 +262,8 @@ static int __watchdog_register_device(st
+ 
+ 		ret = register_restart_handler(&wdd->restart_nb);
+ 		if (ret)
+-			dev_warn(wdd->dev, "Cannot register restart handler (%d)\n",
+-				 ret);
++			pr_warn("watchog%d: Cannot register restart handler (%d)\n",
++				wdd->id, ret);
+ 	}
+ 
+ 	return 0;
+--- a/drivers/watchdog/watchdog_dev.c
++++ b/drivers/watchdog/watchdog_dev.c
+@@ -143,7 +143,8 @@ static int watchdog_stop(struct watchdog
+ 		return 0;
+ 
+ 	if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+-		dev_info(wdd->dev, "nowayout prevents watchdog being stopped!\n");
++		pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
++			wdd->id);
+ 		return -EBUSY;
+ 	}
+ 
+@@ -604,7 +605,7 @@ static int watchdog_release(struct inode
+ 
+ 	/* If the watchdog was not stopped, send a keepalive ping */
+ 	if (err < 0) {
+-		dev_crit(wdd->dev, "watchdog did not stop!\n");
++		pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
+ 		watchdog_ping(wdd);
+ 	}
+ 
+@@ -750,7 +751,6 @@ int watchdog_dev_register(struct watchdo
+ 		watchdog_cdev_unregister(wdd);
+ 		return PTR_ERR(dev);
+ 	}
+-	wdd->dev = dev;
+ 
+ 	return ret;
+ }
+@@ -765,8 +765,7 @@ int watchdog_dev_register(struct watchdo
+ 
+ void watchdog_dev_unregister(struct watchdog_device *wdd)
+ {
+-	device_destroy(&watchdog_class, wdd->dev->devt);
+-	wdd->dev = NULL;
++	device_destroy(&watchdog_class, wdd->wd_data->cdev.dev);
+ 	watchdog_cdev_unregister(wdd);
+ }
+ 
+--- a/include/linux/watchdog.h
++++ b/include/linux/watchdog.h
+@@ -55,7 +55,6 @@ struct watchdog_ops {
+ /** struct watchdog_device - The structure that defines a watchdog device
+  *
+  * @id:		The watchdog's ID. (Allocated by watchdog_register_device)
+- * @dev:	The device for our watchdog
+  * @parent:	The parent bus device
+  * @info:	Pointer to a watchdog_info structure.
+  * @ops:	Pointer to the list of watchdog operations.
+@@ -82,7 +81,6 @@ struct watchdog_ops {
+  */
+ struct watchdog_device {
+ 	int id;
+-	struct device *dev;
+ 	struct device *parent;
+ 	const struct watchdog_info *info;
+ 	const struct watchdog_ops *ops;
diff --git a/target/linux/ipq806x/patches-4.4/009-8-watchdog-kill-unref-ref-ops.patch b/target/linux/ipq806x/patches-4.4/009-8-watchdog-kill-unref-ref-ops.patch
new file mode 100644
index 0000000..ba56a86
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/009-8-watchdog-kill-unref-ref-ops.patch
@@ -0,0 +1,26 @@
+From 62cd1c40ce1c7c16835b599751c7a002eb5bbdf5 Mon Sep 17 00:00:00 2001
+From: Tomas Winkler <tomas.winkler at intel.com>
+Date: Sun, 3 Jan 2016 13:32:37 +0200
+Subject: watchdog: kill unref/ref ops
+
+ref/unref ops are not called at all so even marked them as deprecated
+is misleading, we need to just drop the API.
+
+Signed-off-by: Tomas Winkler <tomas.winkler at intel.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ include/linux/watchdog.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/include/linux/watchdog.h
++++ b/include/linux/watchdog.h
+@@ -47,8 +47,6 @@ struct watchdog_ops {
+ 	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 *) __deprecated;
+-	void (*unref)(struct watchdog_device *) __deprecated;
+ 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+ };
+ 
diff --git a/target/linux/ipq806x/patches-4.4/010-1-qcom-wdt-use-core-restart-handler.patch b/target/linux/ipq806x/patches-4.4/010-1-qcom-wdt-use-core-restart-handler.patch
new file mode 100644
index 0000000..d36dedc
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-1-qcom-wdt-use-core-restart-handler.patch
@@ -0,0 +1,113 @@
+From 80969a68ffed12f82e2a29908306ff43a6861a61 Mon Sep 17 00:00:00 2001
+From: Damien Riegel <damien.riegel at savoirfairelinux.com>
+Date: Mon, 16 Nov 2015 12:28:09 -0500
+Subject: watchdog: qcom-wdt: use core restart handler
+
+Get rid of the custom restart handler by using the one provided by the
+watchdog core.
+
+Signed-off-by: Damien Riegel <damien.riegel at savoirfairelinux.com>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Reviewed-by: Vivien Didelot <vivien.didelot at savoirfairelinux.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/qcom-wdt.c | 49 ++++++++++++++++++---------------------------
+ 1 file changed, 19 insertions(+), 30 deletions(-)
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -17,7 +17,6 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+-#include <linux/reboot.h>
+ #include <linux/watchdog.h>
+ 
+ #define WDT_RST		0x38
+@@ -28,7 +27,6 @@ struct qcom_wdt {
+ 	struct watchdog_device	wdd;
+ 	struct clk		*clk;
+ 	unsigned long		rate;
+-	struct notifier_block	restart_nb;
+ 	void __iomem		*base;
+ };
+ 
+@@ -72,25 +70,9 @@ static int qcom_wdt_set_timeout(struct w
+ 	return qcom_wdt_start(wdd);
+ }
+ 
+-static const struct watchdog_ops qcom_wdt_ops = {
+-	.start		= qcom_wdt_start,
+-	.stop		= qcom_wdt_stop,
+-	.ping		= qcom_wdt_ping,
+-	.set_timeout	= qcom_wdt_set_timeout,
+-	.owner		= THIS_MODULE,
+-};
+-
+-static const struct watchdog_info qcom_wdt_info = {
+-	.options	= WDIOF_KEEPALIVEPING
+-			| WDIOF_MAGICCLOSE
+-			| WDIOF_SETTIMEOUT,
+-	.identity	= KBUILD_MODNAME,
+-};
+-
+-static int qcom_wdt_restart(struct notifier_block *nb, unsigned long action,
+-			    void *data)
++static int qcom_wdt_restart(struct watchdog_device *wdd)
+ {
+-	struct qcom_wdt *wdt = container_of(nb, struct qcom_wdt, restart_nb);
++	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
+ 	u32 timeout;
+ 
+ 	/*
+@@ -110,9 +92,25 @@ static int qcom_wdt_restart(struct notif
+ 	wmb();
+ 
+ 	msleep(150);
+-	return NOTIFY_DONE;
++	return 0;
+ }
+ 
++static const struct watchdog_ops qcom_wdt_ops = {
++	.start		= qcom_wdt_start,
++	.stop		= qcom_wdt_stop,
++	.ping		= qcom_wdt_ping,
++	.set_timeout	= qcom_wdt_set_timeout,
++	.restart        = qcom_wdt_restart,
++	.owner		= THIS_MODULE,
++};
++
++static const struct watchdog_info qcom_wdt_info = {
++	.options	= WDIOF_KEEPALIVEPING
++			| WDIOF_MAGICCLOSE
++			| WDIOF_SETTIMEOUT,
++	.identity	= KBUILD_MODNAME,
++};
++
+ static int qcom_wdt_probe(struct platform_device *pdev)
+ {
+ 	struct qcom_wdt *wdt;
+@@ -187,14 +185,6 @@ static int qcom_wdt_probe(struct platfor
+ 		goto err_clk_unprepare;
+ 	}
+ 
+-	/*
+-	 * WDT restart notifier has priority 0 (use as a last resort)
+-	 */
+-	wdt->restart_nb.notifier_call = qcom_wdt_restart;
+-	ret = register_restart_handler(&wdt->restart_nb);
+-	if (ret)
+-		dev_err(&pdev->dev, "failed to setup restart handler\n");
+-
+ 	platform_set_drvdata(pdev, wdt);
+ 	return 0;
+ 
+@@ -207,7 +197,6 @@ static int qcom_wdt_remove(struct platfo
+ {
+ 	struct qcom_wdt *wdt = platform_get_drvdata(pdev);
+ 
+-	unregister_restart_handler(&wdt->restart_nb);
+ 	watchdog_unregister_device(&wdt->wdd);
+ 	clk_disable_unprepare(wdt->clk);
+ 	return 0;
diff --git a/target/linux/ipq806x/patches-4.4/010-2-qcom-wdt-Do-not-set-dev-in-struct-watchdog_device.patch b/target/linux/ipq806x/patches-4.4/010-2-qcom-wdt-Do-not-set-dev-in-struct-watchdog_device.patch
new file mode 100644
index 0000000..31371c2
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-2-qcom-wdt-Do-not-set-dev-in-struct-watchdog_device.patch
@@ -0,0 +1,25 @@
+From 0933b453f1c7104d873aacf8524f8ac380a7ed08 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux at roeck-us.net>
+Date: Thu, 24 Dec 2015 14:22:04 -0800
+Subject: watchdog: qcom-wdt: Do not set 'dev' in struct watchdog_device
+
+The 'dev' pointer in struct watchdog_device is set by the watchdog core
+when registering the watchdog device and not by the driver. It points to
+the watchdog device, not its parent.
+
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/qcom-wdt.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -164,7 +164,6 @@ static int qcom_wdt_probe(struct platfor
+ 		goto err_clk_unprepare;
+ 	}
+ 
+-	wdt->wdd.dev = &pdev->dev;
+ 	wdt->wdd.info = &qcom_wdt_info;
+ 	wdt->wdd.ops = &qcom_wdt_ops;
+ 	wdt->wdd.min_timeout = 1;
diff --git a/target/linux/ipq806x/patches-4.4/010-3-watchdog-Add-action-and-data-parameters-to-restart-handler-callback.patch b/target/linux/ipq806x/patches-4.4/010-3-watchdog-Add-action-and-data-parameters-to-restart-handler-callback.patch
new file mode 100644
index 0000000..7ceff32
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-3-watchdog-Add-action-and-data-parameters-to-restart-handler-callback.patch
@@ -0,0 +1,51 @@
+rom 4d8b229d5ea610affe672e919021e9d02cd877da Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux at roeck-us.net>
+Date: Fri, 26 Feb 2016 17:32:49 -0800
+Subject: watchdog: Add 'action' and 'data' parameters to restart handler
+ callback
+
+The 'action' (or restart mode) and data parameters may be used by restart
+handlers, so they should be passed to the restart callback functions.
+
+Cc: Sylvain Lemieux <slemieux at tycoint.com>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/qcom-wdt.c      | 3 ++-
+ drivers/watchdog/watchdog_core.c | 2 +-
+ include/linux/watchdog.h         | 2 +-
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -70,7 +70,8 @@ static int qcom_wdt_set_timeout(struct w
+ 	return qcom_wdt_start(wdd);
+ }
+ 
+-static int qcom_wdt_restart(struct watchdog_device *wdd)
++static int qcom_wdt_restart(struct watchdog_device *wdd, unsigned long action,
++			    void *data)
+ {
+ 	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
+ 	u32 timeout;
+--- a/drivers/watchdog/watchdog_core.c
++++ b/drivers/watchdog/watchdog_core.c
+@@ -164,7 +164,7 @@ static int watchdog_restart_notifier(str
+ 
+ 	int ret;
+ 
+-	ret = wdd->ops->restart(wdd);
++	ret = wdd->ops->restart(wdd, action, data);
+ 	if (ret)
+ 		return NOTIFY_BAD;
+ 
+--- a/include/linux/watchdog.h
++++ b/include/linux/watchdog.h
+@@ -46,7 +46,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 *);
++	int (*restart)(struct watchdog_device *, unsigned long, void *);
+ 	long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+ };
+ 
diff --git a/target/linux/ipq806x/patches-4.4/010-4-watchdog-qcom-Report-reboot-reason.patch b/target/linux/ipq806x/patches-4.4/010-4-watchdog-qcom-Report-reboot-reason.patch
new file mode 100644
index 0000000..f7fcaee
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-4-watchdog-qcom-Report-reboot-reason.patch
@@ -0,0 +1,46 @@
+From b6ef36d2c1e391adc1fe1b2dd2a0f887a9f3052b Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <groeck at chromium.org>
+Date: Mon, 4 Apr 2016 17:37:46 -0700
+Subject: watchdog: qcom: Report reboot reason
+
+The Qualcom watchdog timer block reports if the system was reset by the
+watchdog. Pass the information to user space.
+
+Reviewed-by: Grant Grundler <grundler at chromium.org>
+Tested-by: Grant Grundler <grundler at chromium.org>
+Signed-off-by: Guenter Roeck <groeck at chromium.org>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/qcom-wdt.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -21,6 +21,7 @@
+ 
+ #define WDT_RST		0x38
+ #define WDT_EN		0x40
++#define WDT_STS		0x44
+ #define WDT_BITE_TIME	0x5C
+ 
+ struct qcom_wdt {
+@@ -108,7 +109,8 @@ static const struct watchdog_ops qcom_wd
+ static const struct watchdog_info qcom_wdt_info = {
+ 	.options	= WDIOF_KEEPALIVEPING
+ 			| WDIOF_MAGICCLOSE
+-			| WDIOF_SETTIMEOUT,
++			| WDIOF_SETTIMEOUT
++			| WDIOF_CARDRESET,
+ 	.identity	= KBUILD_MODNAME,
+ };
+ 
+@@ -171,6 +173,9 @@ static int qcom_wdt_probe(struct platfor
+ 	wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
+ 	wdt->wdd.parent = &pdev->dev;
+ 
++	if (readl(wdt->base + WDT_STS) & 1)
++		wdt->wdd.bootstatus = WDIOF_CARDRESET;
++
+ 	/*
+ 	 * If 'timeout-sec' unspecified in devicetree, assume a 30 second
+ 	 * default, unless the max timeout is less than 30 seconds, then use
diff --git a/target/linux/ipq806x/patches-4.4/010-5-watchdog-qcom-add-option-for-standalone-watchdog-not-in-timer-block.patch b/target/linux/ipq806x/patches-4.4/010-5-watchdog-qcom-add-option-for-standalone-watchdog-not-in-timer-block.patch
new file mode 100644
index 0000000..82dd875
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-5-watchdog-qcom-add-option-for-standalone-watchdog-not-in-timer-block.patch
@@ -0,0 +1,162 @@
+From f0d9d0f4b44ae5503ea368e7f066b20f12ca1d37 Mon Sep 17 00:00:00 2001
+From: Matthew McClintock <mmcclint at codeaurora.org>
+Date: Wed, 29 Jun 2016 10:50:01 -0700
+Subject: watchdog: qcom: add option for standalone watchdog not in timer block
+
+Commit 0dfd582e026a ("watchdog: qcom: use timer devicetree
+binding") moved to use the watchdog as a subset timer
+register block. Some devices have the watchdog completely
+standalone with slightly different register offsets as
+well so let's account for the differences here.
+
+The existing "kpss-standalone" compatible string doesn't
+make it entirely clear exactly what the device is so
+rename to "kpss-wdt" to reflect watchdog timer
+functionality. Also update ipq4019 DTS with an SoC
+specific compatible.
+
+Signed-off-by: Matthew McClintock <mmcclint at codeaurora.org>
+Signed-off-by: Thomas Pedersen <twp at codeaurora.org>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ .../devicetree/bindings/watchdog/qcom-wdt.txt      |  2 +
+ arch/arm/boot/dts/qcom-ipq4019.dtsi                |  2 +-
+ drivers/watchdog/qcom-wdt.c                        | 64 ++++++++++++++++------
+ 3 files changed, 51 insertions(+), 17 deletions(-)
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -18,19 +18,42 @@
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
+ #include <linux/watchdog.h>
++#include <linux/of_device.h>
+ 
+-#define WDT_RST		0x38
+-#define WDT_EN		0x40
+-#define WDT_STS		0x44
+-#define WDT_BITE_TIME	0x5C
++enum wdt_reg {
++	WDT_RST,
++	WDT_EN,
++	WDT_STS,
++	WDT_BITE_TIME,
++};
++
++static const u32 reg_offset_data_apcs_tmr[] = {
++	[WDT_RST] = 0x38,
++	[WDT_EN] = 0x40,
++	[WDT_STS] = 0x44,
++	[WDT_BITE_TIME] = 0x5C,
++};
++
++static const u32 reg_offset_data_kpss[] = {
++	[WDT_RST] = 0x4,
++	[WDT_EN] = 0x8,
++	[WDT_STS] = 0xC,
++	[WDT_BITE_TIME] = 0x14,
++};
+ 
+ struct qcom_wdt {
+ 	struct watchdog_device	wdd;
+ 	struct clk		*clk;
+ 	unsigned long		rate;
+ 	void __iomem		*base;
++	const u32		*layout;
+ };
+ 
++static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg)
++{
++	return wdt->base + wdt->layout[reg];
++}
++
+ static inline
+ struct qcom_wdt *to_qcom_wdt(struct watchdog_device *wdd)
+ {
+@@ -41,10 +64,10 @@ static int qcom_wdt_start(struct watchdo
+ {
+ 	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
+ 
+-	writel(0, wdt->base + WDT_EN);
+-	writel(1, wdt->base + WDT_RST);
+-	writel(wdd->timeout * wdt->rate, wdt->base + WDT_BITE_TIME);
+-	writel(1, wdt->base + WDT_EN);
++	writel(0, wdt_addr(wdt, WDT_EN));
++	writel(1, wdt_addr(wdt, WDT_RST));
++	writel(wdd->timeout * wdt->rate, wdt_addr(wdt, WDT_BITE_TIME));
++	writel(1, wdt_addr(wdt, WDT_EN));
+ 	return 0;
+ }
+ 
+@@ -52,7 +75,7 @@ static int qcom_wdt_stop(struct watchdog
+ {
+ 	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
+ 
+-	writel(0, wdt->base + WDT_EN);
++	writel(0, wdt_addr(wdt, WDT_EN));
+ 	return 0;
+ }
+ 
+@@ -60,7 +83,7 @@ static int qcom_wdt_ping(struct watchdog
+ {
+ 	struct qcom_wdt *wdt = to_qcom_wdt(wdd);
+ 
+-	writel(1, wdt->base + WDT_RST);
++	writel(1, wdt_addr(wdt, WDT_RST));
+ 	return 0;
+ }
+ 
+@@ -83,10 +106,10 @@ static int qcom_wdt_restart(struct watch
+ 	 */
+ 	timeout = 128 * wdt->rate / 1000;
+ 
+-	writel(0, wdt->base + WDT_EN);
+-	writel(1, wdt->base + WDT_RST);
+-	writel(timeout, wdt->base + WDT_BITE_TIME);
+-	writel(1, wdt->base + WDT_EN);
++	writel(0, wdt_addr(wdt, WDT_EN));
++	writel(1, wdt_addr(wdt, WDT_RST));
++	writel(timeout, wdt_addr(wdt, WDT_BITE_TIME));
++	writel(1, wdt_addr(wdt, WDT_EN));
+ 
+ 	/*
+ 	 * Actually make sure the above sequence hits hardware before sleeping.
+@@ -119,9 +142,16 @@ static int qcom_wdt_probe(struct platfor
+ 	struct qcom_wdt *wdt;
+ 	struct resource *res;
+ 	struct device_node *np = pdev->dev.of_node;
++	const u32 *regs;
+ 	u32 percpu_offset;
+ 	int ret;
+ 
++	regs = of_device_get_match_data(&pdev->dev);
++	if (!regs) {
++		dev_err(&pdev->dev, "Unsupported QCOM WDT module\n");
++		return -ENODEV;
++	}
++
+ 	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ 	if (!wdt)
+ 		return -ENOMEM;
+@@ -172,6 +202,7 @@ static int qcom_wdt_probe(struct platfor
+ 	wdt->wdd.min_timeout = 1;
+ 	wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
+ 	wdt->wdd.parent = &pdev->dev;
++	wdt->layout = regs;
+ 
+ 	if (readl(wdt->base + WDT_STS) & 1)
+ 		wdt->wdd.bootstatus = WDIOF_CARDRESET;
+@@ -208,8 +239,9 @@ static int qcom_wdt_remove(struct platfo
+ }
+ 
+ static const struct of_device_id qcom_wdt_of_table[] = {
+-	{ .compatible = "qcom,kpss-timer" },
+-	{ .compatible = "qcom,scss-timer" },
++	{ .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr },
++	{ .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr },
++	{ .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss },
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
diff --git a/target/linux/ipq806x/patches-4.4/010-6-watchdog-qcom-configure-BARK-time-in-addition-to-BITE-time.patch b/target/linux/ipq806x/patches-4.4/010-6-watchdog-qcom-configure-BARK-time-in-addition-to-BITE-time.patch
new file mode 100644
index 0000000..bdc3f99
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.4/010-6-watchdog-qcom-configure-BARK-time-in-addition-to-BITE-time.patch
@@ -0,0 +1,60 @@
+From 10073a205df269abcbd9c3fbc690a813827107ef Mon Sep 17 00:00:00 2001
+From: Matthew McClintock <mmcclint at codeaurora.org>
+Date: Tue, 28 Jun 2016 11:35:21 -0700
+Subject: watchdog: qcom: configure BARK time in addition to BITE time
+
+For certain parts and some versions of TZ, TZ will reset the chip
+when a BARK is triggered even though it was not configured here. So
+by default let's configure this BARK time as well.
+
+Signed-off-by: Matthew McClintock <mmcclint at codeaurora.org>
+Reviewed-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Thomas Pedersen <twp at codeaurora.org>
+Signed-off-by: Guenter Roeck <linux at roeck-us.net>
+Signed-off-by: Wim Van Sebroeck <wim at iguana.be>
+---
+ drivers/watchdog/qcom-wdt.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -24,6 +24,7 @@ enum wdt_reg {
+ 	WDT_RST,
+ 	WDT_EN,
+ 	WDT_STS,
++	WDT_BARK_TIME,
+ 	WDT_BITE_TIME,
+ };
+ 
+@@ -31,6 +32,7 @@ static const u32 reg_offset_data_apcs_tm
+ 	[WDT_RST] = 0x38,
+ 	[WDT_EN] = 0x40,
+ 	[WDT_STS] = 0x44,
++	[WDT_BARK_TIME] = 0x4C,
+ 	[WDT_BITE_TIME] = 0x5C,
+ };
+ 
+@@ -38,6 +40,7 @@ static const u32 reg_offset_data_kpss[]
+ 	[WDT_RST] = 0x4,
+ 	[WDT_EN] = 0x8,
+ 	[WDT_STS] = 0xC,
++	[WDT_BARK_TIME] = 0x10,
+ 	[WDT_BITE_TIME] = 0x14,
+ };
+ 
+@@ -66,6 +69,7 @@ static int qcom_wdt_start(struct watchdo
+ 
+ 	writel(0, wdt_addr(wdt, WDT_EN));
+ 	writel(1, wdt_addr(wdt, WDT_RST));
++	writel(wdd->timeout * wdt->rate, wdt_addr(wdt, WDT_BARK_TIME));
+ 	writel(wdd->timeout * wdt->rate, wdt_addr(wdt, WDT_BITE_TIME));
+ 	writel(1, wdt_addr(wdt, WDT_EN));
+ 	return 0;
+@@ -108,6 +112,7 @@ static int qcom_wdt_restart(struct watch
+ 
+ 	writel(0, wdt_addr(wdt, WDT_EN));
+ 	writel(1, wdt_addr(wdt, WDT_RST));
++	writel(timeout, wdt_addr(wdt, WDT_BARK_TIME));
+ 	writel(timeout, wdt_addr(wdt, WDT_BITE_TIME));
+ 	writel(1, wdt_addr(wdt, WDT_EN));
+ 
diff --git a/target/linux/ipq806x/patches-4.4/710-watchdog-qcom-set-WDT_BARK_TIME-register-offset-to-o.patch b/target/linux/ipq806x/patches-4.4/710-watchdog-qcom-set-WDT_BARK_TIME-register-offset-to-o.patch
deleted file mode 100644
index dde5822..0000000
--- a/target/linux/ipq806x/patches-4.4/710-watchdog-qcom-set-WDT_BARK_TIME-register-offset-to-o.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From abc9f55079169806bcc31f29ec27f7df11c6184c Mon Sep 17 00:00:00 2001
-From: Ram Chandra Jangir <rjangi at codeaurora.org>
-Date: Thu, 4 Feb 2016 12:41:56 +0530
-Subject: [PATCH 2/2] watchdog: qcom: set WDT_BARK_TIME register offset to one
- second less of bite time
-
-Currently WDT_BARK_TIME register offset is not configured with bark
-timeout during wdt_start,and it is taking bark timeout's default value.
-For some versions of TZ (secure mode) will consider a BARK the same
-as BITE and reset the board.
-
-So instead let's just configure the BARK time to be less than a second
-of the bite timeout so the board does not reset in this scenario
-
-Change-Id: Ie09850ad7e0470ed721e6924911ca2a81fd9ff8a
-Signed-off-by: Ram Chandra Jangir <rjangi at codeaurora.org>
----
- drivers/watchdog/qcom-wdt.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/watchdog/qcom-wdt.c
-+++ b/drivers/watchdog/qcom-wdt.c
-@@ -22,6 +22,7 @@
- 
- #define WDT_RST		0x38
- #define WDT_EN		0x40
-+#define WDT_BARK_TIME	0x4C
- #define WDT_BITE_TIME	0x5C
- 
- struct qcom_wdt {
-@@ -44,6 +45,7 @@ static int qcom_wdt_start(struct watchdo
- 
- 	writel(0, wdt->base + WDT_EN);
- 	writel(1, wdt->base + WDT_RST);
-+	writel((wdd->timeout - 1) * wdt->rate, wdt->base + WDT_BARK_TIME);
- 	writel(wdd->timeout * wdt->rate, wdt->base + WDT_BITE_TIME);
- 	writel(1, wdt->base + WDT_EN);
- 	return 0;



More information about the lede-commits mailing list