NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

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



> Date: Sat, 21 Feb 2026 10:39:41 +0000
> From: Nick Hudson <nick.hudson%gmx.co.uk@localhost>
> 
> 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.



Home | Main Index | Thread Index | Old Index