Merge branches 'acpi-scan' and 'acpi-pm'

* acpi-scan:
  ACPI / scan: Enable GPEs before scanning the namespace
  ACPICA: Make it possible to enable runtime GPEs earlier
  ACPICA: Dispatch active GPEs at init time

* acpi-pm:
  ACPI / PM: Add debug statements to acpi_pm_notify_handler()
  ACPI: Add debug statements to acpi_global_event_handler()
  ACPI / sleep: Make acpi_sleep_syscore_init() static
  ACPI / PCI / PM: Rework acpi_pci_propagate_wakeup()
  ACPI / PM: Split acpi_device_wakeup()
  PCI / PM: Skip bridges in pci_enable_wake()
This commit is contained in:
Rafael J. Wysocki 2017-09-03 23:53:19 +02:00
Родитель b2a84eedca eb7f43c4ad 020a637567
Коммит 4467ade90d
11 изменённых файлов: 186 добавлений и 78 удалений

Просмотреть файл

@ -440,9 +440,11 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
void *ignored)
{
acpi_status status;
acpi_event_status event_status;
struct acpi_gpe_event_info *gpe_event_info;
u32 gpe_enabled_count;
u32 gpe_index;
u32 gpe_number;
u32 i;
u32 j;
@ -470,30 +472,40 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
gpe_event_info = &gpe_block->event_info[gpe_index];
gpe_number = gpe_block->block_base_number + gpe_index;
/*
* Ignore GPEs that have no corresponding _Lxx/_Exx method
* and GPEs that are used to wake the system
* and GPEs that are used for wakeup
*/
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_NONE)
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_HANDLER)
|| (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_RAW_HANDLER)
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_METHOD)
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}
event_status = 0;
(void)acpi_hw_get_gpe_status(gpe_event_info,
&event_status);
status = acpi_ev_add_gpe_reference(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
gpe_index +
gpe_block->block_base_number));
gpe_number));
continue;
}
gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
if (event_status & ACPI_EVENT_FLAG_STATUS_SET) {
ACPI_INFO(("GPE 0x%02X active on init",
gpe_number));
(void)acpi_ev_gpe_dispatch(gpe_block->node,
gpe_event_info,
gpe_number);
}
gpe_enabled_count++;
}
}

Просмотреть файл

