DF-5394 / fix.diff
--- a/sys/bus/u4b/controller/usb_controller.c +++ b/sys/bus/u4b/controller/usb_controller.c @@ -196,8 +196,6 @@ /* was never setup properly */ return (0); } - /* Stop power watchdog */ - usb_callout_drain(&bus->power_wdog); #if USB_HAVE_ROOT_MOUNT_HOLD /* Let the USB explore process detach all devices. */ @@ -221,6 +219,15 @@ #endif USB_BUS_UNLOCK(bus); + /* + * Stop power watchdog. Must happen after the detach job above: + * usb_bus_attach() arms this callout as its last action and the + * detach job is queued behind the attach job in the explore + * process, so draining here always observes the armed callout, + * while draining before the jobs (as before) raced the arming. + */ + usb_callout_drain(&bus->power_wdog); + #if USB_HAVE_PER_BUS_PROCESS /* Get rid of USB callback processes */ @@ -895,6 +902,18 @@ } else #endif { + /* + * Set the softc synchronously, BEFORE signalling the + * asynchronous usb_bus_attach() job, so that a racing + * usb_detach() always observes a non-NULL softc and + * performs the full teardown dance instead of silently + * skipping it while the explore process is still running. + * usb_bus_attach()/usb_bus_detach() set/clear it again; + * device_set_softc() sees DF_EXTERNALSOFTC and will not + * free the pointer. + */ + device_set_softc(dev, bus); + /* Get final attach going */ USB_BUS_LOCK(bus); usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), |