mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Pengfei Lv <lvpengfei20@huawei.com>
To: <gregkh@linuxfoundation.org>
Cc: <stern@rowland.harvard.edu>, <linux-usb@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <stable@vger.kernel.org>,
	<xuhaiyang5@hisilicon.com>, <xuetao09@huawei.com>,
	<caiyadong@huawei.com>, <suzhuangluan@hisilicon.com>,
	Pengfei Lv <lvpengfei20@huawei.com>
Subject: [PATCH] usb: core: hub: Re-guess ep0 maxpacket size on reset
Date: Wed, 4 Nov 2026 20:44:02 +0800	[thread overview]
Message-ID: <20261104124402.1269650-1-lvpengfei20@huawei.com> (raw)

Per USB 2.0 spec section 5.5.3, the ep0 maxpacket size is fixed for
all device speeds except full-speed devices, where it can be 8, 16,
32, or 64 bytes and can only be determined by reading the device
descriptor.  During the initial enumeration of a full-speed device,
the USB core guesses 64 bytes (hub_port_init() with initial=true);
after reading the descriptor, the real value (e.g. 8) is stored in
udev->ep0.desc.wMaxPacketSize and propagated to the xHCI ep0 context
via an Evaluate Context command (xhci_check_maxpacket()).

After a port reset (usb_reset_and_verify_device() -> hub_port_init()
with initial=false), the "if (initial)" guard added by commit
ff33299ec8bb ("USB: core: Fix race by not overwriting udev->descriptor in hub_port_init()") skips the ep0 maxpacket
guess block, so udev->ep0.desc.wMaxPacketSize retains the real value
(e.g. 8).  The xHCI Reset Device command preserves the ep0 context
as well, so the xHC ep0 max_packet also stays at 8.

When the subsequent re-enumeration then uses the "new scheme" and
issues a 64-byte GET_DESCRIPTOR (get_bMaxPacketSize0 with size=64),
xhci_check_maxpacket() sees hw==sw==8 and does not issue an Evaluate
Context command.  The xHC queues a Data TRB of length 64 but applies
ep0 max_packet=8 for short-packet detection.  If the device's first
data packet is exactly 8 bytes and it sends no ZLP, the xHC does not
recognise a short packet, keeps issuing IN tokens for the remaining
56 bytes, and the control transfer hangs in the Data stage until URB
timeout.  (A standard 18-byte descriptor returned as 8+8+2 is not
affected because the final 2-byte packet is a short packet.)

Fix this by removing the "if (initial)" guard so that the ep0
maxpacket size is re-guessed from udev->speed on every reset.  For
full-speed devices this re-establishes the 64-byte guess, which makes
xhci_check_maxpacket() issue an Evaluate Context command that brings
the xHC ep0 context back to max_packet=64 before the GET_DESCRIPTOR
data stage; the data stage then terminates correctly via short-packet
detection, and the ep0 maxpacket is subsequently corrected to the
real value as usual.

For high-speed, low-speed, and SuperSpeed-or-faster devices the
re-guess is a no-op (guessed value equals the fixed real value).
The descriptor-immutability checks (!initial && maxp0 !=
udev->descriptor.bMaxPacketSize0) remain unchanged.

Fixes: ff33299ec8bb ("USB: core: Fix race by not overwriting udev->descriptor in hub_port_init()")
Cc: stable@vger.kernel.org
Signed-off-by: Pengfei Lv <lvpengfei20@huawei.com>
---
 drivers/usb/core/hub.c | 46 ++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 199d3f535a89..51f66b24b353 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4969,31 +4969,29 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
 	}
 	oldspeed = udev->speed;
 
-	if (initial) {
-		/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
-		 * it's fixed size except for full speed devices.
+	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
+	 * it's fixed size except for full speed devices.
+	 */
+	switch (udev->speed) {
+	case USB_SPEED_SUPER_PLUS:
+	case USB_SPEED_SUPER:
+		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
+		break;
+	case USB_SPEED_HIGH:		/* fixed at 64 */
+		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
+		break;
+	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
+		/* to determine the ep0 maxpacket size, try to read
+		 * the device descriptor to get bMaxPacketSize0 and
+		 * then correct our initial guess.
 		 */
-		switch (udev->speed) {
-		case USB_SPEED_SUPER_PLUS:
-		case USB_SPEED_SUPER:
-			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
-			break;
-		case USB_SPEED_HIGH:		/* fixed at 64 */
-			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
-			break;
-		case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
-			/* to determine the ep0 maxpacket size, try to read
-			 * the device descriptor to get bMaxPacketSize0 and
-			 * then correct our initial guess.
-			 */
-			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
-			break;
-		case USB_SPEED_LOW:		/* fixed at 8 */
-			udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
-			break;
-		default:
-			goto fail;
-		}
+		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
+		break;
+	case USB_SPEED_LOW:		/* fixed at 8 */
+		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
+		break;
+	default:
+		goto fail;
 	}
 
 	speed = usb_speed_string(udev->speed);
-- 
2.34.1


             reply	other threads:[~2026-11-04 12:44 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 12:44 Pengfei Lv [this message]
2026-11-04 14:59 ` Alan Stern
2026-11-04 17:36   ` 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=20261104124402.1269650-1-lvpengfei20@huawei.com \
    --to=lvpengfei20@huawei.com \
    --cc=caiyadong@huawei.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    --cc=suzhuangluan@hisilicon.com \
    --cc=xuetao09@huawei.com \
    --cc=xuhaiyang5@hisilicon.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

all inboxes | Powered by JetHome®