From 8f4cf30903cf6daaed0be1e8911363a3984abf72 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 26 Aug 2015 09:48:05 +0200 Subject: watchdog: Allow multiple watchdogs Put watchdogs on a list to allow multiple watchdogs. Add a priority field to be able to pick the highest priority watchdog. This patch also provides a of_get_watchdog_priority() function to allow configuring the watchdog priority from the device tree. Signed-off-by: Sascha Hauer --- drivers/watchdog/wd_core.c | 57 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 3d0cfc635d..b8473b7da3 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#define pr_fmt(fmt) "watchdog: " fmt #include #include @@ -18,40 +19,72 @@ #include #include -/* - * Note: this simple framework supports one watchdog only. - */ -static struct watchdog *watchdog; +static LIST_HEAD(watchdog_list); int watchdog_register(struct watchdog *wd) { - if (watchdog != NULL) - return -EBUSY; + if (!wd->priority) + wd->priority = WATCHDOG_DEFAULT_PRIORITY; + + list_add_tail(&wd->list, &watchdog_list); + + pr_debug("registering watchdog with priority %d\n", wd->priority); - watchdog = wd; return 0; } EXPORT_SYMBOL(watchdog_register); int watchdog_deregister(struct watchdog *wd) { - if (watchdog == NULL || wd != watchdog) - return -ENODEV; + list_del(&wd->list); - watchdog = NULL; return 0; } EXPORT_SYMBOL(watchdog_deregister); +static struct watchdog *watchdog_get_default(void) +{ + struct watchdog *tmp, *wd = NULL; + int priority = 0; + + list_for_each_entry(tmp, &watchdog_list, list) { + if (tmp->priority > priority) { + priority = tmp->priority; + wd = tmp; + } + } + + return wd; +} + /* * start, stop or retrigger the watchdog * timeout in [seconds]. timeout of '0' will disable the watchdog (if possible) */ int watchdog_set_timeout(unsigned timeout) { - if (watchdog == NULL) + struct watchdog *wd; + + wd = watchdog_get_default(); + + if (!wd) return -ENODEV; - return watchdog->set_timeout(watchdog, timeout); + return wd->set_timeout(wd, timeout); } EXPORT_SYMBOL(watchdog_set_timeout); + +/** + * of_get_watchdog_priority() - get the desired watchdog priority from device tree + * @node: The device_node to read the property from + * + * return: The priority + */ +unsigned int of_get_watchdog_priority(struct device_node *node) +{ + unsigned int priority = WATCHDOG_DEFAULT_PRIORITY; + + of_property_read_u32(node, "watchdog-priority", &priority); + + return priority; +} -- cgit v1.2.3