| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: subr_autoconf.c,v 1.175 2009/05/01 08:27:41 cegger Exp $ */ | | 1 | /* $NetBSD: subr_autoconf.c,v 1.176 2009/05/24 12:27:50 ad Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1996, 2000 Christopher G. Demetriou | | 4 | * Copyright (c) 1996, 2000 Christopher G. Demetriou |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -67,27 +67,27 @@ | | | @@ -67,27 +67,27 @@ |
67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
72 | * SUCH DAMAGE. | | 72 | * SUCH DAMAGE. |
73 | * | | 73 | * |
74 | * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) | | 74 | * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) |
75 | * | | 75 | * |
76 | * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94 | | 76 | * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94 |
77 | */ | | 77 | */ |
78 | | | 78 | |
79 | #include <sys/cdefs.h> | | 79 | #include <sys/cdefs.h> |
80 | __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.175 2009/05/01 08:27:41 cegger Exp $"); | | 80 | __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.176 2009/05/24 12:27:50 ad Exp $"); |
81 | | | 81 | |
82 | #include "opt_ddb.h" | | 82 | #include "opt_ddb.h" |
83 | #include "drvctl.h" | | 83 | #include "drvctl.h" |
84 | | | 84 | |
85 | #include <sys/param.h> | | 85 | #include <sys/param.h> |
86 | #include <sys/device.h> | | 86 | #include <sys/device.h> |
87 | #include <sys/disklabel.h> | | 87 | #include <sys/disklabel.h> |
88 | #include <sys/conf.h> | | 88 | #include <sys/conf.h> |
89 | #include <sys/kauth.h> | | 89 | #include <sys/kauth.h> |
90 | #include <sys/malloc.h> | | 90 | #include <sys/malloc.h> |
91 | #include <sys/kmem.h> | | 91 | #include <sys/kmem.h> |
92 | #include <sys/systm.h> | | 92 | #include <sys/systm.h> |
93 | #include <sys/kernel.h> | | 93 | #include <sys/kernel.h> |
| @@ -163,26 +163,27 @@ struct matchinfo { | | | @@ -163,26 +163,27 @@ struct matchinfo { |
163 | const int *locs; | | 163 | const int *locs; |
164 | void *aux; | | 164 | void *aux; |
165 | struct cfdata *match; | | 165 | struct cfdata *match; |
166 | int pri; | | 166 | int pri; |
167 | }; | | 167 | }; |
168 | | | 168 | |
169 | static char *number(char *, int); | | 169 | static char *number(char *, int); |
170 | static void mapply(struct matchinfo *, cfdata_t); | | 170 | static void mapply(struct matchinfo *, cfdata_t); |
171 | static device_t config_devalloc(const device_t, const cfdata_t, const int *); | | 171 | static device_t config_devalloc(const device_t, const cfdata_t, const int *); |
172 | static void config_devdealloc(device_t); | | 172 | static void config_devdealloc(device_t); |
173 | static void config_makeroom(int, struct cfdriver *); | | 173 | static void config_makeroom(int, struct cfdriver *); |
174 | static void config_devlink(device_t); | | 174 | static void config_devlink(device_t); |
175 | static void config_devunlink(device_t); | | 175 | static void config_devunlink(device_t); |
| | | 176 | static void config_twiddle_fn(void *); |
176 | | | 177 | |
177 | static void pmflock_debug(device_t, const char *, int); | | 178 | static void pmflock_debug(device_t, const char *, int); |
178 | static void pmflock_debug_with_flags(device_t, const char *, int PMF_FN_PROTO); | | 179 | static void pmflock_debug_with_flags(device_t, const char *, int PMF_FN_PROTO); |
179 | | | 180 | |
180 | static device_t deviter_next1(deviter_t *); | | 181 | static device_t deviter_next1(deviter_t *); |
181 | static void deviter_reinit(deviter_t *); | | 182 | static void deviter_reinit(deviter_t *); |
182 | | | 183 | |
183 | struct deferred_config { | | 184 | struct deferred_config { |
184 | TAILQ_ENTRY(deferred_config) dc_queue; | | 185 | TAILQ_ENTRY(deferred_config) dc_queue; |
185 | device_t dc_dev; | | 186 | device_t dc_dev; |
186 | void (*dc_func)(device_t); | | 187 | void (*dc_func)(device_t); |
187 | }; | | 188 | }; |
188 | | | 189 | |
| @@ -216,26 +217,27 @@ static lwp_t *alldevs_writer = NULL; | | | @@ -216,26 +217,27 @@ static lwp_t *alldevs_writer = NULL; |
216 | | | 217 | |
217 | static int config_pending; /* semaphore for mountroot */ | | 218 | static int config_pending; /* semaphore for mountroot */ |
218 | static kmutex_t config_misc_lock; | | 219 | static kmutex_t config_misc_lock; |
219 | static kcondvar_t config_misc_cv; | | 220 | static kcondvar_t config_misc_cv; |
220 | | | 221 | |
221 | static int detachall = 0; | | 222 | static int detachall = 0; |
222 | | | 223 | |
223 | #define STREQ(s1, s2) \ | | 224 | #define STREQ(s1, s2) \ |
224 | (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) | | 225 | (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) |
225 | | | 226 | |
226 | static int config_initialized; /* config_init() has been called. */ | | 227 | static int config_initialized; /* config_init() has been called. */ |
227 | | | 228 | |
228 | static int config_do_twiddle; | | 229 | static int config_do_twiddle; |
| | | 230 | static callout_t config_twiddle_ch; |
229 | | | 231 | |
230 | struct vnode * | | 232 | struct vnode * |
231 | opendisk(struct device *dv) | | 233 | opendisk(struct device *dv) |
232 | { | | 234 | { |
233 | int bmajor, bminor; | | 235 | int bmajor, bminor; |
234 | struct vnode *tmpvn; | | 236 | struct vnode *tmpvn; |
235 | int error; | | 237 | int error; |
236 | dev_t dev; | | 238 | dev_t dev; |
237 | | | 239 | |
238 | /* | | 240 | /* |
239 | * Lookup major number for disk block device. | | 241 | * Lookup major number for disk block device. |
240 | */ | | 242 | */ |
241 | bmajor = devsw_name2blk(device_xname(dv), NULL, 0); | | 243 | bmajor = devsw_name2blk(device_xname(dv), NULL, 0); |
| @@ -343,26 +345,29 @@ config_init(void) | | | @@ -343,26 +345,29 @@ config_init(void) |
343 | { | | 345 | { |
344 | const struct cfattachinit *cfai; | | 346 | const struct cfattachinit *cfai; |
345 | int i, j; | | 347 | int i, j; |
346 | | | 348 | |
347 | if (config_initialized) | | 349 | if (config_initialized) |
348 | return; | | 350 | return; |
349 | | | 351 | |
350 | mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE); | | 352 | mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE); |
351 | cv_init(&alldevs_cv, "alldevs"); | | 353 | cv_init(&alldevs_cv, "alldevs"); |
352 | | | 354 | |
353 | mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE); | | 355 | mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE); |
354 | cv_init(&config_misc_cv, "cfgmisc"); | | 356 | cv_init(&config_misc_cv, "cfgmisc"); |
355 | | | 357 | |
| | | 358 | callout_init(&config_twiddle_ch, CALLOUT_MPSAFE); |
| | | 359 | callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL); |
| | | 360 | |
356 | /* allcfdrivers is statically initialized. */ | | 361 | /* allcfdrivers is statically initialized. */ |
357 | for (i = 0; cfdriver_list_initial[i] != NULL; i++) { | | 362 | for (i = 0; cfdriver_list_initial[i] != NULL; i++) { |
358 | if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0) | | 363 | if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0) |
359 | panic("configure: duplicate `%s' drivers", | | 364 | panic("configure: duplicate `%s' drivers", |
360 | cfdriver_list_initial[i]->cd_name); | | 365 | cfdriver_list_initial[i]->cd_name); |
361 | } | | 366 | } |
362 | | | 367 | |
363 | for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) { | | 368 | for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) { |
364 | for (j = 0; cfai->cfai_list[j] != NULL; j++) { | | 369 | for (j = 0; cfai->cfai_list[j] != NULL; j++) { |
365 | if (config_cfattach_attach(cfai->cfai_name, | | 370 | if (config_cfattach_attach(cfai->cfai_name, |
366 | cfai->cfai_list[j]) != 0) | | 371 | cfai->cfai_list[j]) != 0) |
367 | panic("configure: duplicate `%s' attachment " | | 372 | panic("configure: duplicate `%s' attachment " |
368 | "of `%s' driver", | | 373 | "of `%s' driver", |
| @@ -452,26 +457,32 @@ configure2(void) | | | @@ -452,26 +457,32 @@ configure2(void) |
452 | for (CPU_INFO_FOREACH(cii, ci)) { | | 457 | for (CPU_INFO_FOREACH(cii, ci)) { |
453 | uvm_cpu_attach(ci); | | 458 | uvm_cpu_attach(ci); |
454 | } | | 459 | } |
455 | mp_online = true; | | 460 | mp_online = true; |
456 | #if defined(MULTIPROCESSOR) | | 461 | #if defined(MULTIPROCESSOR) |
457 | cpu_boot_secondary_processors(); | | 462 | cpu_boot_secondary_processors(); |
458 | #endif | | 463 | #endif |
459 | | | 464 | |
460 | /* Setup the runqueues and scheduler. */ | | 465 | /* Setup the runqueues and scheduler. */ |
461 | runq_init(); | | 466 | runq_init(); |
462 | sched_init(); | | 467 | sched_init(); |
463 | | | 468 | |
464 | /* | | 469 | /* |
| | | 470 | * Bus scans can make it appear as if the system has paused, so |
| | | 471 | * twiddle constantly while config_interrupts() jobs are running. |
| | | 472 | */ |
| | | 473 | config_twiddle_fn(NULL); |
| | | 474 | |
| | | 475 | /* |
465 | * Create threads to call back and finish configuration for | | 476 | * Create threads to call back and finish configuration for |
466 | * devices that want interrupts enabled. | | 477 | * devices that want interrupts enabled. |
467 | */ | | 478 | */ |
468 | for (i = 0; i < interrupt_config_threads; i++) { | | 479 | for (i = 0; i < interrupt_config_threads; i++) { |
469 | (void)kthread_create(PRI_NONE, 0, NULL, | | 480 | (void)kthread_create(PRI_NONE, 0, NULL, |
470 | config_interrupts_thread, NULL, NULL, "config"); | | 481 | config_interrupts_thread, NULL, NULL, "config"); |
471 | } | | 482 | } |
472 | | | 483 | |
473 | /* Get the threads going and into any sleeps before continuing. */ | | 484 | /* Get the threads going and into any sleeps before continuing. */ |
474 | yield(); | | 485 | yield(); |
475 | } | | 486 | } |
476 | | | 487 | |
477 | /* | | 488 | /* |
| @@ -1017,27 +1028,27 @@ config_found_sm_loc(device_t parent, | | | @@ -1017,27 +1028,27 @@ config_found_sm_loc(device_t parent, |
1017 | const char *ifattr, const int *locs, void *aux, | | 1028 | const char *ifattr, const int *locs, void *aux, |
1018 | cfprint_t print, cfsubmatch_t submatch) | | 1029 | cfprint_t print, cfsubmatch_t submatch) |
1019 | { | | 1030 | { |
1020 | cfdata_t cf; | | 1031 | cfdata_t cf; |
1021 | | | 1032 | |
1022 | #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS) | | 1033 | #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS) |
1023 | if (splash_progress_state) | | 1034 | if (splash_progress_state) |
1024 | splash_progress_update(splash_progress_state); | | 1035 | splash_progress_update(splash_progress_state); |
1025 | #endif | | 1036 | #endif |
1026 | | | 1037 | |
1027 | if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux))) | | 1038 | if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux))) |
1028 | return(config_attach_loc(parent, cf, locs, aux, print)); | | 1039 | return(config_attach_loc(parent, cf, locs, aux, print)); |
1029 | if (print) { | | 1040 | if (print) { |
1030 | if (config_do_twiddle) | | 1041 | if (config_do_twiddle && cold) |
1031 | twiddle(); | | 1042 | twiddle(); |
1032 | aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]); | | 1043 | aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]); |
1033 | } | | 1044 | } |
1034 | | | 1045 | |
1035 | #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS) | | 1046 | #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS) |
1036 | if (splash_progress_state) | | 1047 | if (splash_progress_state) |
1037 | splash_progress_update(splash_progress_state); | | 1048 | splash_progress_update(splash_progress_state); |
1038 | #endif | | 1049 | #endif |
1039 | | | 1050 | |
1040 | return NULL; | | 1051 | return NULL; |
1041 | } | | 1052 | } |
1042 | | | 1053 | |
1043 | device_t | | 1054 | device_t |
| @@ -1326,27 +1337,27 @@ config_attach_loc(device_t parent, cfdat | | | @@ -1326,27 +1337,27 @@ config_attach_loc(device_t parent, cfdat |
1326 | | | 1337 | |
1327 | /* XXX redundant - see below? */ | | 1338 | /* XXX redundant - see below? */ |
1328 | if (cf->cf_fstate != FSTATE_STAR) { | | 1339 | if (cf->cf_fstate != FSTATE_STAR) { |
1329 | KASSERT(cf->cf_fstate == FSTATE_NOTFOUND); | | 1340 | KASSERT(cf->cf_fstate == FSTATE_NOTFOUND); |
1330 | cf->cf_fstate = FSTATE_FOUND; | | 1341 | cf->cf_fstate = FSTATE_FOUND; |
1331 | } | | 1342 | } |
1332 | #ifdef __BROKEN_CONFIG_UNIT_USAGE | | 1343 | #ifdef __BROKEN_CONFIG_UNIT_USAGE |
1333 | else | | 1344 | else |
1334 | cf->cf_unit++; | | 1345 | cf->cf_unit++; |
1335 | #endif | | 1346 | #endif |
1336 | | | 1347 | |
1337 | config_devlink(dev); | | 1348 | config_devlink(dev); |
1338 | | | 1349 | |
1339 | if (config_do_twiddle) | | 1350 | if (config_do_twiddle && cold) |
1340 | twiddle(); | | 1351 | twiddle(); |
1341 | else | | 1352 | else |
1342 | aprint_naive("Found "); | | 1353 | aprint_naive("Found "); |
1343 | /* | | 1354 | /* |
1344 | * We want the next two printfs for normal, verbose, and quiet, | | 1355 | * We want the next two printfs for normal, verbose, and quiet, |
1345 | * but not silent (in which case, we're twiddling, instead). | | 1356 | * but not silent (in which case, we're twiddling, instead). |
1346 | */ | | 1357 | */ |
1347 | if (parent == ROOT) { | | 1358 | if (parent == ROOT) { |
1348 | aprint_naive("%s (root)", device_xname(dev)); | | 1359 | aprint_naive("%s (root)", device_xname(dev)); |
1349 | aprint_normal("%s (root)", device_xname(dev)); | | 1360 | aprint_normal("%s (root)", device_xname(dev)); |
1350 | } else { | | 1361 | } else { |
1351 | aprint_naive("%s at %s", device_xname(dev), device_xname(parent)); | | 1362 | aprint_naive("%s at %s", device_xname(dev), device_xname(parent)); |
1352 | aprint_normal("%s at %s", device_xname(dev), device_xname(parent)); | | 1363 | aprint_normal("%s at %s", device_xname(dev), device_xname(parent)); |
| @@ -1827,38 +1838,52 @@ config_finalize(void) | | | @@ -1827,38 +1838,52 @@ config_finalize(void) |
1827 | config_finalize_done = 1; | | 1838 | config_finalize_done = 1; |
1828 | | | 1839 | |
1829 | /* Now free all the hooks. */ | | 1840 | /* Now free all the hooks. */ |
1830 | while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) { | | 1841 | while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) { |
1831 | TAILQ_REMOVE(&config_finalize_list, f, f_list); | | 1842 | TAILQ_REMOVE(&config_finalize_list, f, f_list); |
1832 | kmem_free(f, sizeof(*f)); | | 1843 | kmem_free(f, sizeof(*f)); |
1833 | } | | 1844 | } |
1834 | | | 1845 | |
1835 | KERNEL_UNLOCK_ONE(NULL); | | 1846 | KERNEL_UNLOCK_ONE(NULL); |
1836 | | | 1847 | |
1837 | errcnt = aprint_get_error_count(); | | 1848 | errcnt = aprint_get_error_count(); |
1838 | if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 && | | 1849 | if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 && |
1839 | (boothowto & AB_VERBOSE) == 0) { | | 1850 | (boothowto & AB_VERBOSE) == 0) { |
| | | 1851 | mutex_enter(&config_misc_lock); |
1840 | if (config_do_twiddle) { | | 1852 | if (config_do_twiddle) { |
1841 | config_do_twiddle = 0; | | 1853 | config_do_twiddle = 0; |
1842 | printf_nolog(" done.\n"); | | 1854 | printf_nolog(" done.\n"); |
1843 | } | | 1855 | } |
| | | 1856 | mutex_exit(&config_misc_lock); |
1844 | if (errcnt != 0) { | | 1857 | if (errcnt != 0) { |
1845 | printf("WARNING: %d error%s while detecting hardware; " | | 1858 | printf("WARNING: %d error%s while detecting hardware; " |
1846 | "check system log.\n", errcnt, | | 1859 | "check system log.\n", errcnt, |
1847 | errcnt == 1 ? "" : "s"); | | 1860 | errcnt == 1 ? "" : "s"); |
1848 | } | | 1861 | } |
1849 | } | | 1862 | } |
1850 | } | | 1863 | } |
1851 | | | 1864 | |
| | | 1865 | void |
| | | 1866 | config_twiddle_fn(void *cookie) |
| | | 1867 | { |
| | | 1868 | |
| | | 1869 | mutex_enter(&config_misc_lock); |
| | | 1870 | if (config_do_twiddle) { |
| | | 1871 | twiddle(); |
| | | 1872 | callout_schedule(&config_twiddle_ch, mstohz(100)); |
| | | 1873 | } |
| | | 1874 | mutex_exit(&config_misc_lock); |
| | | 1875 | } |
| | | 1876 | |
1852 | /* | | 1877 | /* |
1853 | * device_lookup: | | 1878 | * device_lookup: |
1854 | * | | 1879 | * |
1855 | * Look up a device instance for a given driver. | | 1880 | * Look up a device instance for a given driver. |
1856 | */ | | 1881 | */ |
1857 | device_t | | 1882 | device_t |
1858 | device_lookup(cfdriver_t cd, int unit) | | 1883 | device_lookup(cfdriver_t cd, int unit) |
1859 | { | | 1884 | { |
1860 | | | 1885 | |
1861 | if (unit < 0 || unit >= cd->cd_ndevs) | | 1886 | if (unit < 0 || unit >= cd->cd_ndevs) |
1862 | return NULL; | | 1887 | return NULL; |
1863 | | | 1888 | |
1864 | return cd->cd_devs[unit]; | | 1889 | return cd->cd_devs[unit]; |