[PATCH 2/2] PM: ACPI: Refresh wakeup device power configuration every time

Kai-Heng Feng kai.heng.feng at canonical.com
Mon Nov 30 08:13:02 UTC 2020


From: "Rafael J. Wysocki" <rafael.j.wysocki at intel.com>

BugLink: https://bugs.launchpad.net/bugs/1906229

When wakeup signaling is enabled for a bridge for the second (or every
next) time in a row, its existing device wakeup power configuration
may not match the new conditions.  For example, some devices below
it may have been put into low-power states and that changes the
device wakeup power conditions or similar.  This causes functional
problems to appear on some systems (for example,  because of it the
Thunderbolt port on Dell Precision 5550 cannot detect devices plugged
in after it has been suspended).

For this reason, modify __acpi_device_wakeup_enable() to refresh the
device wakeup power configuration of the target device on every
invocation, not just when it is called for that device first time
in a row.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki at intel.com>
Reported-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
Tested-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
Reviewed-by: Mika Westerberg <mika.westerberg at linux.intel.com>
(cherry picked from commit 7400906166b4bbbca79d4e44094dddeefbb6ecd5 linux-next)
Signed-off-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
---
 drivers/acpi/device_pm.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index ef77dbcaf58f..3586434d0ded 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -757,16 +757,26 @@ static int __acpi_device_wakeup_enable(struct acpi_device *adev,
 
 	mutex_lock(&acpi_wakeup_lock);
 
-	if (wakeup->enable_count >= INT_MAX) {
-		acpi_handle_info(adev->handle, "Wakeup enable count out of bounds!\n");
-		goto out;
-	}
+	/*
+	 * If the device wakeup power is already enabled, disable it and enable
+	 * it again in case it depends on the configuration of subordinate
+	 * devices and the conditions have changed since it was enabled last
+	 * time.
+	 */
 	if (wakeup->enable_count > 0)
-		goto inc;
+		acpi_disable_wakeup_device_power(adev);
 
 	error = acpi_enable_wakeup_device_power(adev, target_state);
-	if (error)
+	if (error) {
+		if (wakeup->enable_count > 0) {
+			acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
+			wakeup->enable_count = 0;
+		}
 		goto out;
+	}
+
+	if (wakeup->enable_count > 0)
+		goto inc;
 
 	status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
 	if (ACPI_FAILURE(status)) {
@@ -779,7 +789,10 @@ static int __acpi_device_wakeup_enable(struct acpi_device *adev,
 			  (unsigned int)wakeup->gpe_number);
 
 inc:
-	wakeup->enable_count++;
+	if (wakeup->enable_count < INT_MAX)
+		wakeup->enable_count++;
+	else
+		acpi_handle_info(adev->handle, "Wakeup enable count out of bounds!\n");
 
 out:
 	mutex_unlock(&acpi_wakeup_lock);
-- 
2.29.2




More information about the kernel-team mailing list