PCI: add pci_swizzle_interrupt_pin()
[firefly-linux-kernel-4.4.55.git] / drivers / pci / pci-driver.c
index 4042d211c3e548b7b4796661ceb0842cf6949ef5..888191a3b0d164875d35ffaa6739dc9d4a7524a7 100644 (file)
@@ -48,7 +48,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
                subdevice=PCI_ANY_ID, class=0, class_mask=0;
        unsigned long driver_data=0;
        int fields=0;
-       int retval;
+       int retval=0;
 
        fields = sscanf(buf, "%x %x %x %x %x %x %lx",
                        &vendor, &device, &subvendor, &subdevice,
@@ -58,16 +58,18 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
 
        /* Only accept driver_data values that match an existing id_table
           entry */
-       retval = -EINVAL;
-       while (ids->vendor || ids->subvendor || ids->class_mask) {
-               if (driver_data == ids->driver_data) {
-                       retval = 0;
-                       break;
+       if (ids) {
+               retval = -EINVAL;
+               while (ids->vendor || ids->subvendor || ids->class_mask) {
+                       if (driver_data == ids->driver_data) {
+                               retval = 0;
+                               break;
+                       }
+                       ids++;
                }
-               ids++;
+               if (retval)     /* No match */
+                       return retval;
        }
-       if (retval)     /* No match */
-               return retval;
 
        dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
        if (!dynid)
@@ -300,6 +302,14 @@ static void pci_device_shutdown(struct device *dev)
 
 #ifdef CONFIG_PM_SLEEP
 
+static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
+{
+       struct pci_driver *drv = pci_dev->driver;
+
+       return drv && (drv->suspend || drv->suspend_late || drv->resume
+               || drv->resume_early);
+}
+
 /*
  * Default "suspend" method for devices that have no driver provided suspend,
  * or not even a driver at all.
@@ -317,14 +327,22 @@ static void pci_default_pm_suspend(struct pci_dev *pci_dev)
 
 /*
  * Default "resume" method for devices that have no driver provided resume,
- * or not even a driver at all.
+ * or not even a driver at all (first part).
  */
-static int pci_default_pm_resume(struct pci_dev *pci_dev)
+static void pci_default_pm_resume_early(struct pci_dev *pci_dev)
 {
-       int retval = 0;
-
        /* restore the PCI config space */
        pci_restore_state(pci_dev);
+}
+
+/*
+ * Default "resume" method for devices that have no driver provided resume,
+ * or not even a driver at all (second part).
+ */
+static int pci_default_pm_resume_late(struct pci_dev *pci_dev)
+{
+       int retval;
+
        /* if the device was enabled before suspend, reenable */
        retval = pci_reenable_device(pci_dev);
        /*
@@ -371,10 +389,12 @@ static int pci_legacy_resume(struct device *dev)
        struct pci_dev * pci_dev = to_pci_dev(dev);
        struct pci_driver * drv = pci_dev->driver;
 
-       if (drv && drv->resume)
+       if (drv && drv->resume) {
                error = drv->resume(pci_dev);
-       else
-               error = pci_default_pm_resume(pci_dev);
+       } else {
+               pci_default_pm_resume_early(pci_dev);
+               error = pci_default_pm_resume_late(pci_dev);
+       }
        return error;
 }
 
@@ -420,10 +440,8 @@ static int pci_pm_suspend(struct device *dev)
                if (drv->pm->suspend) {
                        error = drv->pm->suspend(dev);
                        suspend_report_result(drv->pm->suspend, error);
-               } else {
-                       pci_default_pm_suspend(pci_dev);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_suspend(dev, PMSG_SUSPEND);
        }
        pci_fixup_device(pci_fixup_suspend, pci_dev);
@@ -433,6 +451,7 @@ static int pci_pm_suspend(struct device *dev)
 
 static int pci_pm_suspend_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
@@ -441,8 +460,10 @@ static int pci_pm_suspend_noirq(struct device *dev)
                        error = drv->pm->suspend_noirq(dev);
                        suspend_report_result(drv->pm->suspend_noirq, error);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_suspend_late(dev, PMSG_SUSPEND);
+       } else {
+               pci_default_pm_suspend(pci_dev);
        }
 
        return error;
@@ -452,15 +473,17 @@ static int pci_pm_resume(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error;
+       int error = 0;
 
        pci_fixup_device(pci_fixup_resume, pci_dev);
 
        if (drv && drv->pm) {
-               error = drv->pm->resume ? drv->pm->resume(dev) :
-                       pci_default_pm_resume(pci_dev);
-       } else {
+               if (drv->pm->resume)
+                       error = drv->pm->resume(dev);
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_resume(dev);
+       } else {
+               error = pci_default_pm_resume_late(pci_dev);
        }
 
        return error;
@@ -468,6 +491,7 @@ static int pci_pm_resume(struct device *dev)
 
 static int pci_pm_resume_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
@@ -476,8 +500,10 @@ static int pci_pm_resume_noirq(struct device *dev)
        if (drv && drv->pm) {
                if (drv->pm->resume_noirq)
                        error = drv->pm->resume_noirq(dev);
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_resume_early(dev);
+       } else {
+               pci_default_pm_resume_early(pci_dev);
        }
 
        return error;
@@ -504,10 +530,8 @@ static int pci_pm_freeze(struct device *dev)
                if (drv->pm->freeze) {
                        error = drv->pm->freeze(dev);
                        suspend_report_result(drv->pm->freeze, error);
-               } else {
-                       pci_default_pm_suspend(pci_dev);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_suspend(dev, PMSG_FREEZE);
                pci_fixup_device(pci_fixup_suspend, pci_dev);
        }
@@ -517,6 +541,7 @@ static int pci_pm_freeze(struct device *dev)
 
 static int pci_pm_freeze_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
@@ -525,8 +550,10 @@ static int pci_pm_freeze_noirq(struct device *dev)
                        error = drv->pm->freeze_noirq(dev);
                        suspend_report_result(drv->pm->freeze_noirq, error);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_suspend_late(dev, PMSG_FREEZE);
+       } else {
+               pci_default_pm_suspend(pci_dev);
        }
 
        return error;
@@ -534,14 +561,15 @@ static int pci_pm_freeze_noirq(struct device *dev)
 
 static int pci_pm_thaw(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
        if (drv && drv->pm) {
                if (drv->pm->thaw)
                        error =  drv->pm->thaw(dev);
-       } else {
-               pci_fixup_device(pci_fixup_resume, to_pci_dev(dev));
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
+               pci_fixup_device(pci_fixup_resume, pci_dev);
                error = pci_legacy_resume(dev);
        }
 
@@ -550,13 +578,14 @@ static int pci_pm_thaw(struct device *dev)
 
 static int pci_pm_thaw_noirq(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
        if (drv && drv->pm) {
                if (drv->pm->thaw_noirq)
                        error = drv->pm->thaw_noirq(dev);
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev));
                error = pci_legacy_resume_early(dev);
        }
@@ -566,17 +595,18 @@ static int pci_pm_thaw_noirq(struct device *dev)
 
 static int pci_pm_poweroff(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
        int error = 0;
 
-       pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev));
+       pci_fixup_device(pci_fixup_suspend, pci_dev);
 
        if (drv && drv->pm) {
                if (drv->pm->poweroff) {
                        error = drv->pm->poweroff(dev);
                        suspend_report_result(drv->pm->poweroff, error);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_suspend(dev, PMSG_HIBERNATE);
        }
 
@@ -593,7 +623,7 @@ static int pci_pm_poweroff_noirq(struct device *dev)
                        error = drv->pm->poweroff_noirq(dev);
                        suspend_report_result(drv->pm->poweroff_noirq, error);
                }
-       } else {
+       } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) {
                error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
        }
 
@@ -604,13 +634,15 @@ static int pci_pm_restore(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct device_driver *drv = dev->driver;
-       int error;
+       int error = 0;
 
        if (drv && drv->pm) {
-               error = drv->pm->restore ? drv->pm->restore(dev) :
-                       pci_default_pm_resume(pci_dev);
-       } else {
+               if (drv->pm->restore)
+                       error = drv->pm->restore(dev);
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_resume(dev);
+       } else {
+               error = pci_default_pm_resume_late(pci_dev);
        }
        pci_fixup_device(pci_fixup_resume, pci_dev);
 
@@ -628,8 +660,10 @@ static int pci_pm_restore_noirq(struct device *dev)
        if (drv && drv->pm) {
                if (drv->pm->restore_noirq)
                        error = drv->pm->restore_noirq(dev);
-       } else {
+       } else if (pci_has_legacy_pm_support(pci_dev)) {
                error = pci_legacy_resume_early(dev);
+       } else {
+               pci_default_pm_resume_early(pci_dev);
        }
        pci_fixup_device(pci_fixup_resume_early, pci_dev);