diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 7f14f3b9b98a..ccc6a29a081d 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -293,6 +293,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; xhci->quirks |= XHCI_AVOID_DQ_ON_LINK; xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG; + xhci->quirks |= XHCI_VLI_SS_BULK_OUT_BUG; } if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 545387a0679a..29c311263ff9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3414,14 +3414,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, unsigned int num_trbs; unsigned int start_cycle, num_sgs = 0; unsigned int enqd_len, block_len, trb_buff_len, full_len; - int sent_len, ret; - u32 field, length_field, remainder; + int sent_len, ret, vli_quirk = 0; + u32 field, length_field, remainder, maxpacket; u64 addr, send_addr; ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ring) return -EINVAL; + maxpacket = usb_endpoint_maxp(&urb->ep->desc); full_len = urb->transfer_buffer_length; /* If we have scatter/gather list, we use it. */ if (urb->num_sgs) { @@ -3458,6 +3459,17 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_cycle = ring->cycle_state; send_addr = addr; + if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG && + !usb_urb_dir_in(urb) && urb->dev->speed >= USB_SPEED_SUPER) { + /* + * VL805 - superspeed bulk OUT traffic can cause + * an internal fifo overflow if the TRB buffer is larger + * than wMaxPacket and the length is not an integer + * multiple of wMaxPacket. + */ + vli_quirk = 1; + } + /* Queue the TRBs, even if they are zero-length */ for (enqd_len = 0; first_trb || enqd_len < full_len; enqd_len += trb_buff_len) { @@ -3470,6 +3482,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (enqd_len + trb_buff_len > full_len) trb_buff_len = full_len - enqd_len; + if (vli_quirk && trb_buff_len > maxpacket) { + /* SS bulk wMaxPacket is 1024B */ + remainder = trb_buff_len & (maxpacket - 1); + trb_buff_len -= remainder; + } /* Don't change the cycle bit of the first TRB until later */ if (first_trb) { first_trb = false; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index eae8ada4be46..f6b68029f6cc 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1888,6 +1888,7 @@ struct xhci_hcd { #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(41) #define XHCI_AVOID_DQ_ON_LINK BIT_ULL(42) #define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(43) +#define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(44) unsigned int num_active_eps; unsigned int limit_active_eps;