@ -435,6 +435,14 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
*/
gpe_event_info->flags =
(ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED);
} else if (gpe_event_info->flags & ACPI_GPE_AUTO_ENABLED) {
/*
* A reference to this GPE has been added during the GPE block
* initialization, so drop it now to prevent the GPE from being
* permanently enabled and clear its ACPI_GPE_AUTO_ENABLED flag.
*/
(void)acpi_ev_remove_gpe_reference(gpe_event_info);
gpe_event_info->flags &= ~ACPI_GPE_AUTO_ENABLED;
}
/*

Просмотреть файл

@ -401,6 +401,8 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
if (val != ACPI_NOTIFY_DEVICE_WAKE)
return;
acpi_handle_debug(handle, "Wake notify\n");
adev = acpi_bus_get_acpi_device(handle);
if (!adev)
return;
@ -409,8 +411,12 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
if (adev->wakeup.flags.notifier_present) {
pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
if (adev->wakeup.context.func)
if (adev->wakeup.context.func) {
acpi_handle_debug(handle, "Running %pF for %s\n",
adev->wakeup.context.func,
dev_name(adev->wakeup.context.dev));
adev->wakeup.context.func(&adev->wakeup.context);
}
}
mutex_unlock(&acpi_pm_notifier_lock);
@ -682,55 +688,88 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context)
}
}
static DEFINE_MUTEX(acpi_wakeup_lock);
static int __acpi_device_wakeup_enable(struct acpi_device *adev,
u32 target_state, int max_count)
{
struct acpi_device_wakeup *wakeup = &adev->wakeup;
acpi_status status;
int error = 0;
mutex_lock(&acpi_wakeup_lock);
if (wakeup->enable_count >= max_count)
goto out;
if (wakeup->enable_count > 0)
goto inc;
error = acpi_enable_wakeup_device_power(adev, target_state);
if (error)
goto out;
status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_FAILURE(status)) {
acpi_disable_wakeup_device_power(adev);
error = -EIO;
goto out;
}
inc:
wakeup->enable_count++;
out:
mutex_unlock(&acpi_wakeup_lock);
return error;
}
/**
* acpi_device_wakeup - Enable/disable wakeup functionality for device.
* @adev: ACPI device to enable/disable wakeup functionality for.
* acpi_device_wakeup_enable - Enable wakeup functionality for device.
* @adev: ACPI device to enable wakeup functionality for.
* @target_state: State the system is transitioning into.
* @enable: Whether to enable or disable the wakeup functionality.
*
* Enable/disable the GPE associated with @adev so that it can generate
* wakeup signals for the device in response to external (remote) events and
* enable/disable device wakeup power.
* Enable the GPE associated with @adev so that it can generate wakeup signals
* for the device in response to external (remote) events and enable wakeup
* power for it.
*
* Callers must ensure that @adev is a valid ACPI device node before executing
* this function.
*/
static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
bool enable)
static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state)
{
struct acpi_device_wakeup *wakeup = &adev->wakeup;
if (enable) {
acpi_status res;
int error;
if (adev->wakeup.flags.enabled)
return 0;
error = acpi_enable_wakeup_device_power(adev, target_state);
if (error)
return error;
res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_FAILURE(res)) {
acpi_disable_wakeup_device_power(adev);
return -EIO;
}
adev->wakeup.flags.enabled = 1;
} else if (adev->wakeup.flags.enabled) {
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
acpi_disable_wakeup_device_power(adev);
adev->wakeup.flags.enabled = 0;
}
return 0;
return __acpi_device_wakeup_enable(adev, target_state, 1);
}
/**
* acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
* acpi_device_wakeup_disable - Disable wakeup functionality for device.
* @adev: ACPI device to disable wakeup functionality for.
*
* Disable the GPE associated with @adev and disable wakeup power for it.
*
* Callers must ensure that @adev is a valid ACPI device node before executing
* this function.
*/
int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
static void acpi_device_wakeup_disable(struct acpi_device *adev)
{
struct acpi_device_wakeup *wakeup = &adev->wakeup;
mutex_lock(&acpi_wakeup_lock);
if (!wakeup->enable_count)
goto out;
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
acpi_disable_wakeup_device_power(adev);
wakeup->enable_count--;
out:
mutex_unlock(&acpi_wakeup_lock);
}
static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable,
int max_count)
{
struct acpi_device *adev;
int error;
@ -744,13 +783,41 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
if (!acpi_device_can_wakeup(adev))
return -EINVAL;
error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
if (!enable) {
acpi_device_wakeup_disable(adev);
dev_dbg(dev, "Wakeup disabled by ACPI\n");
return 0;
}
error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(),
max_count);
if (!error)
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");
dev_dbg(dev, "Wakeup enabled by ACPI\n");
return error;
}
EXPORT_SYMBOL(acpi_pm_set_device_wakeup);
/**
* acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
*/
int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
{
return __acpi_pm_set_device_wakeup(dev, enable, 1);
}
EXPORT_SYMBOL_GPL(acpi_pm_set_device_wakeup);
/**
* acpi_pm_set_bridge_wakeup - Enable/disable remote wakeup for given bridge.
* @dev: Bridge device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
*/
int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable)
{
return __acpi_pm_set_device_wakeup(dev, enable, INT_MAX);
}
EXPORT_SYMBOL_GPL(acpi_pm_set_bridge_wakeup);
/**
* acpi_dev_pm_low_power - Put ACPI device into a low-power state.
@ -800,13 +867,15 @@ int acpi_dev_runtime_suspend(struct device *dev)
remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
PM_QOS_FLAGS_NONE;
error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
if (remote_wakeup && error)
return -EAGAIN;
if (remote_wakeup) {
error = acpi_device_wakeup_enable(adev, ACPI_STATE_S0);
if (error)
return -EAGAIN;
}
error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
if (error)
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
if (error && remote_wakeup)
acpi_device_wakeup_disable(adev);
return error;
}
@ -829,7 +898,7 @@ int acpi_dev_runtime_resume(struct device *dev)
return 0;
error = acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
return error;
}
EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@ -884,13 +953,15 @@ int acpi_dev_suspend_late(struct device *dev)
target_state = acpi_target_system_state();
wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
error = acpi_device_wakeup(adev, target_state, wakeup);
if (wakeup && error)
return error;
if (wakeup) {
error = acpi_device_wakeup_enable(adev, target_state);
if (error)
return error;
}
error = acpi_dev_pm_low_power(dev, adev, target_state);
if (error)
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
if (error && wakeup)
acpi_device_wakeup_disable(adev);
return error;
}
@ -913,7 +984,7 @@ int acpi_dev_resume_early(struct device *dev)
return 0;
error = acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
acpi_device_wakeup_disable(adev);
return error;
}
EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@ -1056,7 +1127,7 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off)
*/
dev_pm_qos_hide_latency_limit(dev);
dev_pm_qos_hide_flags(dev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
}
}
@ -1100,7 +1171,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
dev_pm_domain_set(dev, &acpi_general_pm_domain);
if (power_on) {
acpi_dev_pm_full_power(adev);
acpi_device_wakeup(adev, ACPI_STATE_S0, false);
acpi_device_wakeup_disable(adev);
}
dev->pm_domain->detach = acpi_dev_pm_detach;

Просмотреть файл

