From baecc470d5fd6e2d94eb2a7e242ba291ac7182ac Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:38:08 +0200 Subject: [PATCH 1/9] PCI / PM: Skip bridges in pci_enable_wake() PCI bridges only have a reason to generate wakeup signals on behalf of devices below them, so avoid preparing bridges for wakeup directly in pci_enable_wake(). Also drop the pci_has_subordinate() check from pci_pm_default_resume() as this will be done by pci_enable_wake() itself now. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Acked-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 4 +--- drivers/pci/pci.c | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d51e8738f9c2..e426f8b44c92 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -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) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index af0cc3456dc1..0d142031ebfb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -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; From 99d8845e756cb91e2865f430401d084cd6a8ccc9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:40:49 +0200 Subject: [PATCH 2/9] ACPI / PM: Split acpi_device_wakeup() To prepare for a subsequent change and make the code somewhat easier to follow, do the following in the ACPI device wakeup handling code: * Replace wakeup.flags.enabled under struct acpi_device with wakeup.enable_count as that will be necessary going forward. For now, wakeup.enable_count is not allowed to grow beyond 1, so the current behavior is retained. * Split acpi_device_wakeup() into acpi_device_wakeup_enable() and acpi_device_wakeup_disable() and modify the callers of it accordingly. * Introduce a new acpi_wakeup_lock mutex to protect the wakeup enabling/disabling code from races in case it is executed more than once in parallel for the same device (which may happen for bridges theoretically). Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/device_pm.c | 125 +++++++++++++++++++++++++-------------- include/acpi/acpi_bus.h | 2 +- 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 2ed6935d4483..4cd4bdab053d 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -682,47 +682,74 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) } } +static DEFINE_MUTEX(acpi_wakeup_lock); + /** - * 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; + acpi_status status; + int error = 0; + + mutex_lock(&acpi_wakeup_lock); + + if (wakeup->enable_count > 0) + goto out; + + 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; + } + + wakeup->enable_count++; + +out: + mutex_unlock(&acpi_wakeup_lock); + return error; +} + +/** + * 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. + */ +static void acpi_device_wakeup_disable(struct acpi_device *adev) { struct acpi_device_wakeup *wakeup = &adev->wakeup; - if (enable) { - acpi_status res; - int error; + mutex_lock(&acpi_wakeup_lock); - if (adev->wakeup.flags.enabled) - return 0; + if (!wakeup->enable_count) + goto out; - error = acpi_enable_wakeup_device_power(adev, target_state); - if (error) - return error; + acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); + acpi_disable_wakeup_device_power(adev); - 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; + wakeup->enable_count--; + +out: + mutex_unlock(&acpi_wakeup_lock); } /** @@ -744,9 +771,15 @@ 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()); if (!error) - dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); + dev_dbg(dev, "Wakeup enabled by ACPI\n"); return error; } @@ -800,13 +833,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 +864,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 +919,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 +950,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 +1093,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 +1137,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; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 68bc6be447fd..b7df95dbe7e9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -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 { From 1ba51a7c1496fd8f6d5bdd58dafcb1894275b7f0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 1 Aug 2017 02:56:18 +0200 Subject: [PATCH 3/9] ACPI / PCI / PM: Rework acpi_pci_propagate_wakeup() The acpi_pci_propagate_wakeup() routine is there to handle cases in which PCI bridges (or PCIe ports) are expected to signal wakeup for devices below them, but currently it doesn't do that correctly. The problem is that acpi_pci_propagate_wakeup() uses acpi_pm_set_device_wakeup() for bridges and if that routine is called for multiple times to disable wakeup for the same device, it will disable it on the first invocation and the next calls will have no effect (it works analogously when called to enable wakeup, but that is not a problem). Now, say acpi_pci_propagate_wakeup() has been called for two different devices under the same bridge and it has called acpi_pm_set_device_wakeup() for that bridge each time. The bridge is now enabled to generate wakeup signals. Next, suppose that one of the devices below it resumes and acpi_pci_propagate_wakeup() is called to disable wakeup for that device. It will then call acpi_pm_set_device_wakeup() for the bridge and that will effectively disable remote wakeup for all devices under it even though some of them may still be suspended and remote wakeup may be expected to work for them. To address this (arguably theoretical) issue, allow wakeup.enable_count under struct acpi_device to grow beyond 1 in certain situations. In particular, allow that to happen in acpi_pci_propagate_wakeup() when wakeup is enabled or disabled for PCI bridges, so that wakeup is actually disabled for the bridge when all devices under it resume and not when just one of them does that. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg Acked-by: Bjorn Helgaas --- drivers/acpi/device_pm.c | 94 ++++++++++++++++++++++++++-------------- drivers/pci/pci-acpi.c | 4 +- include/acpi/acpi_bus.h | 5 +++ 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 4cd4bdab053d..112fd6c55c2c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -684,6 +684,40 @@ 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 - Enable wakeup functionality for device. * @adev: ACPI device to enable wakeup functionality for. @@ -698,31 +732,7 @@ static DEFINE_MUTEX(acpi_wakeup_lock); */ static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) { - struct acpi_device_wakeup *wakeup = &adev->wakeup; - acpi_status status; - int error = 0; - - mutex_lock(&acpi_wakeup_lock); - - if (wakeup->enable_count > 0) - goto out; - - 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; - } - - wakeup->enable_count++; - -out: - mutex_unlock(&acpi_wakeup_lock); - return error; + return __acpi_device_wakeup_enable(adev, target_state, 1); } /** @@ -752,12 +762,8 @@ static void acpi_device_wakeup_disable(struct acpi_device *adev) mutex_unlock(&acpi_wakeup_lock); } -/** - * 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) +static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable, + int max_count) { struct acpi_device *adev; int error; @@ -777,13 +783,35 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable) return 0; } - error = acpi_device_wakeup_enable(adev, acpi_target_system_state()); + error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(), + max_count); if (!error) 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. diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e70c1c7ba1bf..a8da543b3814 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -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; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b7df95dbe7e9..de7e8ac9d806 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -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 From a042e0c62b38e7bb8b5edadc46c2ff23d1091111 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 31 Jul 2017 11:40:13 +0200 Subject: [PATCH 4/9] ACPI / sleep: Make acpi_sleep_syscore_init() static Function acpi_sleep_syscore_init has no external user so it should be static. Signed-off-by: Jean Delvare Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fa8243c5c062..dd5f21ca483e 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -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); } From ecc1165b8b743fd1503b9c799ae3a9933b89877b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:30:09 +0200 Subject: [PATCH 5/9] ACPICA: Dispatch active GPEs at init time In some cases GPEs are already active when they are enabled by acpi_ev_initialize_gpe_block() and whatever happens next may depend on the result of handling the events signaled by them, so the events should not be discarded (which is what happens currently) and they should be handled as soon as reasonably possible. For this reason, modify acpi_ev_initialize_gpe_block() to dispatch GPEs with the status flag set in-band right after enabling them. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/acpica/evgpeblk.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 9c941947a063..c27386cca493 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -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,38 @@ 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; } + 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++; } } From 1312b7e0caca44e7ff312bc2eaa888943384e3e1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:31:58 +0200 Subject: [PATCH 6/9] ACPICA: Make it possible to enable runtime GPEs earlier Runtime GPEs have corresponding _Lxx/_Exx methods and are enabled automatically during the initialization of the ACPI subsystem through acpi_update_all_gpes() with the assumption that acpi_setup_gpe_for_wake() will be called in advance for all of the GPEs pointed to by _PRW objects in the namespace that may be affected by acpi_update_all_gpes(). That is, acpi_ev_initialize_gpe_block() can only be called for a GPE block after acpi_setup_gpe_for_wake() has been called for all of the _PRW (wakeup) GPEs in it. The platform firmware on some systems, however, expects GPEs to be enabled before the enumeration of devices which is when acpi_setup_gpe_for_wake() is called and that goes against the above assumption. For this reason, introduce a new flag to be set by acpi_ev_initialize_gpe_block() when automatically enabling a GPE to indicate to acpi_setup_gpe_for_wake() that it needs to drop the reference to the GPE coming from acpi_ev_initialize_gpe_block() and modify acpi_setup_gpe_for_wake() accordingly. These changes allow acpi_setup_gpe_for_wake() and acpi_ev_initialize_gpe_block() to be invoked in any order. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/acpica/evgpeblk.c | 2 ++ drivers/acpi/acpica/evxfgpe.c | 8 ++++++++ include/acpi/actypes.h | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index c27386cca493..3a3cb8624f41 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -496,6 +496,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 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)); diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 57718a3e029a..67c7c4ce276c 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -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; } /* diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 2fcbaec8b368..71eddf645566 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -775,7 +775,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 * +------------ */ #define ACPI_GPE_DISPATCH_NONE (u8) 0x00 @@ -791,6 +791,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 From eb7f43c4adb4a789f99f53916182c3401b4e33c7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:34:23 +0200 Subject: [PATCH 7/9] ACPI / scan: Enable GPEs before scanning the namespace On some systems the platform firmware expects GPEs to be enabled before the enumeration of devices and if that expectation is not met, the systems in question may not boot in some situations. For this reason, change the initialization ordering of the ACPI subsystem to make it enable GPEs before scanning the namespace for the first time in order to enumerate devices. Reported-by: Mika Westerberg Suggested-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki Acked-by: Lv Zheng Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 70fd5502c284..b7bdf9d0f5c0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -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: From 7db8d1d904e4b64d0d8e2bce75b59f59d445e1e2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Aug 2017 01:31:54 +0200 Subject: [PATCH 8/9] ACPI: Add debug statements to acpi_global_event_handler() It sometimes is useful to examine the timing of ACPI events during certain operations only, like during system suspend/resume, so add pr_debug() statements for that to acpi_global_event_handler(). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index e414fabf7315..32d7e43b64c4 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -2,6 +2,8 @@ * sysfs.c - ACPI sysfs interface to userspace. */ +#define pr_fmt(fmt) "ACPI: " fmt + #include #include #include @@ -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, From 020a63756707d3074fd00507c3bfd461e1cdf3eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Aug 2017 01:32:40 +0200 Subject: [PATCH 9/9] ACPI / PM: Add debug statements to acpi_pm_notify_handler() Add statements to trace invocations of the ACPI PM notify handler and the work functions called by it. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 112fd6c55c2c..fbcc73f7a099 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -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);