Merge git://git.infradead.org/mtd-2.6
[firefly-linux-kernel-4.4.55.git] / drivers / pci / pci-driver.c
index f9a0aec3abcf68c1594ee99d082dcab4a6560ff8..8a6f797de8e55af1b3d0380aefb2173b58ab9fa5 100644 (file)
@@ -289,8 +289,26 @@ struct drv_dev_and_id {
 static long local_pci_probe(void *_ddi)
 {
        struct drv_dev_and_id *ddi = _ddi;
-
-       return ddi->drv->probe(ddi->dev, ddi->id);
+       struct device *dev = &ddi->dev->dev;
+       int rc;
+
+       /* Unbound PCI devices are always set to disabled and suspended.
+        * During probe, the device is set to enabled and active and the
+        * usage count is incremented.  If the driver supports runtime PM,
+        * it should call pm_runtime_put_noidle() in its probe routine and
+        * pm_runtime_get_noresume() in its remove routine.
+        */
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       rc = ddi->drv->probe(ddi->dev, ddi->id);
+       if (rc) {
+               pm_runtime_disable(dev);
+               pm_runtime_set_suspended(dev);
+               pm_runtime_put_noidle(dev);
+       }
+       return rc;
 }
 
 static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
@@ -369,11 +387,19 @@ static int pci_device_remove(struct device * dev)
        struct pci_driver * drv = pci_dev->driver;
 
        if (drv) {
-               if (drv->remove)
+               if (drv->remove) {
+                       pm_runtime_get_sync(dev);
                        drv->remove(pci_dev);
+                       pm_runtime_put_noidle(dev);
+               }
                pci_dev->driver = NULL;
        }
 
+       /* Undo the runtime PM settings in local_pci_probe() */
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_noidle(dev);
+
        /*
         * If the device is still on, set the power state as "unknown",
         * since it might change by the next time we load the driver.