diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-12-04 18:13:03 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-12-04 18:13:03 -0500 |
commit | edb1daab8e91338b7e2a6c41faec695891ccda35 (patch) | |
tree | 2f5ce32e53fee349e7f0ffb384a5d952a0a94f2f | |
parent | be5cd530bd23ef3e00dcb4998e151de9fdd1a104 (diff) | |
parent | 967577b062417b4e4b8e27b711220f4124f5153a (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.c | 67 | ||||
-rw-r--r-- | drivers/pci/pci.c | 2 |
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 { | |||
256 | static long local_pci_probe(void *_ddi) | 256 | static 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 | ||
1047 | static int pci_pm_runtime_idle(struct device *dev) | 1052 | static 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 | ||
1073 | out: | ||
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 | ||