Commit 15013ad8 authored by Guenter Roeck's avatar Guenter Roeck Committed by Wim Van Sebroeck

watchdog: Add support for minimum time between heartbeats

Some watchdogs require a minimum time between heartbeats.
Examples are the watchdogs in DA9062 and AT91SAM9x.
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent d0684c8a
...@@ -52,6 +52,7 @@ struct watchdog_device { ...@@ -52,6 +52,7 @@ struct watchdog_device {
unsigned int timeout; unsigned int timeout;
unsigned int min_timeout; unsigned int min_timeout;
unsigned int max_timeout; unsigned int max_timeout;
unsigned int min_hw_heartbeat_ms;
unsigned int max_hw_heartbeat_ms; unsigned int max_hw_heartbeat_ms;
struct notifier_block reboot_nb; struct notifier_block reboot_nb;
struct notifier_block restart_nb; struct notifier_block restart_nb;
...@@ -81,6 +82,8 @@ It contains following fields: ...@@ -81,6 +82,8 @@ It contains following fields:
* max_timeout: the watchdog timer's maximum timeout value (in seconds), * max_timeout: the watchdog timer's maximum timeout value (in seconds),
as seen from userspace. If set, the maximum configurable value for as seen from userspace. If set, the maximum configurable value for
'timeout'. Not used if max_hw_heartbeat_ms is non-zero. 'timeout'. Not used if max_hw_heartbeat_ms is non-zero.
* min_hw_heartbeat_ms: Minimum time between heartbeats sent to the chip,
in milli-seconds.
* max_hw_heartbeat_ms: Maximum hardware heartbeat, in milli-seconds. * max_hw_heartbeat_ms: Maximum hardware heartbeat, in milli-seconds.
If set, the infrastructure will send heartbeats to the watchdog driver If set, the infrastructure will send heartbeats to the watchdog driver
if 'timeout' is larger than max_hw_heartbeat_ms, unless WDOG_ACTIVE if 'timeout' is larger than max_hw_heartbeat_ms, unless WDOG_ACTIVE
......
...@@ -64,6 +64,7 @@ struct watchdog_core_data { ...@@ -64,6 +64,7 @@ struct watchdog_core_data {
struct watchdog_device *wdd; struct watchdog_device *wdd;
struct mutex lock; struct mutex lock;
unsigned long last_keepalive; unsigned long last_keepalive;
unsigned long last_hw_keepalive;
struct delayed_work work; struct delayed_work work;
unsigned long status; /* Internal status bits */ unsigned long status; /* Internal status bits */
#define _WDOG_DEV_OPEN 0 /* Opened ? */ #define _WDOG_DEV_OPEN 0 /* Opened ? */
...@@ -137,8 +138,19 @@ static inline void watchdog_update_worker(struct watchdog_device *wdd) ...@@ -137,8 +138,19 @@ static inline void watchdog_update_worker(struct watchdog_device *wdd)
static int __watchdog_ping(struct watchdog_device *wdd) static int __watchdog_ping(struct watchdog_device *wdd)
{ {
struct watchdog_core_data *wd_data = wdd->wd_data;
unsigned long earliest_keepalive = wd_data->last_hw_keepalive +
msecs_to_jiffies(wdd->min_hw_heartbeat_ms);
int err; int err;
if (time_is_after_jiffies(earliest_keepalive)) {
mod_delayed_work(watchdog_wq, &wd_data->work,
earliest_keepalive - jiffies);
return 0;
}
wd_data->last_hw_keepalive = jiffies;
if (wdd->ops->ping) if (wdd->ops->ping)
err = wdd->ops->ping(wdd); /* ping the watchdog */ err = wdd->ops->ping(wdd); /* ping the watchdog */
else else
...@@ -819,6 +831,9 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno) ...@@ -819,6 +831,9 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
return err; return err;
} }
/* Record time of most recent heartbeat as 'just before now'. */
wd_data->last_hw_keepalive = jiffies - 1;
/* /*
* If the watchdog is running, prevent its driver from being unloaded, * If the watchdog is running, prevent its driver from being unloaded,
* and schedule an immediate ping. * and schedule an immediate ping.
......
...@@ -65,6 +65,8 @@ struct watchdog_ops { ...@@ -65,6 +65,8 @@ struct watchdog_ops {
* @max_timeout:The watchdog devices maximum timeout value (in seconds) * @max_timeout:The watchdog devices maximum timeout value (in seconds)
* as configurable from user space. Only relevant if * as configurable from user space. Only relevant if
* max_hw_heartbeat_ms is not provided. * max_hw_heartbeat_ms is not provided.
* @min_hw_heartbeat_ms:
* Minimum time between heartbeats, in milli-seconds.
* @max_hw_heartbeat_ms: * @max_hw_heartbeat_ms:
* Hardware limit for maximum timeout, in milli-seconds. * Hardware limit for maximum timeout, in milli-seconds.
* Replaces max_timeout if specified. * Replaces max_timeout if specified.
...@@ -95,6 +97,7 @@ struct watchdog_device { ...@@ -95,6 +97,7 @@ struct watchdog_device {
unsigned int timeout; unsigned int timeout;
unsigned int min_timeout; unsigned int min_timeout;
unsigned int max_timeout; unsigned int max_timeout;
unsigned int min_hw_heartbeat_ms;
unsigned int max_hw_heartbeat_ms; unsigned int max_hw_heartbeat_ms;
struct notifier_block reboot_nb; struct notifier_block reboot_nb;
struct notifier_block restart_nb; struct notifier_block restart_nb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment