Skip to content

Commit

Permalink
watchdog: core: dt: add support for the timeout-sec dt property
Browse files Browse the repository at this point in the history
Add support for watchdog drivers to initialize/set the timeout field
of the watchdog_device structure. The timeout field is initialised
either with the module timeout parameter value (if valid) or with the
timeout-sec dt property (if valid). If both are invalid the initial
value is unchanged.

Signed-off-by: Fabio Porcedda <fabio.porcedda@gmail.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
  • Loading branch information
Fabio Porcedda authored and Wim Van Sebroeck committed Mar 1, 2013
1 parent e3e83d0 commit 3048253
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 12 deletions.
14 changes: 13 additions & 1 deletion Documentation/watchdog/watchdog-kernel-api.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The Linux WatchDog Timer Driver Core kernel API.
===============================================
Last reviewed: 22-May-2012
Last reviewed: 12-Feb-2013

Wim Van Sebroeck <wim@iguana.be>

Expand Down Expand Up @@ -212,3 +212,15 @@ driver specific data to and a pointer to the data itself.
The watchdog_get_drvdata function allows you to retrieve driver specific data.
The argument of this function is the watchdog device where you want to retrieve
data from. The function returns the pointer to the driver specific data.

To initialize the timeout field, the following function can be used:

extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);

The watchdog_init_timeout function allows you to initialize the timeout field
using the module timeout parameter or by retrieving the timeout-sec property from
the device tree (if the module timeout parameter is invalid). Best practice is
to set the default timeout value as timeout value in the watchdog_device and
then use this function to set the user "preferred" timeout value.
This routine returns zero on success and a negative errno code for failure.
66 changes: 57 additions & 9 deletions drivers/watchdog/watchdog_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,68 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/idr.h> /* For ida_* macros */
#include <linux/err.h> /* For IS_ERR macros */
#include <linux/of.h> /* For of_get_timeout_sec */

#include "watchdog_core.h" /* For watchdog_dev_register/... */

static DEFINE_IDA(watchdog_ida);
static struct class *watchdog_class;

static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
{
/*
* Check that we have valid min and max timeout values, if
* not reset them both to 0 (=not used or unknown)
*/
if (wdd->min_timeout > wdd->max_timeout) {
pr_info("Invalid min and max timeout values, resetting to 0!\n");
wdd->min_timeout = 0;
wdd->max_timeout = 0;
}
}

/**
* watchdog_init_timeout() - initialize the timeout field
* @timeout_parm: timeout module parameter
* @dev: Device that stores the timeout-sec property
*
* Initialize the timeout field of the watchdog_device struct with either the
* timeout module parameter (if it is valid value) or the timeout-sec property
* (only if it is a valid value and the timeout_parm is out of bounds).
* If none of them are valid then we keep the old value (which should normally
* be the default timeout value.
*
* A zero is returned on success and -EINVAL for failure.
*/
int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev)
{
unsigned int t = 0;
int ret = 0;

watchdog_check_min_max_timeout(wdd);

/* try to get the tiemout module parameter first */
if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
wdd->timeout = timeout_parm;
return ret;
}
if (timeout_parm)
ret = -EINVAL;

/* try to get the timeout_sec property */
if (dev == NULL || dev->of_node == NULL)
return ret;
of_property_read_u32(dev->of_node, "timeout-sec", &t);
if (!watchdog_timeout_invalid(wdd, t))
wdd->timeout = t;
else
ret = -EINVAL;

return ret;
}
EXPORT_SYMBOL_GPL(watchdog_init_timeout);

/**
* watchdog_register_device() - register a watchdog device
* @wdd: watchdog device
Expand All @@ -63,15 +119,7 @@ int watchdog_register_device(struct watchdog_device *wdd)
if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
return -EINVAL;

/*
* Check that we have valid min and max timeout values, if
* not reset them both to 0 (=not used or unknown)
*/
if (wdd->min_timeout > wdd->max_timeout) {
pr_info("Invalid min and max timeout values, resetting to 0!\n");
wdd->min_timeout = 0;
wdd->max_timeout = 0;
}
watchdog_check_min_max_timeout(wdd);

/*
* Note: now that all watchdog_device data has been verified, we
Expand Down
3 changes: 1 addition & 2 deletions drivers/watchdog/watchdog_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,7 @@ static int watchdog_set_timeout(struct watchdog_device *wddev,
!(wddev->info->options & WDIOF_SETTIMEOUT))
return -EOPNOTSUPP;

if ((wddev->max_timeout != 0) &&
(timeout < wddev->min_timeout || timeout > wddev->max_timeout))
if (watchdog_timeout_invalid(wddev, timeout))
return -EINVAL;

mutex_lock(&wddev->lock);
Expand Down
9 changes: 9 additions & 0 deletions include/linux/watchdog.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool noway
set_bit(WDOG_NO_WAY_OUT, &wdd->status);
}

/* Use the following function to check if a timeout value is invalid */
static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
{
return ((wdd->max_timeout != 0) &&
(t < wdd->min_timeout || t > wdd->max_timeout));
}

/* Use the following functions to manipulate watchdog driver specific data */
static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
{
Expand All @@ -130,6 +137,8 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
}

/* drivers/watchdog/watchdog_core.c */
extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);
extern int watchdog_register_device(struct watchdog_device *);
extern void watchdog_unregister_device(struct watchdog_device *);

Expand Down

0 comments on commit 3048253

Please sign in to comment.