Skip to content

Commit 20f6415

Browse files
P33Mpelwell
authored andcommitted
usb: xhci: add VLI_TRB_CACHE_BUG quirk
The VL805 fetches up to 4 transfer TRBs at a time. TRB reads don't cross a 64B boundary, and if a TRB is fetched and is not on a 64B boundary, the read is sized up to the next 64B boundary. However the VL805 implements a readahead prefetch for TRBs on a transfer ring. This fetches the next 64B after any TRB read has happened. Near the end of a ring segment, the prefetcher can read the first 64B of the next page in physical memory and this is where the behaviour causes a bug. The controller does not tag reads with which endpoint they are for, so if the start of the next page is a ring segment used by a victim endpoint, and the victim endpoint is about to fetch TRBs from the start of the segment, the victim endpoint will read from the prefetched data and not perform a read to main memory. If the data is stale, the ring cycle state bit may not be correct and the endpoint will silently halt. Adjust trbs_per_seg for transfer rings allocated for this controller. See #4685 Signed-off-by: Jonathan Bell <[email protected]>
1 parent 49f2985 commit 20f6415

File tree

3 files changed

+13
-0
lines changed

3 files changed

+13
-0
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,17 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
392392
return ring;
393393

394394
ring->trbs_per_seg = TRBS_PER_SEGMENT;
395+
/*
396+
* The Via VL805 has a bug where cache readahead will fetch off the end
397+
* of a page if the Link TRB of a transfer ring is in the last 4 slots.
398+
* Where there are consecutive physical pages containing ring segments,
399+
* this can cause a desync between the controller's view of a ring
400+
* and the host.
401+
*/
402+
if (xhci->quirks & XHCI_VLI_TRB_CACHE_BUG &&
403+
type != TYPE_EVENT && type != TYPE_COMMAND)
404+
ring->trbs_per_seg -= 4;
405+
395406
ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
396407
&ring->last_seg, num_segs, ring->trbs_per_seg,
397408
cycle_state, type, max_packet, flags);

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
@@ -1887,6 +1887,7 @@ struct xhci_hcd {
18871887
#define XHCI_NO_SOFT_RETRY BIT_ULL(40)
18881888
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(41)
18891889
#define XHCI_AVOID_DQ_ON_LINK BIT_ULL(42)
1890+
#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(43)
18901891

18911892
unsigned int num_active_eps;
18921893
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)