]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - drivers/pci/pci-driver.c
Merge tag 'for-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
[can-eth-gw-linux.git] / drivers / pci / pci-driver.c
index 1dc78c5cabf8f52175159ef6191a479828497e08..f79cbcd3944bf5e61e76a96022331a665e63f93e 100644 (file)
@@ -248,31 +248,26 @@ struct drv_dev_and_id {
 static long local_pci_probe(void *_ddi)
 {
        struct drv_dev_and_id *ddi = _ddi;
-       struct device *dev = &ddi->dev->dev;
-       struct device *parent = dev->parent;
+       struct pci_dev *pci_dev = ddi->dev;
+       struct pci_driver *pci_drv = ddi->drv;
+       struct device *dev = &pci_dev->dev;
        int rc;
 
-       /* The parent bridge must be in active state when probing */
-       if (parent)
-               pm_runtime_get_sync(parent);
-       /* 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.
+       /*
+        * Unbound PCI devices are always put in D0, regardless of
+        * runtime PM status.  During probe, the device is set to
+        * 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);
+       pm_runtime_get_sync(dev);
+       pci_dev->driver = pci_drv;
+       rc = pci_drv->probe(pci_dev, ddi->id);
        if (rc) {
-               pm_runtime_disable(dev);
-               pm_runtime_set_suspended(dev);
-               pm_runtime_put_noidle(dev);
+               pci_dev->driver = NULL;
+               pm_runtime_put_sync(dev);
        }
-       if (parent)
-               pm_runtime_put(parent);
        return rc;
 }
 
@@ -322,10 +317,8 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
                id = pci_match_device(drv, pci_dev);
                if (id)
                        error = pci_call_probe(drv, pci_dev, id);
-               if (error >= 0) {
-                       pci_dev->driver = drv;
+               if (error >= 0)
                        error = 0;
-               }
        }
        return error;
 }
@@ -361,9 +354,7 @@ static int pci_device_remove(struct device * dev)
        }
 
        /* Undo the runtime PM settings in local_pci_probe() */
-       pm_runtime_disable(dev);
-       pm_runtime_set_suspended(dev);
-       pm_runtime_put_noidle(dev);
+       pm_runtime_put_sync(dev);
 
        /*
         * If the device is still on, set the power state as "unknown",
@@ -986,6 +977,13 @@ static int pci_pm_runtime_suspend(struct device *dev)
        pci_power_t prev = pci_dev->current_state;
        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)
                return -ENOSYS;
 
@@ -1007,10 +1005,10 @@ static int pci_pm_runtime_suspend(struct device *dev)
                return 0;
        }
 
-       if (!pci_dev->state_saved)
+       if (!pci_dev->state_saved) {
                pci_save_state(pci_dev);
-
-       pci_finish_runtime_suspend(pci_dev);
+               pci_finish_runtime_suspend(pci_dev);
+       }
 
        return 0;
 }
@@ -1021,6 +1019,13 @@ static int pci_pm_runtime_resume(struct device *dev)
        struct pci_dev *pci_dev = to_pci_dev(dev);
        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)
                return -ENOSYS;
 
@@ -1038,8 +1043,16 @@ static int pci_pm_runtime_resume(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;
 
+       /*
+        * 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)
                return -ENOSYS;
 
@@ -1049,8 +1062,8 @@ static int pci_pm_runtime_idle(struct device *dev)
                        return ret;
        }
 
+out:
        pm_runtime_suspend(dev);
-
        return 0;
 }