]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/pci.c
Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / drivers / pci / pci.c
index d88edf5c563b6f07a709c917204b0a77f54ab1f3..b4b7eab2940024024c46ead23d6b1c415fa146f7 100644 (file)
@@ -1801,7 +1801,11 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
        pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 }
 
-static void pci_pme_restore(struct pci_dev *dev)
+/**
+ * pci_pme_restore - Restore PME configuration after config space restore.
+ * @dev: PCI device to update.
+ */
+void pci_pme_restore(struct pci_dev *dev)
 {
        u16 pmcsr;
 
@@ -1811,6 +1815,7 @@ static void pci_pme_restore(struct pci_dev *dev)
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
        if (dev->wakeup_prepared) {
                pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+               pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
        } else {
                pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
                pmcsr |= PCI_PM_CTRL_PME_STATUS;
@@ -1907,14 +1912,9 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
 {
        int ret = 0;
 
-       /*
-        * Don't do the same thing twice in a row for one device, but restore
-        * PME Enable in case it has been updated by config space restoration.
-        */
-       if (!!enable == !!dev->wakeup_prepared) {
-               pci_pme_restore(dev);
+       /* Don't do the same thing twice in a row for one device. */
+       if (!!enable == !!dev->wakeup_prepared)
                return 0;
-       }
 
        /*
         * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
@@ -4259,6 +4259,41 @@ int pci_reset_function(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_reset_function);
 
+/**
+ * pci_reset_function_locked - quiesce and reset a PCI device function
+ * @dev: PCI device to reset
+ *
+ * Some devices allow an individual function to be reset without affecting
+ * other functions in the same device.  The PCI device must be responsive
+ * to PCI config space in order to use this function.
+ *
+ * This function does not just reset the PCI portion of a device, but
+ * clears all the state associated with the device.  This function differs
+ * from __pci_reset_function() in that it saves and restores device state
+ * over the reset.  It also differs from pci_reset_function() in that it
+ * requires the PCI device lock to be held.
+ *
+ * Returns 0 if the device function was successfully reset or negative if the
+ * device doesn't support resetting a single function.
+ */
+int pci_reset_function_locked(struct pci_dev *dev)
+{
+       int rc;
+
+       rc = pci_probe_reset_function(dev);
+       if (rc)
+               return rc;
+
+       pci_dev_save_and_disable(dev);
+
+       rc = __pci_reset_function_locked(dev);
+
+       pci_dev_restore(dev);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(pci_reset_function_locked);
+
 /**
  * pci_try_reset_function - quiesce and reset a PCI device function
  * @dev: PCI device to reset