Skip to content

Commit

Permalink
PCI / ACPI: Install wakeup notify handlers for all PCI devs with ACPI
Browse files Browse the repository at this point in the history
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 d2e5f0c (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: d2e5f0c (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>
  • Loading branch information
Rafael J. Wysocki committed Dec 29, 2013
1 parent 413541d commit f084280
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions drivers/pci/pci-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,29 +330,32 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
static void pci_acpi_setup(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_device *adev;
struct acpi_device *adev = ACPI_COMPANION(dev);

if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
if (!adev)
return;

pci_acpi_add_pm_notifier(adev, pci_dev);
if (!adev->wakeup.flags.valid)
return;

device_set_wakeup_capable(dev, true);
acpi_pci_sleep_wake(pci_dev, false);

pci_acpi_add_pm_notifier(adev, pci_dev);
if (adev->wakeup.flags.run_wake)
device_set_run_wake(dev, true);
}

static void pci_acpi_cleanup(struct device *dev)
{
acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_device *adev;
struct acpi_device *adev = ACPI_COMPANION(dev);

if (!adev)
return;

if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) {
pci_acpi_remove_pm_notifier(adev);
if (adev->wakeup.flags.valid) {
device_set_wakeup_capable(dev, false);
device_set_run_wake(dev, false);
pci_acpi_remove_pm_notifier(adev);
}
}

Expand Down

0 comments on commit f084280

Please sign in to comment.