diff options
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/diag288_wdt.c | 20 | ||||
-rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 51 |
2 files changed, 56 insertions, 15 deletions
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index 429494b6c822..a9a5210143ae 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c @@ -125,9 +125,7 @@ static int wdt_start(struct watchdog_device *dev) ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); WARN_ON(ret != 0); kfree(ebc_cmd); - } - - if (MACHINE_IS_LPAR) { + } else { ret = __diag288_lpar(WDT_FUNC_INIT, dev->timeout, LPARWDT_RESTART); } @@ -136,7 +134,6 @@ static int wdt_start(struct watchdog_device *dev) pr_err("The watchdog cannot be activated\n"); return ret; } - pr_info("The watchdog was activated\n"); return 0; } @@ -145,7 +142,6 @@ static int wdt_stop(struct watchdog_device *dev) int ret; ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0); - pr_info("The watchdog was deactivated\n"); return ret; } @@ -177,10 +173,9 @@ static int wdt_ping(struct watchdog_device *dev) ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); WARN_ON(ret != 0); kfree(ebc_cmd); - } - - if (MACHINE_IS_LPAR) + } else { ret = __diag288_lpar(WDT_FUNC_CHANGE, dev->timeout, 0); + } if (ret) pr_err("The watchdog timer cannot be started or reset\n"); @@ -202,7 +197,7 @@ static struct watchdog_ops wdt_ops = { }; static struct watchdog_info wdt_info = { - .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .firmware_version = 0, .identity = "z Watchdog", }; @@ -273,21 +268,16 @@ static int __init diag288_init(void) watchdog_set_nowayout(&wdt_dev, nowayout_info); if (MACHINE_IS_VM) { - pr_info("The watchdog device driver detected a z/VM environment\n"); if (__diag288_vm(WDT_FUNC_INIT, 15, ebc_begin, sizeof(ebc_begin)) != 0) { pr_err("The watchdog cannot be initialized\n"); return -EINVAL; } - } else if (MACHINE_IS_LPAR) { - pr_info("The watchdog device driver detected an LPAR environment\n"); + } else { if (__diag288_lpar(WDT_FUNC_INIT, 30, LPARWDT_RESTART)) { pr_err("The watchdog cannot be initialized\n"); return -EINVAL; } - } else { - pr_err("Linux runs in an environment that does not support the diag288 watchdog\n"); - return -ENODEV; } if (__diag288_lpar(WDT_FUNC_CANCEL, 0, 0)) { diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 05ee0bf88ce9..3c3fd417ddeb 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -51,6 +51,7 @@ #define DRV_VERSION "1.11" /* Includes */ +#include <linux/acpi.h> /* For ACPI support */ #include <linux/module.h> /* For module specific items */ #include <linux/moduleparam.h> /* For new moduleparam's */ #include <linux/types.h> /* For standard types (like size_t) */ @@ -103,6 +104,8 @@ static struct { /* this is private data for the iTCO_wdt device */ struct platform_device *dev; /* the PCI-device */ struct pci_dev *pdev; + /* whether or not the watchdog has been suspended */ + bool suspended; } iTCO_wdt_private; /* module parameters */ @@ -571,12 +574,60 @@ static void iTCO_wdt_shutdown(struct platform_device *dev) iTCO_wdt_stop(NULL); } +#ifdef CONFIG_PM_SLEEP +/* + * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so + * the watchdog cannot be pinged while in that state. In ACPI sleep states the + * watchdog is stopped by the platform firmware. + */ + +#ifdef CONFIG_ACPI +static inline bool need_suspend(void) +{ + return acpi_target_system_state() == ACPI_STATE_S0; +} +#else +static inline bool need_suspend(void) { return true; } +#endif + +static int iTCO_wdt_suspend_noirq(struct device *dev) +{ + int ret = 0; + + iTCO_wdt_private.suspended = false; + if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) { + ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); + if (!ret) + iTCO_wdt_private.suspended = true; + } + return ret; +} + +static int iTCO_wdt_resume_noirq(struct device *dev) +{ + if (iTCO_wdt_private.suspended) + iTCO_wdt_start(&iTCO_wdt_watchdog_dev); + + return 0; +} + +static struct dev_pm_ops iTCO_wdt_pm = { + .suspend_noirq = iTCO_wdt_suspend_noirq, + .resume_noirq = iTCO_wdt_resume_noirq, +}; + +#define ITCO_WDT_PM_OPS (&iTCO_wdt_pm) +#else +#define ITCO_WDT_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver iTCO_wdt_driver = { .probe = iTCO_wdt_probe, .remove = iTCO_wdt_remove, .shutdown = iTCO_wdt_shutdown, .driver = { .name = DRV_NAME, + .pm = ITCO_WDT_PM_OPS, }, }; |