diff options
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/davinci_wdt.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/im28wd.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/imxwd.c | 35 | ||||
-rw-r--r-- | drivers/watchdog/jz4740.c | 37 | ||||
-rw-r--r-- | drivers/watchdog/wd_core.c | 70 |
5 files changed, 91 insertions, 53 deletions
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index ecf6e89b47..dfabee230c 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -147,6 +147,7 @@ static int davinci_wdt_probe(struct device_d *dev) clk_enable(davinci_wdt->clk); davinci_wdt->wd.set_timeout = davinci_wdt_set_timeout; + davinci_wdt->wd.dev = dev; ret = watchdog_register(&davinci_wdt->wd); if (ret < 0) diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c index a9093a7b51..3510776a3a 100644 --- a/drivers/watchdog/im28wd.c +++ b/drivers/watchdog/im28wd.c @@ -197,6 +197,7 @@ static int imx28_wd_probe(struct device_d *dev) if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); priv->wd.set_timeout = imx28_watchdog_set_timeout; + priv->wd.dev = dev; if (!(readl(priv->regs + MXS_RTC_STAT) & MXS_RTC_STAT_WD_PRESENT)) { rc = -ENODEV; diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 5ffbac7cdd..dd11a62613 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -18,6 +18,7 @@ #include <of.h> #include <errno.h> #include <malloc.h> +#include <restart.h> #include <watchdog.h> #include <reset_source.h> @@ -33,6 +34,7 @@ struct imx_wd { void __iomem *base; struct device_d *dev; const struct imx_wd_ops *ops; + struct restart_handler restart; }; #define to_imx_wd(h) container_of(h, struct imx_wd, wd) @@ -121,12 +123,11 @@ static int imx_watchdog_set_timeout(struct watchdog *wd, unsigned timeout) return priv->ops->set_timeout(priv, timeout); } -static struct imx_wd *reset_wd; - -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn imxwd_force_soc_reset(struct restart_handler *rst) { - if (reset_wd) - reset_wd->ops->set_timeout(reset_wd, -1); + struct imx_wd *priv = container_of(rst, struct imx_wd, restart); + + priv->ops->set_timeout(priv, -1); mdelay(1000); @@ -185,11 +186,9 @@ static int imx_wd_probe(struct device_d *dev) } priv->ops = ops; priv->wd.set_timeout = imx_watchdog_set_timeout; + priv->wd.dev = dev; priv->dev = dev; - if (!reset_wd) - reset_wd = priv; - if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) { ret = watchdog_register(&priv->wd); if (ret) @@ -206,28 +205,21 @@ static int imx_wd_probe(struct device_d *dev) dev->priv = priv; + priv->restart.name = "imxwd"; + priv->restart.restart = imxwd_force_soc_reset; + + restart_handler_register(&priv->restart); + return 0; error_unregister: if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) watchdog_deregister(&priv->wd); on_error: - if (reset_wd && reset_wd != priv) - free(priv); + free(priv); return ret; } -static void imx_wd_remove(struct device_d *dev) -{ - struct imx_wd *priv = dev->priv; - - if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) - watchdog_deregister(&priv->wd); - - if (reset_wd && reset_wd != priv) - free(priv); -} - static const struct imx_wd_ops imx21_wd_ops = { .set_timeout = imx21_watchdog_set_timeout, .init = imx21_wd_init, @@ -264,7 +256,6 @@ static struct platform_device_id imx_wdt_ids[] = { static struct driver_d imx_wd_driver = { .name = "imx-watchdog", .probe = imx_wd_probe, - .remove = imx_wd_remove, .of_compatible = DRV_OF_COMPAT(imx_wdt_dt_ids), .id_table = imx_wdt_ids, }; diff --git a/drivers/watchdog/jz4740.c b/drivers/watchdog/jz4740.c index 8ac51e060a..3d45b46ee2 100644 --- a/drivers/watchdog/jz4740.c +++ b/drivers/watchdog/jz4740.c @@ -16,6 +16,7 @@ #include <common.h> #include <init.h> +#include <restart.h> #include <io.h> #define JZ_REG_WDT_TIMER_DATA 0x0 @@ -39,33 +40,30 @@ #define JZ_EXTAL 24000000 struct jz4740_wdt_drvdata { + struct restart_handler restart; void __iomem *base; }; -static struct jz4740_wdt_drvdata *reset_wd; - -void __noreturn reset_cpu(unsigned long addr) +static void __noreturn jz4740_reset_soc(struct restart_handler *rst) { - if (reset_wd) { - void __iomem *base = reset_wd->base; + struct jz4740_wdt_drvdata *priv = + container_of(rst, struct jz4740_wdt_drvdata, restart); + void __iomem *base = priv->base; - writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT, - base + JZ_REG_WDT_TIMER_CONTROL); - writew(0, base + JZ_REG_WDT_TIMER_COUNTER); + writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT, + base + JZ_REG_WDT_TIMER_CONTROL); + writew(0, base + JZ_REG_WDT_TIMER_COUNTER); - /* reset after 4ms */ - writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA); + /* reset after 4ms */ + writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA); - /* start wdt */ - writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE); + /* start wdt */ + writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE); - mdelay(1000); - } else - pr_err("%s: can't reset cpu\n", __func__); + mdelay(1000); hang(); } -EXPORT_SYMBOL(reset_cpu); static int jz4740_wdt_probe(struct device_d *dev) { @@ -78,11 +76,12 @@ static int jz4740_wdt_probe(struct device_d *dev) return -ENODEV; } - if (!reset_wd) - reset_wd = priv; - dev->priv = priv; + priv->restart.name = "jz4740-wdt"; + priv->restart.restart = jz4740_reset_soc; + restart_handler_register(&priv->restart); + return 0; } diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 3d0cfc635d..3a3f519648 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#define pr_fmt(fmt) "watchdog: " fmt #include <common.h> #include <command.h> @@ -18,40 +19,85 @@ #include <linux/ctype.h> #include <watchdog.h> -/* - * Note: this simple framework supports one watchdog only. - */ -static struct watchdog *watchdog; +static LIST_HEAD(watchdog_list); + +static const char *watchdog_name(struct watchdog *wd) +{ + if (wd->dev) + return dev_name(wd->dev); + if (wd->name) + return wd->name; + + return "unknown"; +} int watchdog_register(struct watchdog *wd) { - if (watchdog != NULL) - return -EBUSY; + if (!wd->priority) + wd->priority = WATCHDOG_DEFAULT_PRIORITY; + + list_add_tail(&wd->list, &watchdog_list); + + pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd), + wd->priority); - watchdog = wd; return 0; } EXPORT_SYMBOL(watchdog_register); int watchdog_deregister(struct watchdog *wd) { - if (watchdog == NULL || wd != watchdog) - return -ENODEV; + list_del(&wd->list); - watchdog = NULL; return 0; } EXPORT_SYMBOL(watchdog_deregister); +static struct watchdog *watchdog_get_default(void) +{ + struct watchdog *tmp, *wd = NULL; + int priority = 0; + + list_for_each_entry(tmp, &watchdog_list, list) { + if (tmp->priority > priority) { + priority = tmp->priority; + wd = tmp; + } + } + + return wd; +} + /* * start, stop or retrigger the watchdog * timeout in [seconds]. timeout of '0' will disable the watchdog (if possible) */ int watchdog_set_timeout(unsigned timeout) { - if (watchdog == NULL) + struct watchdog *wd; + + wd = watchdog_get_default(); + + if (!wd) return -ENODEV; - return watchdog->set_timeout(watchdog, timeout); + pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout); + + return wd->set_timeout(wd, timeout); } EXPORT_SYMBOL(watchdog_set_timeout); + +/** + * 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; +} |