mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Michal Pecio <michal.pecio@gmail.com>
To: Pawel Laszczak via B4 Relay <devnull+pawell.cadence.com@kernel.org>
Cc: pawell@cadence.com,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mathias Nyman <mathias.nyman@intel.com>,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
Date: Wed, 7 Oct 2026 12:30:47 +0200	[thread overview]
Message-ID: <20261007123047.697f6b5a.michal.pecio@gmail.com> (raw)
In-Reply-To: <20261005-eusb2v2-packet-size-v3-1-fde610a3c47a@cadence.com>

On Mon, 05 Oct 2026 10:18:24 +0200, Pawel Laszczak via B4 Relay wrote:
> From: Pawel Laszczak <pawell@cadence.com>
> 
> The eUSB2 v2 specification (bcdUSB 0x0230) introduces support for
> 1024-byte maximum packet sizes for Bulk endpoints in High-Speed mode.
> However, an eUSB2v2 peripheral will revert its internal maximum packet
> size back to 512 bytes after events like a bus reset, disconnect, or
> deconfiguration.
> 
> To support 1024-byte bulk transfers on capable hosts, add a new
> is_eusb2v2 flag to the usb_bus structure, populated via the HCCPARAMS2
> E2V2C capability bit in the xHCI driver.
> 
> When an eUSB2v2 host configures an eUSB2v2 device, issue a specific
> SET_FEATURE (USB_DEVICE_BULK_MAX_PACKET_UPDATE) request during device
> configuration to switch the peripheral to 1024-byte packet mode, and
> allow the xHCI endpoint initialization to accept up to 1024 bytes for
> HS bulk endpoints.
> 
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> ---
> Changes in v3:
> - Add check for bulk endpoint existence before sending
>   BULK_MAX_PACKET_UPDATE. This avoids sending the request to devices that
>   only use isochronous endpoints, as they do not support it.
> - Do not overwrite ep->desc.wMaxPacketSize to 1024. According to eUSB2v2
>   spec section 5.2, the endpoint descriptor must always report 512 bytes
>   regardless of the current operating mode.
> - Rely on the eusb2v2_mps_active flag in xhci_usb_endpoint_maxp() and
>   xhci-mem.c to dynamically return 1024 for HS bulk endpoints when the 1KB
>   mode is active.
> 
> Changes in v2:
> - Removed change in config.c: per eUSB2v2 spec section 5.2, conformant
>   devices always report wMaxPacketSize=512 in their descriptor regardless
>   of operating mode, so the warning suppression was unnecessary.
> - xhci-mem.c: simplified HS bulk clamp
> - xhci.c: moved is_eusb2v2 assignment into xhci_hcd_init_usb2_data()
> - eusb_update_max_packet(): changed from void to int; returns error on
>   SET_FEATURE failure.
> - Added eusb2v2_mps_active flag to struct usb_device to track whether
>   SET_FEATURE(BULK_MAX_PACKET_UPDATE) succeeded.
> - Added hub.c: usb_reset_and_verify_device() now re-issues SET_FEATURE
>   after bus reset to restore 1KB mode. Failure triggers re-enumeration
>   to prevent a driver from operating with inconsistent MPS state.
> ---
>  drivers/usb/core/hub.c      | 16 ++++++++++
>  drivers/usb/core/message.c  | 74 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/core/usb.h      |  2 ++
>  drivers/usb/host/xhci-mem.c | 15 +++++++--
>  drivers/usb/host/xhci.c     | 10 ++++++
>  include/linux/usb.h         |  7 +++++
>  6 files changed, 121 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 24960ba9caa9..34cfc44c5df8 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -6252,6 +6252,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
>  		mutex_unlock(hcd->bandwidth_mutex);
>  		goto re_enumerate;
>  	}
> +
> +	/*
> +	 * Restore eUSB2v2 1KB bulk mode after reset (device reverts to 512
> +	 * after any bus reset per eUSB2v2 spec section 5.2).
> +	 * Only retry if the initial SET_FEATURE had succeeded.
> +	 */
> +	if (udev->eusb2v2_mps_active) {
> +		ret = eusb_update_max_packet(udev, udev->actconfig);
> +		if (ret < 0) {
> +			dev_err(&udev->dev,
> +				"eUSB2v2: failed to restore 1KB mode after reset (%d)\n", ret);

This seems redundant because the function already logs errors.
Or maybe the function shouldn't log them, if we want different
messages for different call sites?

> +			mutex_unlock(hcd->bandwidth_mutex);
> +			goto re_enumerate;
> +		}
> +	}
> +
>  	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
>  			USB_REQ_SET_CONFIGURATION, 0,
>  			udev->actconfig->desc.bConfigurationValue, 0,
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 75e2bfd744a9..c8540d738a3e 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -2007,6 +2007,71 @@ int usb_set_wireless_status(struct usb_interface *iface,
>  }
>  EXPORT_SYMBOL_GPL(usb_set_wireless_status);
>  
> +/*
> + * eusb_update_max_packet - enable 1024-byte bulk mode for eUSB2v2 device
> + * @udev: target device
> + * @cp: configuration to be checked and enabled
> + *
> + * Per eUSB2v2 spec section 5.2, an eUSB2v2 peripheral will revert the
> + * maximum packet size to 512 for bulk endpoints after bus reset, disconnect,
> + * or deconfiguration.
> + * This function sends the BULK_MAX_PACKET_UPDATE request to restore the
> + * 1024-byte mode. It is valid only if the configuration has bulk endpoints.
> + */
> +int eusb_update_max_packet(struct usb_device *udev, struct usb_host_config *cp)
> +{
> +	struct usb_host_config *config = cp ? cp : udev->actconfig;
> +	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
> +	struct usb_interface_cache *intfc;
> +	struct usb_host_interface *alt;
> +	struct usb_host_endpoint *ep;
> +	bool has_bulk = false;
> +	int i, j, a;
> +	int ret;
> +
> +	if (le16_to_cpu(udev->descriptor.bcdUSB) != 0x0230 ||
> +	    !hcd->self.is_eusb2v2)
> +		return 0;
> +
> +	if (!config)
> +		return 0;
> +
> +	for (i = 0; i < config->desc.bNumInterfaces; i++) {
> +		intfc = config->intf_cache[i];
> +
> +		if (!intfc)
> +			continue;
> +
> +		for (a = 0; a < intfc->num_altsetting; a++) {
> +			alt = &intfc->altsetting[a];
> +
> +			for (j = 0; j < alt->desc.bNumEndpoints; j++) {
> +				ep = &alt->endpoint[j];
> +
> +				if (usb_endpoint_xfer_bulk(&ep->desc)) {
> +					has_bulk = true;
> +					goto found_bulk;
> +				}
> +			}
> +		}
> +	}
> +
> +	if (!has_bulk)
> +		return 0;

Control flow ensures that has_bulk is false here and true below.
The variable is redundant.

> +found_bulk:
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
> +			      USB_DEVICE_BULK_MAX_PACKET_UPDATE, 0, NULL, 0,
> +			      USB_CTRL_SET_TIMEOUT);
> +	if (ret < 0) {
> +		dev_warn(&udev->dev, "eUSB2v2 1KB update failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  /*
>   * usb_set_configuration - Makes a particular device setting be current
>   * @dev: the device whose configuration is being updated
> @@ -2123,6 +2188,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
>  	if (dev->state != USB_STATE_ADDRESS)
>  		usb_disable_device(dev, 1);	/* Skip ep0 */
>  
> +	ret = eusb_update_max_packet(dev, cp);
> +	if (ret < 0)
> +		dev->eusb2v2_mps_active = 0;
> +	else if (cp && le16_to_cpu(dev->descriptor.bcdUSB) == 0x0230 &&
> +		 hcd->self.is_eusb2v2)

Hmm, this code could be simpler if the function returned errors on
unsupported devices or host controllers. Would that cause problems
with anything?

> +		dev->eusb2v2_mps_active = 1;
> +	else
> +		dev->eusb2v2_mps_active = 0;
> +
>  	/* Get rid of pending async Set-Config requests for this device */
>  	cancel_async_set_config(dev);
>  
> diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
> index a9b37aeb515b..c51e4261085c 100644
> --- a/drivers/usb/core/usb.h
> +++ b/drivers/usb/core/usb.h
> @@ -89,6 +89,8 @@ extern int usb_major_init(void);
>  extern void usb_major_cleanup(void);
>  extern int usb_device_supports_lpm(struct usb_device *udev);
>  extern int usb_port_disable(struct usb_device *udev);
> +int eusb_update_max_packet(struct usb_device *udev,
> +			   struct usb_host_config *cp);
>  
>  #ifdef	CONFIG_PM
>  
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index 997fe90f54e5..37a5f9e9bd6d 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -1479,10 +1479,19 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
>  	/* Allow 3 retries for everything but isoc, set CErr = 3 */
>  	if (!usb_endpoint_xfer_isoc(&ep->desc))
>  		err_count = 3;
> -	/* HS bulk max packet should be 512, FS bulk supports 8, 16, 32 or 64 */
> +
> +	/*
> +	 * HS bulk max packet should be 512 (or 1024 for eUSB2v2),
> +	 * FS bulk supports 8, 16, 32 or 64.
> +	 */
>  	if (usb_endpoint_xfer_bulk(&ep->desc)) {
> -		if (udev->speed == USB_SPEED_HIGH)
> -			max_packet = 512;
> +		if (udev->speed == USB_SPEED_HIGH) {
> +			if (udev->eusb2v2_mps_active)
> +				max_packet = 1024;
> +			else
> +				max_packet = 512;
> +		}
> +
>  		if (udev->speed == USB_SPEED_FULL) {
>  			max_packet = rounddown_pow_of_two(max_packet);
>  			max_packet = clamp_val(max_packet, 8, 64);
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index a54f5b57f205..b4a3bdf88fb4 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -2951,6 +2951,12 @@ int xhci_usb_endpoint_maxp(struct usb_device *udev,
>  {
>  	if (usb_endpoint_is_hs_isoc_double(udev, host_ep))
>  		return le16_to_cpu(host_ep->eusb2_isoc_ep_comp.wMaxPacketSize);
> +
> +	if (udev->eusb2v2_mps_active &&
> +	    udev->speed == USB_SPEED_HIGH &&
> +	    usb_endpoint_xfer_bulk(&host_ep->desc))
> +		return 1024;

Is the check for USB_SPEED_HIGH necessary?
Is eusb2v2_mps_active supposed to be set at other speeds?

One tricky edge case is a high-speed device failing to restore
high-speed signaling after reset, but at a quick glance this seems
to result in hub_port_init() error and abort of the reset flow.

> +
>  	return usb_endpoint_maxp(&host_ep->desc);
>  }
>  
> @@ -5371,6 +5377,10 @@ static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
>  	xhci->usb2_rhub.hcd = hcd;
>  	hcd->speed = HCD_USB2;
>  	hcd->self.root_hub->speed = USB_SPEED_HIGH;
> +
> +	if (xhci->hcc_params2 & HCC2_E2V2C)
> +		hcd->self.is_eusb2v2 = 1;
> +
>  	/*
>  	 * USB 2.0 roothub under xHCI has an integrated TT,
>  	 * (rate matching hub) as opposed to having an OHCI/UHCI
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 25a203ac7a7e..57fb4c552740 100644
> --- a/include/linux/usb.h
> +++ b/include/linux/usb.h
> @@ -464,6 +464,10 @@ struct usb_bus {
>  					 * the ep queue on a short transfer
>  					 * with the URB_SHORT_NOT_OK flag set.
>  					 */
> +	unsigned is_eusb2v2:1;		/*
> +					 * true when HC controller supports
> +					 * eusb2v2
> +					 */
>  	unsigned no_sg_constraint:1;	/* no sg constraint */
>  	unsigned sg_tablesize;		/* 0 or largest number of sg list entries */
>  
> @@ -625,6 +629,8 @@ struct usb3_lpm_parameters {
>   * @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled
>   * @usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled
>   * @usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled
> + * @eusb2v2_mps_active: 1024-byte bulk mode is active and must be restored
> + *	 after bus reset.
>   * @string_langid: language ID for strings
>   * @product: iProduct string, if present (static)
>   * @manufacturer: iManufacturer string, if present (static)
> @@ -708,6 +714,7 @@ struct usb_device {
>  	unsigned usb2_hw_lpm_allowed:1;
>  	unsigned usb3_lpm_u1_enabled:1;
>  	unsigned usb3_lpm_u2_enabled:1;
> +	unsigned eusb2v2_mps_active:1;
>  	int string_langid;
>  
>  	/* static strings from the device */
> 
> -- 
> 2.43.0
> 
> 

  reply	other threads:[~2026-10-07 10:30 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05  8:18 [PATCH v3 0/3] usb: Add support for eUSB2v2 1024-byte Bulk MaxPacketSize Pawel Laszczak via B4 Relay
2026-10-05  8:18 ` [PATCH v3 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size Pawel Laszczak via B4 Relay
2026-10-07 10:30   ` Michal Pecio [this message]
2026-10-08  6:58     ` Pawel Laszczak
2026-10-05  8:18 ` [PATCH v3 2/3] usb: gadget: composite: Support eUSB2v2 bulk MPS update Pawel Laszczak via B4 Relay
2026-10-05  8:18 ` [PATCH v3 3/3] usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability Pawel Laszczak via B4 Relay

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=20261007123047.697f6b5a.michal.pecio@gmail.com \
    --to=michal.pecio@gmail.com \
    --cc=devnull+pawell.cadence.com@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=pawell@cadence.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®