Skip to content

Commit 40686d8

Browse files
P33Mpopcornmix
authored andcommitted
usb: xhci: expand the scope of XHCI_VLI_SS_BULK_OUT_BUG
Further testing has revealed that any TRB with buffer length that is not a multiple of wMaxPacket and not the last TRB in a TD can cause data corruption. Work around this by linearising any vulnerable Bulk OUT scatter-gather URBs prior to URB submission. Normal XHCI TRB formation will split buffers on 64K boundaries and align TRBs prior to a Link TRB to wMaxPacket, so keep the residue TRB generation added with the first iteration of the quirk which will guarantee the last TRB is the only TRB with an odd buffer size. Signed-off-by: Jonathan Bell <[email protected]>
1 parent 3066be0 commit 40686d8

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

drivers/usb/host/xhci.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1395,9 +1395,12 @@ static void xhci_unmap_temp_buf(struct usb_hcd *hcd, struct urb *urb)
13951395
static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
13961396
gfp_t mem_flags)
13971397
{
1398+
unsigned int i, maxpacket;
1399+
struct scatterlist *sg;
13981400
struct xhci_hcd *xhci;
13991401

14001402
xhci = hcd_to_xhci(hcd);
1403+
maxpacket = usb_endpoint_maxp(&urb->ep->desc);
14011404

14021405
if (xhci_urb_suitable_for_idt(urb))
14031406
return 0;
@@ -1406,6 +1409,16 @@ static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
14061409
if (xhci_urb_temp_buffer_required(hcd, urb))
14071410
return xhci_map_temp_buffer(hcd, urb);
14081411
}
1412+
1413+
if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG &&
1414+
usb_endpoint_is_bulk_out(&urb->ep->desc) &&
1415+
urb->dev->speed >= USB_SPEED_SUPER &&
1416+
urb->transfer_buffer_length != 0) {
1417+
for_each_sg(urb->sg, sg, urb->num_sgs, i) {
1418+
if (sg->length % maxpacket)
1419+
return xhci_map_temp_buffer(hcd, urb);
1420+
}
1421+
}
14091422
return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
14101423
}
14111424

@@ -1419,7 +1432,8 @@ static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
14191432
if (urb->num_sgs && (urb->transfer_flags & URB_DMA_MAP_SINGLE))
14201433
unmap_temp_buf = true;
14211434

1422-
if ((xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) && unmap_temp_buf)
1435+
if ((xhci->quirks & (XHCI_SG_TRB_CACHE_SIZE_QUIRK | XHCI_VLI_SS_BULK_OUT_BUG))
1436+
&& unmap_temp_buf)
14231437
xhci_unmap_temp_buf(hcd, urb);
14241438
else
14251439
usb_hcd_unmap_urb_for_dma(hcd, urb);

0 commit comments

Comments
 (0)