aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-12-04 18:13:03 -0500
committerBjorn Helgaas <bhelgaas@google.com>2012-12-04 18:13:03 -0500
commitedb1daab8e91338b7e2a6c41faec695891ccda35 (patch)
tree2f5ce32e53fee349e7f0ffb384a5d952a0a94f2f
parentbe5cd530bd23ef3e00dcb4998e151de9fdd1a104 (diff)
parent967577b062417b4e4b8e27b711220f4124f5153a (diff)
Merge branch 'pci/huang-d3cold-fixes' into next
* pci/huang-d3cold-fixes: PCI/PM: Keep runtime PM enabled for unbound PCI devices
-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 24aa44c6ed02..c3088e54fc43 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 adffc6f621e5..5b862b1c93c6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1910,6 +1910,8 @@ void pci_pm_init(struct pci_dev *dev)
1910 u16 pmc; 1910 u16 pmc;
1911 1911
1912 pm_runtime_forbid(&dev->dev); 1912 pm_runtime_forbid(&dev->dev);
1913 pm_runtime_set_active(&dev->dev);
1914 pm_runtime_enable(&dev->dev);
1913 device_enable_async_suspend(&dev->dev); 1915 device_enable_async_suspend(&dev->dev);
1914 dev->wakeup_prepared = false; 1916 dev->wakeup_prepared = false;
1915 1917