All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Pengfei Lv" <lvpengfei20@huawei.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v2] usb: core: hub: Re-guess ep0 maxpacket size on reset
Date: Fri, 06 Nov 2026 03:34:55 +0000	[thread overview]
Message-ID: <sashiko-outbox-200650@kernel.org> (raw)
In-Reply-To: <20261106031625.1824732-1-lvpengfei20@huawei.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] usb: core: hub: usb_ep0_reinit() on unaddressed xHCI slot in hub_port_init()
--

commit d0ddaa8105de736e42e89c86a81968c860e72871
Author: Pengfei Lv <lvpengfei20@huawei.com>

usb: core: hub: Re-guess ep0 maxpacket size on reset

This commit removes the initial guard around the ep0 maxpacket size guess in
hub_port_init() and calls usb_ep0_reinit() on reset so that full-speed devices
with bMaxPacketSize0 < 64 have their ep0 maxpacket reset to 64 in both USB
core and the xHCI ep0 context before re-enumeration issues a 64-byte
GET_DESCRIPTOR request.

> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 199d3f535a891..a6c260d390945 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -4969,33 +4969,34 @@ 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;
>  	}
>  
> +	if (!initial)
> +		usb_ep0_reinit(udev);

[Severity: Medium]
Can calling usb_ep0_reinit(udev) here before hub_enable_device() or
hub_set_address() trigger an invalid Evaluate Context command when the xHCI
slot has been newly allocated during reset?

Earlier in drivers/usb/core/hub.c:hub_port_init(), hub_port_reset() invokes
hcd->driver->reset_device(), which resolves to
drivers/usb/host/xhci.c:xhci_discover_or_reset_device(). When the xHCI slot
was freed and reallocated via xhci_alloc_dev() (for example on Etron hosts
with XHCI_ETRON_HOST, or after host controller power loss / reset on resume),
the newly allocated virt_dev has a zeroed out_ctx in SLOT_STATE_DISABLED
because Address Device (xhci_setup_device()) has not run yet:

drivers/usb/host/xhci.c:xhci_discover_or_reset_device() {
	...
	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
	if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
						SLOT_STATE_DISABLED)
		return 0;

	if (xhci->quirks & XHCI_ETRON_HOST) {
		ret = xhci_disable_and_free_slot(xhci, udev->slot_id);
		if (!ret) {
			ret = xhci_alloc_dev(hcd, udev);
	...
}

When usb_ep0_reinit(udev) is then called for a full-speed device via
usb_enable_endpoint() -> usb_hcd_reset_endpoint() -> xhci_endpoint_reset() ->
xhci_check_ep0_maxpacket(), neither xhci_endpoint_reset() nor
xhci_check_ep0_maxpacket() checks whether vdev->out_ctx is still in
SLOT_STATE_DISABLED:

drivers/usb/host/xhci.c:xhci_check_ep0_maxpacket() {
	...
	ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, 0);
	hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
	max_packet_size = usb_endpoint_maxp(&vdev->udev->ep0.desc);

	if (hw_max_packet_size == max_packet_size)
		return 0;
	...
}

Because vdev->out_ctx is still zeroed, hw_max_packet_size is 0 != 64, so
xhci_check_ep0_maxpacket() copies the zeroed out_ctx ep0 into in_ctx ep0 and
issues an Evaluate Context command on an unaddressed slot in the Enabled
state, which the xHC rejects with COMP_CONTEXT_STATE_ERROR (logging a warning
in xhci_evaluate_context_result()).

Furthermore, if a previous attempt in xhci_setup_device() failed with
COMP_USB_TRANSACTION_ERROR, it reallocates the slot via xhci_alloc_dev() and
calls xhci_setup_addressable_virt_dev(xhci, udev), which populates
vdev->in_ctx (including setting slot_ctx->dev_info and initializing in_ctx
ep0) while vdev->out_ctx remains zeroed. If hub_port_init() retries and calls
usb_ep0_reinit(udev) before the next xhci_setup_device(),
xhci_check_ep0_maxpacket() overwrites vdev->in_ctx ep0 from the zeroed
vdev->out_ctx while leaving slot_ctx->dev_info non-zero:

drivers/usb/host/xhci.c:xhci_setup_device() {
	...
	if (!slot_ctx->dev_info)
		xhci_setup_addressable_virt_dev(xhci, udev);
	/* Otherwise, update the control endpoint ring enqueue pointer. */
	else
		xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
	...
}

Wouldn't xhci_setup_device() then skip xhci_setup_addressable_virt_dev() and
submit Address Device with a zeroed ep0 context (EP_TYPE == 0)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261106031625.1824732-1-lvpengfei20@huawei.com?part=1

  reply	other threads:[~2026-11-06  3:34 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 12:44 [PATCH] usb: core: hub: Re-guess ep0 maxpacket size on reset Pengfei Lv
2026-11-04 12:57 ` sashiko-bot
2026-11-04 14:59 ` Alan Stern
2026-11-04 17:36   ` Michal Pecio
2026-11-05  5:06     ` Alan Stern
2026-11-05 12:30       ` Michal Pecio
2026-11-05  8:41 ` Pengfei Lv
2026-11-05 15:46   ` Alan Stern
2026-11-06  3:16 ` [PATCH v2] " Pengfei Lv
2026-11-06  3:34   ` sashiko-bot [this message]
2026-11-06 22:01     ` Michal Pecio
2026-11-06  7:17   ` 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=sashiko-outbox-200650@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=lvpengfei20@huawei.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.