aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZheng Yan <zheng.z.yan@intel.com>2012-06-22 22:23:49 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-23 12:47:47 -0400
commit71a83bd727cc31c5fe960c3758cb396267ff710e (patch)
treec4655a683b386c98d7c85bddd019e67711310c71
parentee85f543710dd56ce526cb44e39191f32972e5ad (diff)
PCI/PM: add runtime PM support to PCIe port
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>
-rw-r--r--drivers/pci/pci.c10
-rw-r--r--drivers/pci/pcie/portdrv_pci.c24
2 files changed, 34 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 447e83472c01..9eae64b17954 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1518,6 +1518,16 @@ static void pci_pme_list_scan(struct work_struct *work)
1518 if (!list_empty(&pci_pme_list)) { 1518 if (!list_empty(&pci_pme_list)) {
1519 list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { 1519 list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
1520 if (pme_dev->dev->pme_poll) { 1520 if (pme_dev->dev->pme_poll) {
1521 struct pci_dev *bridge;
1522
1523 bridge = pme_dev->dev->bus->self;
1524 /*
1525 * If bridge is in low power state, the
1526 * configuration space of subordinate devices
1527 * may be not accessible
1528 */
1529 if (bridge && bridge->current_state != PCI_D0)
1530 continue;
1521 pci_pme_wakeup(pme_dev->dev, NULL); 1531 pci_pme_wakeup(pme_dev->dev, NULL);
1522 } else { 1532 } else {
1523 list_del(&pme_dev->list); 1533 list_del(&pme_dev->list);
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index e0610bda1dea..7c576b9aa01d 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -11,6 +11,7 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/pm.h> 13#include <linux/pm.h>
14#include <linux/pm_runtime.h>
14#include <linux/init.h> 15#include <linux/init.h>
15#include <linux/pcieport_if.h> 16#include <linux/pcieport_if.h>
16#include <linux/aer.h> 17#include <linux/aer.h>
@@ -99,6 +100,15 @@ static int pcie_port_resume_noirq(struct device *dev)
99 return 0; 100 return 0;
100} 101}
101 102
103#ifdef CONFIG_PM_RUNTIME
104static int pcie_port_runtime_pm(struct device *dev)
105{
106 return 0;
107}
108#else
109#define pcie_port_runtime_pm NULL
110#endif
111
102static const struct dev_pm_ops pcie_portdrv_pm_ops = { 112static const struct dev_pm_ops pcie_portdrv_pm_ops = {
103 .suspend = pcie_port_device_suspend, 113 .suspend = pcie_port_device_suspend,
104 .resume = pcie_port_device_resume, 114 .resume = pcie_port_device_resume,
@@ -107,6 +117,8 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
107 .poweroff = pcie_port_device_suspend, 117 .poweroff = pcie_port_device_suspend,
108 .restore = pcie_port_device_resume, 118 .restore = pcie_port_device_resume,
109 .resume_noirq = pcie_port_resume_noirq, 119 .resume_noirq = pcie_port_resume_noirq,
120 .runtime_suspend = pcie_port_runtime_pm,
121 .runtime_resume = pcie_port_runtime_pm,
110}; 122};
111 123
112#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) 124#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
@@ -117,6 +129,14 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
117#endif /* !PM */ 129#endif /* !PM */
118 130
119/* 131/*
132 * PCIe port runtime suspend is broken for some chipsets, so use a
133 * black list to disable runtime PM for these chipsets.
134 */
135static const struct pci_device_id port_runtime_pm_black_list[] = {
136 { /* end: all zeroes */ }
137};
138
139/*
120 * pcie_portdrv_probe - Probe PCI-Express port devices 140 * pcie_portdrv_probe - Probe PCI-Express port devices
121 * @dev: PCI-Express port device being probed 141 * @dev: PCI-Express port device being probed
122 * 142 *
@@ -144,12 +164,16 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev,
144 return status; 164 return status;
145 165
146 pci_save_state(dev); 166 pci_save_state(dev);
167 if (!pci_match_id(port_runtime_pm_black_list, dev))
168 pm_runtime_put_noidle(&dev->dev);
147 169
148 return 0; 170 return 0;
149} 171}
150 172
151static void pcie_portdrv_remove(struct pci_dev *dev) 173static void pcie_portdrv_remove(struct pci_dev *dev)
152{ 174{
175 if (!pci_match_id(port_runtime_pm_black_list, dev))
176 pm_runtime_get_noresume(&dev->dev);
153 pcie_port_device_remove(dev); 177 pcie_port_device_remove(dev);
154 pci_disable_device(dev); 178 pci_disable_device(dev);
155} 179}