NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/60073: xhci(4): NetBSD xHCI roothub uses ud_addr=0 instead of 1?
>Number: 60073
>Category: kern
>Synopsis: xhci(4): NetBSD xHCI roothub uses ud_addr=0 instead of 1?
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu Mar 12 18:55:00 +0000 2026
>Originator: Izumi Tsutsui
>Release: NetBSD 10.1
>Organization:
>Environment:
System: NetBSD mirage 10.1 NetBSD 10.1 (GENERIC) #3: Mon Jan 5 01:48:52 JST 2026 tsutsui@mirage:/s/netbsd-10/src/sys/arch/i386/compile/GENERIC i386
Architecture: all (tested on i386 and amd64)
Machine: all (S/A)
>Description:
This is partly a question about intended semantics/design,
but it also affects correctness when the USB layer design assumes
"ud_addr and ub_devices[] indexing are consistent".
src/sys/dev/usb/usb.h defines:
#define USB_MAX_DEVICES 128 /* 0, 1-127 */
#define USB_MIN_DEVICES 2 /* unused + root HUB */
#define USB_START_ADDR 0
so this looks to imply
- address 0 as the default/unconfigured address
- address 1 as the first usable permanent address, typically the root hub
The implementation of usbd_new_device() in src/sys/dev/usb/usb_subr.c
seems to follow the above assumption, even in the roothub case:
---
int
usbd_getnewaddr(struct usbd_bus *bus)
{
int addr;
for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
size_t dindex = usb_addr2dindex(addr);
if (bus->ub_devices[dindex] == NULL)
return addr;
}
return -1;
}
:
usbd_status
usbd_new_device(device_t parent, struct usbd_bus *bus, int depth, int speed,
int port, struct usbd_port *up)
{
:
addr = usbd_getnewaddr(bus);
:
dev->ud_addr = USB_START_ADDR;
:
/* Set the address */
DPRINTFN(5, "setting device address=%jd", addr, 0, 0, 0);
err = usbd_set_address(dev, addr);
if (err) {
DPRINTF("set address %jd failed, err = %jd", addr, err, 0, 0);
err = USBD_SET_ADDR_FAILED;
usbd_remove_device(dev, up);
return err;
}
/* Allow device time to set new address */
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
dev->ud_addr = addr; /* new device address now */
bus->ub_devices[usb_addr2dindex(addr)] = dev;
:
---
However, in xHCI xhci_new_device(), the root hub is created with
addr=0 (without explicit initialization):
---
static usbd_status
xhci_new_device(device_t parent, struct usbd_bus *bus, int depth,
int speed, int port, struct usbd_port *up)
{
:
dev->ud_addr = 0;
:
if (depth == 0 && port == 0) {
KASSERT(bus->ub_devices[USB_ROOTHUB_INDEX] == NULL);
bus->ub_devices[USB_ROOTHUB_INDEX] = dev;
/* Establish the default pipe. */
err = usbd_setup_pipe(dev, 0, &dev->ud_ep0,
USBD_DEFAULT_INTERVAL, &dev->ud_pipe0);
if (err) {
DPRINTFN(1, "setup default pipe failed %jd", err,0,0,0);
goto bad;
}
err = usbd_get_initial_ddesc(dev, dd);
if (err) {
DPRINTFN(1, "get_initial_ddesc %ju", err, 0, 0, 0);
goto bad;
}
} else {
:
---
Actually, xHCI root hub is attached at addr 0:
---
uhub0 at usb0: NetBSD (0x0000) xHCI root hub (0x0000), class 9/0, rev 3.00/1.00, addr 0
uhub0: 4 ports with 4 removable, self powered
uhub1 at usb1: NetBSD (0x0000) xHCI root hub (0x0000), class 9/0, rev 2.00/1.00, addr 0
uhub1: 4 ports with 4 removable, self powered
---
So xHCI stores the roothub in ub_devices[USB_ROOTHUB_INDEX]
(where USB_ROOTHUB_INDEX is 1) while keeping ud_addr == 0.
Note ehci, ohci, and dwtwo etc. use addr=1 for root hubs:
---
uhub2 at usb4: NetBSD (0x0000) OHCI root hub (0x0000), class 9/0, rev 1.00/1.00, addr 1
uhub2: 2 ports with 2 removable, self powered
uhub3 at usb2: NetBSD (0x0000) OHCI root hub (0x0000), class 9/0, rev 1.00/1.00, addr 1
uhub3: 2 ports with 2 removable, self powered
uhub4 at usb3: NetBSD (0x0000) OHCI root hub (0x0000), class 9/0, rev 1.00/1.00, addr 1
uhub4: 2 ports with 2 removable, self powered
uhub5 at usb6: NetBSD (0x0000) OHCI root hub (0x0000), class 9/0, rev 1.00/1.00, addr 1
uhub5: 2 ports with 2 removable, self powered
uhub6 at usb5: NetBSD (0x0000) OHCI root hub (0x0000), class 9/0, rev 1.00/1.00, addr 1
uhub6: 2 ports with 2 removable, self powered
uhub7 at usb7: NetBSD (0x0000) EHCI root hub (0x0000), class 9/0, rev 2.00/1.00, addr 1
uhub7: 10 ports with 10 removable, self powered
---
---
uhub0 at usb0: NetBSD (0x0000) DWC2 root hub (0x0000), class 9/0, rev 2.00/1.00, addr 1
uhub0: 1 port with 1 removable, self powered
---
FreeBSD and OpenBSD also use addr=0 for xHCI root hubs.
I am not sure whether this is an intentional NetBSD xHCI design choice,
or an inconsistency in the xHCI implementation.
If intentional, it may be worth documenting clearly.
If not intentional, it may be preferable to align xHCI
roothub address handling with the rest of the USB stack
(ehci/ohci etc.) and with other BSDs.
This question became visible while debugging a separate
xHCI cleanup issue: the roothub is kept at ub_devices[1]
but has ud_addr == 0, code paths that index cleanup by
ud_addr can accidentally affect the roothub slot
(I'll file an independent PR about this issue).
>How-To-Repeat:
1) Boot NetBSD on a machine with xHCI
2) Observe xHCI roothub attach lines in dmesg (see above)
>Fix:
Yes, please.
---
Izumi Tsutsui
Home |
Main Index |
Thread Index |
Old Index