All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] usb: Add support for eUSB2v2 1024-byte Bulk MaxPacketSize
@ 2026-07-17 10:44 ` Pawel Laszczak
  0 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak via B4 Relay @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

The Embedded USB2 (eUSB2) v2 specification (bcdUSB 0x0230) introduces a
mechanism that allows High-Speed Bulk endpoints to support a maximum packet
size (MPS) of 1024 bytes, expanding it from the traditional 512-byte limit
defined in the standard USB 2.0 specification. This capability is highly
beneficial for Mass Storage Class (MSC) devices, significantly improving
overall throughput.

Per the eUSB2v2 specification, a peripheral device will revert its internal
Bulk MPS back to 512 bytes after major bus events, including a bus reset,
disconnect, or deconfiguration. To establish and maintain the 1024-byte mode,
the host controller must explicitly issue a device-recipient SET_FEATURE
request called USB_DEVICE_BULK_MAX_PACKET_UPDATE. This must occur after the
device enters the ADDRESSED state, but strictly *before* it transitions to the
CONFIGURED state.

This patch series implements the required infrastructure on both the host and
gadget sides, and enables it for the Cadence (cdnsp) controller.

Structure of the series:
- Patch 1: Introduces host-side core support in usb_set_configuration() to
  detect eUSB2v2 devices and issue the SET_FEATURE update request prior to
  activating the device configuration. It also updates xHCI endpoint
  initialization routines to allow 1024-byte packets for High-Speed Bulk
  endpoints when the host capability bit HCC2_E2V2C is present.
  
- Patch 2: Extends the USB Gadget Composite framework to advertise bcdUSB
  0x0230 when eUSB2v2 is supported, intercept the incoming feature request,
  and dynamically update the wMaxPacketSize fields across all High-Speed
  Bulk descriptors before configuration is completed.
  
- Patch 3: Implements peripheral-specific handling in the Cadence (cdnsp)
  driver, reading HCCPARAMS2 to discover the hardware capability and adapting
  cdnsp_endpoint_init() boundaries to allow for the larger packet size.

Testing:
The flow has been validated using the Cadence eUSB2v2 Host and Device
controllers, ensuring seamless transition to 1024-byte mode during early
enumeration stages and successful verification under USB-IF Compliance
Verification (CV) tooling.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
Pawel Laszczak (3):
      usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
      usb: gadget: composite: Support eUSB2v2 bulk MPS update request
      usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability

 drivers/usb/cdns3/cdnsp-ep0.c    |  2 ++
 drivers/usb/cdns3/cdnsp-gadget.c |  4 +++
 drivers/usb/cdns3/cdnsp-gadget.h |  8 +++++
 drivers/usb/cdns3/cdnsp-mem.c    | 11 +++++--
 drivers/usb/common/debug.c       |  2 ++
 drivers/usb/core/config.c        |  4 ++-
 drivers/usb/core/message.c       | 65 +++++++++++++++++++++++++++++++++++++-
 drivers/usb/gadget/composite.c   | 67 ++++++++++++++++++++++++++++++++++++----
 drivers/usb/host/xhci-mem.c      | 18 +++++++++--
 drivers/usb/host/xhci.c          |  3 ++
 include/linux/usb.h              |  4 +++
 include/linux/usb/gadget.h       |  2 ++
 12 files changed, 177 insertions(+), 13 deletions(-)
---
base-commit: 1d52b92ce8748624f84eca7eaea3ac31ed7b09a5
change-id: 20260609-eusb2v2-packet-size-4cb668455465

Best regards,
--  
Pawel Laszczak <pawell@cadence.com>



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 0/3] usb: Add support for eUSB2v2 1024-byte Bulk MaxPacketSize
@ 2026-07-17 10:44 ` Pawel Laszczak
  0 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

The Embedded USB2 (eUSB2) v2 specification (bcdUSB 0x0230) introduces a
mechanism that allows High-Speed Bulk endpoints to support a maximum packet
size (MPS) of 1024 bytes, expanding it from the traditional 512-byte limit
defined in the standard USB 2.0 specification. This capability is highly
beneficial for Mass Storage Class (MSC) devices, significantly improving
overall throughput.

Per the eUSB2v2 specification, a peripheral device will revert its internal
Bulk MPS back to 512 bytes after major bus events, including a bus reset,
disconnect, or deconfiguration. To establish and maintain the 1024-byte mode,
the host controller must explicitly issue a device-recipient SET_FEATURE
request called USB_DEVICE_BULK_MAX_PACKET_UPDATE. This must occur after the
device enters the ADDRESSED state, but strictly *before* it transitions to the
CONFIGURED state.

This patch series implements the required infrastructure on both the host and
gadget sides, and enables it for the Cadence (cdnsp) controller.

Structure of the series:
- Patch 1: Introduces host-side core support in usb_set_configuration() to
  detect eUSB2v2 devices and issue the SET_FEATURE update request prior to
  activating the device configuration. It also updates xHCI endpoint
  initialization routines to allow 1024-byte packets for High-Speed Bulk
  endpoints when the host capability bit HCC2_E2V2C is present.
  
- Patch 2: Extends the USB Gadget Composite framework to advertise bcdUSB
  0x0230 when eUSB2v2 is supported, intercept the incoming feature request,
  and dynamically update the wMaxPacketSize fields across all High-Speed
  Bulk descriptors before configuration is completed.
  
