1afe830091fddf66d3b0e4225cee04c37ba31d8b
[openwrt/staging/neocturne.git] /
1 From 18f08bf8df95c687d6fee3d2bb747cbd2fa0b878 Mon Sep 17 00:00:00 2001
2 From: Jonathan Bell <jonathan@raspberrypi.com>
3 Date: Thu, 22 Sep 2022 14:55:54 +0100
4 Subject: [PATCH] usb: xhci: account for num_trbs_free when
5 invalidating TDs
6
7 If a ring has a number of TDs enqueued past the dequeue pointer, and the
8 URBs corresponding to these TDs are dequeued, then num_trbs_free isn't
9 updated to show that these TDs have been converted to no-ops and
10 effectively "freed". This means that num_trbs_free creeps downwards
11 until the count is exhausted, which then triggers xhci_ring_expansion()
12 and effectively leaks memory by infinitely growing the transfer ring.
13
14 This is commonly encounted through the use of a usb-serial port where
15 the port is repeatedly opened, read, then closed.
16
17 Move the num_trbs_free crediting out of the Set TR Dequeue Pointer
18 handling and into xhci_invalidate_cancelled_tds().
19
20 There is a potential for overestimating the actual space on the ring if
21 the ring is nearly full and TDs are arbitrarily enqueued by a device
22 driver while it is dequeueing them, but dequeues are usually batched
23 during device close/shutdown or endpoint error recovery.
24
25 See https://github.com/raspberrypi/linux/issues/5088
26
27 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
28 ---
29 drivers/usb/host/xhci-ring.c | 14 +++-----------
30 1 file changed, 3 insertions(+), 11 deletions(-)
31
32 --- a/drivers/usb/host/xhci-ring.c
33 +++ b/drivers/usb/host/xhci-ring.c
34 @@ -1013,11 +1013,13 @@ static int xhci_invalidate_cancelled_tds
35 td->urb->stream_id, td->urb,
36 cached_td->urb->stream_id, cached_td->urb);
37 cached_td = td;
38 + ring->num_trbs_free += td->num_trbs;
39 break;
40 }
41 } else {
42 td_to_noop(xhci, ring, td, false);
43 td->cancel_status = TD_CLEARED;
44 + ring->num_trbs_free += td->num_trbs;
45 }
46 }
47
48 @@ -1265,10 +1267,7 @@ static void update_ring_for_set_deq_comp
49 unsigned int ep_index)
50 {
51 union xhci_trb *dequeue_temp;
52 - int num_trbs_free_temp;
53 - bool revert = false;
54
55 - num_trbs_free_temp = ep_ring->num_trbs_free;
56 dequeue_temp = ep_ring->dequeue;
57
58 /* If we get two back-to-back stalls, and the first stalled transfer
59 @@ -1283,8 +1282,6 @@ static void update_ring_for_set_deq_comp
60 }
61
62 while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
63 - /* We have more usable TRBs */
64 - ep_ring->num_trbs_free++;
65 ep_ring->dequeue++;
66 if (trb_is_link(ep_ring->dequeue)) {
67 if (ep_ring->dequeue ==
68 @@ -1294,15 +1291,10 @@ static void update_ring_for_set_deq_comp
69 ep_ring->dequeue = ep_ring->deq_seg->trbs;
70 }
71 if (ep_ring->dequeue == dequeue_temp) {
72 - revert = true;
73 + xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
74 break;
75 }
76 }
77 -
78 - if (revert) {
79 - xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
80 - ep_ring->num_trbs_free = num_trbs_free_temp;
81 - }
82 }
83
84 /*