aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
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/pci/pci.c
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/pci/pci.c')
-rw-r--r--drivers/pci/pci.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5723446544fd..df55a2f351b3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,7 @@
20#include <linux/pm_wakeup.h> 20#include <linux/pm_wakeup.h>
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/device.h> 22#include <linux/device.h>
23#include <linux/pm_runtime.h>
23#include <asm/setup.h> 24#include <asm/setup.h>
24#include "pci.h" 25#include "pci.h"
25 26
@@ -462,6 +463,12 @@ static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
462 pci_platform_pm->sleep_wake(dev, enable) : -ENODEV; 463 pci_platform_pm->sleep_wake(dev, enable) : -ENODEV;
463} 464}
464 465
466static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable)
467{
468 return pci_platform_pm ?
469 pci_platform_pm->run_wake(dev, enable) : -ENODEV;
470}
471
465/** 472/**
466 * pci_raw_set_power_state - Use PCI PM registers to set the power state of 473 * pci_raw_set_power_state - Use PCI PM registers to set the power state of
467 * given PCI device 474 * given PCI device
@@ -1230,6 +1237,31 @@ bool pci_check_pme_status(struct pci_dev *dev)
1230} 1237}
1231 1238
1232/** 1239/**
1240 * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
1241 * @dev: Device to handle.
1242 * @ign: Ignored.
1243 *
1244 * Check if @dev has generated PME and queue a resume request for it in that
1245 * case.
1246 */
1247static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
1248{
1249 if (pci_check_pme_status(dev))
1250 pm_request_resume(&dev->dev);
1251 return 0;
1252}
1253
1254/**
1255 * pci_pme_wakeup_bus - Walk given bus and wake up devices on it, if necessary.
1256 * @bus: Top bus of the subtree to walk.
1257 */
1258void pci_pme_wakeup_bus(struct pci_bus *bus)
1259{
1260 if (bus)
1261 pci_walk_bus(bus, pci_pme_wakeup, NULL);
1262}
1263
1264/**
1233 * pci_pme_capable - check the capability of PCI device to generate PME# 1265 * pci_pme_capable - check the capability of PCI device to generate PME#
1234 * @dev: PCI device to handle. 1266 * @dev: PCI device to handle.
1235 * @state: PCI state from which device will issue PME#. 1267 * @state: PCI state from which device will issue PME#.
@@ -1434,6 +1466,41 @@ int pci_back_from_sleep(struct pci_dev *dev)
1434} 1466}
1435 1467
1436/** 1468/**
1469 * pci_dev_run_wake - Check if device can generate run-time wake-up events.
1470 * @dev: Device to check.
1471 *
1472 * Return true if the device itself is cabable of generating wake-up events
1473 * (through the platform or using the native PCIe PME) or if the device supports
1474 * PME and one of its upstream bridges can generate wake-up events.
1475 */
1476bool pci_dev_run_wake(struct pci_dev *dev)
1477{
1478 struct pci_bus *bus = dev->bus;
1479
1480 if (device_run_wake(&dev->dev))
1481 return true;
1482
1483 if (!dev->pme_support)
1484 return false;
1485
1486 while (bus->parent) {
1487 struct pci_dev *bridge = bus->self;
1488
1489 if (device_run_wake(&bridge->dev))
1490 return true;
1491
1492 bus = bus->parent;
1493 }
1494
1495 /* We have reached the root bus. */
1496 if (bus->bridge)
1497 return device_run_wake(bus->bridge);
1498
1499 return false;
1500}
1501EXPORT_SYMBOL_GPL(pci_dev_run_wake);
1502
1503/**
1437 * pci_pm_init - Initialize PM functions of given PCI device 1504 * pci_pm_init - Initialize PM functions of given PCI device
1438 * @dev: PCI device to handle. 1505 * @dev: PCI device to handle.
1439 */ 1506 */