NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/59939: usbnet(9): support multi-packet tx transfers
>Number: 59939
>Category: kern
>Synopsis: usbnet(9): support multi-packet tx transfers
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Jan 24 21:30:00 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11, 10, 9, ...
>Organization:
The NetBSD Foundation The NetBSD Foundation The NetBSD Foundation
>Environment:
>Description:
Some USB ethernet devices such as ure(4) support transmitting
multiple packets in a single USB transfer.^[citation needed]
usbnet(9) currently supports _receiving_ multiple packets in a
single USB transfer -- it is the driver's responsibility to
iterate over the packets in uno_rx_loop and run usbnet_enqueue
on each of them:
(usbnet(9) transfer completion callback)
351 static void
352 usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
353 {
...
388 uno_rx_loop(un, c, total_len);
https://nxr.netbsd.org/xref/src/sys/dev/usb/usbnet.c?r=1.121#347
944 static void
945 ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
946 {
...
953 do {
...
976 usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN,
977 ure_rxcsum(ifp, &rxhdr), 0, 0);
978
979 pkt_count++;
980
981 } while (total_len > 0);
https://nxr.netbsd.org/xref/src/sys/dev/usb/if_ure.c?r=1.60#944
But usbnet(9) only _transmits_ a single packet at a time in
each USB transfer:
523 while (cd->uncd_tx_cnt < un->un_tx_list_cnt) {
524 IFQ_POLL(&ifp->if_snd, m);
...
533 length = uno_tx_prepare(un, m, c);
...
546 usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length,
547 un->un_tx_xfer_flags, 10000, usbnet_txeof);
548
549 /* Transmit */
550 usbd_status err = usbd_transfer(c->unc_xfer);
551 if (err != USBD_IN_PROGRESS) {
...
556 }
557 done_transmit = true;
558
559 IFQ_DEQUEUE(&ifp->if_snd, m);
https://nxr.netbsd.org/xref/src/sys/dev/usb/usbnet.c?r=1.121#523
For better performance,^[citation needed] it should offer the
driver a batch of packets and let the driver say when to stop
and send out a transfer (probably when the transfer buffer is
full).
As a side note, I notice that usbnet(9) doesn't make
ABI-compatible extensions easy -- there's no version numbers or
feature flags for a driver to use. We should consider having a
version number on struct usbnet_ops so we can safely add new
optional operations for drivers to implement without changing
the module ABI.
>How-To-Repeat:
observe the competition claiming to speed up
>Fix:
New argument `offset' to uno_tx_prepare callback. The packets
m[0], m[1], m[2], ... to be transmitted will be passed to the
driver roughly like:
length0 = uno_tx_prepare(un, c, m[0], 0);
length1 = uno_tx_prepare(un, c, m[1], length0);
length2 = uno_tx_prepare(un, c, m[2], length0 + length1);
...
=> If uno_tx_prepare returns 0 for the _first_ packet m[0],
we drop it because it can't be transmitted.
=> If uno_tx_prepare returns 0 for packet m[i] when i > 0, we
transfer what we have and put m[i] back in the queue for the
next transfer.
Home |
Main Index |
Thread Index |
Old Index