Linux USB
 help / color / mirror / Atom feed
From: Mathias Nyman <mathias.nyman@linux.intel.com>
To: yiyu@yiyuzhou.io
Cc: <linux-usb@vger.kernel.org>,
	regressions@lists.linux.dev, diogochaves@me.com,
	michal.pecio@gmail.com, raoxu@uniontech.com, dennis@dsine.de,
	gregkh@linuxfoundation.org,
	Mathias Nyman <mathias.nyman@linux.intel.com>
Subject: [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect
Date: Tue, 27 Oct 2026 21:21:26 +0200	[thread overview]
Message-ID: <20261027192128.386082-2-mathias.nyman@linux.intel.com> (raw)
In-Reply-To: <20261027192128.386082-1-mathias.nyman@linux.intel.com>

From: Yiyu Zhou <yiyu@yiyuzhou.io>

Commit 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub
disconnect") makes xhci_handle_halted_endpoint() return early when the
root port is disconnected, and commit 7e0ef4332ed9 ("xhci: avoid xHC
endpoint changes after disconnect or link error.") also sets
EP_DROP_PENDING there, which keeps the doorbell from being rung until
the device is reset.

The callers rely on xhci_handle_halted_endpoint() to take over the
halted TD.  For example, finish_td() returns right after calling it,
expecting the TD to be given back once the Reset Endpoint command
completes.  With the early return, nobody gives the TD back.  Its URB
stays pending until the submitter times out and unlinks it.  URBs
queued behind it are stuck the same way, and every URB queued on the
endpoint afterwards never starts, because the doorbell is blocked, and
also has to time out.

Devices that disconnect and reconnect themselves during enumeration hit
this.  A PFU HHKB Professional HYBRID Type-S keyboard (04fe:0021) drops
off the bus about 300 ms after its first enumeration, while usbhid is
still probing its third interface.  The probe runs in hub_wq, so the
disconnect is not handled until the probe returns.  On a root port the
HID descriptor request and its four retries in hid_get_class_descriptor()
each wait for the full 5 second USB_CTRL_GET_TIMEOUT:

  [57685.006036] usb 3-2: new full-speed USB device number 24 using xhci_hcd
  ...
  [57685.291304] hid-generic 0003:04FE:0021.0017: input,hidraw1: USB HID v1.11 Keyboard [PFU Limited HHKB-Hybrid] on usb-0000:00:14.0-2/input1
  [57711.221083] usbhid 3-2:1.2: can't add hid device: -110
  [57711.221613] usbhid 3-2:1.2: probe with driver usbhid failed with error -110
  [57711.221842] usb 3-2: USB disconnect, device number 24

The re-enumeration that follows can stall the same way, leaving the
keyboard dead until reboot.  Behind an external hub, where the root
port stays connected, the same keyboard recovers in about 300 ms, as it
did on the root port before these commits.

Keep skipping Reset Endpoint on a disconnected or inactive port, but
give back the halted TD right away, with -EPROTO if no error status was
set yet, and all other TDs on the endpoint with -ESHUTDOWN.  The
endpoint is not restarted until the device is reset or dropped, so the
ring dequeue pointer can stay where it is, as
xhci_invalidate_cancelled_tds() already assumes for cancelled TDs on
such endpoints.  Also refuse new URBs on an endpoint with
EP_DROP_PENDING set, like xhci_urb_enqueue() already does for an
inactive link, so they fail right away instead of timing out.

[mn: merge EP_DROP_PENDING and link_inactive checks in xhci_urb_enqueue()]

Fixes: 042aad8d0db6 ("xhci: prevent endpoint recovery after roothub disconnect")
Fixes: 7e0ef4332ed9 ("xhci: avoid xHC endpoint changes after disconnect or link error.")
Closes: https://lore.kernel.org/all/20261010071811.20483-1-yiyu@yiyuzhou.io/
Assisted-by: LLM
Signed-off-by: Yiyu Zhou <yiyu@yiyuzhou.io>
Tested-by: Diogo Chaves <diogochaves@me.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
 drivers/usb/host/xhci-ring.c | 12 ++++++++++--
 drivers/usb/host/xhci.c      | 13 +++++++------
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ec278a9f9540..8262ed516d37 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -65,6 +65,7 @@
 static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
 			 u32 field1, u32 field2,
 			 u32 field3, u32 field4, bool command_must_succeed);
+static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index);
 
 /*
  * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
@@ -989,12 +990,19 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
 	int err;
 
 	/*
-	 * Avoid resetting endpoint if link is inactive or device disonnected.
+	 * Avoid resetting endpoint if link is inactive or device disconnected.
 	 * Can cause host hang.
-	 * Device will be reset to recover an inactive link, so don't do anything
+	 * The endpoint won't restart before the device is reset or the endpoint
+	 * dropped, so give back all its TDs now instead of letting them time out.
 	 */
 	if (rhub_port->link_inactive || !rhub_port->connected) {
+		xhci_dbg(xhci, "Not resetting ep %u slot %u after disconnect or link error\n",
+			 ep->ep_index, slot_id);
 		ep->ep_state |= EP_DROP_PENDING;
+		if (td)
+			xhci_td_cleanup(xhci, td, xhci_urb_to_transfer_ring(xhci, td->urb),
+					td->status ?: -EPROTO);
+		xhci_kill_endpoint_urbs(xhci, slot_id, ep->ep_index);
 		return -ENODEV;
 	}
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7f7babe9d681..fa3012bf4c0f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1665,12 +1665,6 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
 		goto free_priv;
 	}
 
