Skip to content

Commit a1d0f80

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 7b6fa21 commit a1d0f80

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
@@ -1445,6 +1445,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14451445
unsigned int mult;
14461446
unsigned int avg_trb_len;
14471447
unsigned int err_count = 0;
1448+
unsigned int nsegs = 2;
14481449

14491450
ep_index = xhci_get_endpoint_index(&ep->desc);
14501451
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1455,6 +1456,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14551456

14561457
ring_type = usb_endpoint_type(&ep->desc);
14571458

1459+
if (xhci->quirks & XHCI_VLI_TRB_CACHE_BUG &&
1460+
udev->speed != USB_SPEED_SUPER) {
1461+
nsegs = 1;
1462+
}
14581463
/*
14591464
* Get values to fill the endpoint context, mostly from ep descriptor.
14601465
* The average TRB buffer lengt for bulk endpoints is unclear as we
@@ -1502,7 +1507,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
15021507

15031508
/* Set up the endpoint ring */
15041509
virt_dev->eps[ep_index].new_ring =
1505-
xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
1510+
xhci_ring_alloc(xhci, nsegs, 1, ring_type, max_packet, mem_flags);
15061511
if (!virt_dev->eps[ep_index].new_ring)
15071512
return -ENOMEM;
15081513

drivers/usb/host/xhci-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
287287
xhci->quirks |= XHCI_LPM_SUPPORT;
288288
xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
289289
xhci->quirks |= XHCI_AVOID_DQ_ON_LINK;
290+
xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG;
290291
}
291292

292293
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
@@ -1886,6 +1886,7 @@ struct xhci_hcd {
18861886
#define XHCI_NO_SOFT_RETRY BIT_ULL(40)
18871887
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(41)
18881888
#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(42)
1889+
#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(43)
18891890

18901891
unsigned int num_active_eps;
18911892
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)