- Patch 3: Implements peripheral-specific handling in the Cadence (cdnsp)
  driver, reading HCCPARAMS2 to discover the hardware capability and adapting
  cdnsp_endpoint_init() boundaries to allow for the larger packet size.

Testing:
The flow has been validated using the Cadence eUSB2v2 Host and Device
controllers, ensuring seamless transition to 1024-byte mode during early
enumeration stages and successful verification under USB-IF Compliance
Verification (CV) tooling.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
Pawel Laszczak (3):
      usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
      usb: gadget: composite: Support eUSB2v2 bulk MPS update request
      usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability

 drivers/usb/cdns3/cdnsp-ep0.c    |  2 ++
 drivers/usb/cdns3/cdnsp-gadget.c |  4 +++
 drivers/usb/cdns3/cdnsp-gadget.h |  8 +++++
 drivers/usb/cdns3/cdnsp-mem.c    | 11 +++++--
 drivers/usb/common/debug.c       |  2 ++
 drivers/usb/core/config.c        |  4 ++-
 drivers/usb/core/message.c       | 65 +++++++++++++++++++++++++++++++++++++-
 drivers/usb/gadget/composite.c   | 67 ++++++++++++++++++++++++++++++++++++----
 drivers/usb/host/xhci-mem.c      | 18 +++++++++--
 drivers/usb/host/xhci.c          |  3 ++
 include/linux/usb.h              |  4 +++
 include/linux/usb/gadget.h       |  2 ++
 12 files changed, 177 insertions(+), 13 deletions(-)
---
base-commit: 1d52b92ce8748624f84eca7eaea3ac31ed7b09a5
change-id: 20260609-eusb2v2-packet-size-4cb668455465

Best regards,
--  
Pawel Laszczak <pawell@cadence.com>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
  2026-07-17 10:44 ` Pawel Laszczak
@ 2026-07-17 10:44   ` Pawel Laszczak
  -1 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak via B4 Relay @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

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>
---
 drivers/usb/core/config.c   |  4 ++-
 drivers/usb/core/message.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/usb/host/xhci-mem.c | 18 ++++++++++---
 drivers/usb/host/xhci.c     |  3 +++
 include/linux/usb.h         |  4 +++
 5 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 45e20c6d76c0..0c7ab3f44cd9 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -491,7 +491,9 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
 	 * be able to handle that particular bug, so let's warn...
 	 */
 	if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
-		if (maxp != 512)
+		struct usb_hcd *hcd =  bus_to_hcd(udev->bus);
+
+		if (maxp != 512 && (bcdUSB != 0x230 || !hcd->self.is_eusb2v2))
 			dev_notice(ddev, "config %d interface %d altsetting %d "
 				"bulk endpoint 0x%X has invalid maxpacket %d\n",
 				cfgno, inum, asnum, d->bEndpointAddress,
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 75e2bfd744a9..3b4f7aedd381 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -2007,6 +2007,65 @@ int usb_set_wireless_status(struct usb_interface *iface,
 }
 EXPORT_SYMBOL_GPL(usb_set_wireless_status);
 
+/*
+ * eusb_update_max_packet - set or restore max packet size
+ * @udev: target device
+ * @cp: if NULL restore MPS to 512 else set 1024
+ *
+ * This request is specific to eUSB2v2.
+ * An eUSB2v2 peripheral will revert the maximum packet size to 512
+ * for bulk endpoints after bus reset, disconnect and deconfiguration.
+ * This function allows updating the max packet size for BULK endpoints
+ * to 1024 after above events.
+ */
+static void 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;
+	u16 mps = 512;
+	int i, j, a;
+	int ret;
+
+	if (le16_to_cpu(udev->descriptor.bcdUSB) != 0x0230 ||
+	    !hcd->self.is_eusb2v2)
+		return;
+
+	if (cp) {
+		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;
+		}
+
+		mps = 1024;
+	} else if (!udev->actconfig)
+		return;
+
+	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))
+					ep->desc.wMaxPacketSize = cpu_to_le16(mps);
+			}
+		}
+	}
+}
+
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
@@ -2120,8 +2179,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
 	/* if it's already configured, clear out old state first.
 	 * getting rid of old interfaces means unbinding their drivers.
 	 */
