static int watchdog_stop(struct watchdog_device *wdd) { int err = 0; if (!watchdog_active(wdd)) return 0; if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) { pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n", wdd->id); return -EBUSY; } if (wdd->ops->stop) { clear_bit(WDOG_HW_RUNNING, &wdd->status); err = wdd->ops->stop(wdd); } else { set_bit(WDOG_HW_RUNNING, &wdd->status); } if (err == 0) { clear_bit(WDOG_ACTIVE, &wdd->status); watchdog_update_worker(wdd); } return err; }
static int __watchdog_ping(struct watchdog_device *wdd) { struct watchdog_core_data *wd_data = wdd->wd_data; ktime_t earliest_keepalive, now; int err; earliest_keepalive = ktime_add(wd_data->last_hw_keepalive, ms_to_ktime(wdd->min_hw_heartbeat_ms)); now = ktime_get(); if (ktime_after(earliest_keepalive, now)) { hrtimer_start(&wd_data->timer, ktime_sub(earliest_keepalive, now), HRTIMER_MODE_REL); return 0; } wd_data->last_hw_keepalive = now; if (wdd->ops->ping) err = wdd->ops->ping(wdd); /* ping the watchdog */ else err = wdd->ops->start(wdd); /* restart watchdog */ watchdog_update_worker(wdd); return err; }
static int watchdog_release(struct inode *inode, struct file *file) { struct watchdog_core_data *wd_data = file->private_data; struct watchdog_device *wdd; int err = -EBUSY; bool running; mutex_lock(&wd_data->lock); wdd = wd_data->wdd; if (!wdd) goto done; /* * We only stop the watchdog if we received the magic character * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then * watchdog_stop will fail. */ if (!test_bit(WDOG_ACTIVE, &wdd->status)) err = 0; else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) || !(wdd->info->options & WDIOF_MAGICCLOSE)) err = watchdog_stop(wdd); /* If the watchdog was not stopped, send a keepalive ping */ if (err < 0) { pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id); watchdog_ping(wdd); } watchdog_update_worker(wdd); /* make sure that /dev/watchdog can be re-opened */ clear_bit(_WDOG_DEV_OPEN, &wd_data->status); done: running = wdd && watchdog_hw_running(wdd); mutex_unlock(&wd_data->lock); /* * Allow the owner module to be unloaded again unless the watchdog * is still running. If the watchdog is still running, it can not * be stopped, and its driver must not be unloaded. */ if (!running) { module_put(wd_data->cdev.owner); kref_put(&wd_data->kref, watchdog_core_data_release); } return 0; }
static int watchdog_set_timeout(struct watchdog_device *wdd, unsigned int timeout) { int err = 0; if (!(wdd->info->options & WDIOF_SETTIMEOUT)) return -EOPNOTSUPP; if (watchdog_timeout_invalid(wdd, timeout)) return -EINVAL; if (wdd->ops->set_timeout) err = wdd->ops->set_timeout(wdd, timeout); else wdd->timeout = timeout; watchdog_update_worker(wdd); return err; }
static int watchdog_set_timeout(struct watchdog_device *wdd, unsigned int timeout) { int err = 0; if (!(wdd->info->options & WDIOF_SETTIMEOUT)) return -EOPNOTSUPP; if (watchdog_timeout_invalid(wdd, timeout)) return -EINVAL; if (wdd->ops->set_timeout) { err = wdd->ops->set_timeout(wdd, timeout); } else { wdd->timeout = timeout; /* Disable pretimeout if it doesn't fit the new timeout */ if (wdd->pretimeout >= wdd->timeout) wdd->pretimeout = 0; } watchdog_update_worker(wdd); return err; }
static int watchdog_start(struct watchdog_device *wdd) { struct watchdog_core_data *wd_data = wdd->wd_data; unsigned long started_at; int err; if (watchdog_active(wdd)) return 0; set_bit(_WDOG_KEEPALIVE, &wd_data->status); started_at = jiffies; if (watchdog_hw_running(wdd) && wdd->ops->ping) err = wdd->ops->ping(wdd); else err = wdd->ops->start(wdd); if (err == 0) { set_bit(WDOG_ACTIVE, &wdd->status); wd_data->last_keepalive = started_at; watchdog_update_worker(wdd); } return err; }
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; 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) err = wdd->ops->ping(wdd); /* ping the watchdog */ else err = wdd->ops->start(wdd); /* restart watchdog */ watchdog_update_worker(wdd); return err; }