Index: sys/kern/device_if.m =================================================================== --- sys/kern/device_if.m +++ sys/kern/device_if.m @@ -48,6 +48,11 @@ # Default implementations of some methods. # CODE { + static int null_delay_attach(device_t dev) + { + return FALSE; + } + static int null_shutdown(device_t dev) { return 0; @@ -188,6 +193,27 @@ }; /** + * @brief See if a device's dependencies are present. + * If not, delay attach for the future but continue claiming the device. + + * To include this method in a device driver, use a line like this + * in the driver's method list: + * + * @code + * KOBJMETHOD(device_delay_attach, foo_delay_attach) + * @endcode + * + * @param dev the device to probe + * + * @retval TRUE postpone attachment + * @retval FALSE attach now + * @see DEVICE_ATTACH() + */ +METHOD int delay_attach { + device_t dev; +} DEFAULT null_delay_attach; + +/** * @brief Attach a device to a device driver * * Normally only called via device_probe_and_attach(), this is called Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -2908,6 +2908,12 @@ return (ENXIO); } + if (DEVICE_DELAY_ATTACH(dev)) { + if (bootverbose) + device_printf(dev, "attach postponed\n"); + return (EAGAIN); + } + device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); @@ -3962,6 +3968,7 @@ driverlink_t dl; devclass_t dc; device_t child; + int attachments_pending, last_attachments_pending; dc = dev->devclass; TAILQ_FOREACH(dl, &dc->drivers, link) { @@ -3974,6 +3981,21 @@ else if (child->state == DS_NOTPRESENT) device_probe_and_attach(child); } + + /* + * Keep trying to attach pending devices so long as there are any + * and we are making forward progress on dependency resolution. + */ + do { + last_attachments_pending = attachments_pending; + attachments_pending = 0; + TAILQ_FOREACH(child, &dev->children, link) { + if (child->state == DS_ALIVE) + if (device_attach(child) == EAGAIN) + attachments_pending++; + } + } while (attachments_pending > 0 && + attachments_pending != last_attachments_pending); } /** Index: sys/powerpc/powermac/smu.c =================================================================== --- sys/powerpc/powermac/smu.c +++ sys/powerpc/powermac/smu.c @@ -154,6 +154,7 @@ /* regular bus attachment functions */ static int smu_probe(device_t); +static int smu_delay_attach(device_t); static int smu_attach(device_t); static const struct ofw_bus_devinfo * smu_get_devinfo(device_t bus, device_t dev); @@ -186,6 +187,7 @@ static device_method_t smu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, smu_probe), + DEVMETHOD(device_delay_attach, smu_delay_attach), DEVMETHOD(device_attach, smu_attach), /* Clock interface */ @@ -279,6 +281,14 @@ } static int +smu_delay_attach(device_t dev) +{ + + /* Delay attachment until our GPIO has attached */ + return (smu_doorbell == NULL); +} + +static int smu_attach(device_t dev) { struct smu_softc *sc;