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

Commit 4e082e9b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull PCI fix from Bjorn Helgaas:
 "Work around Renesas uPD72020x 32-bit DMA issue"

* tag 'pci-v4.13-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  xhci: Reset Renesas uPD72020x USB controller for 32-bit DMA issue
  PCI: Add pci_reset_function_locked()
parents 26273939 8466489e
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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
+20 −0
Original line number Diff line number Diff line
@@ -1150,3 +1150,23 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);

bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
{
	/*
	 * Our dear uPD72020{1,2} friend only partially resets when
	 * asked to via the XHCI interface, and may end up doing DMA
	 * at the wrong addresses, as it keeps the top 32bit of some
	 * addresses from its previous programming under obscure
	 * circumstances.
	 * Give it a good wack at probe time. Unfortunately, this
	 * needs to happen before we've had a chance to discover any
	 * quirk, or the system will be in a rather bad state.
	 */
	if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
	    (pdev->device == 0x0014 || pdev->device == 0x0015))
		return true;

	return false;
}
EXPORT_SYMBOL_GPL(usb_xhci_needs_pci_reset);
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev);
void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
void sb800_prefetch(struct device *dev, int on);
bool usb_xhci_needs_pci_reset(struct pci_dev *pdev);
#else
struct pci_dev;
static inline void usb_amd_quirk_pll_disable(void) {}
+7 −0
Original line number Diff line number Diff line
@@ -284,6 +284,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)

	driver = (struct hc_driver *)id->driver_data;

	/* For some HW implementation, a XHCI reset is just not enough... */
	if (usb_xhci_needs_pci_reset(dev)) {
		dev_info(&dev->dev, "Resetting\n");
		if (pci_reset_function_locked(dev))
			dev_warn(&dev->dev, "Reset failed");
	}

	/* Prevent runtime suspending between USB-2 and USB-3 initialization */
	pm_runtime_get_noresume(&dev->dev);

+1 −0
Original line number Diff line number Diff line
@@ -1067,6 +1067,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);