Re: [PATCH] usb: core: Fix bandwidth for devices with invalid wBytesPerInterval

Xuetao (kirin)
2026-04-02T11:55:27Z

在 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@kernel.org>
>> Signed-off-by: Tao Xue <xuetao09@huawei.com>
>> ---
>> 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
>>