From 147a7d9d25ca2551aab15071cb1f048ecd9b7953 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 20 Feb 2018 12:10:32 +0100 Subject: ACPI / PM: Do not reconfigure GPEs for suspend-to-idle It is reported that commit 235d81a630ca (ACPI / PM: Clean up device wakeup enable/disable code) broke wakeup from suspend-to-idle on some platforms. That is due to the acpi_enable_all_wakeup_gpes() in acpi_s2idle_prepare() which needs acpi_enable_wakeup_devices() to be called before it as the latter sets up the GPE masks used by the former and commit 235d81a630ca removed acpi_enable_wakeup_devices() invocation from the suspend-to-idle path. However, acpi_enable_wakeup_devices() does more than just setting the GPE masks and the remaining part of it is not necessary for suspend-to-idle. Moreover, non-wakeup GPEs are disabled on suspend- to-idle entry to avoid spurious wakeups, but that should not be strictly necessary any more after commit 33e4f80ee69b (ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle) which prevents spurious GPE wakeups from resuming the system. The only consequence of leaving non-wakeup GPEs enabled may be more interrupt-related activity while suspended, which is not ideal (more energy is used if that happens), but it is not critical too. For this reason, drop the GPE reconfiguration from the suspend-to-idle path entirely. This change also allows Dells XPS13 9360 blacklisted by commit 71630b7a832f (ACPI / PM: Blacklist Low Power S0 Idle _DSM for Dell XPS13 9360) to use the power button for waking up from suspend- to-idle and it helps at least one other older Dell system (the wakeup button GPE on that one is not listed in _PRW for any devices, so it is not regarded as a wakeup one and gets disabled on suspend-to-idle entry today). Fixes: 235d81a630ca (ACPI / PM: Clean up device wakeup enable/disable code) Reported-by: Du Wenkai Tested-by: Du Wenkai Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 46cde0912762..c53119740a3c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -953,15 +953,8 @@ static int acpi_s2idle_prepare(void) if (lps0_device_handle) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); - } else { - /* - * The configuration of GPEs is changed here to avoid spurious - * wakeups, but that should not be necessary if this is a - * "low-power S0" platform and the low-power S0 _DSM is present. - */ - acpi_enable_all_wakeup_gpes(); - acpi_os_wait_events_complete(); } + if (acpi_sci_irq_valid()) enable_irq_wake(acpi_sci_irq); @@ -1007,8 +1000,6 @@ static void acpi_s2idle_restore(void) if (lps0_device_handle) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); - } else { - acpi_enable_all_runtime_gpes(); } } -- cgit v1.2.3 From fa54150aad84dbbd92b26ce47e6b2cf7c686dca0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 13 Mar 2018 10:47:36 +0100 Subject: ACPI / PM: Reduce LPI constraints logging noise If a device referred to by ACPI LPI constrains (coming from function 1 of the Low Power S0 Idle _DSM interface) is not power-manageable via ACPI (no _PS0 method and no power resources), the code generating diagnostic information for the LPI constraints will print a message about that to the kernel log on every system suspend-resume cycle (possibly for multiple times). That is not very useful and noisy, so modify that code to disregard the LPI list entries corresponding to the devices that are not power- manageable after printing that information for them once. Signed-off-by: Rafael J. Wysocki Reviewed-by: Srinivas Pandruvada --- drivers/acpi/sleep.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index c53119740a3c..b5d27a4213ab 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -851,23 +851,25 @@ static void lpi_check_constraints(void) int i; for (i = 0; i < lpi_constraints_table_size; ++i) { + acpi_handle handle = lpi_constraints_table[i].handle; struct acpi_device *adev; - if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev)) + if (!handle || acpi_bus_get_device(handle, &adev)) continue; - acpi_handle_debug(adev->handle, + acpi_handle_debug(handle, "LPI: required min power state:%s current power state:%s\n", acpi_power_state_string(lpi_constraints_table[i].min_dstate), acpi_power_state_string(adev->power.state)); if (!adev->flags.power_manageable) { - acpi_handle_info(adev->handle, "LPI: Device not power manageble\n"); + acpi_handle_info(handle, "LPI: Device not power manageable\n"); + lpi_constraints_table[i].handle = NULL; continue; } if (adev->power.state < lpi_constraints_table[i].min_dstate) - acpi_handle_info(adev->handle, + acpi_handle_info(handle, "LPI: Constraint not met; min power state:%s current power state:%s\n", acpi_power_state_string(lpi_constraints_table[i].min_dstate), acpi_power_state_string(adev->power.state)); -- cgit v1.2.3 From bf8c6184e0c3d4d5e005e085e9f96f478a267b20 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 20 Mar 2018 12:07:35 +0800 Subject: ACPI / PM: Allow deeper wakeup power states with no _SxD nor _SxW acpi_dev_pm_get_state() is used to determine the range of allowable device power states when going into S3 suspend. This is implemented by executing the _S3D and _S3W ACPI methods. Linux follows the ACPI spec behaviour in that when _S3D is implemented and _S3W is not, Linux will not go into a power state deeper than the one returned by _S3D for a wakeup-enabled device. However, this same logic is being applied to the case when neither _S3D nor _S3W are present, and the result is that this function decides that the device must stay in D0 (fully on) state. This is breaking USB wakeups on Asus V222GA and Acer XC-830. _S3D and _S3W are not present, so the USB controller is left in the D0 running state during S3, and hence it is unable to generate a PME# wake event. The ACPI spec is unclear on which power states are permissable for wakeup-enabled devices when both _S3D and _S3W are missing. However, USB wakeups work fine on these platforms under Windows, where device manager shows that they are using D3 device state for the USB controller in S3. I assume that the "max = min" clamping done by the code here is specifically written for the _S3D but no _S3W case. By making the code true to those conditions, avoiding them on these platforms, the controller will be put into D3 state and USB wakeups start working. Additionally I feel that this change makes the code more directly mirror the wording of the ACPI spec and it's associated lack of clarity. Thanks to Mathias Nyman for pointing us in the right direction. Signed-off-by: Daniel Drake Link: http://lkml.kernel.org/r/CAB4CAwf_k-WsF3zL4epm9TKAOu0h=Bv1XhXV_gY3bziOo_NPKA@mail.gmail.com https://phabricator.endlessm.com/T21410 Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index c4d0a1c912f0..3d96e4da2d98 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -543,6 +543,7 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, unsigned long long ret; int d_min, d_max; bool wakeup = false; + bool has_sxd = false; acpi_status status; /* @@ -581,6 +582,10 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, else return -ENODATA; } + + if (status == AE_OK) + has_sxd = true; + d_min = ret; wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid && adev->wakeup.sleep_state >= target_state; @@ -599,7 +604,11 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, method[3] = 'W'; status = acpi_evaluate_integer(handle, method, NULL, &ret); if (status == AE_NOT_FOUND) { - if (target_state > ACPI_STATE_S0) + /* No _SxW. In this case, the ACPI spec says that we + * must not go into any power state deeper than the + * value returned from _SxD. + */ + if (has_sxd && target_state > ACPI_STATE_S0) d_max = d_min; } else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) { /* Fall back to D3cold if ret is not a valid state. */ -- cgit v1.2.3 From 6f1d7c45dbbadd1a3c6eb9a9a485ef1975be4760 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Sat, 31 Mar 2018 10:09:31 +0800 Subject: ACPI / PM: Fix keyboard wakeup from suspend-to-idle on ASUS UX331UA This issue happens on new ASUS laptop UX331UA which has modern standby mode (suspend-to-idle). Pressing keys on the PS2 keyboard can't wake up the system from suspend-to-idle which is not expected. However, pressing power button can wake up without problem. Per the engineers of ASUS, the keypress event is routed to Embedded Controller (EC) in standby mode. EC then signals the SCI event to BIOS so BIOS would Notify() power button to wake up the system. It's from BIOS perspective. What we observe here is that kernel receives the SCI event from SCI interrupt handler which informs that the GPE status bit belongs to EC needs to be handled and then queries the EC to find out what event is pending. Then execute the following ACPI _QDF method which defined in ACPI DSDT for EC to notify power button. Method (_QDF, 0, NotSerialized) // _Qxx: EC Query { Notify (PWRB, 0x80) // Status Change } With more debug messages added to analyze this problem, we find that the keypress does wake up the system from suspend-to-idle but it's back to suspend again almost immediately. As we see in the following messages, the acpi_button_notify() is invoked but acpi_pm_wakeup_event() can not really wake up the system here because acpi_s2idle_wakeup() is false. The acpi_s2idle_wakeup() returnd false because the acpi_s2idle_sync() has alrealdy exited. [ 52.987048] s2idle_loop going s2idle [ 59.713392] acpi_s2idle_wake enter [ 59.713394] acpi_s2idle_wake exit [ 59.760888] acpi_ev_gpe_detect enter [ 59.760893] acpi_s2idle_sync enter [ 59.760893] acpi_ec_query_flushed ec pending queries 0 [ 59.760953] Read registers for GPE 50-57: Status=01, Enable=01, RunEnable=01, WakeEnable=00 [ 59.760955] ACPI: EC: ===== IRQ (1) ===== [ 59.760972] ACPI: EC: EC_SC(R) = 0x28 SCI_EVT=1 BURST=0 CMD=1 IBF=0 OBF=0 [ 59.760979] ACPI: EC: +++++ Polling enabled +++++ [ 59.760979] ACPI: EC: ##### Command(QR_EC) submitted/blocked ##### [ 59.761003] acpi_s2idle_sync exit [ 59.769587] ACPI: EC: ##### Query(0xdf) started ##### [ 59.769611] ACPI: EC: ##### Query(0xdf) stopped ##### [ 59.774154] acpi_button_notify button type 1 [ 59.813175] s2idle_loop going s2idle acpi_s2idle_sync() already makes an effort to flush the EC event queue, but in this case, the EC event has yet to be generated when the call to acpi_ec_flush_work() is made. The event is generated shortly after, through the ongoing handling of the SCI interrupt which is happening on another CPU, and we must synchronize that to make sure that it has run and completed. Adding another call to acpi_os_wait_events_complete() solves this issue, since that function synchronizes with SCI interrupt completion. Signed-off-by: Chris Chiu [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index b5d27a4213ab..4a59c16915c3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -989,8 +989,9 @@ static void acpi_s2idle_sync(void) * The EC driver uses the system workqueue and an additional special * one, so those need to be flushed too. */ + acpi_os_wait_events_complete(); /* synchronize SCI IRQ handling */ acpi_ec_flush_work(); - acpi_os_wait_events_complete(); + acpi_os_wait_events_complete(); /* synchronize Notify handling */ s2idle_wakeup = false; } -- cgit v1.2.3