aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-12-29 17:37:15 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-12-29 17:37:15 -0500
commitf084280cd34e375cd9736d14b023cfc7df3374bb (patch)
tree1c40ba9145e4449a9394e299a9d7f631bed009ac
parent413541dd66d51f791a0b169d9b9014e4f56be13c (diff)
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>
-rw-r--r--drivers/pci/pci-acpi.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 577074efbe62..f7ebdba14bde 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -330,29 +330,32 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
330static void pci_acpi_setup(struct device *dev) 330static void pci_acpi_setup(struct device *dev)
331{ 331{
332 struct pci_dev *pci_dev = to_pci_dev(dev); 332 struct pci_dev *pci_dev = to_pci_dev(dev);
333 acpi_handle handle = ACPI_HANDLE(dev); 333 struct acpi_device *adev = ACPI_COMPANION(dev);
334 struct acpi_device *adev;
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 return; 340 return;
338 341
339 device_set_wakeup_capable(dev, true); 342 device_set_wakeup_capable(dev, true);
340 acpi_pci_sleep_wake(pci_dev, false); 343 acpi_pci_sleep_wake(pci_dev, false);
341
342 pci_acpi_add_pm_notifier(adev, pci_dev);
343 if (adev->wakeup.flags.run_wake) 344 if (adev->wakeup.flags.run_wake)
344 device_set_run_wake(dev, true); 345 device_set_run_wake(dev, true);
345} 346}
346 347
347static void pci_acpi_cleanup(struct device *dev) 348static void pci_acpi_cleanup(struct device *dev)
348{ 349{
349 acpi_handle handle = ACPI_HANDLE(dev); 350 struct acpi_device *adev = ACPI_COMPANION(dev);
350 struct acpi_device *adev; 351
352 if (!adev)
353 return;
351 354
352 if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) { 355 pci_acpi_remove_pm_notifier(adev);
356 if (adev->wakeup.flags.valid) {
353 device_set_wakeup_capable(dev, false); 357 device_set_wakeup_capable(dev, false);
354 device_set_run_wake(dev, false); 358 device_set_run_wake(dev, false);
355 pci_acpi_remove_pm_notifier(adev);
356 } 359 }
357} 360}
358 361