@@ -111,12 +111,18 @@ EXPORT_SYMBOL_GPL(watchdog_init_timeout);
*/
int watchdog_init_params(struct watchdog_device *wdd, struct device *dev)
{
+ unsigned int t = 0;
int ret = 0;
ret = watchdog_init_timeout(wdd, wdd->timeout, dev);
if (ret < 0)
return ret;
+ if (!of_property_read_u32(dev->of_node, "early-timeout-sec", &t))
+ wdd->early_timeout_sec = t;
+ else
+ wdd->early_timeout_sec = -1;
+
/*
* Max HW timeout needs to be set so that core knows when to
* use a kernel worker to support longer watchdog timeouts
@@ -134,11 +140,16 @@ static void watchdog_worker(struct work_struct *work)
struct watchdog_device, work);
bool boot_keepalive;
bool active_keepalive;
+ bool early_timeout_expired;
mutex_lock(&wdd->lock);
- boot_keepalive = !watchdog_active(wdd) &&
- !watchdog_is_stoppable(wdd);
+ early_timeout_expired = !watchdog_active(wdd) &&
+ wdd->early_timeout_sec >= 0 &&
+ time_after(jiffies, wdd->expires);
+
+ boot_keepalive = (!watchdog_active(wdd) &&
+ !watchdog_is_stoppable(wdd)) || !early_timeout_expired;
active_keepalive = watchdog_active(wdd) &&
wdd->hw_max_timeout < wdd->timeout * HZ;
@@ -165,18 +176,33 @@ static int prepare_watchdog(struct watchdog_device *wdd)
{
int err = 0;
- /* Stop the watchdog now before user space opens the device */
- if (watchdog_is_stoppable(wdd) &&
- wdd->hw_features & WDOG_HW_RUNNING_AT_BOOT) {
- err = wdd->ops->stop(wdd);
-
- } else if (!watchdog_is_stoppable(wdd) &&
- wdd->hw_features & WDOG_HW_RUNNING_AT_BOOT) {
+ if (wdd->early_timeout_sec >= 0) {
/*
- * Can't stop it, use a delayed worker to tick it
- * until it's open by user space
+ * early timeout, if set, ensures that watchdog will
+ * reset the device unless user space opens the
+ * watchdog device within the given interval.
*/
- schedule_delayed_work(&wdd->work, wdd->hw_heartbeat);
+ if (!(wdd->hw_features & WDOG_HW_RUNNING_AT_BOOT))
+ wdd->ops->start(wdd);
+
+ if (wdd->early_timeout_sec > 0) {
+ wdd->expires = jiffies + wdd->early_timeout_sec * HZ;
+ schedule_delayed_work(&wdd->work, wdd->hw_heartbeat);
+ }
+ } else {
+ /* Stop the watchdog now before user space opens the device */
+ if (watchdog_is_stoppable(wdd) &&
+ wdd->hw_features & WDOG_HW_RUNNING_AT_BOOT) {
+ err = wdd->ops->stop(wdd);
+
+ } else if (!watchdog_is_stoppable(wdd) &&
+ wdd->hw_features & WDOG_HW_RUNNING_AT_BOOT) {
+ /*
+ * Can't stop it, use a delayed worker to tick it
+ * until it's open by user space
+ */
+ schedule_delayed_work(&wdd->work, wdd->hw_heartbeat);
+ }
}
return err;
}
@@ -128,6 +128,10 @@ static int watchdog_start(struct watchdog_device *wddev)
} else
cancel_delayed_work(&wddev->work);
+ /* Once we open the device, early timeout can be disabled */
+ if (wddev->early_timeout_sec >= 0)
+ wddev->early_timeout_sec = -1;
+
out_start:
mutex_unlock(&wddev->lock);
return err;
@@ -94,6 +94,7 @@ struct watchdog_device {
unsigned int hw_max_timeout; /* in jiffies */
unsigned int hw_heartbeat; /* in jiffies */
unsigned long int expires; /* for keepalive worker */
+ int early_timeout_sec;
void *driver_data;
struct mutex lock;
struct delayed_work work;