-	if (dev->state != USB_STATE_ADDRESS)
+	if (dev->state != USB_STATE_ADDRESS) {
+		eusb_update_max_packet(dev, NULL);
 		usb_disable_device(dev, 1);	/* Skip ep0 */
+	}
+
+	eusb_update_max_packet(dev, cp);
 
 	/* Get rid of pending async Set-Config requests for this device */
 	cancel_async_set_config(dev);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 997fe90f54e5..a4d3e03f9e14 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1479,10 +1479,22 @@ 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 (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0230 &&
+			    xhci->hcc_params2 & HCC2_E2V2C) {
+				max_packet = rounddown_pow_of_two(max_packet);
+				max_packet = clamp_val(max_packet, 512, 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..254638dc1e18 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5548,6 +5548,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	else
 		xhci_hcd_init_usb2_data(xhci, hcd);
 
+	if (xhci->hcc_params2 & HCC2_E2V2C)
+		hcd->self.is_eusb2v2 = 1;
+
 	xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
 		  xhci->hcc_params, xhci->hci_version, xhci->quirks);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 25a203ac7a7e..790c2295aec6 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 */
 

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
@ 2026-07-17 10:44   ` Pawel Laszczak
  0 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

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>
---
 drivers/usb/core/config.c   |  4 ++-
 drivers/usb/core/message.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/usb/host/xhci-mem.c | 18 ++++++++++---
 drivers/usb/host/xhci.c     |  3 +++
 include/linux/usb.h         |  4 +++
 5 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 45e20c6d76c0..0c7ab3f44cd9 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -491,7 +491,9 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
 	 * be able to handle that particular bug, so let's warn...
 	 */
 	if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
-		if (maxp != 512)
+		struct usb_hcd *hcd =  bus_to_hcd(udev->bus);
+
+		if (maxp != 512 && (bcdUSB != 0x230 || !hcd->self.is_eusb2v2))
 			dev_notice(ddev, "config %d interface %d altsetting %d "
 				"bulk endpoint 0x%X has invalid maxpacket %d\n",
 				cfgno, inum, asnum, d->bEndpointAddress,
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 75e2bfd744a9..3b4f7aedd381 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -2007,6 +2007,65 @@ int usb_set_wireless_status(struct usb_interface *iface,
 }
 EXPORT_SYMBOL_GPL(usb_set_wireless_status);
 
+/*
+ * eusb_update_max_packet - set or restore max packet size
+ * @udev: target device
+ * @cp: if NULL restore MPS to 512 else set 1024
+ *
+ * This request is specific to eUSB2v2.
+ * An eUSB2v2 peripheral will revert the maximum packet size to 512
+ * for bulk endpoints after bus reset, disconnect and deconfiguration.
+ * This function allows updating the max packet size for BULK endpoints
+ * to 1024 after above events.
+ */
+static void 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;
+	u16 mps = 512;
+	int i, j, a;
+	int ret;
+
+	if (le16_to_cpu(udev->descriptor.bcdUSB) != 0x0230 ||
+	    !hcd->self.is_eusb2v2)
+		return;
+
+	if (cp) {
+		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;
+		}
+
+		mps = 1024;
+	} else if (!udev->actconfig)
+		return;
+
+	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))
+					ep->desc.wMaxPacketSize = cpu_to_le16(mps);
+			}
+		}
+	}
+}
+
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
@@ -2120,8 +2179,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
 	/* if it's already configured, clear out old state first.
 	 * getting rid of old interfaces means unbinding their drivers.
 	 */
-	if (dev->state != USB_STATE_ADDRESS)
+	if (dev->state != USB_STATE_ADDRESS) {
+		eusb_update_max_packet(dev, NULL);
 		usb_disable_device(dev, 1);	/* Skip ep0 */
+	}
+
+	eusb_update_max_packet(dev, cp);
 
 	/* Get rid of pending async Set-Config requests for this device */
 	cancel_async_set_config(dev);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 997fe90f54e5..a4d3e03f9e14 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1479,10 +1479,22 @@ 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 (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0230 &&
+			    xhci->hcc_params2 & HCC2_E2V2C) {
+				max_packet = rounddown_pow_of_two(max_packet);
+				max_packet = clamp_val(max_packet, 512, 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..254638dc1e18 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5548,6 +5548,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	else
 		xhci_hcd_init_usb2_data(xhci, hcd);
 
+	if (xhci->hcc_params2 & HCC2_E2V2C)
+		hcd->self.is_eusb2v2 = 1;
+
 	xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
 		  xhci->hcc_params, xhci->hci_version, xhci->quirks);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 25a203ac7a7e..790c2295aec6 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 */
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] usb: gadget: composite: Support eUSB2v2 bulk MPS update request
  2026-07-17 10:44 ` Pawel Laszczak
@ 2026-07-17 10:44   ` Pawel Laszczak
  -1 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak via B4 Relay @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

From: Pawel Laszczak <pawell@cadence.com>

Add support for eUSB2v2 1024-byte Bulk MPS negotiation to the Gadget
Composite framework.

If 'gadget->is_eusb2v2' is set, force bcdUSB to 0x0230 and bMaxPacketSize0
to 64 bytes. Handle the USB_DEVICE_BULK_MAX_PACKET_UPDATE feature request
by introducing eusb2_update_mps_bulk(), which dynamically updates the
wMaxPacketSize of all HS Bulk endpoint descriptors to 1024 bytes before
the device is configured.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
 drivers/usb/gadget/composite.c | 67 ++++++++++++++++++++++++++++++++++++++----
 include/linux/usb/gadget.h     |  2 ++
 2 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index dc3664374596..e009f8c4281c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -924,6 +924,48 @@ static void device_qual(struct usb_composite_dev *cdev)
 }
 
 /*-------------------------------------------------------------------------*/
+static void eusb2_update_ep_mps(struct usb_descriptor_header *header, __le16 mps)
+{
+	struct usb_endpoint_descriptor *epd;
+
+	if (header->bDescriptorType != USB_DT_ENDPOINT)
+		return;
+
+	epd = (void *)header;
+	if (usb_endpoint_xfer_bulk(epd))
+		epd->wMaxPacketSize = mps;
+}
+
+static int eusb2_update_mps_bulk(struct usb_composite_dev *cdev, bool set)
+{
+	__le16 mps = cpu_to_le16(set ? 1024 : 512);
+	struct usb_gadget *gadget = cdev->gadget;
+	struct usb_configuration *config;
+	struct usb_function *f;
+
+	if (!gadget->is_eusb2v2)
+		return -EINVAL;
+
+	if (set && gadget->state >= USB_STATE_CONFIGURED)
+		return -EINVAL;
+
+	list_for_each_entry(config, &cdev->configs, list) {
+		if (!config->highspeed)
+			continue;
+
+		list_for_each_entry(f, &config->functions, list) {
+			struct usb_descriptor_header **desc = f->hs_descriptors;
+
+			if (!desc)
+				continue;
+
+			for (; *desc; desc++)
+				eusb2_update_ep_mps(*desc, mps);
+		}
+	}
+
+	return 0;
+}
 
 static void reset_config(struct usb_composite_dev *cdev)
 {
@@ -971,8 +1013,10 @@ static int set_config(struct usb_composite_dev *cdev,
 		if (result < 0)
 			goto done;
 	} else { /* Zero configuration value - need to reset the config */
-		if (cdev->config)
+		if (cdev->config) {
 			reset_config(cdev);
+			eusb2_update_mps_bulk(cdev, false);
+		}
 		result = 0;
 	}
 
@@ -1807,7 +1851,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 				count_configs(cdev, USB_DT_DEVICE);
 			cdev->desc.bMaxPacketSize0 =
 				cdev->gadget->ep0->maxpacket;
-			if (gadget_is_superspeed(gadget)) {
+
+			if (gadget->is_eusb2v2) {
+				cdev->desc.bcdUSB = cpu_to_le16(0x0230);
+				cdev->desc.bMaxPacketSize0 = 64;
+			} else if (gadget_is_superspeed(gadget)) {
 				if (gadget->speed >= USB_SPEED_SUPER) {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0320);
 					cdev->desc.bMaxPacketSize0 = 9;
@@ -2005,12 +2053,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	 */
 	case USB_REQ_CLEAR_FEATURE:
 	case USB_REQ_SET_FEATURE:
-		if (!gadget_is_superspeed(gadget))
-			goto unknown;
-		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
-			goto unknown;
 		switch (w_value) {
+		case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+			if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+				goto unknown;
+
+			value = eusb2_update_mps_bulk(cdev, true);
+			break;
 		case USB_INTRF_FUNC_SUSPEND:
+			if (!gadget_is_superspeed(gadget))
+				goto unknown;
+			if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+				goto unknown;
 			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
 				break;
 			f = cdev->config->interface[intf];
@@ -2303,6 +2357,7 @@ static void __composite_disconnect(struct usb_gadget *gadget)
 
 void composite_disconnect(struct usb_gadget *gadget)
 {
+	eusb2_update_mps_bulk(get_gadget_data(gadget), false);
 	usb_gadget_vbus_draw(gadget, 0);
 	__composite_disconnect(gadget);
 }
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 8285b19a25e0..3c554fe95f87 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -420,6 +420,7 @@ struct usb_gadget_ops {
  * @wakeup_armed: True if gadget is armed by the host for remote wakeup.
  * @irq: the interrupt number for device controller.
  * @id_number: a unique ID number for ensuring that gadget names are distinct
+ * @is_eusb2v2: True if controller is Embedded usb2.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -483,6 +484,7 @@ struct usb_gadget {
 	unsigned			lpm_capable:1;
 	unsigned			wakeup_capable:1;
 	unsigned			wakeup_armed:1;
+	unsigned			is_eusb2v2:1;
 	int				irq;
 	int				id_number;
 };

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] usb: gadget: composite: Support eUSB2v2 bulk MPS update request
@ 2026-07-17 10:44   ` Pawel Laszczak
  0 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

Add support for eUSB2v2 1024-byte Bulk MPS negotiation to the Gadget
Composite framework.

If 'gadget->is_eusb2v2' is set, force bcdUSB to 0x0230 and bMaxPacketSize0
to 64 bytes. Handle the USB_DEVICE_BULK_MAX_PACKET_UPDATE feature request
by introducing eusb2_update_mps_bulk(), which dynamically updates the
wMaxPacketSize of all HS Bulk endpoint descriptors to 1024 bytes before
the device is configured.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
 drivers/usb/gadget/composite.c | 67 ++++++++++++++++++++++++++++++++++++++----
 include/linux/usb/gadget.h     |  2 ++
 2 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index dc3664374596..e009f8c4281c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -924,6 +924,48 @@ static void device_qual(struct usb_composite_dev *cdev)
 }
 
 /*-------------------------------------------------------------------------*/
