From 5bcc2fb4e8157d829a38093b98e23329ac8acff7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Sep 2009 23:12:59 +0200 Subject: PCI PM: Simplify PCI wake-up code Rework the PCI wake-up code so that it's easier to read without changing the functionality. Reviewed-by: Matthew Garrett Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index ea15b05..e798c47 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -111,12 +111,16 @@ static bool acpi_pci_can_wakeup(struct pci_dev *dev) static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) { - int error = acpi_pm_device_sleep_wake(&dev->dev, enable); + int error; + if (!acpi_pci_can_wakeup(dev)) + return 0; + + error = acpi_pm_device_sleep_wake(&dev->dev, enable); if (!error) - dev_printk(KERN_INFO, &dev->dev, - "wake-up capability %s by ACPI\n", + dev_info(&dev->dev, "wake-up capability %s by ACPI\n", enable ? "enabled" : "disabled"); + return error; } -- cgit v1.1 From df8db91fc3b543d373afa61beef35b072eea1368 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Sep 2009 23:13:49 +0200 Subject: PCI / ACPI PM: Rework some debug messages Move a debug message from acpi_pci_sleep_wake() to acpi_pm_device_sleep_wake() and use the standard dev_*() macros in there. Reviewed-by: Matthew Garrett Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e798c47..0bddd78 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -111,17 +111,8 @@ static bool acpi_pci_can_wakeup(struct pci_dev *dev) static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) { - int error; - - if (!acpi_pci_can_wakeup(dev)) - return 0; - - error = acpi_pm_device_sleep_wake(&dev->dev, enable); - if (!error) - dev_info(&dev->dev, "wake-up capability %s by ACPI\n", - enable ? "enabled" : "disabled"); - - return error; + return acpi_pci_can_wakeup(dev) ? + acpi_pm_device_sleep_wake(&dev->dev, enable) : 0; } static struct pci_platform_pm_ops acpi_pci_platform_pm = { -- cgit v1.1 From 0baed8da1ed91b664759f6c7f955b3a804457389 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Sep 2009 23:16:24 +0200 Subject: PCI / ACPI PM: Propagate wake-up enable for devices w/o ACPI support Some PCI devices (not PCI Express), like PCI add-on cards, can generate PME#, but they don't have any special platform wake-up support. For this reason, even if they generate PME# to wake up the system from a sleep state, wake-up events are not generated by the platform. It turns out that, at least on some systems, PCI bridges and the PCI host bridge have ACPI GPEs associated with them that, if enabled to generate wake-up events, allow the system to wake up if one of the add-on devices asserts PME# while the system is in a sleep state. Following this observation, if a PCI device without direct ACPI wake-up support is prepared to wake up the system during a transition into a sleep state (eg. suspend to RAM), try to configure the bridges on the path from the device to the root bridge to wake-up the system. Reviewed-by: Matthew Garrett Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/pci/pci-acpi.c') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 0bddd78..33317df 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -109,10 +109,32 @@ static bool acpi_pci_can_wakeup(struct pci_dev *dev) return handle ? acpi_bus_can_wakeup(handle) : false; } +static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable) +{ + while (bus->parent) { + struct pci_dev *bridge = bus->self; + int ret; + + ret = acpi_pm_device_sleep_wake(&bridge->dev, enable); + if (!ret || bridge->is_pcie) + return; + bus = bus->parent; + } + + /* We have reached the root bus. */ + if (bus->bridge) + acpi_pm_device_sleep_wake(bus->bridge, enable); +} + static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) { - return acpi_pci_can_wakeup(dev) ? - acpi_pm_device_sleep_wake(&dev->dev, enable) : 0; + if (acpi_pci_can_wakeup(dev)) + return acpi_pm_device_sleep_wake(&dev->dev, enable); + + if (!dev->is_pcie) + acpi_pci_propagate_wakeup_enable(dev->bus, enable); + + return 0; } static struct pci_platform_pm_ops acpi_pci_platform_pm = { -- cgit v1.1