aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/usb/host/pci-quirks.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-08-01 20:11:08 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-08-02 12:05:07 -0500
commit8466489ef5ba48272ba4fa4ea9f8f403306de4c7 (patch)
treeab765d1c3f8acaf71a7e4341633fd390e80042e5 /drivers/usb/host/pci-quirks.c
parentPCI: Add pci_reset_function_locked() (diff)
downloadwireguard-linux-8466489ef5ba48272ba4fa4ea9f8f403306de4c7.tar.xz
wireguard-linux-8466489ef5ba48272ba4fa4ea9f8f403306de4c7.zip
xhci: Reset Renesas uPD72020x USB controller for 32-bit DMA issue
The Renesas uPD72020x XHCI controller seems to suffer from a really annoying bug, where it may retain some of its DMA programming across a XHCI reset, and despite the driver correctly programming new DMA addresses. This is visible if the device has been using 64-bit DMA addresses, and is then switched to using 32-bit DMA addresses. The top 32 bits of the address (now zero) are ignored are replaced by the 32 bits from the *previous* programming. Sticking with 64-bit DMA always works, but doesn't seem very appropriate. A PCI reset of the device restores the normal functionality, which is done at probe time. Unfortunately, this has to be done before any quirk has been discovered, hence the intrusive nature of the fix. Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com> CC: stable@vger.kernel.org # v4.11+
Diffstat (limited to 'drivers/usb/host/pci-quirks.c')
-rw-r--r--drivers/usb/host/pci-quirks.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c8989c62a262..858fefd67ebe 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -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);