summaryrefslogtreecommitdiff
path: root/drivers/watchdog/watchdog_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r--drivers/watchdog/watchdog_dev.c86
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);
}