All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Michal Pecio" <michal.pecio@gmail.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH 4/4] usb: xhci: Reject URBs to disconnected devices
Date: Thu, 29 Oct 2026 07:24:45 +0000	[thread overview]
Message-ID: <sashiko-outbox-188861@kernel.org> (raw)
In-Reply-To: <20261029075706.69aaa77f.michal.pecio@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] usb: xhci: stale rhub_port state in xhci_urb_enqueue() rejects valid URBs
--

commit 3e6930cee6e8275b8d271ab4827ba5004d45037f
Author: Michal Pecio <michal.pecio@gmail.com>

usb: xhci: Reject URBs to disconnected devices

This commit extends the port link error check in xhci_urb_enqueue() to also
reject URBs with -ENODEV when the root hub port is marked disconnected or the
endpoint has EP_DROP_PENDING set.

> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index a9e47e178c280..4a893a8438c3a 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 ||
> +	    !xhci->devs[slot_id]->rhub_port->connected || *ep_state & EP_DROP_PENDING) {
> +		xhci_dbg(xhci, "Can't queue urb, link error or disconnected\n");
> +		ret = -ENODEV;
> +		goto free_priv;
> +	}

[Severity: High]
Can rhub_port->connected, rhub_port->link_inactive, or EP_DROP_PENDING remain
stale here and cause xhci_urb_enqueue() to reject valid URBs (including EP0
control transfers) during device reset, resuscitation, resume, or enumeration?

Across the xHCI driver, port->connected and port->link_inactive are only
updated in drivers/usb/host/xhci-ring.c:handle_port_status() when a hardware
TRB_PORT_STATUS event is received while PORT_RESET is not set:

drivers/usb/host/xhci-ring.c:handle_port_status() {
	...
	if (!(portsc & PORT_RESET)) {
		port->link_inactive = (pls == XDEV_INACTIVE);
		port->connected = !!(portsc & PORT_CONNECT);
	}
	...
	/*
	 * xHCI port-status-change events occur when the "or" of all the
	 * status-change bits in the portsc register changes from 0 to 1.
	 * New status changes won't cause an event if any other change
	 * bits are still set.  When an event occurs, switch over to
	 * polling to avoid losing status changes.
	 */
}

Neither xhci_get_port_status(), xhci_clear_port_change_bit(), nor
xhci_discover_or_reset_device() updates port->connected or
port->link_inactive:

drivers/usb/host/xhci-hub.c:xhci_get_port_status() {
	...
	/* common wPortStatus bits */
	if (portsc & PORT_CONNECT) {
		status |= USB_PORT_STAT_CONNECTION;
		status |= xhci_port_speed(portsc);
	}
}

drivers/usb/host/xhci.c:xhci_discover_or_reset_device() {
	...
command_cleanup:
	for (i = 0; i < EP_CTX_PER_DEV; i++)
		virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING;
}

When a disconnect (PORT_CSC = 1, PORT_CONNECT = 0) or link error (PORT_PLC = 1,
pls = XDEV_INACTIVE) occurs, handle_port_status() sets port->connected = 0 or
port->link_inactive = 1, leaves the status-change bits set in PORTSC, and
switches the roothub to polling. Because the xHC only generates a
TRB_PORT_STATUS event when the logical OR of all PORTSC status-change bits
transitions from 0 to 1, subsequent transitions back to PORT_CONNECT = 1 or
XDEV_U0 will not generate a new TRB_PORT_STATUS event while any change bit
remains set in PORTSC.

This appears to leave rhub_port state (or EP_DROP_PENDING) stale in several
paths:

1. Device reset or resuscitation across a disconnect or link error via
usb_reset_device() -> usb_reset_and_verify_device() -> hub_port_init() ->
hub_port_reset(), where port_dev->status_lock is held so port_event() cannot
clear PORT_CSC or PORT_PLC. On USB3 root ports, PORT_CSC or PORT_PLC stays set
throughout the reset, suppressing TRB_PORT_STATUS when the device reconnects
and reset completes. On USB2 root ports, if the first reset completes while
PORT_CSC is set, hub_port_wait_reset() clears only C_CONNECTION and returns
-EAGAIN without clearing C_RESET (PORT_RC), so PORT_RC stays set throughout
the retry reset and suppresses TRB_PORT_STATUS when the retry completes.
Although xhci_discover_or_reset_device() clears EP_DROP_PENDING,
rhub_port->connected remains 0 (or link_inactive remains 1), causing
get_bMaxPacketSize0() or usb_get_device_descriptor() in hub_port_init() to
fail with -ENODEV.

2. Delayed connection after reset completion in
drivers/usb/core/hub.c:hub_port_wait_reset():

drivers/usb/core/hub.c:hub_port_wait_reset() {
	...
		if (!(portstatus & USB_PORT_STAT_RESET) &&
		    (portstatus & USB_PORT_STAT_CONNECTION))
			break;
}

If PORT_RESET clears (setting PORT_RC = 1) before PORT_CONNECT is asserted,
handle_port_status() runs on the PORT_RC event while PORT_CONNECT is 0 and
sets port->connected = 0. When PORT_CONNECT subsequently becomes 1 while
PORT_RC is still set, no new TRB_PORT_STATUS event fires.

3. Connect bounce during hub_port_debounce(): a bounce disconnect sets
PORT_CSC = 1 (and/or PORT_PLC = 1) and port->connected = 0. If the port
reconnects during the debounce sleep while PORT_CSC is still 1, no
TRB_PORT_STATUS event fires on reconnect, and hub_port_debounce() clears
C_CONNECTION while leaving port->connected == 0.

4. Status change during active reset: if PORT_CSC or PORT_PLC becomes 1 while
PORT_RESET is active, TRB_PORT_STATUS fires while (portsc & PORT_RESET) is
true, so handle_port_status() skips updating port->connected and
port->link_inactive, and the uncleared change bit suppresses the event when
PORT_RESET clears.

5. USB3 resuscitation without a port reset in
drivers/usb/core/hub.c:hub_port_connect_change(), or transient disconnect
during wait_for_connected() in usb_port_resume():

drivers/usb/core/hub.c:hub_port_connect_change() {
	...
		if (portstatus & USB_PORT_STAT_ENABLE) {
			/*
			 * USB-3 connections are initialized automatically by
			 * the hostcontroller hardware. Therefore check for
			 * changed device descriptors before resuscitating the
			 * device.
			 */
			descr = usb_get_device_descriptor(udev);
}

If a USB3 device briefly disconnects (setting PORT_CSC = 1,
port->connected = 0, and EP_DROP_PENDING on halted/stopped endpoints) and
reconnects to U0 while PORT_CSC is still 1, no second TRB_PORT_STATUS event
fires. When hub_port_connect_change() or finish_port_resume() then submits EP0
control URBs without calling xhci_discover_or_reset_device(), won't
xhci_urb_enqueue() reject them with -ENODEV due to stale
rhub_port->connected == 0 or stale EP_DROP_PENDING on EP0?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261029075409.4b203658.michal.pecio@gmail.com?part=4

  reply	other threads:[~2026-10-29  7:24 UTC|newest]

Thread overview: 43+ 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                       ` [RFT PATCH 1/2] xhci: give back all TDs when skipping endpoint reset after disconnect Mathias Nyman
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-29 14:07                         ` Mathias Nyman
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 [this message]
2026-10-29  4:18                       ` [RFT PATCH 0/2] xhci: clean up endpoint rings after disconnect detect Yiyu Zhou
2026-10-29 13:15                         ` Mathias Nyman
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=sashiko-outbox-188861@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=michal.pecio@gmail.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.