aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2012-11-20 03:08:22 -0500
committerBjorn Helgaas <bhelgaas@google.com>2012-12-04 18:04:09 -0500
commit967577b062417b4e4b8e27b711220f4124f5153a (patch)
tree8dd7f2bc3754eaa932588cd5a0e0798fe910849e
parentb3c32c4f9565f93407921c0d8a4458042eb8998e (diff)
PCI/PM: Keep runtime PM enabled for unbound PCI devices
For unbound PCI devices, what we need is: - Always in D0 state, because some devices do not work again after being put into D3 by the PCI bus. - In SUSPENDED state if allowed, so that the parent devices can still be put into low power state. To satisfy these requirements, the runtime PM for the unbound PCI devices are disabled and set to SUSPENDED state. One issue of this solution is that the PCI devices will be put into SUSPENDED state even if the SUSPENDED state is forbidden via the sysfs interface (.../power/control) of the device. This is not an issue for most devices, because most PCI devices are not used at all if unbound. But there are exceptions. For example, unbound VGA card can be used for display, but suspending its parents makes it stop working. To fix the issue, we keep the runtime PM enabled when the PCI devices are unbound. But the runtime PM callbacks will do nothing if the PCI devices are unbound. This way, we can put the PCI devices into SUSPENDED state without putting the PCI devices into D3 state. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=48201 Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> CC: stable@vger.kernel.org # v3.6+
-rw-r--r--drivers/pci/pci-driver.c67
-rw-r--r--drivers/pci/pci.c2
2 files changed, 42 insertions, 27 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 6c94fc9489e7..6c66c5b8e152 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -256,31 +256,26 @@ struct drv_dev_and_id {
256static long local_pci_probe(void *_ddi) 256static long local_pci_probe(void *_ddi)
257{ 257{
258 struct drv_dev_and_id *ddi = _ddi; 258 struct drv_dev_and_id *ddi = _ddi;
259 struct device *dev = &ddi->dev->dev; 259 struct pci_dev *pci_dev = ddi->dev;
260 struct device *parent = dev->parent; 260 struct pci_driver *pci_drv = ddi->drv;
261 struct device *dev = &pci_dev->dev;
261 int rc; 262 int rc;
262 263
263 /* The parent bridge must be in active state when probing */ 264 /*
264 if (parent) 265 * Unbound PCI devices are always put in D0, regardless of
265 pm_runtime_get_sync(parent); 266 * runtime PM status. During probe, the device is set to
266 /* Unbound PCI devices are always set to disabled and suspended. 267 * active and the usage count is incremented. If the driver
267 * During probe, the device is set to enabled and active and the 268 * supports runtime PM, it should call pm_runtime_put_noidle()
268 * usage count is incremented. If the driver supports runtime PM, 269 * in its probe routine and pm_runtime_get_noresume() in its
269 * it should call pm_runtime_put_noidle() in its probe routine and 270 * remove routine.
270 * pm_runtime_get_noresume() in its remove routine.
271 */ 271 */
272 pm_runtime_get_noresume(dev); 272 pm_runtime_get_sync(dev);
273 pm_runtime_set_active(dev); 273 pci_dev->driver = pci_drv;
274 pm_runtime_enable(dev); 274 rc = pci_drv->probe(pci_dev, ddi->id);
275
276 rc = ddi->drv->probe(ddi->dev, ddi->id);
277 if (rc) { 275 if (rc) {
278 pm_runtime_disable(dev); 276 pci_dev->driver = NULL;
279 pm_runtime_set_suspended(dev); 277 pm_runtime_put_sync(dev);
280 pm_runtime_put_noidle(dev);
281 } 278 }
282 if (parent)
283 pm_runtime_put(parent);
284 return rc; 279 return rc;
285} 280}
286 281
@@ -330,10 +325,8 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
330 id = pci_match_device(drv, pci_dev); 325 id = pci_match_device(drv, pci_dev);
331 if (id) 326 if (id)
332 error = pci_call_probe(drv, pci_dev, id); 327 error = pci_call_probe(drv, pci_dev, id);
333 if (error >= 0) { 328 if (error >= 0)
334 pci_dev->driver = drv;
335 error = 0; 329 error = 0;
336 }
337 } 330 }
338 return error; 331 return error;
339} 332}
@@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev)
369 } 362 }
370 363
371 /* Undo the runtime PM settings in local_pci_probe() */ 364 /* Undo the runtime PM settings in local_pci_probe() */
372 pm_runtime_disable(dev); 365 pm_runtime_put_sync(dev);
373 pm_runtime_set_suspended(dev);
374 pm_runtime_put_noidle(dev);
375 366
376 /* 367 /*
377 * If the device is still on, set the power state as "unknown", 368 * If the device is still on, set the power state as "unknown",
@@ -994,6 +985,13 @@ static int pci_pm_runtime_suspend(struct device *dev)
994 pci_power_t prev = pci_dev->current_state; 985 pci_power_t prev = pci_dev->current_state;
995 int error; 986 int error;
996 987
988 /*
989 * If pci_dev->driver is not set (unbound), the device should
990 * always remain in D0 regardless of the runtime PM status
991 */
992 if (!pci_dev->driver)
993 return 0;
994
997 if (!pm || !pm->runtime_suspend) 995 if (!pm || !pm->runtime_suspend)
998 return -ENOSYS; 996 return -ENOSYS;
999 997
@@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev)
1029 struct pci_dev *pci_dev = to_pci_dev(dev); 1027 struct pci_dev *pci_dev = to_pci_dev(dev);
1030 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 1028 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
1031 1029
1030 /*
1031 * If pci_dev->driver is not set (unbound), the device should
1032 * always remain in D0 regardless of the runtime PM status
1033 */
1034 if (!pci_dev->driver)
1035 return 0;
1036
1032 if (!pm || !pm->runtime_resume) 1037 if (!pm || !pm->runtime_resume)
1033 return -ENOSYS; 1038 return -ENOSYS;
1034 1039
@@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev)
1046 1051
1047static int pci_pm_runtime_idle(struct device *dev) 1052static int pci_pm_runtime_idle(struct device *dev)
1048{ 1053{
1054 struct pci_dev *pci_dev = to_pci_dev(dev);
1049 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 1055 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
1050 1056
1057 /*
1058 * If pci_dev->driver is not set (unbound), the device should
1059 * always remain in D0 regardless of the runtime PM status
1060 */
1061 if (!pci_dev->driver)
1062 goto out;
1063
1051 if (!pm) 1064 if (!pm)
1052 return -ENOSYS; 1065 return -ENOSYS;
1053 1066
@@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev)
1057 return ret; 1070 return ret;
1058 } 1071 }
1059 1072
1073out:
1060 pm_runtime_suspend(dev); 1074 pm_runtime_suspend(dev);
1061
1062 return 0; 1075 return 0;
1063} 1076}
1064 1077
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index aabf64798bda..8e06adb9898f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1900,6 +1900,8 @@ void pci_pm_init(struct pci_dev *dev)
1900 u16 pmc; 1900 u16 pmc;
1901 1901
1902 pm_runtime_forbid(&dev->dev); 1902 pm_runtime_forbid(&dev->dev);
1903 pm_runtime_set_active(&dev->dev);
1904 pm_runtime_enable(&dev->dev);
1903 device_enable_async_suspend(&dev->dev); 1905 device_enable_async_suspend(&dev->dev);
1904 dev->wakeup_prepared = false; 1906 dev->wakeup_prepared = false;
1905 1907