474698e913054bcee1f38897f550fa17e6e68f00
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-6.1 / 950-0469-usb-xhci-add-XHCI_VLI_HUB_TT_QUIRK.patch
1 From 4f3e85c6f129199a432ef4ed3edbb667a5dedcc1 Mon Sep 17 00:00:00 2001
2 From: Jonathan Bell <jonathan@raspberrypi.com>
3 Date: Thu, 1 Dec 2022 16:59:44 +0000
4 Subject: [PATCH] usb: xhci: add XHCI_VLI_HUB_TT_QUIRK
5
6 The integrated USB2.0 hub in the VL805 chipset has a bug where it
7 incorrectly determines the remaining available frame time before the
8 host next sends a SOF packet with an incremented frame_number.
9
10 See the USB2.0 specification sections 11.3 and 11.14.2.3.
11
12 The hub's non-periodic TT handler can transmit the IN/OUT handshake
13 token too late, so a following 64-byte DATA0/1 packet causes the ACK
14 handshake to collide with the propagated SOF. This causes port babble.
15
16 Avoid ringing doorbells for vulnerable endpoints during uFrame 7 if the
17 TR is Idle to stop one source of babble. An IN transfer for a Running TR
18 may happen at any time, so there's not much we can do about that.
19
20 Ideally a hub firmware update to properly implement frame timeouts is
21 needed, and to avoid spinning for up to 125us when submitting TDs to
22 Idle rings.
23
24 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
25 ---
26 drivers/usb/host/xhci-pci.c | 1 +
27 drivers/usb/host/xhci-ring.c | 46 ++++++++++++++++++++++++++++++++++++
28 drivers/usb/host/xhci.h | 1 +
29 3 files changed, 48 insertions(+)
30
31 --- a/drivers/usb/host/xhci-pci.c
32 +++ b/drivers/usb/host/xhci-pci.c
33 @@ -299,6 +299,7 @@ static void xhci_pci_quirks(struct devic
34 xhci->quirks |= XHCI_AVOID_DQ_ON_LINK;
35 xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG;
36 xhci->quirks |= XHCI_VLI_SS_BULK_OUT_BUG;
37 + xhci->quirks |= XHCI_VLI_HUB_TT_QUIRK;
38 }
39
40 if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
41 --- a/drivers/usb/host/xhci-ring.c
42 +++ b/drivers/usb/host/xhci-ring.c
43 @@ -3555,6 +3555,48 @@ static int xhci_align_td(struct xhci_hcd
44 return 1;
45 }
46
47 +static void xhci_vl805_hub_tt_quirk(struct xhci_hcd *xhci, struct urb *urb,
48 + struct xhci_ring *ring)
49 +{
50 + struct list_head *tmp;
51 + struct usb_device *udev = urb->dev;
52 + unsigned int timeout = 0;
53 + unsigned int single_td = 0;
54 +
55 + /*
56 + * Adding a TD to an Idle ring for a FS nonperiodic endpoint
57 + * that is behind the internal hub's TT will run the risk of causing a
58 + * downstream port babble if submitted late in uFrame 7.
59 + * Wait until we've moved on into at least uFrame 0
60 + * (MFINDEX references the next SOF to be transmitted).
61 + *
62 + * Rings for IN endpoints in the Running state also risk causing
63 + * babble if the returned data is large, but there's not much we can do
64 + * about it here.
65 + */
66 + if (udev->route & 0xffff0 || udev->speed != USB_SPEED_FULL)
67 + return;
68 +
69 + list_for_each(tmp, &ring->td_list) {
70 + single_td++;
71 + if (single_td == 2) {
72 + single_td = 0;
73 + break;
74 + }
75 + }
76 + if (single_td) {
77 + while (timeout < 20 &&
78 + (readl(&xhci->run_regs->microframe_index) & 0x7) == 0) {
79 + udelay(10);
80 + timeout++;
81 + }
82 + if (timeout >= 20)
83 + xhci_warn(xhci, "MFINDEX didn't advance - %u.%u dodged\n",
84 + readl(&xhci->run_regs->microframe_index) >> 3,
85 + readl(&xhci->run_regs->microframe_index) & 7);
86 + }
87 +}
88 +
89 /* This is very similar to what ehci-q.c qtd_fill() does */
90 int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
91 struct urb *urb, int slot_id, unsigned int ep_index)
92 @@ -3723,6 +3765,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
93 }
94
95 check_trb_math(urb, enqd_len);
96 + if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
97 + xhci_vl805_hub_tt_quirk(xhci, urb, ring);
98 giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
99 start_cycle, start_trb);
100 return 0;
101 @@ -3858,6 +3902,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
102 /* Event on completion */
103 field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
104
105 + if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
106 + xhci_vl805_hub_tt_quirk(xhci, urb, ep_ring);
107 giveback_first_trb(xhci, slot_id, ep_index, 0,
108 start_cycle, start_trb);
109 return 0;
110 --- a/drivers/usb/host/xhci.h
111 +++ b/drivers/usb/host/xhci.h
112 @@ -1903,6 +1903,7 @@ struct xhci_hcd {
113 #define XHCI_AVOID_DQ_ON_LINK BIT_ULL(45)
114 #define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(46)
115 #define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(47)
116 +#define XHCI_VLI_HUB_TT_QUIRK BIT_ULL(48)
117
118 unsigned int num_active_eps;
119 unsigned int limit_active_eps;