diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c index 4c31beb..1f32869 100644 --- a/drivers/mfd/da9053.c +++ b/drivers/mfd/da9053.c @@ -271,7 +271,6 @@ da9053->dev = dev; da9053->client = to_i2c_client(dev); da9053->wd.set_timeout = da9053_set_timeout; - da9053->wd.priority = of_get_watchdog_priority(dev->device_node); da9053->wd.hwdev = dev; ret = da9053_enable_multiwrite(da9053); diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c index 967ca9a..e48c38a 100644 --- a/drivers/mfd/da9063.c +++ b/drivers/mfd/da9063.c @@ -377,7 +377,6 @@ dev_data = ret < 0 ? NULL : dev_data_tmp; priv = xzalloc(sizeof(struct da9063)); - priv->wd.priority = of_get_watchdog_priority(dev->device_node); priv->wd.set_timeout = da9063_watchdog_set_timeout; priv->wd.hwdev = dev; priv->timeout = DA9063_INITIAL_TIMEOUT; diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 4f881a1..5307ab0 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -222,7 +222,7 @@ { struct watchdog *wdd = &wd->wdd; const char * const *names = pulse_width_names; - int wdt_conf; + unsigned long wdt_conf; int ret; superio_enter(wd->sioaddr); @@ -262,6 +262,11 @@ dev_info(dev, "reset reason: %s\n", reset_source_name()); + if (test_bit(F71808FG_FLAG_WD_EN, &wdt_conf)) + wdd->running = WDOG_HW_RUNNING; + else + wdd->running = WDOG_HW_NOT_RUNNING; + ret = watchdog_register(wdd); if (ret) return ret; diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 77a3bd7..b2cfd1c 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -28,6 +28,7 @@ int (*set_timeout)(struct imx_wd *, unsigned); void (*soc_reset)(struct imx_wd *); int (*init)(struct imx_wd *); + bool (*is_running)(struct imx_wd *); unsigned int timeout_max; }; @@ -111,6 +112,11 @@ writew(IMX1_WDOG_WCR_WDE, priv->base + IMX1_WDOG_WCR); } +static inline bool imx21_watchdog_is_running(struct imx_wd *priv) +{ + return imxwd_read(priv, IMX21_WDOG_WCR) & IMX21_WDOG_WCR_WDE; +} + static int imx21_watchdog_set_timeout(struct imx_wd *priv, unsigned timeout) { u16 val; @@ -243,6 +249,13 @@ "fsl,ext-reset-output"); if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) { + if (priv->ops->is_running) { + if (priv->ops->is_running(priv)) + priv->wd.running = WDOG_HW_RUNNING; + else + priv->wd.running = WDOG_HW_NOT_RUNNING; + } + ret = watchdog_register(&priv->wd); if (ret) goto on_error; @@ -277,6 +290,7 @@ .set_timeout = imx21_watchdog_set_timeout, .soc_reset = imx21_soc_reset, .init = imx21_wd_init, + .is_running = imx21_watchdog_is_running, .timeout_max = 128, }; diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index 808d7c8..c7a5cb9 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -256,6 +256,7 @@ wdd->set_timeout = stm32_iwdg_set_timeout; wdd->timeout_max = (RLR_MAX + 1) * data->max_prescaler * 1000; wdd->timeout_max /= wd->rate * 1000; + wdd->running = WDOG_HW_RUNNING_UNSUPPORTED; /* ONF bit not present in IP */ ret = watchdog_register(wdd); if (ret) { diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 8b13950..b6e2a37 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -37,6 +37,8 @@ */ int watchdog_set_timeout(struct watchdog *wd, unsigned timeout) { + int ret; + if (!wd) return -ENODEV; @@ -45,7 +47,13 @@ pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout); - return wd->set_timeout(wd, timeout); + ret = wd->set_timeout(wd, timeout); + if (ret) + return ret; + + wd->running = timeout ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING; + + return 0; } EXPORT_SYMBOL(watchdog_set_timeout); @@ -127,6 +135,23 @@ return register_device(&wd->dev); } +/** + * dev_get_watchdog_priority() - get a device's desired watchdog priority + * @dev: The device, which device_node to read the property from + * + * return: The priority + */ +static unsigned int dev_get_watchdog_priority(struct device_d *dev) +{ + unsigned int priority = WATCHDOG_DEFAULT_PRIORITY; + + if (dev) + of_property_read_u32(dev->device_node, "watchdog-priority", + &priority); + + return priority; +} + int watchdog_register(struct watchdog *wd) { struct param_d *p; @@ -145,8 +170,12 @@ if (ret) return ret; + p = dev_add_param_tristate_ro(&wd->dev, "running", &wd->running); + if (IS_ERR(p)) + return PTR_ERR(p); + if (!wd->priority) - wd->priority = WATCHDOG_DEFAULT_PRIORITY; + wd->priority = dev_get_watchdog_priority(wd->hwdev); p = dev_add_param_uint32(&wd->dev, "priority", watchdog_set_priority, NULL, @@ -232,18 +261,3 @@ return NULL; } EXPORT_SYMBOL(watchdog_get_by_name); - -/** - * of_get_watchdog_priority() - get the desired watchdog priority from device tree - * @node: The device_node to read the property from - * - * return: The priority - */ -unsigned int of_get_watchdog_priority(struct device_node *node) -{ - unsigned int priority = WATCHDOG_DEFAULT_PRIORITY; - - of_property_read_u32(node, "watchdog-priority", &priority); - - return priority; -} diff --git a/include/param.h b/include/param.h index 4ac502e..d75f50e 100644 --- a/include/param.h +++ b/include/param.h @@ -63,6 +63,16 @@ int (*get)(struct param_d *p, void *priv), int *value, const char * const *names, int max, void *priv); +enum param_tristate { PARAM_TRISTATE_UNKNOWN, PARAM_TRISTATE_TRUE, PARAM_TRISTATE_FALSE }; + +struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + int *value, void *priv); + +struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name, + int *value); + struct param_d *dev_add_param_bitmask(struct device_d *dev, const char *name, int (*set)(struct param_d *p, void *priv), int (*get)(struct param_d *p, void *priv), @@ -144,6 +154,20 @@ return ERR_PTR(-ENOSYS); } +static inline struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + int *value, void *priv) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name, + int *value) +{ + return ERR_PTR(-ENOSYS); +} + static inline struct param_d *dev_add_param_ip(struct device_d *dev, const char *name, int (*set)(struct param_d *p, void *priv), int (*get)(struct param_d *p, void *priv), diff --git a/include/watchdog.h b/include/watchdog.h index 184a218..9741570 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -15,6 +15,13 @@ #include #include +#include + +enum wdog_hw_runnning { + WDOG_HW_RUNNING_UNSUPPORTED = PARAM_TRISTATE_UNKNOWN, + WDOG_HW_RUNNING = PARAM_TRISTATE_TRUE, + WDOG_HW_NOT_RUNNING = PARAM_TRISTATE_FALSE +}; struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); @@ -27,15 +34,27 @@ unsigned int poller_enable; struct poller_async poller; struct list_head list; + int running; /* enum wdog_hw_running */ }; +/* + * Use the following function to check whether or not the hardware watchdog + * is running + */ +static inline int watchdog_hw_running(struct watchdog *w) +{ + if (w->running == WDOG_HW_RUNNING_UNSUPPORTED) + return -ENOSYS; + + return w->running == WDOG_HW_RUNNING; +} + #ifdef CONFIG_WATCHDOG int watchdog_register(struct watchdog *); int watchdog_deregister(struct watchdog *); struct watchdog *watchdog_get_default(void); struct watchdog *watchdog_get_by_name(const char *name); int watchdog_set_timeout(struct watchdog*, unsigned); -unsigned int of_get_watchdog_priority(struct device_node *node); #else static inline int watchdog_register(struct watchdog *w) { @@ -61,12 +80,6 @@ { return 0; } - - -static inline unsigned int of_get_watchdog_priority(struct device_node *node) -{ - return 0; -} #endif #define WATCHDOG_DEFAULT_PRIORITY 100 diff --git a/lib/parameter.c b/lib/parameter.c index fdbb2e7..2269563 100644 --- a/lib/parameter.c +++ b/lib/parameter.c @@ -588,6 +588,28 @@ return &pe->param; } +static const char *const tristate_names[] = { + [PARAM_TRISTATE_UNKNOWN] = "unknown", + [PARAM_TRISTATE_TRUE] = "1", + [PARAM_TRISTATE_FALSE] = "0", +}; + +struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name, + int (*set)(struct param_d *p, void *priv), + int (*get)(struct param_d *p, void *priv), + int *value, void *priv) +{ + return dev_add_param_enum(dev, name, set, get, value, tristate_names, + ARRAY_SIZE(tristate_names), priv); +} + +struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name, + int *value) +{ + return dev_add_param_enum_ro(dev, name, value, tristate_names, + ARRAY_SIZE(tristate_names)); +} + struct param_bitmask { struct param_d param; unsigned long *value;