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 <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
55cc33ceb7
commit
f25c0ae2b4
3 changed files with 42 additions and 8 deletions
|
@ -900,17 +900,45 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
|
||||||
*/
|
*/
|
||||||
int acpi_subsys_prepare(struct device *dev)
|
int acpi_subsys_prepare(struct device *dev)
|
||||||
{
|
{
|
||||||
/*
|
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||||
* Devices having power.ignore_children set may still be necessary for
|
u32 sys_target;
|
||||||
* suspending their children in the next phase of device suspend.
|
int ret, state;
|
||||||
*/
|
|
||||||
if (dev->power.ignore_children)
|
|
||||||
pm_runtime_resume(dev);
|
|
||||||
|
|
||||||
return pm_generic_prepare(dev);
|
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;
|
||||||
|
|
||||||
|
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);
|
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.
|
* acpi_subsys_suspend - Run the device driver's suspend callback.
|
||||||
* @dev: Device to handle.
|
* @dev: Device to handle.
|
||||||
|
@ -979,6 +1007,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.prepare = acpi_subsys_prepare,
|
.prepare = acpi_subsys_prepare,
|
||||||
|
.complete = acpi_subsys_complete,
|
||||||
.suspend = acpi_subsys_suspend,
|
.suspend = acpi_subsys_suspend,
|
||||||
.suspend_late = acpi_subsys_suspend_late,
|
.suspend_late = acpi_subsys_suspend_late,
|
||||||
.resume_early = acpi_subsys_resume_early,
|
.resume_early = acpi_subsys_resume_early,
|
||||||
|
|
|
@ -1551,9 +1551,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
|
||||||
*/
|
*/
|
||||||
if (acpi_has_method(device->handle, "_PSC"))
|
if (acpi_has_method(device->handle, "_PSC"))
|
||||||
device->power.flags.explicit_get = 1;
|
device->power.flags.explicit_get = 1;
|
||||||
|
|
||||||
if (acpi_has_method(device->handle, "_IRC"))
|
if (acpi_has_method(device->handle, "_IRC"))
|
||||||
device->power.flags.inrush_current = 1;
|
device->power.flags.inrush_current = 1;
|
||||||
|
|
||||||
|
if (acpi_has_method(device->handle, "_DSW"))
|
||||||
|
device->power.flags.dsw_present = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumerate supported power management states
|
* Enumerate supported power management states
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -261,7 +261,8 @@ struct acpi_device_power_flags {
|
||||||
u32 inrush_current:1; /* Serialize Dx->D0 */
|
u32 inrush_current:1; /* Serialize Dx->D0 */
|
||||||
u32 power_removed:1; /* Optimize Dx->D0 */
|
u32 power_removed:1; /* Optimize Dx->D0 */
|
||||||
u32 ignore_parent:1; /* Power is independent of parent power state */
|
u32 ignore_parent:1; /* Power is independent of parent power state */
|
||||||
u32 reserved:27;
|
u32 dsw_present:1; /* _DSW present? */
|
||||||
|
u32 reserved:26;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acpi_device_power_state {
|
struct acpi_device_power_state {
|
||||||
|
|
Loading…
Reference in a new issue