+static void eusb2_update_ep_mps(struct usb_descriptor_header *header, __le16 mps)
+{
+	struct usb_endpoint_descriptor *epd;
+
+	if (header->bDescriptorType != USB_DT_ENDPOINT)
+		return;
+
+	epd = (void *)header;
+	if (usb_endpoint_xfer_bulk(epd))
+		epd->wMaxPacketSize = mps;
+}
+
+static int eusb2_update_mps_bulk(struct usb_composite_dev *cdev, bool set)
+{
+	__le16 mps = cpu_to_le16(set ? 1024 : 512);
+	struct usb_gadget *gadget = cdev->gadget;
+	struct usb_configuration *config;
+	struct usb_function *f;
+
+	if (!gadget->is_eusb2v2)
+		return -EINVAL;
+
+	if (set && gadget->state >= USB_STATE_CONFIGURED)
+		return -EINVAL;
+
+	list_for_each_entry(config, &cdev->configs, list) {
+		if (!config->highspeed)
+			continue;
+
+		list_for_each_entry(f, &config->functions, list) {
+			struct usb_descriptor_header **desc = f->hs_descriptors;
+
+			if (!desc)
+				continue;
+
+			for (; *desc; desc++)
+				eusb2_update_ep_mps(*desc, mps);
+		}
+	}
+
+	return 0;
+}
 
 static void reset_config(struct usb_composite_dev *cdev)
 {
@@ -971,8 +1013,10 @@ static int set_config(struct usb_composite_dev *cdev,
 		if (result < 0)
 			goto done;
 	} else { /* Zero configuration value - need to reset the config */
-		if (cdev->config)
+		if (cdev->config) {
 			reset_config(cdev);
+			eusb2_update_mps_bulk(cdev, false);
+		}
 		result = 0;
 	}
 
@@ -1807,7 +1851,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 				count_configs(cdev, USB_DT_DEVICE);
 			cdev->desc.bMaxPacketSize0 =
 				cdev->gadget->ep0->maxpacket;
-			if (gadget_is_superspeed(gadget)) {
+
+			if (gadget->is_eusb2v2) {
+				cdev->desc.bcdUSB = cpu_to_le16(0x0230);
+				cdev->desc.bMaxPacketSize0 = 64;
+			} else if (gadget_is_superspeed(gadget)) {
 				if (gadget->speed >= USB_SPEED_SUPER) {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0320);
 					cdev->desc.bMaxPacketSize0 = 9;
@@ -2005,12 +2053,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	 */
 	case USB_REQ_CLEAR_FEATURE:
 	case USB_REQ_SET_FEATURE:
-		if (!gadget_is_superspeed(gadget))
-			goto unknown;
-		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
-			goto unknown;
 		switch (w_value) {
+		case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+			if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+				goto unknown;
+
+			value = eusb2_update_mps_bulk(cdev, true);
+			break;
 		case USB_INTRF_FUNC_SUSPEND:
+			if (!gadget_is_superspeed(gadget))
+				goto unknown;
+			if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+				goto unknown;
 			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
 				break;
 			f = cdev->config->interface[intf];
@@ -2303,6 +2357,7 @@ static void __composite_disconnect(struct usb_gadget *gadget)
 
 void composite_disconnect(struct usb_gadget *gadget)
 {
+	eusb2_update_mps_bulk(get_gadget_data(gadget), false);
 	usb_gadget_vbus_draw(gadget, 0);
 	__composite_disconnect(gadget);
 }
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 8285b19a25e0..3c554fe95f87 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -420,6 +420,7 @@ struct usb_gadget_ops {
  * @wakeup_armed: True if gadget is armed by the host for remote wakeup.
  * @irq: the interrupt number for device controller.
  * @id_number: a unique ID number for ensuring that gadget names are distinct
+ * @is_eusb2v2: True if controller is Embedded usb2.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -483,6 +484,7 @@ struct usb_gadget {
 	unsigned			lpm_capable:1;
 	unsigned			wakeup_capable:1;
 	unsigned			wakeup_armed:1;
+	unsigned			is_eusb2v2:1;
 	int				irq;
 	int				id_number;
 };

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability
  2026-07-17 10:44 ` Pawel Laszczak
@ 2026-07-17 10:44   ` Pawel Laszczak
  -1 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak via B4 Relay @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

From: Pawel Laszczak <pawell@cadence.com>

Implement peripheral-side changes in the Cadence (cdnsp) driver
to support eUSB2v2 1024-byte Bulk MaxPacketSize.

Check the HCC2_E2V2C bit in HCCPARAMS2 during setup and set
'pdev->gadget.is_eusb2v2 = 1' if supported. Update cdnsp_endpoint_init()
to allow internal max_packet size allocation up to 1024 bytes for HS
Bulk endpoints, and delegate the incoming update setup request from
ep0 to the composite layer.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
 drivers/usb/cdns3/cdnsp-ep0.c    |  2 ++
 drivers/usb/cdns3/cdnsp-gadget.c |  4 ++++
 drivers/usb/cdns3/cdnsp-gadget.h |  8 ++++++++
 drivers/usb/cdns3/cdnsp-mem.c    | 11 +++++++++--
 drivers/usb/common/debug.c       |  2 ++
 5 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/cdns3/cdnsp-ep0.c b/drivers/usb/cdns3/cdnsp-ep0.c
index 5cd9b898ce97..090d20b307ee 100644
--- a/drivers/usb/cdns3/cdnsp-ep0.c
+++ b/drivers/usb/cdns3/cdnsp-ep0.c
@@ -253,6 +253,8 @@ static int cdnsp_ep0_handle_feature_device(struct cdnsp_device *pdev,
 		 */
 		cdnsp_enter_test_mode(pdev);
 		break;
+	case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+		return cdnsp_ep0_delegate_req(pdev, ctrl);
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index a5275c2fb43b..ac1dde43ce1d 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -1853,6 +1853,10 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev)
 	pdev->hcc_params = readl(&pdev->cap_regs->hc_capbase);
 	pdev->hci_version = HC_VERSION(pdev->hcc_params);
 	pdev->hcc_params = readl(&pdev->cap_regs->hcc_params);
+	pdev->hcc_params2 = readl(&pdev->cap_regs->hcc_params2);
+
+	if (pdev->hcc_params2 & HCC2_E2V2C)
+		pdev->gadget.is_eusb2v2 = 1;
 
 	/*
 	 * Override the APB timeout value to give the controller more time for
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index c44bca348a41..75bc3f15bde5 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -89,6 +89,12 @@ struct cdnsp_cap_regs {
 
 #define CTX_SIZE(_hcc)		(HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
 
+/* HCCPARAMS2 - hcc_params2 - bitmasks */
+/* bit 11 - DC support Double BW on a eUSB2 HS ISOC EP */
+#define HCC2_EUSB2_DIC		BIT(11)
+/* bit 12 - DC support eUSB2V2 capability */
+#define HCC2_E2V2C		BIT(12)
+
 /* db_off bitmask - bits 0:1 reserved. */
 #define DBOFF_MASK	GENMASK(31, 2)
 
@@ -1370,6 +1376,7 @@ struct cdnsp_port {
  * @rev_cap: Controller Capabilities Registers.
  * @hcs_params1: Cached register copies of read-only HCSPARAMS1
  * @hcc_params: Cached register copies of read-only HCCPARAMS1
+ * @hcc_params2: Cached register copies of read-only HCCPARAMS2
  * @rtl_revision: Cached controller rtl revision.
  * @setup: Temporary buffer for setup packet.
  * @ep0_preq: Internal allocated request used during enumeration.
@@ -1425,6 +1432,7 @@ struct cdnsp_device {
 	__u32 hcs_params1;
 	__u32 hcs_params3;
 	__u32 hcc_params;
+	__u32 hcc_params2;
 	#define RTL_REVISION_NEW_LPM 0x2700
 	__u32 rtl_revision;
 	/* Lock used in interrupt thread context. */
diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
index 5d8cdc91927d..62e496e5225e 100644
--- a/drivers/usb/cdns3/cdnsp-mem.c
+++ b/drivers/usb/cdns3/cdnsp-mem.c
@@ -978,8 +978,15 @@ int cdnsp_endpoint_init(struct cdnsp_device *pdev,
 	if (!usb_endpoint_xfer_isoc(pep->endpoint.desc))
 		err_count = 3;
 	if (usb_endpoint_xfer_bulk(pep->endpoint.desc) &&
-	    pdev->gadget.speed == USB_SPEED_HIGH)
-		max_packet = 512;
+	    pdev->gadget.speed == USB_SPEED_HIGH) {
+		if (!pdev->gadget.is_eusb2v2) {
+			max_packet = 512;
+		} else {
+			max_packet = rounddown_pow_of_two(max_packet);
+			max_packet = clamp_val(max_packet, 512, 1024);
+		}
+	}
+
 	/* Controller spec indicates that ctrl ep avg TRB Length should be 8. */
 	if (usb_endpoint_xfer_control(pep->endpoint.desc))
 		avg_trb_len = 8;
diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c
index f204cec8d380..b9696fae7ef5 100644
--- a/drivers/usb/common/debug.c
+++ b/drivers/usb/common/debug.c
@@ -46,6 +46,8 @@ static const char *usb_decode_device_feature(u16 wValue)
 		return "U2 Enable";
 	case USB_DEVICE_LTM_ENABLE:
 		return "LTM Enable";
+	case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+		return "Bulk mps update";
 	default:
 		return "UNKNOWN";
 	}

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability
@ 2026-07-17 10:44   ` Pawel Laszczak
  0 siblings, 0 replies; 9+ messages in thread
From: Pawel Laszczak @ 2026-07-17 10:44 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mathias Nyman; +Cc: linux-usb, linux-kernel, Pawel Laszczak

Implement peripheral-side changes in the Cadence (cdnsp) driver
to support eUSB2v2 1024-byte Bulk MaxPacketSize.

Check the HCC2_E2V2C bit in HCCPARAMS2 during setup and set
'pdev->gadget.is_eusb2v2 = 1' if supported. Update cdnsp_endpoint_init()
to allow internal max_packet size allocation up to 1024 bytes for HS
Bulk endpoints, and delegate the incoming update setup request from
ep0 to the composite layer.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
 drivers/usb/cdns3/cdnsp-ep0.c    |  2 ++
 drivers/usb/cdns3/cdnsp-gadget.c |  4 ++++
 drivers/usb/cdns3/cdnsp-gadget.h |  8 ++++++++
 drivers/usb/cdns3/cdnsp-mem.c    | 11 +++++++++--
 drivers/usb/common/debug.c       |  2 ++
 5 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/cdns3/cdnsp-ep0.c b/drivers/usb/cdns3/cdnsp-ep0.c
index 5cd9b898ce97..090d20b307ee 100644
--- a/drivers/usb/cdns3/cdnsp-ep0.c
+++ b/drivers/usb/cdns3/cdnsp-ep0.c
@@ -253,6 +253,8 @@ static int cdnsp_ep0_handle_feature_device(struct cdnsp_device *pdev,
 		 */
 		cdnsp_enter_test_mode(pdev);
 		break;
+	case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+		return cdnsp_ep0_delegate_req(pdev, ctrl);
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index a5275c2fb43b..ac1dde43ce1d 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -1853,6 +1853,10 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev)
 	pdev->hcc_params = readl(&pdev->cap_regs->hc_capbase);
 	pdev->hci_version = HC_VERSION(pdev->hcc_params);
 	pdev->hcc_params = readl(&pdev->cap_regs->hcc_params);
+	pdev->hcc_params2 = readl(&pdev->cap_regs->hcc_params2);
+
+	if (pdev->hcc_params2 & HCC2_E2V2C)
+		pdev->gadget.is_eusb2v2 = 1;
 
 	/*
 	 * Override the APB timeout value to give the controller more time for
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index c44bca348a41..75bc3f15bde5 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -89,6 +89,12 @@ struct cdnsp_cap_regs {
 
 #define CTX_SIZE(_hcc)		(HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
 
+/* HCCPARAMS2 - hcc_params2 - bitmasks */
+/* bit 11 - DC support Double BW on a eUSB2 HS ISOC EP */
+#define HCC2_EUSB2_DIC		BIT(11)
+/* bit 12 - DC support eUSB2V2 capability */
+#define HCC2_E2V2C		BIT(12)
+
 /* db_off bitmask - bits 0:1 reserved. */
 #define DBOFF_MASK	GENMASK(31, 2)
 
@@ -1370,6 +1376,7 @@ struct cdnsp_port {
  * @rev_cap: Controller Capabilities Registers.
  * @hcs_params1: Cached register copies of read-only HCSPARAMS1
  * @hcc_params: Cached register copies of read-only HCCPARAMS1
+ * @hcc_params2: Cached register copies of read-only HCCPARAMS2
  * @rtl_revision: Cached controller rtl revision.
  * @setup: Temporary buffer for setup packet.
  * @ep0_preq: Internal allocated request used during enumeration.
@@ -1425,6 +1432,7 @@ struct cdnsp_device {
 	__u32 hcs_params1;
 	__u32 hcs_params3;
 	__u32 hcc_params;
+	__u32 hcc_params2;
 	#define RTL_REVISION_NEW_LPM 0x2700
 	__u32 rtl_revision;
 	/* Lock used in interrupt thread context. */
diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
index 5d8cdc91927d..62e496e5225e 100644
--- a/drivers/usb/cdns3/cdnsp-mem.c
+++ b/drivers/usb/cdns3/cdnsp-mem.c
@@ -978,8 +978,15 @@ int cdnsp_endpoint_init(struct cdnsp_device *pdev,
 	if (!usb_endpoint_xfer_isoc(pep->endpoint.desc))
 		err_count = 3;
 	if (usb_endpoint_xfer_bulk(pep->endpoint.desc) &&
-	    pdev->gadget.speed == USB_SPEED_HIGH)
-		max_packet = 512;
+	    pdev->gadget.speed == USB_SPEED_HIGH) {
+		if (!pdev->gadget.is_eusb2v2) {
+			max_packet = 512;
+		} else {
+			max_packet = rounddown_pow_of_two(max_packet);
+			max_packet = clamp_val(max_packet, 512, 1024);
+		}
+	}
+
 	/* Controller spec indicates that ctrl ep avg TRB Length should be 8. */
 	if (usb_endpoint_xfer_control(pep->endpoint.desc))
 		avg_trb_len = 8;
diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c
index f204cec8d380..b9696fae7ef5 100644
--- a/drivers/usb/common/debug.c
+++ b/drivers/usb/common/debug.c
@@ -46,6 +46,8 @@ static const char *usb_decode_device_feature(u16 wValue)
 		return "U2 Enable";
 	case USB_DEVICE_LTM_ENABLE:
 		return "LTM Enable";
+	case USB_DEVICE_BULK_MAX_PACKET_UPDATE:
+		return "Bulk mps update";
 	default:
 		return "UNKNOWN";
 	}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size
  2026-07-17 10:44   ` Pawel Laszczak
  (?)
@ 2026-07-26 18:41   ` Michal Pecio
  -1 siblings, 0 replies; 9+ messages in thread
From: Michal Pecio @ 2026-07-26 18:41 UTC (permalink / raw)
  To: Pawel Laszczak via B4 Relay
  Cc: pawell, Greg Kroah-Hartman, Mathias Nyman, linux-usb,
	linux-kernel

On Fri, 17 Jul 2026 12:44:14 +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>
> ---
>  drivers/usb/core/config.c   |  4 ++-
>  drivers/usb/core/message.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/usb/host/xhci-mem.c | 18 ++++++++++---
>  drivers/usb/host/xhci.c     |  3 +++
>  include/linux/usb.h         |  4 +++
>  5 files changed, 89 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
> index 45e20c6d76c0..0c7ab3f44cd9 100644
> --- a/drivers/usb/core/config.c
> +++ b/drivers/usb/core/config.c
> @@ -491,7 +491,9 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
>  	 * be able to handle that particular bug, so let's warn...
>  	 */
>  	if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
> -		if (maxp != 512)
> +		struct usb_hcd *hcd =  bus_to_hcd(udev->bus);
> +
> +		if (maxp != 512 && (bcdUSB != 0x230 || !hcd->self.is_eusb2v2))
>  			dev_notice(ddev, "config %d interface %d altsetting %d "
>  				"bulk endpoint 0x%X has invalid maxpacket %d\n",
>  				cfgno, inum, asnum, d->bEndpointAddress,

AFAIU the spec (5.2), every bulk endpoint supports 1024 byte packets
and no bulk endpoint advertises 1024 wMaxPacketSize in its descriptor.

So no change should be needed here for conformant devices.

Neither xhci-hcd nor your code has any clever solution for devices with
illegal wMaxPacketSize, so it may be prudent to retain this warning.

> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 75e2bfd744a9..3b4f7aedd381 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -2007,6 +2007,65 @@ int usb_set_wireless_status(struct usb_interface *iface,
>  }
>  EXPORT_SYMBOL_GPL(usb_set_wireless_status);
>  
> +/*
> + * eusb_update_max_packet - set or restore max packet size
> + * @udev: target device
> + * @cp: if NULL restore MPS to 512 else set 1024
> + *
> + * This request is specific to eUSB2v2.
> + * An eUSB2v2 peripheral will revert the maximum packet size to 512
> + * for bulk endpoints after bus reset, disconnect and deconfiguration.
> + * This function allows updating the max packet size for BULK endpoints
> + * to 1024 after above events.
> + */
> +static void 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;
> +	u16 mps = 512;
> +	int i, j, a;
> +	int ret;
> +
> +	if (le16_to_cpu(udev->descriptor.bcdUSB) != 0x0230 ||
> +	    !hcd->self.is_eusb2v2)
> +		return;
> +
> +	if (cp) {
> +		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;

In theory, a nonconformant device may have 1024 in its descriptor.
Then xhci-hcd will think that the update succeeded.

Not sure if anyone cares.

> +		}
> +
> +		mps = 1024;
> +	} else if (!udev->actconfig)
> +		return;
> +
> +	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))
> +					ep->desc.wMaxPacketSize = cpu_to_le16(mps);
> +			}
> +		}
> +	}
> +}
> +
>  /*
>   * usb_set_configuration - Makes a particular device setting be current
>   * @dev: the device whose configuration is being updated
> @@ -2120,8 +2179,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
>  	/* if it's already configured, clear out old state first.
>  	 * getting rid of old interfaces means unbinding their drivers.
>  	 */
> -	if (dev->state != USB_STATE_ADDRESS)
> +	if (dev->state != USB_STATE_ADDRESS) {
> +		eusb_update_max_packet(dev, NULL);
>  		usb_disable_device(dev, 1);	/* Skip ep0 */
> +	}
> +
> +	eusb_update_max_packet(dev, cp);
>  
>  	/* Get rid of pending async Set-Config requests for this device */
>  	cancel_async_set_config(dev);
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index 997fe90f54e5..a4d3e03f9e14 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -1479,10 +1479,22 @@ 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 (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0230 &&
> +			    xhci->hcc_params2 & HCC2_E2V2C) {
> +				max_packet = rounddown_pow_of_two(max_packet);
> +				max_packet = clamp_val(max_packet, 512, 1024);

Isn't this equivalent to
				if (max_packet != 1024)
					max_packet = 512;

except for the case of rounddown_pow_of_two(0) being "undefined"?
 
> +			} 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..254638dc1e18 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -5548,6 +5548,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
>  	else
>  		xhci_hcd_init_usb2_data(xhci, hcd);
>  
> +	if (xhci->hcc_params2 & HCC2_E2V2C)
> +		hcd->self.is_eusb2v2 = 1;
> +

May be better to put this in xhci_hcd_init_usb2_data(), so that it
doesn't apply to USB3 buses in dual-speed HCs, if any such HCs have
or will have E2V2C capability. That would be just confusing.

>  	xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
>  		  xhci->hcc_params, xhci->hci_version, xhci->quirks);
>  
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 25a203ac7a7e..790c2295aec6 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 */
>  
> 
> -- 
> 2.43.0
> 
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-07-26 18:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-17 10:44 [PATCH 0/3] usb: Add support for eUSB2v2 1024-byte Bulk MaxPacketSize Pawel Laszczak via B4 Relay
2026-07-17 10:44 ` Pawel Laszczak
2026-07-17 10:44 ` [PATCH 1/3] usb: xhci: Add support for eUSB2v2 1024-byte bulk packet size Pawel Laszczak via B4 Relay
2026-07-17 10:44   ` Pawel Laszczak
2026-07-26 18:41   ` Michal Pecio
2026-07-17 10:44 ` [PATCH 2/3] usb: gadget: composite: Support eUSB2v2 bulk MPS update request Pawel Laszczak via B4 Relay
2026-07-17 10:44   ` Pawel Laszczak
2026-07-17 10:44 ` [PATCH 3/3] usb: cdns3: cdnsp: Enable eUSB2v2 1KB bulk packet capability Pawel Laszczak via B4 Relay
2026-07-17 10:44   ` Pawel Laszczak

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.