diff options
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 86 |
1 files changed, 47 insertions, 39 deletions
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 2946f3a63110..3bab32485273 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -7,6 +7,7 @@ * * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. * + * (c) Copyright 2021 Hewlett Packard Enterprise Development LP. * * This source code is part of the generic code that can be used * by all the watchdog timer drivers. @@ -46,30 +47,6 @@ #include "watchdog_core.h" #include "watchdog_pretimeout.h" -/* - * struct watchdog_core_data - watchdog core internal data - * @dev: The watchdog's internal device - * @cdev: The watchdog's Character device. - * @wdd: Pointer to watchdog device. - * @lock: Lock for watchdog core. - * @status: Watchdog core internal status bits. - */ -struct watchdog_core_data { - struct device dev; - struct cdev cdev; - struct watchdog_device *wdd; - struct mutex lock; - ktime_t last_keepalive; - ktime_t last_hw_keepalive; - ktime_t open_deadline; - struct hrtimer timer; - struct kthread_work work; - unsigned long status; /* Internal status bits */ -#define _WDOG_DEV_OPEN 0 /* Opened ? */ -#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */ -#define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */ -}; - /* the dev_t structure to store the dynamically allocated watchdog devices */ static dev_t watchdog_devt; /* Reference to watchdog device behind /dev/watchdog */ @@ -185,6 +162,9 @@ static int __watchdog_ping(struct watchdog_device *wdd) else err = wdd->ops->start(wdd); /* restart watchdog */ + if (err == 0) + watchdog_hrtimer_pretimeout_start(wdd); + watchdog_update_worker(wdd); return err; @@ -275,8 +255,10 @@ static int watchdog_start(struct watchdog_device *wdd) started_at = ktime_get(); if (watchdog_hw_running(wdd) && wdd->ops->ping) { err = __watchdog_ping(wdd); - if (err == 0) + if (err == 0) { set_bit(WDOG_ACTIVE, &wdd->status); + watchdog_hrtimer_pretimeout_start(wdd); + } } else { err = wdd->ops->start(wdd); if (err == 0) { @@ -284,6 +266,7 @@ static int watchdog_start(struct watchdog_device *wdd) wd_data->last_keepalive = started_at; wd_data->last_hw_keepalive = started_at; watchdog_update_worker(wdd); + watchdog_hrtimer_pretimeout_start(wdd); } } @@ -325,6 +308,7 @@ static int watchdog_stop(struct watchdog_device *wdd) if (err == 0) { clear_bit(WDOG_ACTIVE, &wdd->status); watchdog_update_worker(wdd); + watchdog_hrtimer_pretimeout_stop(wdd); } return err; @@ -361,6 +345,9 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd) if (test_and_clear_bit(_WDOG_KEEPALIVE, &wd_data->status)) status |= WDIOF_KEEPALIVEPING; + if (IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT)) + status |= WDIOF_PRETIMEOUT; + return status; } @@ -408,7 +395,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd, { int err = 0; - if (!(wdd->info->options & WDIOF_PRETIMEOUT)) + if (!watchdog_have_pretimeout(wdd)) return -EOPNOTSUPP; if (watchdog_pretimeout_invalid(wdd, timeout)) @@ -451,7 +438,8 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status)); + return sysfs_emit(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, + &wdd->status)); } static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr, @@ -485,7 +473,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr, status = watchdog_get_status(wdd); mutex_unlock(&wd_data->lock); - return sprintf(buf, "0x%x\n", status); + return sysfs_emit(buf, "0x%x\n", status); } static DEVICE_ATTR_RO(status); @@ -494,7 +482,7 @@ static ssize_t bootstatus_show(struct device *dev, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->bootstatus); + return sysfs_emit(buf, "%u\n", wdd->bootstatus); } static DEVICE_ATTR_RO(bootstatus); @@ -510,7 +498,7 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, status = watchdog_get_timeleft(wdd, &val); mutex_unlock(&wd_data->lock); if (!status) - status = sprintf(buf, "%u\n", val); + status = sysfs_emit(buf, "%u\n", val); return status; } @@ -521,16 +509,34 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->timeout); + return sysfs_emit(buf, "%u\n", wdd->timeout); } static DEVICE_ATTR_RO(timeout); +static ssize_t min_timeout_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", wdd->min_timeout); +} +static DEVICE_ATTR_RO(min_timeout); + +static ssize_t max_timeout_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", wdd->max_timeout); +} +static DEVICE_ATTR_RO(max_timeout); + static ssize_t pretimeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", wdd->pretimeout); + return sysfs_emit(buf, "%u\n", wdd->pretimeout); } static DEVICE_ATTR_RO(pretimeout); @@ -539,7 +545,7 @@ static ssize_t identity_show(struct device *dev, struct device_attribute *attr, { struct watchdog_device *wdd = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", wdd->info->identity); + return sysfs_emit(buf, "%s\n", wdd->info->identity); } static DEVICE_ATTR_RO(identity); @@ -549,9 +555,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, struct watchdog_device *wdd = dev_get_drvdata(dev); if (watchdog_active(wdd)) - return sprintf(buf, "active\n"); + return sysfs_emit(buf, "active\n"); - return sprintf(buf, "inactive\n"); + return sysfs_emit(buf, "inactive\n"); } static DEVICE_ATTR_RO(state); @@ -594,13 +600,11 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) mode = 0; - else if (attr == &dev_attr_pretimeout.attr && - !(wdd->info->options & WDIOF_PRETIMEOUT)) + else if (attr == &dev_attr_pretimeout.attr && !watchdog_have_pretimeout(wdd)) mode = 0; else if ((attr == &dev_attr_pretimeout_governor.attr || attr == &dev_attr_pretimeout_available_governors.attr) && - (!(wdd->info->options & WDIOF_PRETIMEOUT) || - !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) + (!watchdog_have_pretimeout(wdd) || !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) mode = 0; return mode; @@ -609,6 +613,8 @@ static struct attribute *wdt_attrs[] = { &dev_attr_state.attr, &dev_attr_identity.attr, &dev_attr_timeout.attr, + &dev_attr_min_timeout.attr, + &dev_attr_max_timeout.attr, &dev_attr_pretimeout.attr, &dev_attr_timeleft.attr, &dev_attr_bootstatus.attr, @@ -1009,6 +1015,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd) kthread_init_work(&wd_data->work, watchdog_ping_work); hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); wd_data->timer.function = watchdog_timer_expired; + watchdog_hrtimer_pretimeout_init(wdd); if (wdd->id == 0) { old_wd_data = wd_data; @@ -1096,6 +1103,7 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd) hrtimer_cancel(&wd_data->timer); kthread_cancel_work_sync(&wd_data->work); + watchdog_hrtimer_pretimeout_stop(wdd); put_device(&wd_data->dev); } |