From: Michal Pecio <michal.pecio@gmail.com>
To: Mathias Nyman <mathias.nyman@intel.com>
Cc: linux-usb@vger.kernel.org
Subject: [PATCH 2/9] usb: xhci: Fix handling errors mid TD followed by other errors
Date: Tue, 27 Aug 2024 19:48:54 +0200 [thread overview]
Message-ID: <20240827194854.089ddf0d@foxbook> (raw)
In-Reply-To: <20240827194625.61be5733@foxbook>
Some host controllers fail to produce the final completion event on an
isochronous TD which experienced an error mid TD. We deal with it by
flagging such TDs and checking if the next event points at the flagged
TD or at the next one, and completing the flagged TD if the latter.
This is not enough, because the next TD may be missed by the xHC. And
we need to do the check early, or errors on the next TD may confuse us.
If the next TD experiences a Missed Service Error, we will set the skip
flag on the endpoint and then attempt skipping TDs when yet another
event arrives. In such scenario, we ought to report the 'erorr mid TD'
transfer as such rather than skip it. We also need to detect that it is
there and in need of handling, despite never receiving a completion of
the subsequent TD. For this purpose, add a check for ep->skip flag and
move the whole error handling logic before the skipping logic.
Note that when we see both td->error_mid_td and ep->skip, they surely
must have been set in this order. Otherwise, skip flag would have been
cleared when the error mid TD was being handled.
Another problem case are Stopped Endpoint events. If we see one after
an error mid TD, we naively assume that it's a Forced Stopped Event
because it doesn't match the pending TD, even though it might actually
be a Stopped Event on the next TD, which we fail to recognize. This is
fixed similarly, by reordering erorr handling before FSE handling.
Lastly, error mid TD handling is reordered with last_td_was_short. This
is harmless, because these two cases are mutually exclusive - only one
can happen in any given execution of handle_tx_event().
And if we are here, add a FIXME comment on the last_td_was_short thing
because it's a wholly broken idea.
Tested on the NEC host and a USB camera with flaky cable. Dynamic debug
confirmed that Transaction Errors are sometimes seen, sometimes mid-TD,
sometimes followed by Missed Service. In such cases, they were finished
properly before skipping began.
Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
---
drivers/usb/host/xhci-ring.c | 78 ++++++++++++++++++------------------
1 file changed, 40 insertions(+), 38 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e960609dcf51..401c34ff2260 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2798,8 +2798,39 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Is this a TRB in the currently executing TD? */
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
+ if (!ep_seg) {
+ /*
+ * xhci 4.10.2 states isoc endpoints should continue
+ * processing the next TD if there was an error mid TD.
+ * So host like NEC don't generate an event for the last
+ * isoc TRB even if the IOC flag is set.
+ * xhci 4.9.1 states that if there are errors in mult-TRB
+ * TDs xHC should generate an error for that TRB, and if xHC
+ * proceeds to the next TD it should genete an event for
+ * any TRB with IOC flag on the way. Other host follow this.
+ * So this event might be for the next TD.
+ */
+ if (td->error_mid_td &&
+ !list_is_last(&td->td_list, &ep_ring->td_list)) {
+ struct xhci_td *td_next = list_next_entry(td, td_list);
+
+ /* Is this a TRB in the next queued TD? */
+ /* *OR* did we miss some TDs meanwhile? */
+ ep_seg = trb_in_td(xhci, td_next, ep_trb_dma, false);
+ if (ep_seg || ep->skip) {
+ /* give back previous TD, start handling new */
+ xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
+ ep_ring->dequeue = td->last_trb;
+ ep_ring->deq_seg = td->last_trb_seg;
+ inc_deq(xhci, ep_ring);
+ xhci_td_cleanup(xhci, td, ep_ring, td->status);
+ td = td_next;
+ }
+ }
+ }
+
if (!ep_seg) {
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
skip_isoc_td(xhci, td, ep, status);
@@ -2820,53 +2851,24 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/*
* Some hosts give a spurious success event after a short
* transfer. Ignore it.
+ * FIXME xHCI 4.10.1.1: this should be freed now, not mid-TD
*/
if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
ep_ring->last_td_was_short) {
ep_ring->last_td_was_short = false;
return 0;
}
- /*
- * xhci 4.10.2 states isoc endpoints should continue
- * processing the next TD if there was an error mid TD.
- * So host like NEC don't generate an event for the last
- * isoc TRB even if the IOC flag is set.
- * xhci 4.9.1 states that if there are errors in mult-TRB
- * TDs xHC should generate an error for that TRB, and if xHC
- * proceeds to the next TD it should genete an event for
- * any TRB with IOC flag on the way. Other host follow this.
- * So this event might be for the next TD.
- */
- if (td->error_mid_td &&
- !list_is_last(&td->td_list, &ep_ring->td_list)) {
- struct xhci_td *td_next = list_next_entry(td, td_list);
-
- ep_seg = trb_in_td(xhci, td_next, ep_trb_dma, false);
- if (ep_seg) {
- /* give back previous TD, start handling new */
- xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
- ep_ring->dequeue = td->last_trb;
- ep_ring->deq_seg = td->last_trb_seg;
- inc_deq(xhci, ep_ring);
- xhci_td_cleanup(xhci, td, ep_ring, td->status);
- td = td_next;
- }
- }
-
- if (!ep_seg) {
- /* HC is busted, give up! */
- xhci_err(xhci,
- "ERROR Transfer event TRB DMA ptr not "
- "part of current TD ep_index %d "
- "comp_code %u\n", ep_index,
- trb_comp_code);
- trb_in_td(xhci, td, ep_trb_dma, true);
-
- return -ESHUTDOWN;
- }
+ /* HC is busted, give up! */
+ xhci_err(xhci,
+ "ERROR Transfer event TRB DMA ptr not "
+ "part of current TD ep_index %d "
+ "comp_code %u\n", ep_index,
+ trb_comp_code);
+ trb_in_td(xhci, td, ep_trb_dma, true);
+ return -ESHUTDOWN;
}
if (ep->skip) {
xhci_dbg(xhci,
--
2.43.0
next prev parent reply other threads:[~2024-08-27 17:48 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-27 17:46 [PATCH 0/9] Various xhci fixes and improvements Michal Pecio
2024-08-27 17:47 ` [PATCH 1/9] usb: xhci: Fix double newline in a debug message Michal Pecio
2024-08-27 17:48 ` Michal Pecio [this message]
2024-08-27 17:49 ` [PATCH 3/9] usb: xhci: Clean up the TD skipping loop Michal Pecio
2024-08-27 17:50 ` [PATCH 4/9] usb: xhci: Expedite processing missed isoch TDs on modern HCs Michal Pecio
2024-08-27 17:51 ` [PATCH 5/9] usb: xhci: Simplify error_mid_td marking Michal Pecio
2024-08-27 17:52 ` [PATCH 6/9] usb: xhci: Sanity check "spurious success" handling Michal Pecio
2024-08-27 17:53 ` [PATCH 7/9] usb: xhci: Don't lie about trb_comp_code in handle_tx_event() Michal Pecio
2024-08-27 17:54 ` [PATCH 8/9] usb: xhci: Print completion code in the empty ring warning Michal Pecio
2024-08-27 17:55 ` [PATCH 9/9] usb: xhci: Clean up and rename bad stream event handler Michal Pecio
2024-08-28 10:21 ` [PATCH 0/9] Various xhci fixes and improvements FPS
2024-08-28 13:24 ` Michał Pecio
2024-08-28 13:48 ` fps
2024-08-28 11:14 ` Mathias Nyman
2024-08-28 15:02 ` Michał Pecio
2024-08-30 11:53 ` Michał Pecio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240827194854.089ddf0d@foxbook \
--to=michal.pecio@gmail.com \
--cc=linux-usb@vger.kernel.org \
--cc=mathias.nyman@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox