Commit edb1daab authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/huang-d3cold-fixes' into next

* pci/huang-d3cold-fixes:
  PCI/PM: Keep runtime PM enabled for unbound PCI devices
parents be5cd530 967577b0
...@@ -256,31 +256,26 @@ struct drv_dev_and_id { ...@@ -256,31 +256,26 @@ struct drv_dev_and_id {
static long local_pci_probe(void *_ddi) static long local_pci_probe(void *_ddi)
{ {
struct drv_dev_and_id *ddi = _ddi; struct drv_dev_and_id *ddi = _ddi;
struct device *dev = &ddi->dev->dev; struct pci_dev *pci_dev = ddi->dev;
struct device *parent = dev->parent; struct pci_driver *pci_drv = ddi->drv;
struct device *dev = &pci_dev->dev;
int rc; int rc;
/* The parent bridge must be in active state when probing */ /*
if (parent) * Unbound PCI devices are always put in D0, regardless of
pm_runtime_get_sync(parent); * runtime PM status. During probe, the device is set to
/* Unbound PCI devices are always set to disabled and suspended. * active and the usage count is incremented. If the driver
* During probe, the device is set to enabled and active and the * supports runtime PM, it should call pm_runtime_put_noidle()
* usage count is incremented. If the driver supports runtime PM, * in its probe routine and pm_runtime_get_noresume() in its
* it should call pm_runtime_put_noidle() in its probe routine and * remove routine.
* pm_runtime_get_noresume() in its remove routine.
*/ */
pm_runtime_get_noresume(dev); pm_runtime_get_sync(dev);
pm_runtime_set_active(dev); pci_dev->driver = pci_drv;
pm_runtime_enable(dev); rc = pci_drv->probe(pci_dev, ddi->id);
rc = ddi->drv->probe(ddi->dev, ddi->id);
if (rc) { if (rc) {
pm_runtime_disable(dev); pci_dev->driver = NULL;
pm_runtime_set_suspended(dev); pm_runtime_put_sync(dev);
pm_runtime_put_noidle(dev);
} }
if (parent)
pm_runtime_put(parent);
return rc; return rc;
} }
...@@ -330,10 +325,8 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) ...@@ -330,10 +325,8 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
id = pci_match_device(drv, pci_dev); id = pci_match_device(drv, pci_dev);
if (id) if (id)
error = pci_call_probe(drv, pci_dev, id); error = pci_call_probe(drv, pci_dev, id);
if (error >= 0) { if (error >= 0)
pci_dev->driver = drv;
error = 0; error = 0;
}
} }
return error; return error;
} }
...@@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev) ...@@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev)
} }
/* Undo the runtime PM settings in local_pci_probe() */ /* Undo the runtime PM settings in local_pci_probe() */
pm_runtime_disable(dev); pm_runtime_put_sync(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
/* /*
* If the device is still on, set the power state as "unknown", * 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,6 +985,13 @@ static int pci_pm_runtime_suspend(struct device *dev)
pci_power_t prev = pci_dev->current_state; pci_power_t prev = pci_dev->current_state;
int error; int error;
/*
* If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status
*/
if (!pci_dev->driver)
return 0;
if (!pm || !pm->runtime_suspend) if (!pm || !pm->runtime_suspend)
return -ENOSYS; return -ENOSYS;
...@@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev) ...@@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
/*
* If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status
*/
if (!pci_dev->driver)
return 0;
if (!pm || !pm->runtime_resume) if (!pm || !pm->runtime_resume)
return -ENOSYS; return -ENOSYS;
...@@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev) ...@@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev)
static int pci_pm_runtime_idle(struct device *dev) static int pci_pm_runtime_idle(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev);
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
/*
* If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status
*/
if (!pci_dev->driver)
goto out;
if (!pm) if (!pm)
return -ENOSYS; return -ENOSYS;
...@@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev) ...@@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev)
return ret; return ret;
} }
out:
pm_runtime_suspend(dev); pm_runtime_suspend(dev);
return 0; return 0;
} }
......
...@@ -1910,6 +1910,8 @@ void pci_pm_init(struct pci_dev *dev) ...@@ -1910,6 +1910,8 @@ void pci_pm_init(struct pci_dev *dev)
u16 pmc; u16 pmc;
pm_runtime_forbid(&dev->dev); pm_runtime_forbid(&dev->dev);
pm_runtime_set_active(&dev->dev);
pm_runtime_enable(&dev->dev);
device_enable_async_suspend(&dev->dev); device_enable_async_suspend(&dev->dev);
dev->wakeup_prepared = false; dev->wakeup_prepared = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment