From fad16dd9c962229c5965ec6f5cd5f48180f94fd4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 8 May 2014 23:22:15 +0200 Subject: ACPI / PM: Export acpi_target_system_state() to modules Export the acpi_target_system_state() function to modules so that modular drivers can use it to check what the target ACPI sleep state of the system is (that is needed for i915 mostly at this point). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index c40fb2e81bb..2281ca31c1b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -89,6 +89,7 @@ u32 acpi_target_system_state(void) { return acpi_target_sleep_state; } +EXPORT_SYMBOL_GPL(acpi_target_system_state); static bool pwr_btn_event_pending; -- cgit v1.2.3-18-g5258 From 1f0b63866fc1be700260547be8edf8e6f0af37f2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 May 2014 23:29:57 +0200 Subject: ACPI / PM: Hold ACPI scan lock over the "freeze" sleep state The "freeze" sleep state suffers from the same issue that was addressed by commit ad07277e82de (ACPI / PM: Hold acpi_scan_lock over system PM transitions) for ACPI sleep states, that is, things break if ->remove() is called for devices whose system resume callbacks haven't been executed yet. It also can be addressed in the same way, by holding the ACPI scan lock over the "freeze" sleep state and PM transitions to and from that state, but ->begin() and ->end() platform operations for the "freeze" sleep state are needed for this purpose. This change has been tested on Acer Aspire S5 with Thunderbolt. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2281ca31c1b..c11e3795431 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -612,6 +612,22 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .recover = acpi_pm_finish, }; +static int acpi_freeze_begin(void) +{ + acpi_scan_lock_acquire(); + return 0; +} + +static void acpi_freeze_end(void) +{ + acpi_scan_lock_release(); +} + +static const struct platform_freeze_ops acpi_freeze_ops = { + .begin = acpi_freeze_begin, + .end = acpi_freeze_end, +}; + static void acpi_sleep_suspend_setup(void) { int i; @@ -622,7 +638,9 @@ static void acpi_sleep_suspend_setup(void) suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); + freeze_set_ops(&acpi_freeze_ops); } + #else /* !CONFIG_SUSPEND */ static inline void acpi_sleep_suspend_setup(void) {} #endif /* !CONFIG_SUSPEND */ -- cgit v1.2.3-18-g5258 From f25c0ae2b4c41996c1a6b609132c1788a6eea080 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 17 May 2014 00:18:13 +0200 Subject: ACPI / PM: Avoid resuming devices in ACPI PM domain during system suspend Rework the ACPI PM domain's PM callbacks to avoid resuming devices during system suspend (in order to modify their wakeup settings etc.) if that isn't necessary. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 43 ++++++++++++++++++++++++++++++++++++------- drivers/acpi/scan.c | 4 ++++ 2 files changed, 40 insertions(+), 7 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index d047739f338..9e5fd9c440b 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -900,17 +900,45 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early); */ int acpi_subsys_prepare(struct device *dev) { - /* - * Devices having power.ignore_children set may still be necessary for - * suspending their children in the next phase of device suspend. - */ - if (dev->power.ignore_children) - pm_runtime_resume(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + u32 sys_target; + int ret, state; + + ret = pm_generic_prepare(dev); + if (ret < 0) + return ret; + + if (!adev || !pm_runtime_suspended(dev) + || device_may_wakeup(dev) != !!adev->wakeup.prepare_count) + return 0; + + sys_target = acpi_target_system_state(); + if (sys_target == ACPI_STATE_S0) + return 1; - return pm_generic_prepare(dev); + if (adev->power.flags.dsw_present) + return 0; + + ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state); + return !ret && state == adev->power.state; } EXPORT_SYMBOL_GPL(acpi_subsys_prepare); +/** + * acpi_subsys_complete - Finalize device's resume during system resume. + * @dev: Device to handle. + */ +static void acpi_subsys_complete(struct device *dev) +{ + /* + * If the device had been runtime-suspended before the system went into + * the sleep state it is going out of and it has never been resumed till + * now, resume it in case the firmware powered it up. + */ + if (dev->power.direct_complete) + pm_request_resume(dev); +} + /** * acpi_subsys_suspend - Run the device driver's suspend callback. * @dev: Device to handle. @@ -979,6 +1007,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { #endif #ifdef CONFIG_PM_SLEEP .prepare = acpi_subsys_prepare, + .complete = acpi_subsys_complete, .suspend = acpi_subsys_suspend, .suspend_late = acpi_subsys_suspend_late, .resume_early = acpi_subsys_resume_early, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7efe546a8c4..df6e4c924b3 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1551,9 +1551,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device) */ if (acpi_has_method(device->handle, "_PSC")) device->power.flags.explicit_get = 1; + if (acpi_has_method(device->handle, "_IRC")) device->power.flags.inrush_current = 1; + if (acpi_has_method(device->handle, "_DSW")) + device->power.flags.dsw_present = 1; + /* * Enumerate supported power management states */ -- cgit v1.2.3-18-g5258 From 4cf563c5d97c83d4b2fb3a778dd7d5e362cc3e34 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 15 May 2014 16:40:23 +0300 Subject: ACPI / PM: Export rest of the subsys PM callbacks No reason for excluding the remaining ones. Signed-off-by: Heikki Krogerus [rjw: Rebased and exported the new acpi_subsys_complete() too.] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 9e5fd9c440b..49a51277f81 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -928,7 +928,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare); * acpi_subsys_complete - Finalize device's resume during system resume. * @dev: Device to handle. */ -static void acpi_subsys_complete(struct device *dev) +void acpi_subsys_complete(struct device *dev) { /* * If the device had been runtime-suspended before the system went into @@ -938,6 +938,7 @@ static void acpi_subsys_complete(struct device *dev) if (dev->power.direct_complete) pm_request_resume(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_complete); /** * acpi_subsys_suspend - Run the device driver's suspend callback. @@ -951,6 +952,7 @@ int acpi_subsys_suspend(struct device *dev) pm_runtime_resume(dev); return pm_generic_suspend(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_suspend); /** * acpi_subsys_suspend_late - Suspend device using ACPI. @@ -996,6 +998,7 @@ int acpi_subsys_freeze(struct device *dev) pm_runtime_resume(dev); return pm_generic_freeze(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_freeze); #endif /* CONFIG_PM_SLEEP */ -- cgit v1.2.3-18-g5258