aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-02-17 17:44:09 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-22 19:21:02 -0500
commitb67ea76172d4b1922c4b3c46c8ea8e9fec1ff38c (patch)
treec2f51811376060b3b59ac43243a182b94a48be9b /drivers/acpi
parent3f0be67188c60ebf1b5d00354b44b4b24f5af313 (diff)
PCI / ACPI / PM: Platform support for PCI PME wake-up
Although the majority of PCI devices can generate PMEs that in principle may be used to wake up devices suspended at run time, platform support is generally necessary to convert PMEs into wake-up events that can be delivered to the kernel. If ACPI is used for this purpose, PME signals generated by a PCI device will trigger the ACPI GPE associated with the device to generate an ACPI wake-up event that we can set up a handler for, provided that everything is configured correctly. Unfortunately, the subset of PCI devices that have GPEs associated with them is quite limited. The devices without dedicated GPEs have to rely on the GPEs associated with other devices (in the majority of cases their upstream bridges and, possibly, the root bridge) to generate ACPI wake-up events in response to PME signals from them. Add ACPI platform support for PCI PME wake-up: o Add a framework making is possible to use ACPI system notify handlers for run-time PM. o Add new PCI platform callback ->run_wake() to struct pci_platform_pm_ops allowing us to enable/disable the platform to generate wake-up events for given device. Implemet this callback for the ACPI platform. o Define ACPI wake-up handlers for PCI devices and PCI root buses and make the PCI-ACPI binding code register wake-up notifiers for all PCI devices present in the ACPI tables. o Add function pci_dev_run_wake() which can be used by PCI drivers to check if given device is capable of generating wake-up events at run time. Developed in cooperation with Matthew Garrett <mjg@redhat.com>. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/pci_bind.c14
-rw-r--r--drivers/acpi/pci_root.c8
-rw-r--r--drivers/acpi/scan.c1
4 files changed, 22 insertions, 3 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index cb28e0502acc..9c4c962e46e3 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -36,8 +36,6 @@ static inline int acpi_debug_init(void) { return 0; }
36int acpi_power_init(void); 36int acpi_power_init(void);
37int acpi_device_sleep_wake(struct acpi_device *dev, 37int acpi_device_sleep_wake(struct acpi_device *dev,
38 int enable, int sleep_state, int dev_state); 38 int enable, int sleep_state, int dev_state);
39int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state);
40int acpi_disable_wakeup_device_power(struct acpi_device *dev);
41int acpi_power_get_inferred_state(struct acpi_device *device); 39int acpi_power_get_inferred_state(struct acpi_device *device);
42int acpi_power_transition(struct acpi_device *device, int state); 40int acpi_power_transition(struct acpi_device *device, int state);
43extern int acpi_power_nocheck; 41extern int acpi_power_nocheck;
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index a5a77b78a723..2ef04098cc1d 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -26,7 +26,9 @@
26#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/pci.h> 28#include <linux/pci.h>
29#include <linux/pci-acpi.h>
29#include <linux/acpi.h> 30#include <linux/acpi.h>
31#include <linux/pm_runtime.h>
30#include <acpi/acpi_bus.h> 32#include <acpi/acpi_bus.h>
31#include <acpi/acpi_drivers.h> 33#include <acpi/acpi_drivers.h>
32 34
@@ -38,7 +40,13 @@ static int acpi_pci_unbind(struct acpi_device *device)
38 struct pci_dev *dev; 40 struct pci_dev *dev;
39 41
40 dev = acpi_get_pci_dev(device->handle); 42 dev = acpi_get_pci_dev(device->handle);
41 if (!dev || !dev->subordinate) 43 if (!dev)
44 goto out;
45
46 device_set_run_wake(&dev->dev, false);
47 pci_acpi_remove_pm_notifier(device);
48
49 if (!dev->subordinate)
42 goto out; 50 goto out;
43 51
44 acpi_pci_irq_del_prt(dev->subordinate); 52 acpi_pci_irq_del_prt(dev->subordinate);
@@ -62,6 +70,10 @@ static int acpi_pci_bind(struct acpi_device *device)
62 if (!dev) 70 if (!dev)
63 return 0; 71 return 0;
64 72
73 pci_acpi_add_pm_notifier(device, dev);
74 if (device->wakeup.flags.run_wake)
75 device_set_run_wake(&dev->dev, true);
76
65 /* 77 /*
66 * Install the 'bind' function to facilitate callbacks for 78 * Install the 'bind' function to facilitate callbacks for
67 * children of the P2P bridge. 79 * children of the P2P bridge.
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 64f55b6db73c..9cd8bedb1e5a 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -30,6 +30,7 @@
30#include <linux/proc_fs.h> 30#include <linux/proc_fs.h>
31#include <linux/spinlock.h> 31#include <linux/spinlock.h>
32#include <linux/pm.h> 32#include <linux/pm.h>
33#include <linux/pm_runtime.h>
33#include <linux/pci.h> 34#include <linux/pci.h>
34#include <linux/pci-acpi.h> 35#include <linux/pci-acpi.h>
35#include <linux/acpi.h> 36#include <linux/acpi.h>
@@ -528,6 +529,10 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
528 if (flags != base_flags) 529 if (flags != base_flags)
529 acpi_pci_osc_support(root, flags); 530 acpi_pci_osc_support(root, flags);
530 531
532 pci_acpi_add_bus_pm_notifier(device, root->bus);
533 if (device->wakeup.flags.run_wake)
534 device_set_run_wake(root->bus->bridge, true);
535
531 return 0; 536 return 0;
532 537
533end: 538end:
@@ -549,6 +554,9 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
549{ 554{
550 struct acpi_pci_root *root = acpi_driver_data(device); 555 struct acpi_pci_root *root = acpi_driver_data(device);
551 556
557 device_set_run_wake(root->bus->bridge, false);
558 pci_acpi_remove_bus_pm_notifier(device);
559
552 kfree(root); 560 kfree(root);
553 return 0; 561 return 0;
554} 562}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7491a52ad97a..fb7fc24fe727 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -753,6 +753,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
753 acpi_event_status event_status; 753 acpi_event_status event_status;
754 754
755 device->wakeup.run_wake_count = 0; 755 device->wakeup.run_wake_count = 0;
756 device->wakeup.flags.notifier_present = 0;
756 757
757 /* Power button, Lid switch always enable wakeup */ 758 /* Power button, Lid switch always enable wakeup */
758 if (!acpi_match_device_ids(device, button_device_ids)) { 759 if (!acpi_match_device_ids(device, button_device_ids)) {