@ -2058,6 +2058,9 @@ int __init acpi_scan_init(void)
acpi_get_spcr_uart_addr();
}
acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();
mutex_lock(&acpi_scan_lock);
/*
* Enumerate devices in the ACPI namespace.
@ -2082,9 +2085,6 @@ int __init acpi_scan_init(void)
}
}
acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();
acpi_scan_initialized = true;
out:

Просмотреть файл

@ -870,7 +870,7 @@ static struct syscore_ops acpi_sleep_syscore_ops = {
.resume = acpi_restore_bm_rld,
};
void acpi_sleep_syscore_init(void)
static void acpi_sleep_syscore_init(void)
{
register_syscore_ops(&acpi_sleep_syscore_ops);
}

Просмотреть файл

@ -2,6 +2,8 @@
* sysfs.c - ACPI sysfs interface to userspace.
*/
#define pr_fmt(fmt) "ACPI: " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
@ -552,11 +554,15 @@ static void fixed_event_count(u32 event_number)
static void acpi_global_event_handler(u32 event_type, acpi_handle device,
u32 event_number, void *context)
{
if (event_type == ACPI_EVENT_TYPE_GPE)
if (event_type == ACPI_EVENT_TYPE_GPE) {
gpe_count(event_number);
if (event_type == ACPI_EVENT_TYPE_FIXED)
pr_debug("GPE event 0x%02x\n", event_number);
} else if (event_type == ACPI_EVENT_TYPE_FIXED) {
fixed_event_count(event_number);
pr_debug("Fixed event 0x%02x\n", event_number);
} else {
pr_debug("Other event 0x%02x\n", event_number);
}
}
static int get_status(u32 index, acpi_event_status *status,

Просмотреть файл

@ -573,7 +573,7 @@ static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
{
while (bus->parent) {
if (acpi_pm_device_can_wakeup(&bus->self->dev))
return acpi_pm_set_device_wakeup(&bus->self->dev, enable);
return acpi_pm_set_bridge_wakeup(&bus->self->dev, enable);
bus = bus->parent;
}
@ -581,7 +581,7 @@ static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
/* We have reached the root bus. */
if (bus->bridge) {
if (acpi_pm_device_can_wakeup(bus->bridge))
return acpi_pm_set_device_wakeup(bus->bridge, enable);
return acpi_pm_set_bridge_wakeup(bus->bridge, enable);
}
return 0;
}

Просмотреть файл

@ -647,9 +647,7 @@ static int pci_legacy_resume(struct device *dev)
static void pci_pm_default_resume(struct pci_dev *pci_dev)
{
pci_fixup_device(pci_fixup_resume, pci_dev);
if (!pci_has_subordinate(pci_dev))
pci_enable_wake(pci_dev, PCI_D0, false);
pci_enable_wake(pci_dev, PCI_D0, false);
}
static void pci_pm_default_suspend(struct pci_dev *pci_dev)

Просмотреть файл

@ -1912,6 +1912,13 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
{
int ret = 0;
/*
* Bridges can only signal wakeup on behalf of subordinate devices,
* but that is set up elsewhere, so skip them.
*/
if (pci_has_subordinate(dev))
return 0;
/* Don't do the same thing twice in a row for one device. */
if (!!enable == !!dev->wakeup_prepared)
return 0;

Просмотреть файл

@ -316,7 +316,6 @@ struct acpi_device_perf {
struct acpi_device_wakeup_flags {
u8 valid:1; /* Can successfully enable wakeup? */
u8 notifier_present:1; /* Wake-up notify handler has been installed */
u8 enabled:1; /* Enabled for wakeup */
};
struct acpi_device_wakeup_context {
@ -333,6 +332,7 @@ struct acpi_device_wakeup {
struct acpi_device_wakeup_context context;
struct wakeup_source *ws;
int prepare_count;
int enable_count;
};
struct acpi_device_physical_node {
@ -606,6 +606,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
bool acpi_pm_device_can_wakeup(struct device *dev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
int acpi_pm_set_device_wakeup(struct device *dev, bool enable);
int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable);
#else
static inline void acpi_pm_wakeup_event(struct device *dev)
{
@ -636,6 +637,10 @@ static inline int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
{
return -ENODEV;
}
static inline int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable)
{
return -ENODEV;
}
#endif
#ifdef CONFIG_ACPI_SLEEP

Просмотреть файл

@ -783,7 +783,7 @@ typedef u32 acpi_event_status;
* | | | | +-- Type of dispatch:to method, handler, notify, or none
* | | | +----- Interrupt type: edge or level triggered
* | | +------- Is a Wake GPE
* | +--------- Is GPE masked by the software GPE masking mechanism
* | +--------- Has been enabled automatically at init time
* +------------ <Reserved>
*/
#define ACPI_GPE_DISPATCH_NONE (u8) 0x00
@ -799,6 +799,7 @@ typedef u32 acpi_event_status;
#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x08
#define ACPI_GPE_CAN_WAKE (u8) 0x10
#define ACPI_GPE_AUTO_ENABLED (u8) 0x20
/*
* Flags for GPE and Lock interfaces