Re: port-arm/60021: USB-only boot: uhub0 attaches but uhub1 never appears, no hotplug events; SD-boot sees hub+umass fine

Taylor R Campbell <[email protected]>
Newsgroups gmane.os.netbsd.bugs
Message-ID <[email protected]>
> Date: Sat, 21 Feb 2026 10:39:41 +0000
> From: Nick Hudson <[email protected]>
> 
> This is almost certainly that autoconf doesn't wait (long enough) for
> sub-ordintate hubs
> 
> https://nxr.netbsd.org/xref/src/sys/dev/usb/uhub.c#880
> 
>      880 	mutex_enter(&sc->sc_lock);
>      881 	sc->sc_explorepending = false;
>      882 	for (int i = 0; i < sc->sc_statuslen; i++) {
>      883 		if (sc->sc_statuspend[i] != 0) {
>      884 			memcpy(sc->sc_status, sc->sc_statuspend,
>      885 			    sc->sc_statuslen);
>      886 			memset(sc->sc_statuspend, 0, sc->sc_statuslen);
>      887 			usb_needs_explore(sc->sc_hub);
>      888 			break;
>      889 		}
>      890 	}
>      891 	mutex_exit(&sc->sc_lock);
>      892 	if (sc->sc_first_explore) {
>      893 		config_pending_decr(sc->sc_dev);
>      894 		sc->sc_first_explore = false;
>      895 	}

I don't understand, doesn't it wait for subordinate hubs?  Maybe the
USB hub just doesn't report the device ready at first?

Here's a fuller picture of the logic -- note that uhub_explore will
_synchronously_ attach autoconf drivers for the devices it finds on
the hub, and then uhub_attach will _also_ config_pending_incr:

    529 usbd_status
    530 uhub_explore(struct usbd_device *dev)
    531 {
...
    598 	for (port = 1; port <= hd->bNbrPorts; port++) {
    599 		up = &dev->ud_hub->uh_ports[port - 1];
...
    848 		/* Get device info and set its address. */
    849 		err = usbd_new_device(sc->sc_dev, dev->ud_bus,
    850 			  dev->ud_depth + 1, speed, port, up);
...
    858 		if (err) {
...
    872 		} else {
...
    878 			if (up->up_dev->ud_hub)
    879 				up->up_dev->ud_hub->uh_explore(up->up_dev);
    880 		}
    881 	}
    882 	mutex_enter(&sc->sc_lock);
    883 	sc->sc_explorepending = false;
    884 	for (int i = 0; i < sc->sc_statuslen; i++) {
    885 		if (sc->sc_statuspend[i] != 0) {
    886 			memcpy(sc->sc_status, sc->sc_statuspend,
    887 			    sc->sc_statuslen);
    888 			memset(sc->sc_statuspend, 0, sc->sc_statuslen);
    889 			usb_needs_explore(sc->sc_hub);
    890 			break;
    891 		}
    892 	}
    893 	mutex_exit(&sc->sc_lock);
    894 	if (sc->sc_first_explore) {
    895 		config_pending_decr(sc->sc_dev);
    896 		sc->sc_first_explore = false;
    897 	}

https://nxr.netbsd.org/xref/src/sys/dev/usb/uhub.c?r=1.163#529

usbd_new_device synchronously attaches autoconf drivers:

   1394 usbd_status
   1395 usbd_new_device(device_t parent, struct usbd_bus *bus, int depth, int speed,
   1396     int port, struct usbd_port *up)
   1397 {
...
   1606 	if (port == 0) { /* root hub */
   1607 		KASSERT(addr == 1);
   1608 		usbd_attach_roothub(parent, dev);
   1609 		return USBD_NORMAL_COMPLETION;
   1610 	}
   1611 
   1612 	err = usbd_probe_and_attach(parent, dev, port, addr);
   1613 	if (err) {
   1614 		usbd_remove_device(dev, up);
   1615 		return err;
   1616 	}
   1617 
   1618 	return USBD_NORMAL_COMPLETION;
   1619 }

https://nxr.netbsd.org/xref/src/sys/dev/usb/usb_subr.c?r=1.281#1388

   1047 usbd_status
   1048 usbd_attach_roothub(device_t parent, struct usbd_device *dev)
   1049 {
...
   1065 	dv = config_found(parent, &uaa, NULL,
   1066 	    CFARGS(.iattr = "usbroothubif"));

https://nxr.netbsd.org/xref/src/sys/dev/usb/usb_subr.c?r=1.281#1047

   1270 usbd_status
   1271 usbd_probe_and_attach(device_t parent, struct usbd_device *dev,
   1272     int port, int addr)
   1273 {
...
   1283 	err = usbd_attachwholedevice(parent, dev, port, 0);
   1284 	if (dev->ud_nifaces_claimed || err)
   1285 		return err;
...
   1290 	for (confi = 0; confi < dd->bNumConfigurations; confi++) {
...
   1305 		err = usbd_attachinterfaces(parent, dev, port, NULL);
...
   1313 		if (dev->ud_nifaces_claimed || err)
   1314 			return err;
   1315 	}
...
   1324 	err = usbd_attachwholedevice(parent, dev, port, 1);

https://nxr.netbsd.org/xref/src/sys/dev/usb/usb_subr.c?r=1.281#1270

   1129 static usbd_status
   1130 usbd_attachwholedevice(device_t parent, struct usbd_device *dev, int port,
   1131     int usegeneric)
   1132 {
...
   1161 	dv = config_found(parent, &uaa, usbd_print,
   1162 			  CFARGS(.submatch = config_stdsubmatch,
   1163 				 .iattr = "usbdevif",
   1164 				 .locators = dlocs));
...

https://nxr.netbsd.org/xref/src/sys/dev/usb/usb_subr.c?r=1.281#1129

   1177 static usbd_status
   1178 usbd_attachinterfaces(device_t parent, struct usbd_device *dev,
   1179     int port, const int *locators)
   1180 {
...
   1242 		dv = config_found(parent, &uiaa, usbd_ifprint,
   1243 				  CFARGS(.submatch = config_stdsubmatch,
   1244 					 .iattr = "usbifif",
   1245 					 .locators = ilocs));

uhub is only at one of these (usbdevif or usbifif), but the point is
the attach happens synchronously for subordinate hubs, before
uhub_explore gets to config_pending_decr.

And in uhub_attach, pretty much the first thing it does is
config_pending_incr -- and it also sets the hub of the USB device to
be the one it just created, so uhub_attach's call to uh_explore should
take care of this:

    299 static void
    300 uhub_attach(device_t parent, device_t self, void *aux)
    301 {
...
    318 	config_pending_incr(self);
...
    371 	hub = kmem_alloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
    372 	    KM_SLEEP);
    373 	dev->ud_hub = hub;
    374 	dev->ud_hub->uh_hubsoftc = sc;
    375 	hub->uh_explore = uhub_explore;
    376 	hub->uh_hubdesc = hubdesc;

https://nxr.netbsd.org/xref/src/sys/dev/usb/uhub.c?r=1.163#529

As noted above, uhub_explore even explores the subordinate hubs
synchronously too by calling uh_explore!

So, does the USB device not appear to be connected at the time of the
initial probe, perhaps?

Building with USB_DEBUG and enabling usb_debug=1 so you can drop into
ddb and `show kernhist usbhist' might help.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.