Re: [PATCH] usb: core: Fix bandwidth for devices with invalid wBytesPerInterval
From: Xuetao (kirin)
Date: Thu Apr 02 2026 - 08:06:11 EST
在 2026/4/2 17:44, Michal Pecio 写道:
On Thu, 2 Apr 2026 10:14:00 +0800, Tao Xue wrote:
As specified in Section 4.14.2 of the xHCI Specification, the xHC
reserves bandwidth for periodic endpoints according to bInterval and
wBytesPerInterval (Max ESIT Payload).
For SuperSpeed endpoints, yes.
This follows from USB3 spec 9.6.7.
Some peripherals report an invalid wBytesPerInterval in their device
descriptor, which is either 0 or smaller than the actual data length
transmitted. This issue is observed on ASIX AX88179 series USB 3.0
Ethernet adapters.
Damn, it really does.
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 11
bMaxBurst 0
wBytesPerInterval 0
Any other examples besides AX88179?
We tested 18 different USB 3.0 docks, but they only contained two different types of USB 3.0 Ethernet devices based on VID/PID.
The dwc3 controller works fine with all of the devices mentioned above. The other USB host controller works fine with all 12 Realtek devices,
but fails with all 6 ASIX devices.
1. Realtek USB 10/100/1000 LAN (12 devices)
All 12 devices share the same VID/PID and descriptor values.
VID = 0x0BDA, PID = 0x8153
wMaxPacketSize = 0x10
bMaxBurst = 0
wBytesPerInterval = 0x8
2. ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter (6 devices)
All 6 devices share the same VID/PID.
VID = 0x0B95, PID = 0x1790
(a) 4 devices:
wMaxPacketSize = 0x10
bMaxBurst = 0
wBytesPerInterval = 0x0
(b) 2 devices:
wMaxPacketSize = 0x10
bMaxBurst = 0
wBytesPerInterval = 0x8
We also tested 3 different USB 3.0 camera devices. On all of these devices, the wBytesPerInterval of all SuperSpeed isochronous endpoints is equal to Mult * wMaxPacketSize * (bMaxBurst + 1).
These errors may lead to unexpected behavior on certain USB host
controllers, causing USB peripherals to malfunction.
Out of curiosity, Bandwidth Overrun Error or something worse?
This host controller reports a Babble error.
It's an oversight that these URBs aren't rejected with EMSGSIZE in the
first place. IIRC zero-length interrupt transfers are allowed by USB
specs and a zero-payload endpoint is probably legal per xHCI, but then
submitting non-empty URBs to it is not.
To address the issue, return max(wBytesPerInterval, max_payload) when
calculating bandwidth reservation.
Fixes: 9238f25d5d32 ("USB: xhci: properly set endpoint context fields for periodic eps.")
Cc: <stable@xxxxxxxxxx>
Signed-off-by: Tao Xue <xuetao09@xxxxxxxxxx>
---
drivers/usb/core/usb.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index e9a10a33534c..8f2e05a5a015 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1125,6 +1125,8 @@ EXPORT_SYMBOL_GPL(usb_free_noncoherent);
u32 usb_endpoint_max_periodic_payload(struct usb_device *udev,
const struct usb_host_endpoint *ep)
{
+ u32 max_payload;
+
if (!usb_endpoint_xfer_isoc(&ep->desc) &&
!usb_endpoint_xfer_int(&ep->desc))
return 0;
@@ -1135,7 +1137,12 @@ u32 usb_endpoint_max_periodic_payload(struct usb_device *udev,
return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval);
fallthrough;
case USB_SPEED_SUPER:
- return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
+ max_payload = usb_endpoint_maxp(&ep->desc) * (ep->ss_ep_comp.bMaxBurst + 1);
+ if (usb_endpoint_xfer_isoc(&ep->desc))
+ return max_t(u32, max_payload * USB_SS_MULT(ep->ss_ep_comp.bmAttributes),
+ ep->ss_ep_comp.wBytesPerInterval);
+ else
+ return max_t(u32, max_payload, ep->ss_ep_comp.wBytesPerInterval);
Obviously a kludge is necessary here to make these abominable devices
work reliably with xHCI, but OTOH exceeding wBytesPerInterval violates
USB3 9.6.7 and it's unclear if all devices would be happy.
There are devices which define such odd isochronous alt settings with
apparent intent to allow fine-grained bandwidth reservation:
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 1
bMaxBurst 0
wBytesPerInterval 512
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 1
bMaxBurst 0
wBytesPerInterval 1024
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 1
bMaxBurst 1 # 2 packets per interval
wBytesPerInterval 1536
Isochronous drivers use this function to size their URBs or select the
right altsetting for given bandwidth. UVC has obeyed wBytesPerInterval
since forever with no apparent issues and UAC has recently been patched
to work like that too with no issues so far AFAIK.
Maybe start with something specific to the known bogus hardware, i.e.
interrupt endpoint with one packet and zero payload? In such case
it's high chance that the device actually meant it to be wMaxPacket.
default:
if (usb_endpoint_is_hs_isoc_double(udev, ep))
return le32_to_cpu(ep->eusb2_isoc_ep_comp.dwBytesPerInterval);
--
2.17.1