From: Michal Pecio <michal.pecio@gmail.com>
To: Mathias Nyman <mathias.nyman@intel.com>,
Niklas Neronin <niklas.neronin@linux.intel.com>
Cc: linux-usb@vger.kernel.org
Subject: [PATCH 3/5] usb: xhci: Unify event handler's 'empty list' and 'no match' cases
Date: Tue, 10 Sep 2024 13:15:17 +0200 [thread overview]
Message-ID: <20240910131517.2bc8a403@foxbook> (raw)
In-Reply-To: <20240910131233.409c6481@foxbook>
Sometimes handle_tx_event() gets an event which doesn't match any
pending TD. Or it may be that there are simply no pending TDs at all.
These two cases are hardly different, but they are handled by two
separate blocks of code. Some logic is pointlessly duplicated, some
logic is missing or buggy in one branch or in the other.
Reduce the 'empty list' case in the searching loop to a minimum and
merge the code removed from there with almost identical code after
the loop, which deals with the 'no match' case.
This fixes the "spurious success" check in the 'empty list' case not
verifying if the host actually has the quirk, and the lack of halted
endpoint recovery in the 'no match' case.
Remove an obsolete attempt at stall recovery. This code relied on a
bug which has been fixed earlier this year, and it was never really
fully effective because not all cancelled TDs get No-Op'ed.
Make the empty list warning print event completion code, like the
'no match' case does.
Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
---
drivers/usb/host/xhci-ring.c | 68 ++++++++++++------------------------
1 file changed, 23 insertions(+), 45 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 0eef7cd2f20a..56b0c0e85293 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2606,7 +2606,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int ep_index;
struct xhci_td *td = NULL;
dma_addr_t ep_trb_dma;
- struct xhci_segment *ep_seg;
+ struct xhci_segment *ep_seg = NULL;
union xhci_trb *ep_trb;
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
@@ -2793,28 +2793,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* TD list.
*/
if (list_empty(&ep_ring->td_list)) {
- /*
- * Don't print wanings if it's due to a stopped endpoint
- * generating an extra completion event if the device
- * was suspended. Or, a event for the last TRB of a
- * short TD we already got a short event for.
- * The short TD is already removed from the TD list.
- */
-
- if (!(trb_comp_code == COMP_STOPPED ||
- trb_comp_code == COMP_STOPPED_LENGTH_INVALID ||
- ep_ring->last_td_was_short)) {
- xhci_warn(xhci, "WARN Event TRB for slot %u ep %d with no TDs queued?\n",
- slot_id, ep_index);
- }
if (ep->skip) {
ep->skip = false;
xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n",
slot_id, ep_index);
}
-
- td = NULL;
- goto check_endpoint_halted;
+ break;
}
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
@@ -2848,11 +2832,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!ep_seg) {
/*
- * Skip the Force Stopped Event. The 'ep_trb' of FSE is not in the current
- * TD pointed by 'ep_ring->dequeue' because that the hardware dequeue
- * pointer still at the previous TRB of the current TD. The previous TRB
- * maybe a Link TD or the last TRB of the previous TD. The command
- * completion handle will take care the rest.
+ * Ignore the Force Stopped Event. The endpoint may stop on
+ * some Link or No-Op TRB outside our TDs. We don't care.
*/
if (trb_comp_code == COMP_STOPPED ||
trb_comp_code == COMP_STOPPED_LENGTH_INVALID) {
@@ -2870,13 +2851,25 @@ static int handle_tx_event(struct xhci_hcd *xhci,
}
/* 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 (list_empty(&ep_ring->td_list)) {
+ xhci_warn(xhci, "WARN Event TRB for slot %u ep %d comp_code %u with no TDs queued?\n",
+ slot_id, ep_index, trb_comp_code);
+ } else {
+ 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);
+ }
+
+ /*
+ * Bugs (in HW or SW) may cause the xHC to execute transfers as
+ * they are being cancelled and forgotten about. Then we get some
+ * event and have no idea which transfer caused it. If the event
+ * indicates that the EP halted, try to fix that at least.
+ */
+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
+
+ return 0;
}
if (trb_comp_code == COMP_SHORT_PACKET)
@@ -2887,16 +2880,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb);
- /*
- * No-op TRB could trigger interrupts in a case where a URB was killed
- * and a STALL_ERROR happens right after the endpoint ring stopped.
- * Reset the halted endpoint. Otherwise, the endpoint remains stalled
- * indefinitely.
- */
-
- if (trb_is_noop(ep_trb))
- goto check_endpoint_halted;
-
td->status = status;
/* update the urb's actual_length and give back to the core */
@@ -2906,11 +2889,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
else
process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
- return 0;
-
-check_endpoint_halted:
- if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
- xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return 0;
--
2.43.0
next prev parent reply other threads:[~2024-09-10 11:15 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-10 11:12 [PATCH 0/5] Quick and effective handle_tx_event() cleanup Michal Pecio
2024-09-10 11:13 ` [PATCH 1/5] usb: xhci: Fix handling errors mid TD followed by other errors Michal Pecio
2024-09-10 11:14 ` [PATCH 2/5] usb: xhci: Clean up the TD skipping loop Michal Pecio
2024-09-10 11:15 ` Michal Pecio [this message]
2024-09-10 11:16 ` [PATCH 4/5] usb: xhci: Simplify the TD skipping loop further Michal Pecio
2024-09-10 11:16 ` [PATCH 5/5] usb: xhci: Fix Ring Underrun/Overrun handling Michal 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=20240910131517.2bc8a403@foxbook \
--to=michal.pecio@gmail.com \
--cc=linux-usb@vger.kernel.org \
--cc=mathias.nyman@intel.com \
--cc=niklas.neronin@linux.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;
as well as URLs for NNTP newsgroup(s).