From ee68565ca0e6728a79e11fb4c6aa54f2ce45c2e8 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 26 Oct 2020 14:03:35 +0000 Subject: [PATCH] xhci: quirks: add link TRB quirk for VL805 The VL805 controller can't cope with the TR Dequeue Pointer for an endpoint being set to a Link TRB. The hardware-maintained endpoint context ends up stuck at the address of the Link TRB, leading to erroneous ring expansion events whenever the enqueue pointer wraps to the dequeue position. If the search for the end of the current TD and ring cycle state lands on a Link TRB, move to the next segment. Link: https://github.com/raspberrypi/linux/issues/3919 [6.5.y Fixup - move downstream quirk bits further along] Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-ring.c | 10 ++++++++++ drivers/usb/host/xhci.h | 3 +++ 3 files changed, 14 insertions(+) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d83ee397b8a273..c41f58ff976af3 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -421,6 +421,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; + xhci->quirks |= XHCI_AVOID_DQ_ON_LINK; } if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 12d4ccf8dd5cf4..bf6ff92bec4f8c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -712,6 +712,16 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, } while (!cycle_found || !td_last_trb_found); + /* + * Quirk: the xHC does not correctly parse link TRBs if the HW Dequeue + * pointer is set to one. Advance to the next TRB (and next segment). + */ + if (xhci->quirks & XHCI_AVOID_DQ_ON_LINK && trb_is_link(new_deq)) { + if (link_trb_toggles_cycle(new_deq)) + new_cycle ^= 0x1; + next_trb(&new_seg, &new_deq); + } + /* Don't update the ring cycle state for the producer (us). */ addr = xhci_trb_virt_to_dma(new_seg, new_deq); if (addr == 0) { diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8c164340a2c350..3c03cf186a51c2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1638,6 +1638,9 @@ struct xhci_hcd { #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) #define XHCI_ETRON_HOST BIT_ULL(49) +/* Downstream VLI fixes */ +#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(56) + unsigned int num_active_eps; unsigned int limit_active_eps; struct xhci_port *hw_ports;