Skip to content

Commit c9e051a

Browse files
committed
usb: xhci: expand mitigations for VLI_SS_BULK_OUT_BUG quirk
The VL805 can cause data corruption if a SS Bulk OUT endpoint enters a flow-control condition and there are TRBs in the transfer ring that are not an integral size of wMaxPacket and the endpoint is behind one or more hubs. This is frequently the case encountered when FAT32 filesystems are present on mass-storage devices with cluster sizes of 1 sector, and the filesystem is being written to with an aggregate of small files. The initial implementation of this quirk separated TRBs that didn't adhere to this limitation into two - the first a multiple of wMaxPacket and the second the 512-byte remainder - in an attempt to force TD fragments to align with packet boundaries. This reduced the incidence rate of data corruption but did not resolve it. The fix as recommended by VIA is to disable bursts if this sequence of TRBs can occur. Limit turning off bursts to just USB mass-storage devices by searching the device's configuration for an interface with a class type of USB_CLASS_MASS_STORAGE. Signed-off-by: Jonathan Bell <[email protected]>
1 parent dc0f752 commit c9e051a

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

drivers/usb/host/xhci-mem.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14371437
unsigned int ep_index;
14381438
struct xhci_ep_ctx *ep_ctx;
14391439
struct xhci_ring *ep_ring;
1440+
struct usb_interface_cache *intfc;
14401441
unsigned int max_packet;
14411442
enum xhci_ring_type ring_type;
14421443
u32 max_esit_payload;
@@ -1446,6 +1447,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14461447
unsigned int mult;
14471448
unsigned int avg_trb_len;
14481449
unsigned int err_count = 0;
1450+
unsigned int is_ums_dev = 0;
1451+
unsigned int i;
14491452

14501453
ep_index = xhci_get_endpoint_index(&ep->desc);
14511454
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1477,9 +1480,35 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
14771480

14781481
mult = xhci_get_endpoint_mult(udev, ep);
14791482
max_packet = usb_endpoint_maxp(&ep->desc);
1480-
max_burst = xhci_get_endpoint_max_burst(udev, ep);
14811483
avg_trb_len = max_esit_payload;
14821484

1485+
/*
1486+
* VL805 errata - Bulk OUT bursts to superspeed mass-storage
1487+
* devices behind hub ports can cause data corruption with
1488+
* non-wMaxPacket-multiple transfers.
1489+
*/
1490+
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
1491+
intfc = udev->config->intf_cache[i];
1492+
/*
1493+
* Slight hack - look at interface altsetting 0, which
1494+
* should be the UMS bulk-only interface. If the class
1495+
* matches, then we disable out bursts for all OUT
1496+
* endpoints because endpoint assignments may change
1497+
* between alternate settings.
1498+
*/
1499+
if (intfc->altsetting[0].desc.bInterfaceClass ==
1500+
USB_CLASS_MASS_STORAGE) {
1501+
is_ums_dev = 1;
1502+
break;
1503+
}
1504+
}
1505+
if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG &&
1506+
usb_endpoint_is_bulk_out(&ep->desc) && is_ums_dev &&
1507+
udev->route)
1508+
max_burst = 0;
1509+
else
1510+
max_burst = xhci_get_endpoint_max_burst(udev, ep);
1511+
14831512
/* FIXME dig Mult and streams info out of ep companion desc */
14841513

14851514
/* Allow 3 retries for everything but isoc, set CErr = 3 */

0 commit comments

Comments
 (0)