Linux USB
 help / color / mirror / Atom feed
From: Henry Tseng <henrytseng@qnap.com>
To: Mathias Nyman <mathias.nyman@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-usb@vger.kernel.org, Henry Tseng <henrytseng@qnap.com>
Subject: [PATCH 2/2] xhci: skip configure endpoint when dropping endpoints of a disconnected device
Date: Wed, 30 Sep 2026 18:17:52 +0800	[thread overview]
Message-ID: <20260930101752.15794-3-henrytseng@qnap.com> (raw)
In-Reply-To: <20260930101752.15794-1-henrytseng@qnap.com>

When a USB device is disconnected, its endpoints are dropped with a
configure endpoint command, immediately followed by a disable slot
command for the same slot.

Per xHCI 1.2b section 4.8.3 that configure endpoint transitions the
dropped endpoints to the Disabled state, and the following disable slot
transitions all endpoints of the slot to Disabled. The dropped
endpoints end up Disabled either way, so skipping the configure
endpoint does not change the outcome.

xhci_check_bandwidth() already returns -ENODEV without issuing the
command when the host is dying or being removed, and teardown then
continues to disable slot in xhci_free_dev(). Add the case of the
device's roothub port being disconnected or its link being inactive to
that condition, using the port state tracked since commit 042aad8d0db6
("xhci: prevent endpoint recovery after roothub disconnect"). Device
disconnect then follows the same path as host removal. The caller runs
xhci_reset_bandwidth() on -ENODEV, and the rings of the dropped
endpoints are freed by xhci_free_virt_device() after disable slot.

On an AMD Raven USB 3.1 xHCI (1022:15e0), unplugging a USB device
sometimes leaves the configure endpoint command incomplete. The command
ring abort then fails too, and the host is declared dead, taking
unrelated devices on other root ports with it:

  [   80.928319] usb 2-1: USB disconnect, device number 3
  [   80.939654] xhci_hcd 0000:0c:00.3: drop ep 0x83, slot id 5, new drop flags = 0x80, new add flags = 0x0
  [   86.086412] xhci_hcd 0000:0c:00.3: Command timeout, USBSTS: 0x00000010 PCD
  [  101.924383] xhci_hcd 0000:0c:00.3: Abort failed to stop command ring: -110
  [  101.936213] xhci_hcd 0000:0c:00.3: xHCI host controller not responding, assume dead
  [  101.937662] xhci_hcd 0000:0c:00.3: Timeout while waiting for configure endpoint command

With this change the same slot 5 drop returns immediately. Teardown
continues and the port 2-1 device is unregistered with the host still
alive:

  [  114.356084] usb 2-1: USB disconnect, device number 3
  [  114.356982] xhci_hcd 0000:0c:00.3: drop ep 0x83, slot id 5, new drop flags = 0x80, new add flags = 0x0
  [  114.357675] xhci_hcd 0000:0c:00.3: drop ep 0x81, slot id 6, new drop flags = 0x8, new add flags = 0x0
  ...
  [  114.564127] usb 2-1: unregistering device

Signed-off-by: Henry Tseng <henrytseng@qnap.com>
---
 drivers/usb/host/xhci.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8169d30dd40e..3d701d0fd3df 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3088,6 +3088,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 	struct xhci_input_control_ctx *ctrl_ctx;
 	struct xhci_slot_ctx *slot_ctx;
 	struct xhci_command *command;
+	struct xhci_port *rhub_port;
 
 	ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
 	if (ret <= 0)
@@ -3099,6 +3100,15 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 
 	xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
 	virt_dev = xhci->devs[udev->slot_id];
+	rhub_port = virt_dev->rhub_port;
+
+	/*
+	 * Skip configure endpoint if the roothub port is gone or its link
+	 * is inactive. Some hosts stop completing endpoint commands after
+	 * disconnect, wedging the command ring.
+	 */
+	if (rhub_port->link_inactive || !rhub_port->connected)
+		return -ENODEV;
 
 	command = xhci_alloc_command(xhci, true, GFP_KERNEL);
 	if (!command)
-- 
2.43.0


  parent reply	other threads:[~2026-09-30 10:18 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30 10:17 [PATCH 0/2] xhci: handshake timeout overrun and configure endpoint hang on device disconnect Henry Tseng
2026-09-30 10:17 ` [PATCH 1/2] xhci: make xhci_handshake() timeout wall-clock based again Henry Tseng
2026-09-30 10:17 ` Henry Tseng [this message]
2026-10-02  9:30 ` [PATCH 0/2] xhci: handshake timeout overrun and configure endpoint hang on device disconnect Michal Pecio
2026-10-07  9:52   ` Henry Tseng
2026-10-08  9:06     ` Michal Pecio
2026-10-08  9:13       ` Michal Pecio
2026-10-08 10:25       ` Henry Tseng

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=20260930101752.15794-3-henrytseng@qnap.com \
    --to=henrytseng@qnap.com \
    --cc=gregkh@linuxfoundation.org \
    --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