From: ykzhao <yakui.zhao@intel.com>
To: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: "linux-pm@lists.linux-foundation.org"
<linux-pm@lists.linux-foundation.org>,
ACPI Devel Maling List <linux-acpi@vger.kernel.org>,
Henrique de Moraes Holschuh <hmh@hmh.eng.br>,
Jesse Barnes <jbarnes@virtuousgeek.org>,
Linux PCI <linux-pci@vger.kernel.org>
Subject: Re: [RFC][PATCH 4/4] PCI/ACPI PM: Propagate wake-up enable for devices w/o ACPI support
Date: Fri, 04 Sep 2009 10:13:04 +0800 [thread overview]
Message-ID: <1252030384.3609.45.camel@localhost.localdomain> (raw)
In-Reply-To: <200909040007.09926.rjw@sisk.pl>
On Fri, 2009-09-04 at 06:07 +0800, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rjw@sisk.pl>
>
> 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), configure all the bridges on
> the path from the device to the root bridge (including the root
> bridge itself) to wake-up the system.
>From the description it seems that it will propagate the wake-up
function to its parent device.
Is it enough to stop the propagation when we find one device that can
generate wake-up events in its parent device tree?
thanks.
>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
> drivers/acpi/power.c | 52 ++++++++++++++++++++++++++++++++----------------
> drivers/acpi/scan.c | 1
> drivers/acpi/sleep.c | 2 -
> drivers/acpi/wakeup.c | 4 +--
> drivers/pci/pci-acpi.c | 25 +++++++++++++++++++++--
> include/acpi/acpi_bus.h | 2 -
> 6 files changed, 63 insertions(+), 23 deletions(-)
>
> Index: linux-2.6/drivers/pci/pci-acpi.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/pci-acpi.c
> +++ linux-2.6/drivers/pci/pci-acpi.c
> @@ -109,10 +109,31 @@ static bool acpi_pci_can_wakeup(struct p
> 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;
> +
> + acpi_pm_device_sleep_wake(&bridge->dev, enable);
> + if (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 = {
> Index: linux-2.6/drivers/acpi/sleep.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/sleep.c
> +++ linux-2.6/drivers/acpi/sleep.c
> @@ -691,7 +691,7 @@ int acpi_pm_device_sleep_wake(struct dev
> struct acpi_device *adev;
> int error;
>
> - if (!device_may_wakeup(dev))
> + if (!device_can_wakeup(dev))
> return -EINVAL;
>
> handle = DEVICE_ACPI_HANDLE(dev);
> Index: linux-2.6/drivers/acpi/scan.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/scan.c
> +++ linux-2.6/drivers/acpi/scan.c
> @@ -782,6 +782,7 @@ static int acpi_bus_get_wakeup_device_fl
> kfree(buffer.pointer);
>
> device->wakeup.flags.valid = 1;
> + device->wakeup.prepare_count = 0;
> /* Call _PSW/_DSW object to disable its ability to wake the sleeping
> * system for the ACPI device with the _PRW object.
> * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
> Index: linux-2.6/include/acpi/acpi_bus.h
> ===================================================================
> --- linux-2.6.orig/include/acpi/acpi_bus.h
> +++ linux-2.6/include/acpi/acpi_bus.h
> @@ -248,7 +248,6 @@ struct acpi_device_perf {
> /* Wakeup Management */
> struct acpi_device_wakeup_flags {
> u8 valid:1; /* Can successfully enable wakeup? */
> - u8 prepared:1; /* Has the wake-up capability been enabled? */
> u8 run_wake:1; /* Run-Wake GPE devices */
> };
>
> @@ -263,6 +262,7 @@ struct acpi_device_wakeup {
> struct acpi_handle_list resources;
> struct acpi_device_wakeup_state state;
> struct acpi_device_wakeup_flags flags;
> + int prepare_count;
> };
>
> /* Device */
> Index: linux-2.6/drivers/acpi/power.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/power.c
> +++ linux-2.6/drivers/acpi/power.c
> @@ -44,6 +44,8 @@
> #include <acpi/acpi_bus.h>
> #include <acpi/acpi_drivers.h>
>
> +#include "sleep.h"
> +
> #define _COMPONENT ACPI_POWER_COMPONENT
> ACPI_MODULE_NAME("power");
> #define ACPI_POWER_CLASS "power_resource"
> @@ -361,17 +363,19 @@ int acpi_device_sleep_wake(struct acpi_d
> */
> int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
> {
> - int i, err;
> + int i, err = 0;
>
> if (!dev || !dev->wakeup.flags.valid)
> return -EINVAL;
>
> + mutex_lock(&acpi_device_lock);
> +
> /*
> * Do not execute the code below twice in a row without calling
> * acpi_disable_wakeup_device_power() in between for the same device
> */
> - if (dev->wakeup.flags.prepared)
> - return 0;
> + if (dev->wakeup.prepare_count++)
> + goto out;
>
> /* Open power resource */
> for (i = 0; i < dev->wakeup.resources.count; i++) {
> @@ -379,7 +383,8 @@ int acpi_enable_wakeup_device_power(stru
> if (ret) {
> printk(KERN_ERR PREFIX "Transition power state\n");
> dev->wakeup.flags.valid = 0;
> - return -ENODEV;
> + err = -ENODEV;
> + goto err_out;
> }
> }
>
> @@ -388,9 +393,13 @@ int acpi_enable_wakeup_device_power(stru
> * in arbitrary power state afterwards.
> */
> err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
> - if (!err)
> - dev->wakeup.flags.prepared = 1;
>
> + err_out:
> + if (err)
> + dev->wakeup.prepare_count = 0;
> +
> + out:
> + mutex_unlock(&acpi_device_lock);
> return err;
> }
>
> @@ -402,35 +411,44 @@ int acpi_enable_wakeup_device_power(stru
> */
> int acpi_disable_wakeup_device_power(struct acpi_device *dev)
> {
> - int i, ret;
> + int i, err = 0;
>
> if (!dev || !dev->wakeup.flags.valid)
> return -EINVAL;
>
> + mutex_lock(&acpi_device_lock);
> +
> /*
> * Do not execute the code below twice in a row without calling
> * acpi_enable_wakeup_device_power() in between for the same device
> */
> - if (!dev->wakeup.flags.prepared)
> - return 0;
> -
> - dev->wakeup.flags.prepared = 0;
> + if (--dev->wakeup.prepare_count) {
> + if (dev->wakeup.prepare_count < 0) {
> + dev_warn(&dev->dev, "unbalanced %s!\n", __func__);
> + dev->wakeup.prepare_count = 0;
> + }
> + goto out;
> + }
>
> - ret = acpi_device_sleep_wake(dev, 0, 0, 0);
> - if (ret)
> - return ret;
> + err = acpi_device_sleep_wake(dev, 0, 0, 0);
> + if (err)
> + goto out;
>
> /* Close power resource */
> for (i = 0; i < dev->wakeup.resources.count; i++) {
> - ret = acpi_power_off_device(dev->wakeup.resources.handles[i], dev);
> + int ret = acpi_power_off_device(
> + dev->wakeup.resources.handles[i], dev);
> if (ret) {
> printk(KERN_ERR PREFIX "Transition power state\n");
> dev->wakeup.flags.valid = 0;
> - return -ENODEV;
> + err = -ENODEV;
> + goto out;
> }
> }
>
> - return ret;
> + out:
> + mutex_unlock(&acpi_device_lock);
> + return err;
> }
>
> /* --------------------------------------------------------------------------
> Index: linux-2.6/drivers/acpi/wakeup.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/wakeup.c
> +++ linux-2.6/drivers/acpi/wakeup.c
> @@ -68,7 +68,7 @@ void acpi_enable_wakeup_device(u8 sleep_
> /* If users want to disable run-wake GPE,
> * we only disable it for wake and leave it for runtime
> */
> - if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
> + if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
> || sleep_state > (u32) dev->wakeup.sleep_state) {
> if (dev->wakeup.flags.run_wake) {
> /* set_gpe_type will disable GPE, leave it like that */
> @@ -100,7 +100,7 @@ void acpi_disable_wakeup_device(u8 sleep
> if (!dev->wakeup.flags.valid)
> continue;
>
> - if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
> + if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count)
> || sleep_state > (u32) dev->wakeup.sleep_state) {
> if (dev->wakeup.flags.run_wake) {
> acpi_set_gpe_type(dev->wakeup.gpe_device,
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2009-09-04 2:13 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-29 22:41 [PATCH] ACPI / PM: Allow PCI root bridges to wake up the system Rafael J. Wysocki
2009-08-31 19:41 ` [linux-pm] " Rafael J. Wysocki
2009-08-31 21:24 ` [RFC][PATCH update] " Rafael J. Wysocki
2009-09-01 13:25 ` Matthew Garrett
2009-09-01 19:03 ` Rafael J. Wysocki
2009-09-01 22:41 ` [linux-pm] " Rafael J. Wysocki
2009-09-03 22:02 ` [RFC][PATCH 0/4] PCI/ACPI PM: Propagate wake-up enable upstream Rafael J. Wysocki
2009-09-03 22:03 ` [RFC][PATCH 1/4] PCI PM: Simplify PCI wake-up code Rafael J. Wysocki
2009-09-03 22:04 ` [RFC][PATCH 2/4] PCI/ACPI PM: Rework some debug messages Rafael J. Wysocki
2009-09-03 22:05 ` [RFC][PATCH 3/4] PCI PM: Introduce device flag wakeup_prepared Rafael J. Wysocki
2009-09-03 22:07 ` [RFC][PATCH 4/4] PCI/ACPI PM: Propagate wake-up enable for devices w/o ACPI support Rafael J. Wysocki
2009-09-04 2:13 ` ykzhao [this message]
2009-09-04 14:39 ` Rafael J. Wysocki
2009-09-04 14:56 ` Matthew Garrett
2009-09-04 22:00 ` Rafael J. Wysocki
2009-09-04 22:06 ` Matthew Garrett
2009-09-04 22:21 ` Rafael J. Wysocki
2009-09-04 22:03 ` [linux-pm] " Rafael J. Wysocki
2009-09-04 22:05 ` [RFC][PATCH 4/4 replacement] ACPI PM: Replace wakeup.prepared with reference counter Rafael J. Wysocki
2009-09-04 22:06 ` [RFC][PATCH 5] PCI/ACPI PM: Propagate wake-up enable for devices w/o ACPI support Rafael J. Wysocki
2009-09-08 21:11 ` [PATCH 0/5 update] PCI / ACPI PM: Propagate wake-up enable upstream Rafael J. Wysocki
2009-09-08 21:12 ` [PATCH 1/5] PCI PM: Simplify PCI wake-up code Rafael J. Wysocki
2009-09-09 21:20 ` Jesse Barnes
2009-09-08 21:13 ` [PATCH 2/5] PCI / ACPI PM: Rework some debug messages Rafael J. Wysocki
2009-09-08 21:14 ` [PATCH 3/5] PCI PM: Introduce device flag wakeup_prepared Rafael J. Wysocki
2009-09-08 21:15 ` [PATCH 4/5] ACPI PM: Replace wakeup.prepared with reference counter Rafael J. Wysocki
2009-09-08 21:16 ` [PATCH 5/5] PCI / ACPI PM: Propagate wake-up enable for devices w/o ACPI support Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1252030384.3609.45.camel@localhost.localdomain \
--to=yakui.zhao@intel.com \
--cc=hmh@hmh.eng.br \
--cc=jbarnes@virtuousgeek.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@lists.linux-foundation.org \
--cc=rjw@sisk.pl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox