Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a60a2b73 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Bjorn Helgaas
Browse files

PCI: Export pcie_flr()



Currently we opencode the FLR sequence in lots of place; export a core
helper instead.  We split out the probing for FLR support as all the
non-core callers already know their hardware.

Note that in the new pci_has_flr() function the quirk check has been moved
before the capability check as there is no point in reading the capability
in this case.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 0e7df224
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -3773,27 +3773,41 @@ static void pci_flr_wait(struct pci_dev *dev)
			 (i - 1) * 100);
}

static int pcie_flr(struct pci_dev *dev, int probe)
/**
 * pcie_has_flr - check if a device supports function level resets
 * @dev:	device to check
 *
 * Returns true if the device advertises support for PCIe function level
 * resets.
 */
static bool pcie_has_flr(struct pci_dev *dev)
{
	u32 cap;

	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
	if (!(cap & PCI_EXP_DEVCAP_FLR))
		return -ENOTTY;

	if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
		return -ENOTTY;
		return false;

	if (probe)
		return 0;
	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
	return cap & PCI_EXP_DEVCAP_FLR;
}

/**
 * pcie_flr - initiate a PCIe function level reset
 * @dev:	device to reset
 *
 * Initiate a function level reset on @dev.  The caller should ensure the
 * device supports FLR before calling this function, e.g. by using the
 * pcie_has_flr() helper.
 */
void pcie_flr(struct pci_dev *dev)
{
	if (!pci_wait_for_pending_transaction(dev))
		dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n");

	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
	pci_flr_wait(dev);
	return 0;
}
EXPORT_SYMBOL_GPL(pcie_flr);

static int pci_af_flr(struct pci_dev *dev, int probe)
{
@@ -3977,9 +3991,12 @@ static int __pci_dev_reset(struct pci_dev *dev, int probe)
	if (rc != -ENOTTY)
		goto done;

	rc = pcie_flr(dev, probe);
	if (rc != -ENOTTY)
	if (pcie_has_flr(dev)) {
		if (!probe)
			pcie_flr(dev);
		rc = 0;
		goto done;
	}

	rc = pci_af_flr(dev, probe);
	if (rc != -ENOTTY)
+1 −0
Original line number Diff line number Diff line
@@ -1054,6 +1054,7 @@ int pcie_get_mps(struct pci_dev *dev);
int pcie_set_mps(struct pci_dev *dev, int mps);
int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
			  enum pcie_link_width *width);
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);