diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3defb9d..1d6b156 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -10,6 +10,12 @@ if WATCHDOG +menuconfig WATCHDOG_POLLER + bool "Watchdog periodic feeder support" + select POLLER + help + Provides support for periodic watchdog feeder. + config WATCHDOG_AR9344 bool "QCA AR9344" depends on SOC_QCA_AR9344 || SOC_QCA_AR9331 diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 425e785..d330544 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -31,6 +31,16 @@ return "unknown"; } +static int _watchdog_set_timeout(struct watchdog *wd, unsigned timeout) +{ + if (timeout > wd->timeout_max) + return -EINVAL; + + pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout); + + return wd->set_timeout(wd, timeout); +} + static int watchdog_set_cur(struct param_d *param, void *priv) { struct watchdog *wd = priv; @@ -41,6 +51,55 @@ return 0; } +static void watchdog_poller_cb(void *priv); + +static void watchdog_poller_start(struct watchdog *wd) +{ + _watchdog_set_timeout(wd, wd->timeout_cur); + poller_call_async(&wd->poller, 500 * MSECOND, + watchdog_poller_cb, wd); + +} + +static void watchdog_poller_cb(void *priv) +{ + struct watchdog *wd = priv; + + if (wd->poller_enable) + watchdog_poller_start(wd); +} + +static int watchdog_set_poller(struct param_d *param, void *priv) +{ + struct watchdog *wd = priv; + + + if (wd->poller_enable) { + dev_info(&wd->dev, "enable watchdog poller\n"); + watchdog_poller_start(wd); + } else { + dev_info(&wd->dev, "disable watchdog poller\n"); + poller_async_cancel(&wd->poller); + } + + return 0; +} + +static int watchdog_register_poller(struct watchdog *wd) +{ + struct param_d *p; + int ret; + + ret = poller_async_register(&wd->poller); + if (ret) + return ret; + + p = dev_add_param_bool(&wd->dev, "autoping", watchdog_set_poller, + NULL, &wd->poller_enable, wd); + + return PTR_ERR_OR_ZERO(p); +} + static int watchdog_register_dev(struct watchdog *wd, const char *name, int id) { wd->dev.parent = wd->hwdev; @@ -86,6 +145,12 @@ if (IS_ERR(p)) return PTR_ERR(p); + if (IS_ENABLED(CONFIG_WATCHDOG_POLLER)) { + ret = watchdog_register_poller(wd); + if (ret) + return ret; + } + list_add_tail(&wd->list, &watchdog_list); pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd), @@ -97,6 +162,11 @@ int watchdog_deregister(struct watchdog *wd) { + if (IS_ENABLED(CONFIG_WATCHDOG_POLLER)) { + poller_async_cancel(&wd->poller); + poller_async_unregister(&wd->poller); + } + unregister_device(&wd->dev); list_del(&wd->list); @@ -132,12 +202,7 @@ if (!wd) return -ENODEV; - if (timeout > wd->timeout_max) - return -EINVAL; - - pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout); - - return wd->set_timeout(wd, timeout); + return _watchdog_set_timeout(wd, timeout); } EXPORT_SYMBOL(watchdog_set_timeout); diff --git a/include/watchdog.h b/include/watchdog.h index 2f1874c..0db4263 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -13,6 +13,8 @@ #ifndef INCLUDE_WATCHDOG_H # define INCLUDE_WATCHDOG_H +#include + struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); const char *name; @@ -21,6 +23,8 @@ unsigned int priority; unsigned int timeout_max; unsigned int timeout_cur; + unsigned int poller_enable; + struct poller_async poller; struct list_head list; };