Skip to content

Commit

Permalink
PCI/PM: add runtime PM support to PCIe port
Browse files Browse the repository at this point in the history
This patch adds runtime PM support to PCIe port.  This is needed by
PCIe D3cold support, where PCIe device without ACPI node may be
powered on/off by PCIe port.

Because runtime suspend is broken for some chipsets, a black list is
used to disable runtime PM support for these chipsets.

Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  • Loading branch information
Zheng Yan authored and Bjorn Helgaas committed Jun 23, 2012
1 parent ee85f54 commit 71a83bd
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,16 @@ static void pci_pme_list_scan(struct work_struct *work)
if (!list_empty(&pci_pme_list)) {
list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
if (pme_dev->dev->pme_poll) {
struct pci_dev *bridge;

bridge = pme_dev->dev->bus->self;
/*
* If bridge is in low power state, the
* configuration space of subordinate devices
* may be not accessible
*/
if (bridge && bridge->current_state != PCI_D0)
continue;
pci_pme_wakeup(pme_dev->dev, NULL);
} else {
list_del(&pme_dev->list);
Expand Down
24 changes: 24 additions & 0 deletions drivers/pci/pcie/portdrv_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/init.h>
#include <linux/pcieport_if.h>
#include <linux/aer.h>
Expand Down Expand Up @@ -99,6 +100,15 @@ static int pcie_port_resume_noirq(struct device *dev)
return 0;
}

#ifdef CONFIG_PM_RUNTIME
static int pcie_port_runtime_pm(struct device *dev)
{
return 0;
}
#else
#define pcie_port_runtime_pm NULL
#endif

static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.suspend = pcie_port_device_suspend,
.resume = pcie_port_device_resume,
Expand All @@ -107,6 +117,8 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.poweroff = pcie_port_device_suspend,
.restore = pcie_port_device_resume,
.resume_noirq = pcie_port_resume_noirq,
.runtime_suspend = pcie_port_runtime_pm,
.runtime_resume = pcie_port_runtime_pm,
};

#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
Expand All @@ -116,6 +128,14 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
#define PCIE_PORTDRV_PM_OPS NULL
#endif /* !PM */

/*
* PCIe port runtime suspend is broken for some chipsets, so use a
* black list to disable runtime PM for these chipsets.
*/
static const struct pci_device_id port_runtime_pm_black_list[] = {
{ /* end: all zeroes */ }
};

/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
Expand Down Expand Up @@ -144,12 +164,16 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev,
return status;

pci_save_state(dev);
if (!pci_match_id(port_runtime_pm_black_list, dev))
pm_runtime_put_noidle(&dev->dev);

return 0;
}

static void pcie_portdrv_remove(struct pci_dev *dev)
{
if (!pci_match_id(port_runtime_pm_black_list, dev))
pm_runtime_get_noresume(&dev->dev);
pcie_port_device_remove(dev);
pci_disable_device(dev);
}
Expand Down

0 comments on commit 71a83bd

Please sign in to comment.