]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: Add pci_reset_function_locked()
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 2 Aug 2017 01:11:02 +0000 (20:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Aug 2017 20:47:00 +0000 (13:47 -0700)
commit a477b9cd37aa81a490dfa3265b7ff4f2c5a92463 upstream.

The implementation of PCI workarounds may require that the device is reset
from its probe function.  This implies that the PCI device lock is already
held, and makes calling pci_reset_function() impossible (since it will
itself try to take that lock).

Add pci_reset_function_locked(), which is the equivalent of
pci_reset_function(), except that it requires the PCI device lock to be
already held by the caller.

Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
[bhelgaas: folded in fix for conflict with 52354b9d1f46 ("PCI: Remove
__pci_dev_reset() and pci_dev_reset()")]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/pci.c
include/linux/pci.h

index f4d39aac74d21104179f04e3a2d608136f663742..9e5483780c978d10689fec0a500aac362457df24 100644 (file)
@@ -4290,6 +4290,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
index 8039f9f0ca054ba20fd9992b13b7926859d029b5..16be18678ca1325be76a1edcb668b79c39ca6609 100644 (file)
@@ -1049,6 +1049,7 @@ void pcie_flr(struct pci_dev *dev);
 int __pci_reset_function(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
+int pci_reset_function_locked(struct pci_dev *dev);
 int pci_try_reset_function(struct pci_dev *dev);
 int pci_probe_reset_slot(struct pci_slot *slot);
 int pci_reset_slot(struct pci_slot *slot);