summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2019-11-08 12:03:30 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2019-11-11 09:20:18 +0100
commite8a1aef7c1b8395ae7971d24a13db9b9a935902f (patch)
tree0c5163ec9e87d10e7f77ebbfb46e3b3c09e10aaa
parent85876c8be75894ecaa8ac75e01bfba0cbe1cfc45 (diff)
downloadbarebox-e8a1aef7c1b8395ae7971d24a13db9b9a935902f.tar.gz
watchdog: implement generic support for .running device parameter
Linux watchdog have an optional WDOG_HW_RUNNING bit that is used in conjunction with CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED to automatically ping running watchdogs until userspace takes over. So far, when we ported Linux drivers, we dropped this detection, but it would be useful to have this information in barebox as well: The American Megatrends BIOS I am using allows configuring the hardware watchdog from the BIOS. barebox enables the WDT as well, so in normal operation we would never notice if after a BIOS update, the watchdog is no longer enabled. If we maintain a running parameter on watchdog devices, board code can be written to check whether the watchdog device is indeed running. To achieve this, add the necessary bits to the watchdog API. How we go about it differs from Linux a little: - We use an enum instead of a single bit, so we can differentiate between watchdogs that are not running and watchdogs whose running status is unknown. - Because we can check whether watchdog_hw_running is supported, it now can fail and return a negative value in that case - We do the maintenance of the running parameter after barebox feeds/disables the watchdog in the core, so it doesn't need to be replicated across drivers. Drivers hould only initialize the running parameter once at probe time. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--drivers/watchdog/wd_core.c21
-rw-r--r--include/watchdog.h17
2 files changed, 37 insertions, 1 deletions
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 39cac6f..fcead11 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -37,6 +37,8 @@ static const char *watchdog_name(struct watchdog *wd)
*/
int watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
{
+ int ret;
+
if (!wd)
return -ENODEV;
@@ -45,7 +47,13 @@ int watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout);
- return wd->set_timeout(wd, timeout);
+ ret = wd->set_timeout(wd, timeout);
+ if (ret)
+ return ret;
+
+ wd->running = timeout ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+
+ return 0;
}
EXPORT_SYMBOL(watchdog_set_timeout);
@@ -144,6 +152,12 @@ static unsigned int dev_get_watchdog_priority(struct device_d *dev)
return priority;
}
+const char *running_names[] = {
+ [WDOG_HW_RUNNING_UNSUPPORTED] = "unknown",
+ [WDOG_HW_RUNNING] = "1",
+ [WDOG_HW_NOT_RUNNING] = "0",
+};
+
int watchdog_register(struct watchdog *wd)
{
struct param_d *p;
@@ -162,6 +176,11 @@ int watchdog_register(struct watchdog *wd)
if (ret)
return ret;
+ p = dev_add_param_enum_ro(&wd->dev, "running", &wd->running,
+ running_names, ARRAY_SIZE(running_names));
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
if (!wd->priority)
wd->priority = dev_get_watchdog_priority(wd->hwdev);
diff --git a/include/watchdog.h b/include/watchdog.h
index 105b7ca..5790205 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -16,6 +16,10 @@
#include <poller.h>
#include <driver.h>
+enum wdog_hw_runnning {
+ WDOG_HW_RUNNING_UNSUPPORTED, WDOG_HW_RUNNING, WDOG_HW_NOT_RUNNING
+};
+
struct watchdog {
int (*set_timeout)(struct watchdog *, unsigned);
const char *name;
@@ -27,8 +31,21 @@ struct watchdog {
unsigned int poller_enable;
struct poller_async poller;
struct list_head list;
+ int running; /* enum wdog_hw_running */
};
+/*
+ * Use the following function to check whether or not the hardware watchdog
+ * is running
+ */
+static inline int watchdog_hw_running(struct watchdog *w)
+{
+ if (w->running == WDOG_HW_RUNNING_UNSUPPORTED)
+ return -ENOSYS;
+
+ return w->running == WDOG_HW_RUNNING;
+}
+
#ifdef CONFIG_WATCHDOG
int watchdog_register(struct watchdog *);
int watchdog_deregister(struct watchdog *);