-	if (xhci->devs[slot_id]->rhub_port->link_inactive) {
-		xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
-		ret = -ENODEV;
-		goto free_priv;
-	}
-
 	if (xhci->xhc_state & XHCI_STATE_DYING) {
 		xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n",
 			 urb->ep->desc.bEndpointAddress, urb);
@@ -1680,6 +1674,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
 
 	ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
 
+	if (xhci->devs[slot_id]->rhub_port->link_inactive ||
+	    *ep_state & EP_DROP_PENDING) {
+		xhci_dbg(xhci, "Can't queue urb, port disconnect or link inactive\n");
+		ret = -ENODEV;
+		goto free_priv;
+	}
+
 	if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) {
 		xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n",
 			  *ep_state);
-- 
2.43.0


  reply	other threads:[~2026-10-27 19:22 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24 17:47 [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Dennis Wissel
2026-10-24 20:34 ` Yiyu Zhou
2026-10-24 20:35 ` Yiyu Zhou
2026-10-24 23:10   ` Dennis Wissel
2026-10-25  8:59     ` Thorsten Leemhuis
2026-10-26  9:28       ` Mathias Nyman
2026-10-26  9:49         ` Thorsten Leemhuis
2026-10-26 10:47         ` Greg KH
2026-10-25 10:14     ` Michal Pecio
2026-10-25 11:11       ` Dennis Wissel
2026-10-26 11:15         ` Michal Pecio
2026-10-26 20:39           ` Yiyu Zhou
2026-10-27  7:29             ` Dennis Wissel
2026-10-27  8:48               ` [PATCH] xhci: keep ep0 blocked after disconnect until Address Device reloads it Yiyu Zhou
2026-10-27  9:10                 ` sashiko-bot
2026-10-27 10:36                 ` Mathias Nyman
2026-10-27 11:27                   ` Michal Pecio
2026-10-27 18:40                   ` Yiyu Zhou
2026-10-27 19:21                     ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Mathias Nyman
2026-10-27 19:21                       ` Mathias Nyman [this message]
2026-10-27 19:21                       ` [RFT PATCH 2/2] xhci: clean up ep0 ring after disconnect instead of leaving stale TRBs Mathias Nyman
2026-10-27 23:05                       ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Dennis Wissel
2026-10-28  7:07                       ` Michal Pecio
2026-10-29  6:54                         ` [PATCH 0/4] Fix problems on disconnected devices in 7.3 Michal Pecio
2026-10-29  6:54                           ` [PATCH 1/4] usb: xhci: Fix TD invalidation on disconnected endpoints Michal Pecio
2026-10-29  7:12                             ` sashiko-bot
2026-10-29  6:55                           ` [PATCH 2/4] usb: xhci: Give back stranded URBs " Michal Pecio
2026-10-29  7:23                             ` sashiko-bot
2026-10-29  6:56                           ` [PATCH 3/4] usb: xhci: Give back URBs on halted " Michal Pecio
2026-10-29  7:19                             ` sashiko-bot
2026-10-29  6:57                           ` [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices Michal Pecio
2026-10-29  7:24                             ` sashiko-bot
2026-10-29  4:18                       ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Yiyu Zhou
2026-10-27 10:58             ` [REGRESSION] usbhid -110 timeouts and reset loop for Keychron M5 (3434:d068) at boot since v7.3 Michal Pecio
2026-10-26  9:18       ` Mathias Nyman
2026-10-26  9:51         ` Michal Pecio
2026-10-26 11:38           ` Michal Pecio
2026-10-26 11:54             ` Mathias Nyman
2026-10-26 18:56           ` Alan Stern
2026-10-26 18:58             ` Alan Stern
2026-10-25  6:28 ` Greg KH

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=20261027192128.386082-2-mathias.nyman@linux.intel.com \
    --to=mathias.nyman@linux.intel.com \
    --cc=dennis@dsine.de \
    --cc=diogochaves@me.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=michal.pecio@gmail.com \
    --cc=raoxu@uniontech.com \
    --cc=regressions@lists.linux.dev \
    --cc=yiyu@yiyuzhou.io \
    /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