aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-03 09:25:04 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-03 09:25:04 -0400
commitf321c9cbf3bbf86f6e6153419eaf93ad085e3d74 (patch)
tree8326d454c934c8833ecc7e365c2cb52f0f0616be /drivers/watchdog
parent431d452af13720463dda498999b2e9a08729c03a (diff)
PM / watchdog: iTCO: stop watchdog during system suspend
If the target sleep state of the system is not an ACPI sleep state (S1, S2 or S3), the TCO watchdog needs to be stopped during system suspend, because it may not be possible to ping it any more after timekeeping has been suspended (suspend-to-idle does that for one example). For this reason, provide ->suspend_noirq and ->resume_noirq callbacks for the iTCO watchdog driver and use them to stop and restart the watchdog during system suspend and resume, respectively, if the system is not going to enter an ACPI sleep state (in which case the watchdog will be stopped by the platform firmware before the state is entered). Reported-and-tested-by: Borun Fu <borun.fu@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/iTCO_wdt.c51
1 files changed, 51 insertions, 0 deletions
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 @@
51#define DRV_VERSION "1.11" 51#define DRV_VERSION "1.11"
52 52
53/* Includes */ 53/* Includes */
54#include <linux/acpi.h> /* For ACPI support */
54#include <linux/module.h> /* For module specific items */ 55#include <linux/module.h> /* For module specific items */
55#include <linux/moduleparam.h> /* For new moduleparam's */ 56#include <linux/moduleparam.h> /* For new moduleparam's */
56#include <linux/types.h> /* For standard types (like size_t) */ 57#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 */
103 struct platform_device *dev; 104 struct platform_device *dev;
104 /* the PCI-device */ 105 /* the PCI-device */
105 struct pci_dev *pdev; 106 struct pci_dev *pdev;
107 /* whether or not the watchdog has been suspended */
108 bool suspended;
106} iTCO_wdt_private; 109} iTCO_wdt_private;
107 110
108/* module parameters */ 111/* module parameters */
@@ -571,12 +574,60 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
571 iTCO_wdt_stop(NULL); 574 iTCO_wdt_stop(NULL);
572} 575}
573 576
577#ifdef CONFIG_PM_SLEEP
578/*
579 * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
580 * the watchdog cannot be pinged while in that state. In ACPI sleep states the
581 * watchdog is stopped by the platform firmware.
582 */
583
584#ifdef CONFIG_ACPI
585static inline bool need_suspend(void)
586{
587 return acpi_target_system_state() == ACPI_STATE_S0;
588}
589#else
590static inline bool need_suspend(void) { return true; }
591#endif
592
593static int iTCO_wdt_suspend_noirq(struct device *dev)
594{
595 int ret = 0;
596
597 iTCO_wdt_private.suspended = false;
598 if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) {
599 ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
600 if (!ret)
601 iTCO_wdt_private.suspended = true;
602 }
603 return ret;
604}
605
606static int iTCO_wdt_resume_noirq(struct device *dev)
607{
608 if (iTCO_wdt_private.suspended)
609 iTCO_wdt_start(&iTCO_wdt_watchdog_dev);
610
611 return 0;
612}
613
614static struct dev_pm_ops iTCO_wdt_pm = {
615 .suspend_noirq = iTCO_wdt_suspend_noirq,
616 .resume_noirq = iTCO_wdt_resume_noirq,
617};
618
619#define ITCO_WDT_PM_OPS (&iTCO_wdt_pm)
620#else
621#define ITCO_WDT_PM_OPS NULL
622#endif /* CONFIG_PM_SLEEP */
623
574static struct platform_driver iTCO_wdt_driver = { 624static struct platform_driver iTCO_wdt_driver = {
575 .probe = iTCO_wdt_probe, 625 .probe = iTCO_wdt_probe,
576 .remove = iTCO_wdt_remove, 626 .remove = iTCO_wdt_remove,
577 .shutdown = iTCO_wdt_shutdown, 627 .shutdown = iTCO_wdt_shutdown,
578 .driver = { 628 .driver = {
579 .name = DRV_NAME, 629 .name = DRV_NAME,
630 .pm = ITCO_WDT_PM_OPS,
580 }, 631 },
581}; 632};
582 633