Skip to content

Commit 600521a

Browse files
P33Mpelwell
authored andcommitted
usb: xhci: add a quirk for Superspeed bulk OUT transfers on VL805
The VL805 has a bug in its internal FIFO space accounting that results in bulk OUT babble if a TRB in a large multi-element TD has a data buffer size that is larger than and not a multiple of wMaxPacketSize for the endpoint. If the downstream USB3.0 link is congested, or latency is increased through an intermediate hub, then the VL805 enters a suspected FIFO overflow condition and transmits repeated, garbled data to the endpoint. TDs with TRBs of exact multiples of wMaxPacketSize and smaller than wMaxPacketSize appear to be handled correctly, so split buffers at a 1024-byte length boundary and put the remainder in a separate smaller TRB. Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
1 parent bd14681 commit 600521a

3 files changed

Lines changed: 21 additions & 2 deletions

File tree

drivers/usb/host/xhci-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
298298
xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
299299
xhci->quirks |= XHCI_AVOID_DQ_ON_LINK;
300300
xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG;
301+
xhci->quirks |= XHCI_VLI_SS_BULK_OUT_BUG;
301302
}
302303

303304
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&

drivers/usb/host/xhci-ring.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3607,14 +3607,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
36073607
unsigned int num_trbs;
36083608
unsigned int start_cycle, num_sgs = 0;
36093609
unsigned int enqd_len, block_len, trb_buff_len, full_len;
3610-
int sent_len, ret;
3611-
u32 field, length_field, remainder;
3610+
int sent_len, ret, vli_quirk = 0;
3611+
u32 field, length_field, remainder, maxpacket;
36123612
u64 addr, send_addr;
36133613

36143614
ring = xhci_urb_to_transfer_ring(xhci, urb);
36153615
if (!ring)
36163616
return -EINVAL;
36173617

3618+
maxpacket = usb_endpoint_maxp(&urb->ep->desc);
36183619
full_len = urb->transfer_buffer_length;
36193620
/* If we have scatter/gather list, we use it. */
36203621
if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)) {
@@ -3651,6 +3652,17 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
36513652
start_cycle = ring->cycle_state;
36523653
send_addr = addr;
36533654

3655+
if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG &&
3656+
!usb_urb_dir_in(urb) && urb->dev->speed >= USB_SPEED_SUPER) {
3657+
/*
3658+
* VL805 - superspeed bulk OUT traffic can cause
3659+
* an internal fifo overflow if the TRB buffer is larger
3660+
* than wMaxPacket and the length is not an integer
3661+
* multiple of wMaxPacket.
3662+
*/
3663+
vli_quirk = 1;
3664+
}
3665+
36543666
/* Queue the TRBs, even if they are zero-length */
36553667
for (enqd_len = 0; first_trb || enqd_len < full_len;
36563668
enqd_len += trb_buff_len) {
@@ -3663,6 +3675,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
36633675
if (enqd_len + trb_buff_len > full_len)
36643676
trb_buff_len = full_len - enqd_len;
36653677

3678+
if (vli_quirk && trb_buff_len > maxpacket) {
3679+
/* SS bulk wMaxPacket is 1024B */
3680+
remainder = trb_buff_len & (maxpacket - 1);
3681+
trb_buff_len -= remainder;
3682+
}
36663683
/* Don't change the cycle bit of the first TRB until later */
36673684
if (first_trb) {
36683685
first_trb = false;

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,7 @@ struct xhci_hcd {
19031903
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
19041904
#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(43)
19051905
#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(44)
1906+
#define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(45)
19061907

19071908
unsigned int num_active_eps;
19081909
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)