diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2015-07-31 09:21:36 +0200 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2015-09-09 21:35:37 +0200 |
commit | 4f2d0b2d1b31cbe704c8f94e74e46cb64187ab0c (patch) | |
tree | 30a9e56910f1f654f0ef240ca0d771c7067e9203 /drivers | |
parent | watchdog: gpio-wdt: be more strict about hw_algo matching (diff) | |
download | linux-4f2d0b2d1b31cbe704c8f94e74e46cb64187ab0c.tar.xz linux-4f2d0b2d1b31cbe704c8f94e74e46cb64187ab0c.zip |
watchdog: gpio-wdt: ping already at startup for always running devices
During probe for an always-running watchdog a timer is setup to
constantly ping the watchdog while the device is not open. The gpio to
ping the watchdog is setup to inactive.
For a watchdog with hw_algo = "toggle" this results in a ping depending
on the initial state of the gpio, for hw_algo = "level" no ping is
generated.
Make sure that the first automatic ping is sent immediately and not only
when the timer expires the first time. This makes the machine survive in
case more than half of the watchdog timeout is already elapsed. (Which
is very probable for the chip I'm faced with that has a timeout of one
second.)
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/watchdog/gpio_wdt.c | 60 |
1 files changed, 30 insertions, 30 deletions
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 57d30f1f55ab..5e16b0983e2a 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -50,12 +50,41 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv) gpio_direction_input(priv->gpio); } +static void gpio_wdt_hwping(unsigned long data) +{ + struct watchdog_device *wdd = (struct watchdog_device *)data; + struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); + + if (priv->armed && time_after(jiffies, priv->last_jiffies + + msecs_to_jiffies(wdd->timeout * 1000))) { + dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); + return; + } + + /* Restart timer */ + mod_timer(&priv->timer, jiffies + priv->hw_margin); + + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + /* Toggle output pin */ + priv->state = !priv->state; + gpio_set_value_cansleep(priv->gpio, priv->state); + break; + case HW_ALGO_LEVEL: + /* Pulse */ + gpio_set_value_cansleep(priv->gpio, !priv->active_low); + udelay(1); + gpio_set_value_cansleep(priv->gpio, priv->active_low); + break; + } +} + static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) { priv->state = priv->active_low; gpio_direction_output(priv->gpio, priv->state); priv->last_jiffies = jiffies; - mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); + gpio_wdt_hwping((unsigned long)&priv->wdd); } static int gpio_wdt_start(struct watchdog_device *wdd) @@ -97,35 +126,6 @@ static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) return gpio_wdt_ping(wdd); } -static void gpio_wdt_hwping(unsigned long data) -{ - struct watchdog_device *wdd = (struct watchdog_device *)data; - struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); - - if (priv->armed && time_after(jiffies, priv->last_jiffies + - msecs_to_jiffies(wdd->timeout * 1000))) { - dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); - return; - } - - /* Restart timer */ - mod_timer(&priv->timer, jiffies + priv->hw_margin); - - switch (priv->hw_algo) { - case HW_ALGO_TOGGLE: - /* Toggle output pin */ - priv->state = !priv->state; - gpio_set_value_cansleep(priv->gpio, priv->state); - break; - case HW_ALGO_LEVEL: - /* Pulse */ - gpio_set_value_cansleep(priv->gpio, !priv->active_low); - udelay(1); - gpio_set_value_cansleep(priv->gpio, priv->active_low); - break; - } -} - static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, void *unused) { |