diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 12:45:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-05 12:45:03 -0700 |
commit | 53ac64aac9af8cd0e5456c8a9bb68c47b571b0a9 (patch) | |
tree | a61a7b6dda6a728fd32a2f505010e33b8ae28e65 /drivers/acpi/device_pm.c | |
parent | 439644096c1a6afb9bd9953130f4444a856f76c5 (diff) | |
parent | 298bd7fb26cb2797a8b19b66a68389b3f27ae7e2 (diff) |
Merge tag 'acpi-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"These include a usual ACPICA code update (this time to upstream
revision 20170728), a fix for a boot crash on some systems with
Thunderbolt devices connected at boot time, a rework of the handling
of PCI bridges when setting up device wakeup, new support for Apple
device properties, support for DMA configurations reported via ACPI on
ARM64, APEI-related updates, ACPI EC driver updates and assorted minor
modifications in several places.
Specifics:
- Update the ACPICA code in the kernel to upstream revision 20170728
including:
* Alias operator handling update (Bob Moore).
* Deferred resolution of reference package elements (Bob Moore).
* Support for the _DMA method in walk resources (Bob Moore).
* Tables handling update and support for deferred table
verification (Lv Zheng).
* Update of SMMU models for IORT (Robin Murphy).
* Compiler and disassembler updates (Alex James, Erik Schmauss,
Ganapatrao Kulkarni, James Morse).
* Tools updates (Erik Schmauss, Lv Zheng).
* Assorted minor fixes and cleanups (Bob Moore, Kees Cook, Lv
Zheng, Shao Ming).
- Rework the initialization of non-wakeup GPEs with method handlers
in order to address a boot crash on some systems with Thunderbolt
devices connected at boot time where we miss an early hotplug event
due to a delay in GPE enabling (Rafael Wysocki).
- Rework the handling of PCI bridges when setting up ACPI-based
device wakeup in order to avoid disabling wakeup for bridges
prematurely (Rafael Wysocki).
- Consolidate Apple DMI checks throughout the tree, add support for
Apple device properties to the device properties framework and use
these properties for the handling of I2C and SPI devices on Apple
systems (Lukas Wunner).
- Add support for _DMA to the ACPI-based device properties lookup
code and make it possible to use the information from there to
configure DMA regions on ARM64 systems (Lorenzo Pieralisi).
- Fix several issues in the APEI code, add support for exporting the
BERT error region over sysfs and update APEI MAINTAINERS entry with
reviewers information (Borislav Petkov, Dongjiu Geng, Loc Ho, Punit
Agrawal, Tony Luck, Yazen Ghannam).
- Fix a potential initialization ordering issue in the ACPI EC driver
and clean it up somewhat (Lv Zheng).
- Update the ACPI SPCR driver to extend the existing XGENE 8250
workaround in it to a new platform (m400) and to work around an
Xgene UART clock issue (Graeme Gregory).
- Add a new utility function to the ACPI core to support using ACPI
OEM ID / OEM Table ID / Revision for system identification in
blacklisting or similar and switch over the existing code already
using this information to this new interface (Toshi Kani).
- Fix an xpower PMIC issue related to GPADC reads that always return
0 without extra pin manipulations (Hans de Goede).
- Add statements to print debug messages in a couple of places in the
ACPI core for easier diagnostics (Rafael Wysocki).
- Clean up the ACPI processor driver slightly (Colin Ian King, Hanjun
Guo).
- Clean up the ACPI x86 boot code somewhat (Andy Shevchenko).
- Add a quirk for Dell OptiPlex 9020M to the ACPI backlight driver
(Alex Hung).
- Assorted fixes, cleanups and updates related to ACPI (Amitoj Kaur
Chawla, Bhumika Goyal, Frank Rowand, Jean Delvare, Punit Agrawal,
Ronald Tschalär, Sumeet Pawnikar)"
* tag 'acpi-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (75 commits)
ACPI / APEI: Suppress message if HEST not present
intel_pstate: convert to use acpi_match_platform_list()
ACPI / blacklist: add acpi_match_platform_list()
ACPI, APEI, EINJ: Subtract any matching Register Region from Trigger resources
ACPI: make device_attribute const
ACPI / sysfs: Extend ACPI sysfs to provide access to boot error region
ACPI: APEI: fix the wrong iteration of generic error status block
ACPI / processor: make function acpi_processor_check_duplicates() static
ACPI / EC: Clean up EC GPE mask flag
ACPI: EC: Fix possible issues related to EC initialization order
ACPI / PM: Add debug statements to acpi_pm_notify_handler()
ACPI: Add debug statements to acpi_global_event_handler()
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: SPCR: work around clock issue on xgene UART
ACPI: SPCR: extend XGENE 8250 workaround to m400
ACPI / LPSS: Don't abort ACPI scan on missing mem resource
mailbox: pcc: Drop uninformative output during boot
ACPI/IORT: Add IORT named component memory address limits
...
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r-- | drivers/acpi/device_pm.c | 175 |
1 files changed, 123 insertions, 52 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 2ed6935d4483..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); @@ -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_enable(struct acpi_device *adev, u32 target_state) +{ + return __acpi_device_wakeup_enable(adev, target_state, 1); +} + +/** + * 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 int acpi_device_wakeup(struct acpi_device *adev, u32 target_state, - bool enable) +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); } -/** - * 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; @@ -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; |