Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI / ACPI: Install wakeup notify handlers for all PCI devs with ACPI

It turns out that some BIOSes don't report wakeup GPEs through
_PRW, but use them for signaling wakeup anyway, which causes GPE
storms to occur on some systems after resume from system suspend.
This issue has been uncovered by commit d2e5f0c16ad6 (ACPI / PCI:
Rework the setup and cleanup of device wakeup) during the 3.9
development cycle.

Work around the problem by installing wakeup notify handlers for all
PCI devices with ACPI support (i.e. having ACPI companions) regardless
of whether or not the BIOS reports ACPI wakeup support for them. The
presence of the wakeup notify handlers alone is not harmful in any
way if there are no events for them to handle (they are simply never
executed then), but on some systems they are needed to take care of
spurious events.

Fixes: d2e5f0c16ad6 (ACPI / PCI: Rework the setup and cleanup of device wakeup)
References: https://bugzilla.kernel.org/show_bug.cgi?id=63021
Reported-and-tested-by: Agustin Barto <abarto@gmail.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+12 -9
+12 -9
drivers/pci/pci-acpi.c
··· 330 330 static void pci_acpi_setup(struct device *dev) 331 331 { 332 332 struct pci_dev *pci_dev = to_pci_dev(dev); 333 - acpi_handle handle = ACPI_HANDLE(dev); 334 - struct acpi_device *adev; 333 + struct acpi_device *adev = ACPI_COMPANION(dev); 335 334 336 - if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) 335 + if (!adev) 336 + return; 337 + 338 + pci_acpi_add_pm_notifier(adev, pci_dev); 339 + if (!adev->wakeup.flags.valid) 337 340 return; 338 341 339 342 device_set_wakeup_capable(dev, true); 340 343 acpi_pci_sleep_wake(pci_dev, false); 341 - 342 - pci_acpi_add_pm_notifier(adev, pci_dev); 343 344 if (adev->wakeup.flags.run_wake) 344 345 device_set_run_wake(dev, true); 345 346 } 346 347 347 348 static void pci_acpi_cleanup(struct device *dev) 348 349 { 349 - acpi_handle handle = ACPI_HANDLE(dev); 350 - struct acpi_device *adev; 350 + struct acpi_device *adev = ACPI_COMPANION(dev); 351 351 352 - if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) { 352 + if (!adev) 353 + return; 354 + 355 + pci_acpi_remove_pm_notifier(adev); 356 + if (adev->wakeup.flags.valid) { 353 357 device_set_wakeup_capable(dev, false); 354 358 device_set_run_wake(dev, false); 355 - pci_acpi_remove_pm_notifier(adev); 356 359 } 357 360 } 358 361