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