Skip to content

Commit 6a40ed4

Browse files
P33Mpelwell
authored andcommitted
xhci: add a quirk to work around a suspected cache bug on VLI controllers
Certain transfer ring access patterns can cause the controller to hang fetching TRBs for a USB2.0 endpoint. - If two USB2.0 endpoints are active at once and - Both endpoints are traversing a Link TRB where the following segment has a lower page address and - One of the endpoints is a Bulk IN and - The other endpoint is an Interrupt IN Then the Interrupt IN endpoint can end up not getting polled. It is unclear what the precise failure mode is, as the controller seems to haphazardly and repeatedly fetch TRBs for both endpoints but does not advance the Interrupt endpoint transfer. As a workaround, add a quirk that initially constrains all USB2.0 transfer rings to a single segment in size. If for any reason a device driver queues up enough outstanding transfers to fill the ring segment, then the ring will be expanded. This has not been seen to occur with UMS or UVC drivers, which aggressively queue buffers. Signed-off-by: Jonathan Bell <[email protected]>
1 parent 5c9bdc3 commit 6a40ed4

File tree

3 files changed

+8
-1
lines changed

3 files changed

+8
-1
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14311431
unsigned int mult;
14321432
unsigned int avg_trb_len;
14331433
unsigned int err_count = 0;
1434+
unsigned int nsegs = 2;
14341435

14351436
ep_index = xhci_get_endpoint_index(&ep->desc);
14361437
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1441,6 +1442,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14411442

14421443
ring_type = usb_endpoint_type(&ep->desc);
14431444

1445+
if (xhci->quirks & XHCI_VLI_TRB_CACHE_BUG &&
1446+
udev->speed != USB_SPEED_SUPER) {
1447+
nsegs = 1;
1448+
}
14441449
/*
14451450
* Get values to fill the endpoint context, mostly from ep descriptor.
14461451
* The average TRB buffer lengt for bulk endpoints is unclear as we
@@ -1488,7 +1493,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14881493

14891494
/* Set up the endpoint ring */
14901495
virt_dev->eps[ep_index].new_ring =
1491-
xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
1496+
xhci_ring_alloc(xhci, nsegs, 1, ring_type, max_packet, mem_flags);
14921497
if (!virt_dev->eps[ep_index].new_ring)
14931498
return -ENOMEM;
14941499

drivers/usb/host/xhci-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
292292
xhci->quirks |= XHCI_LPM_SUPPORT;
293293
xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
294294
xhci->quirks |= XHCI_AVOID_DQ_ON_LINK;
295+
xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG;
295296
}
296297

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

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,7 @@ struct xhci_hcd {
19011901
#define XHCI_BROKEN_D3COLD BIT_ULL(41)
19021902
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
19031903
#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(43)
1904+
#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(44)
19041905

19051906
unsigned int num_active_eps;
19061907
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)