Index: share/man/man9/autoconf.9 =================================================================== RCS file: /cvsroot/src/share/man/man9/autoconf.9,v retrieving revision 1.26 diff -u -r1.26 autoconf.9 --- share/man/man9/autoconf.9 7 Dec 2009 23:50:39 -0000 1.26 +++ share/man/man9/autoconf.9 18 Jun 2010 09:03:49 -0000 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd December 7, 2009 +.Dd June 13, 2010 .Dt AUTOCONF 9 .Os .Sh NAME @@ -45,6 +45,7 @@ .Nm config_deactivate , .Nm config_defer , .Nm config_interrupts , +.Nm config_mountroot , .Nm config_pending_incr , .Nm config_pending_decr , .Nm config_finalize_register @@ -86,6 +87,8 @@ .Ft void .Fn config_interrupts "device_t dev" "void (*func)(device_t)" .Ft void +.Fn config_mountroot "device_t dev" "void (*func)(device_t)" +.Ft void .Fn config_pending_incr .Ft void .Fn config_pending_decr @@ -369,6 +372,15 @@ .Fa func is called with the argument .Fa dev . +.It Fn config_mountroot "dev" "func" +Called by the child to defer the remainder of its configuration until +the root file system is mounted. +At this point, the function +.Fa func +is called with the argument +.Fa dev . +This is used for devices that need to load firmware image from +a mounted file system. .It Fn config_pending_incr Increment the .Va config_pending Index: sys/kern/init_main.c =================================================================== RCS file: /cvsroot/src/sys/kern/init_main.c,v retrieving revision 1.420 diff -u -r1.420 init_main.c --- sys/kern/init_main.c 10 Jun 2010 20:54:53 -0000 1.420 +++ sys/kern/init_main.c 13 Jun 2010 03:00:12 -0000 @@ -266,6 +266,7 @@ static void start_init(void *); static void configure(void); static void configure2(void); +static void configure3(void); void main(void); /* @@ -626,6 +627,8 @@ } while (error != 0); mountroothook_destroy(); + configure3(); + /* * Initialise the time-of-day clock, passing the time recorded * in the root filesystem (if any) for use by systems that @@ -783,6 +786,20 @@ } static void +configure3(void) +{ + + /* + * Create threads to call back and finish configuration for + * devices that want the mounted root file system. + */ + config_create_mountrootthreads(); + + /* Get the threads going and into any sleeps before continuing. */ + yield(); +} + +static void check_console(struct lwp *l) { struct vnode *vp; Index: sys/kern/subr_autoconf.c =================================================================== RCS file: /cvsroot/src/sys/kern/subr_autoconf.c,v retrieving revision 1.206 diff -u -r1.206 subr_autoconf.c --- sys/kern/subr_autoconf.c 30 Apr 2010 21:17:22 -0000 1.206 +++ sys/kern/subr_autoconf.c 13 Jun 2010 03:00:12 -0000 @@ -200,6 +200,9 @@ struct deferred_config_head interrupt_config_queue = TAILQ_HEAD_INITIALIZER(interrupt_config_queue); int interrupt_config_threads = 8; +struct deferred_config_head mountroot_config_queue = + TAILQ_HEAD_INITIALIZER(mountroot_config_queue); +int mountroot_config_threads = 2; static void config_process_deferred(struct deferred_config_head *, device_t); @@ -427,6 +430,7 @@ { config_process_deferred(&deferred_config_queue, dev); config_process_deferred(&interrupt_config_queue, dev); + config_process_deferred(&mountroot_config_queue, dev); } static void @@ -454,6 +458,30 @@ } } +static void +config_mountroot_thread(void *cookie) +{ + struct deferred_config *dc; + + while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) { + TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue); + (*dc->dc_func)(dc->dc_dev); + kmem_free(dc, sizeof(*dc)); + } + kthread_exit(0); +} + +void +config_create_mountrootthreads() +{ + int i; + + for (i = 0; i < mountroot_config_threads; i++) { + (void)kthread_create(PRI_NONE, 0, NULL, + config_mountroot_thread, NULL, NULL, "config"); + } +} + /* * Announce device attach/detach to userland listeners. */ @@ -1848,6 +1876,39 @@ } /* + * Defer some autoconfiguration for a device until after root file system + * is mounted (to load firmware etc). + */ +void +config_mountroot(device_t dev, void (*func)(device_t)) +{ + struct deferred_config *dc; + + /* + * If root file system is mounted, callback now. + */ + if (rootvnode != NULL) { + (*func)(dev); + return; + } + +#ifdef DIAGNOSTIC + TAILQ_FOREACH(dc, &mountroot_config_queue, dc_queue) { + if (dc->dc_dev == dev) + panic("%s: deferred twice", __func__); + } +#endif + + dc = kmem_alloc(sizeof(*dc), KM_SLEEP); + if (dc == NULL) + panic("%s: unable to allocate callback", __func__); + + dc->dc_dev = dev; + dc->dc_func = func; + TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue); +} + +/* * Process a deferred configuration queue. */ static void Index: sys/device.h =================================================================== RCS file: /cvsroot/src/sys/sys/device.h,v retrieving revision 1.136 diff -u -r1.136 device.h --- sys/device.h 25 Mar 2010 19:23:18 -0000 1.136 +++ sys/device.h 13 Jun 2010 03:00:15 -0000 @@ -479,9 +479,11 @@ void config_defer(device_t, void (*)(device_t)); void config_deferred(device_t); void config_interrupts(device_t, void (*)(device_t)); +void config_mountroot(device_t, void (*)(device_t)); void config_pending_incr(void); void config_pending_decr(void); void config_create_interruptthreads(void); +void config_create_mountrootthreads(void); int config_finalize_register(device_t, int (*)(device_t)); void config_finalize(void);