Commit f35cec25 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

ACPI / PM: Always enable wakeup GPEs when enabling device wakeup

Wakeup GPEs are currently only enabled when setting up devices for
remote wakeup at run time.  During system-wide transitions they are
enabled by ACPICA at the very last stage of suspend (before asking
the BIOS to take over).  Of course, that only works for system
sleep states supported by ACPI, so in particular it doesn't work
for the "freeze" sleep state.

For this reason, modify the ACPI core device PM code to enable wakeup
GPEs for devices when setting them up for wakeup regardless of whether
that is remote wakeup at runtime or system wakeup.  That allows the
same device wakeup setup routine to be used for both runtime PM and
system-wide PM and makes it possible to reduce code size quite a bit.

This make ACPI-based PCI Wake-on-LAN work with the "freeze" sleep
state on my venerable Toshiba Portege R500 and should help other
systems too.
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent c072530f
...@@ -638,7 +638,6 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) ...@@ -638,7 +638,6 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
} }
EXPORT_SYMBOL(acpi_pm_device_sleep_state); EXPORT_SYMBOL(acpi_pm_device_sleep_state);
#ifdef CONFIG_PM_RUNTIME
/** /**
* acpi_pm_notify_work_func - ACPI devices wakeup notification work function. * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
* @work: Work item to handle. * @work: Work item to handle.
...@@ -655,8 +654,9 @@ static void acpi_pm_notify_work_func(struct work_struct *work) ...@@ -655,8 +654,9 @@ static void acpi_pm_notify_work_func(struct work_struct *work)
} }
/** /**
* __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. * acpi_device_wakeup - Enable/disable wakeup functionality for device.
* @adev: ACPI device to enable/disable the remote wakeup for. * @adev: ACPI device to enable/disable wakeup functionality for.
* @target_state: State the system is transitioning into.
* @enable: Whether to enable or disable the wakeup functionality. * @enable: Whether to enable or disable the wakeup functionality.
* *
* Enable/disable the GPE associated with @adev so that it can generate * Enable/disable the GPE associated with @adev so that it can generate
...@@ -666,7 +666,8 @@ static void acpi_pm_notify_work_func(struct work_struct *work) ...@@ -666,7 +666,8 @@ static void acpi_pm_notify_work_func(struct work_struct *work)
* Callers must ensure that @adev is a valid ACPI device node before executing * Callers must ensure that @adev is a valid ACPI device node before executing
* this function. * this function.
*/ */
int __acpi_device_run_wake(struct acpi_device *adev, bool enable) static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
bool enable)
{ {
struct acpi_device_wakeup *wakeup = &adev->wakeup; struct acpi_device_wakeup *wakeup = &adev->wakeup;
...@@ -674,7 +675,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable) ...@@ -674,7 +675,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
acpi_status res; acpi_status res;
int error; int error;
error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0); error = acpi_enable_wakeup_device_power(adev, target_state);
if (error) if (error)
return error; return error;
...@@ -690,6 +691,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable) ...@@ -690,6 +691,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
return 0; return 0;
} }
#ifdef CONFIG_PM_RUNTIME
/** /**
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable the platform to wake up. * @dev: Device to enable/disable the platform to wake up.
...@@ -710,28 +712,12 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) ...@@ -710,28 +712,12 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
return -ENODEV; return -ENODEV;
} }
return __acpi_device_run_wake(adev, enable); return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
} }
EXPORT_SYMBOL(acpi_pm_device_run_wake); EXPORT_SYMBOL(acpi_pm_device_run_wake);
#else
static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/**
* __acpi_device_sleep_wake - Enable or disable device to wake up the system.
* @dev: Device to enable/desible to wake up the system.
* @target_state: System state the device is supposed to wake up from.
* @enable: Whether to enable or disable @dev to wake up the system.
*/
int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state,
bool enable)
{
return enable ?
acpi_enable_wakeup_device_power(adev, target_state) :
acpi_disable_wakeup_device_power(adev);
}
/** /**
* acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system.
* @dev: Device to enable/desible to wake up the system from sleep states. * @dev: Device to enable/desible to wake up the system from sleep states.
...@@ -752,8 +738,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) ...@@ -752,8 +738,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return -ENODEV; return -ENODEV;
} }
error = __acpi_device_sleep_wake(adev, acpi_target_system_state(), error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
enable);
if (!error) if (!error)
dev_info(dev, "System wakeup %s by ACPI\n", dev_info(dev, "System wakeup %s by ACPI\n",
enable ? "enabled" : "disabled"); enable ? "enabled" : "disabled");
...@@ -811,13 +796,13 @@ int acpi_dev_runtime_suspend(struct device *dev) ...@@ -811,13 +796,13 @@ int acpi_dev_runtime_suspend(struct device *dev)
remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) > remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
PM_QOS_FLAGS_NONE; PM_QOS_FLAGS_NONE;
error = __acpi_device_run_wake(adev, remote_wakeup); error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
if (remote_wakeup && error) if (remote_wakeup && error)
return -EAGAIN; return -EAGAIN;
error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
if (error) if (error)
__acpi_device_run_wake(adev, false); acpi_device_wakeup(adev, ACPI_STATE_S0, false);
return error; return error;
} }
...@@ -840,7 +825,7 @@ int acpi_dev_runtime_resume(struct device *dev) ...@@ -840,7 +825,7 @@ int acpi_dev_runtime_resume(struct device *dev)
return 0; return 0;
error = acpi_dev_pm_full_power(adev); error = acpi_dev_pm_full_power(adev);
__acpi_device_run_wake(adev, false); acpi_device_wakeup(adev, ACPI_STATE_S0, false);
return error; return error;
} }
EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
...@@ -896,13 +881,13 @@ int acpi_dev_suspend_late(struct device *dev) ...@@ -896,13 +881,13 @@ int acpi_dev_suspend_late(struct device *dev)
target_state = acpi_target_system_state(); target_state = acpi_target_system_state();
wakeup = device_may_wakeup(dev); wakeup = device_may_wakeup(dev);
error = __acpi_device_sleep_wake(adev, target_state, wakeup); error = acpi_device_wakeup(adev, target_state, wakeup);
if (wakeup && error) if (wakeup && error)
return error; return error;
error = acpi_dev_pm_low_power(dev, adev, target_state); error = acpi_dev_pm_low_power(dev, adev, target_state);
if (error) if (error)
__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
return error; return error;
} }
...@@ -925,7 +910,7 @@ int acpi_dev_resume_early(struct device *dev) ...@@ -925,7 +910,7 @@ int acpi_dev_resume_early(struct device *dev)
return 0; return 0;
error = acpi_dev_pm_full_power(adev); error = acpi_dev_pm_full_power(adev);
__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
return error; return error;
} }
EXPORT_SYMBOL_GPL(acpi_dev_resume_early); EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
...@@ -1088,7 +1073,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) ...@@ -1088,7 +1073,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
dev->pm_domain = &acpi_general_pm_domain; dev->pm_domain = &acpi_general_pm_domain;
if (power_on) { if (power_on) {
acpi_dev_pm_full_power(adev); acpi_dev_pm_full_power(adev);
__acpi_device_run_wake(adev, false); acpi_device_wakeup(adev, ACPI_STATE_S0, false);
} }
return 0; return 0;
} }
...@@ -1122,7 +1107,7 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off) ...@@ -1122,7 +1107,7 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
*/ */
dev_pm_qos_hide_latency_limit(dev); dev_pm_qos_hide_latency_limit(dev);
dev_pm_qos_hide_flags(dev); dev_pm_qos_hide_flags(dev);
__acpi_device_run_wake(adev, false); acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
} }
} }
......
...@@ -543,13 +543,8 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m) ...@@ -543,13 +543,8 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
#endif #endif
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
int __acpi_device_run_wake(struct acpi_device *, bool);
int acpi_pm_device_run_wake(struct device *, bool); int acpi_pm_device_run_wake(struct device *, bool);
#else #else
static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
{
return -ENODEV;
}
static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
{ {
return -ENODEV; return -ENODEV;
...@@ -557,14 +552,8 @@ static inline int acpi_pm_device_run_wake(struct device *dev, bool enable) ...@@ -557,14 +552,8 @@ static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
#endif #endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
int acpi_pm_device_sleep_wake(struct device *, bool); int acpi_pm_device_sleep_wake(struct device *, bool);
#else #else
static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
u32 target_state, bool enable)
{
return -ENODEV;
}
static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
{ {
return -ENODEV; return -ENODEV;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment