Message ID | 1717218.WU8ttdIIEu@kreacher (mailing list archive) |
---|---|
State | Not Applicable, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Series | PM: ACPI: PCI: Address issues related to signaling wakeup from bridges | expand |
On Tue, Nov 24, 2020 at 08:46:38PM +0100, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > 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@intel.com> > Reported-by: Kai-Heng Feng <kai.heng.feng@canonical.com> > Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Index: linux-pm/drivers/acpi/device_pm.c =================================================================== --- linux-pm.orig/drivers/acpi/device_pm.c +++ linux-pm/drivers/acpi/device_pm.c @@ -757,16 +757,26 @@ static int __acpi_device_wakeup_enable(s 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(s (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);