1 1.314 riastrad /* $NetBSD: subr_autoconf.c,v 1.314 2023/07/18 11:57:37 riastradh Exp $ */ 2 1.53 cgd 3 1.53 cgd /* 4 1.53 cgd * Copyright (c) 1996, 2000 Christopher G. Demetriou 5 1.53 cgd * All rights reserved. 6 1.93 perry * 7 1.53 cgd * Redistribution and use in source and binary forms, with or without 8 1.53 cgd * modification, are permitted provided that the following conditions 9 1.53 cgd * are met: 10 1.53 cgd * 1. Redistributions of source code must retain the above copyright 11 1.53 cgd * notice, this list of conditions and the following disclaimer. 12 1.53 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.53 cgd * notice, this list of conditions and the following disclaimer in the 14 1.53 cgd * documentation and/or other materials provided with the distribution. 15 1.53 cgd * 3. All advertising materials mentioning features or use of this software 16 1.53 cgd * must display the following acknowledgement: 17 1.54 cgd * This product includes software developed for the 18 1.88 keihan * NetBSD Project. See http://www.NetBSD.org/ for 19 1.54 cgd * information about NetBSD. 20 1.53 cgd * 4. The name of the author may not be used to endorse or promote products 21 1.54 cgd * derived from this software without specific prior written permission. 22 1.93 perry * 23 1.53 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.53 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.53 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.53 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.53 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.53 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.53 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.53 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.53 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 1.53 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.93 perry * 34 1.54 cgd * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )-- 35 1.53 cgd */ 36 1.9 cgd 37 1.1 glass /* 38 1.7 glass * Copyright (c) 1992, 1993 39 1.7 glass * The Regents of the University of California. All rights reserved. 40 1.1 glass * 41 1.1 glass * This software was developed by the Computer Systems Engineering group 42 1.1 glass * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 43 1.1 glass * contributed to Berkeley. 44 1.1 glass * 45 1.1 glass * All advertising materials mentioning features or use of this software 46 1.1 glass * must display the following acknowledgement: 47 1.1 glass * This product includes software developed by the University of 48 1.1 glass * California, Lawrence Berkeley Laboratories. 49 1.1 glass * 50 1.7 glass * Redistribution and use in source and binary forms, with or without 51 1.7 glass * modification, are permitted provided that the following conditions 52 1.7 glass * are met: 53 1.7 glass * 1. Redistributions of source code must retain the above copyright 54 1.7 glass * notice, this list of conditions and the following disclaimer. 55 1.7 glass * 2. Redistributions in binary form must reproduce the above copyright 56 1.7 glass * notice, this list of conditions and the following disclaimer in the 57 1.7 glass * documentation and/or other materials provided with the distribution. 58 1.87 agc * 3. Neither the name of the University nor the names of its contributors 59 1.7 glass * may be used to endorse or promote products derived from this software 60 1.7 glass * without specific prior written permission. 61 1.1 glass * 62 1.7 glass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 1.7 glass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 1.7 glass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 1.7 glass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 1.7 glass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 1.7 glass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 1.7 glass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 1.7 glass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 1.7 glass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 1.7 glass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 1.7 glass * SUCH DAMAGE. 73 1.1 glass * 74 1.8 cgd * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) 75 1.9 cgd * 76 1.28 fvdl * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94 77 1.1 glass */ 78 1.1 glass 79 1.51 cgd #include <sys/cdefs.h> 80 1.314 riastrad __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.314 2023/07/18 11:57:37 riastradh Exp $"); 81 1.62 simonb 82 1.180 pooka #ifdef _KERNEL_OPT 83 1.62 simonb #include "opt_ddb.h" 84 1.217 jmcneill #include "drvctl.h" 85 1.180 pooka #endif 86 1.51 cgd 87 1.4 mycroft #include <sys/param.h> 88 1.4 mycroft #include <sys/device.h> 89 1.301 riastrad #include <sys/device_impl.h> 90 1.118 dyoung #include <sys/disklabel.h> 91 1.118 dyoung #include <sys/conf.h> 92 1.118 dyoung #include <sys/kauth.h> 93 1.159 matt #include <sys/kmem.h> 94 1.17 christos #include <sys/systm.h> 95 1.43 thorpej #include <sys/kernel.h> 96 1.33 thorpej #include <sys/errno.h> 97 1.47 thorpej #include <sys/proc.h> 98 1.82 mrg #include <sys/reboot.h> 99 1.142 ad #include <sys/kthread.h> 100 1.118 dyoung #include <sys/buf.h> 101 1.118 dyoung #include <sys/dirent.h> 102 1.118 dyoung #include <sys/mount.h> 103 1.118 dyoung #include <sys/namei.h> 104 1.118 dyoung #include <sys/unistd.h> 105 1.118 dyoung #include <sys/fcntl.h> 106 1.118 dyoung #include <sys/lockf.h> 107 1.124 jmcneill #include <sys/callout.h> 108 1.149 jmcneill #include <sys/devmon.h> 109 1.153 cegger #include <sys/cpu.h> 110 1.174 dyoung #include <sys/sysctl.h> 111 1.278 thorpej #include <sys/stdarg.h> 112 1.298 riastrad #include <sys/localcount.h> 113 1.118 dyoung 114 1.118 dyoung #include <sys/disk.h> 115 1.118 dyoung 116 1.235 riastrad #include <sys/rndsource.h> 117 1.231 tls 118 1.16 mycroft #include <machine/limits.h> 119 1.1 glass 120 1.1 glass /* 121 1.1 glass * Autoconfiguration subroutines. 122 1.1 glass */ 123 1.1 glass 124 1.1 glass /* 125 1.231 tls * Device autoconfiguration timings are mixed into the entropy pool. 126 1.231 tls */ 127 1.270 riastrad static krndsource_t rnd_autoconf_source; 128 1.231 tls 129 1.231 tls /* 130 1.1 glass * ioconf.c exports exactly two names: cfdata and cfroots. All system 131 1.1 glass * devices and drivers are found via these tables. 132 1.1 glass */ 133 1.1 glass extern struct cfdata cfdata[]; 134 1.84 matt extern const short cfroots[]; 135 1.1 glass 136 1.65 thorpej /* 137 1.67 thorpej * List of all cfdriver structures. We use this to detect duplicates 138 1.67 thorpej * when other cfdrivers are loaded. 139 1.67 thorpej */ 140 1.69 thorpej struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers); 141 1.69 thorpej extern struct cfdriver * const cfdriver_list_initial[]; 142 1.67 thorpej 143 1.67 thorpej /* 144 1.76 thorpej * Initial list of cfattach's. 145 1.76 thorpej */ 146 1.76 thorpej extern const struct cfattachinit cfattachinit[]; 147 1.76 thorpej 148 1.76 thorpej /* 149 1.65 thorpej * List of cfdata tables. We always have one such list -- the one 150 1.65 thorpej * built statically when the kernel was configured. 151 1.65 thorpej */ 152 1.121 matt struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables); 153 1.65 thorpej static struct cftable initcftable; 154 1.65 thorpej 155 1.102 thorpej #define ROOT ((device_t)NULL) 156 1.1 glass 157 1.16 mycroft struct matchinfo { 158 1.99 drochner cfsubmatch_t fn; 159 1.224 chs device_t parent; 160 1.99 drochner const int *locs; 161 1.25 cgd void *aux; 162 1.25 cgd struct cfdata *match; 163 1.25 cgd int pri; 164 1.16 mycroft }; 165 1.17 christos 166 1.198 dyoung struct alldevs_foray { 167 1.198 dyoung int af_s; 168 1.198 dyoung struct devicelist af_garbage; 169 1.198 dyoung }; 170 1.198 dyoung 171 1.289 thorpej /* 172 1.289 thorpej * Internal version of the cfargs structure; all versions are 173 1.289 thorpej * canonicalized to this. 174 1.289 thorpej */ 175 1.289 thorpej struct cfargs_internal { 176 1.289 thorpej union { 177 1.289 thorpej cfsubmatch_t submatch;/* submatch function (direct config) */ 178 1.289 thorpej cfsearch_t search; /* search function (indirect config) */ 179 1.289 thorpej }; 180 1.289 thorpej const char * iattr; /* interface attribute */ 181 1.289 thorpej const int * locators; /* locators array */ 182 1.289 thorpej devhandle_t devhandle; /* devhandle_t (by value) */ 183 1.289 thorpej }; 184 1.289 thorpej 185 1.51 cgd static char *number(char *, int); 186 1.102 thorpej static void mapply(struct matchinfo *, cfdata_t); 187 1.187 dyoung static void config_devdelete(device_t); 188 1.190 dyoung static void config_devunlink(device_t, struct devicelist *); 189 1.117 drochner static void config_makeroom(int, struct cfdriver *); 190 1.117 drochner static void config_devlink(device_t); 191 1.198 dyoung static void config_alldevs_enter(struct alldevs_foray *); 192 1.198 dyoung static void config_alldevs_exit(struct alldevs_foray *); 193 1.221 pgoyette static void config_add_attrib_dict(device_t); 194 1.289 thorpej static device_t config_attach_internal(device_t, cfdata_t, void *, 195 1.289 thorpej cfprint_t, const struct cfargs_internal *); 196 1.197 rmind 197 1.197 rmind static void config_collect_garbage(struct devicelist *); 198 1.197 rmind static void config_dump_garbage(struct devicelist *); 199 1.197 rmind 200 1.139 dyoung static void pmflock_debug(device_t, const char *, int); 201 1.139 dyoung 202 1.136 dyoung static device_t deviter_next1(deviter_t *); 203 1.136 dyoung static void deviter_reinit(deviter_t *); 204 1.136 dyoung 205 1.29 thorpej struct deferred_config { 206 1.29 thorpej TAILQ_ENTRY(deferred_config) dc_queue; 207 1.102 thorpej device_t dc_dev; 208 1.102 thorpej void (*dc_func)(device_t); 209 1.29 thorpej }; 210 1.29 thorpej 211 1.42 thorpej TAILQ_HEAD(deferred_config_head, deferred_config); 212 1.29 thorpej 213 1.263 mrg static struct deferred_config_head deferred_config_queue = 214 1.121 matt TAILQ_HEAD_INITIALIZER(deferred_config_queue); 215 1.263 mrg static struct deferred_config_head interrupt_config_queue = 216 1.121 matt TAILQ_HEAD_INITIALIZER(interrupt_config_queue); 217 1.263 mrg static int interrupt_config_threads = 8; 218 1.263 mrg static struct deferred_config_head mountroot_config_queue = 219 1.207 tsutsui TAILQ_HEAD_INITIALIZER(mountroot_config_queue); 220 1.263 mrg static int mountroot_config_threads = 2; 221 1.234 mrg static lwp_t **mountroot_config_lwpids; 222 1.234 mrg static size_t mountroot_config_lwpids_size; 223 1.263 mrg bool root_is_mounted = false; 224 1.42 thorpej 225 1.102 thorpej static void config_process_deferred(struct deferred_config_head *, device_t); 226 1.29 thorpej 227 1.75 thorpej /* Hooks to finalize configuration once all real devices have been found. */ 228 1.75 thorpej struct finalize_hook { 229 1.75 thorpej TAILQ_ENTRY(finalize_hook) f_list; 230 1.102 thorpej int (*f_func)(device_t); 231 1.102 thorpej device_t f_dev; 232 1.75 thorpej }; 233 1.121 matt static TAILQ_HEAD(, finalize_hook) config_finalize_list = 234 1.121 matt TAILQ_HEAD_INITIALIZER(config_finalize_list); 235 1.75 thorpej static int config_finalize_done; 236 1.75 thorpej 237 1.56 thorpej /* list of all devices */ 238 1.257 mlelstv static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs); 239 1.257 mlelstv static kmutex_t alldevs_lock __cacheline_aligned; 240 1.257 mlelstv static devgen_t alldevs_gen = 1; 241 1.257 mlelstv static int alldevs_nread = 0; 242 1.257 mlelstv static int alldevs_nwrite = 0; 243 1.257 mlelstv static bool alldevs_garbage = false; 244 1.56 thorpej 245 1.274 riastrad static struct devicelist config_pending = 246 1.274 riastrad TAILQ_HEAD_INITIALIZER(config_pending); 247 1.151 ad static kmutex_t config_misc_lock; 248 1.151 ad static kcondvar_t config_misc_cv; 249 1.47 thorpej 250 1.210 martin static bool detachall = false; 251 1.174 dyoung 252 1.67 thorpej #define STREQ(s1, s2) \ 253 1.70 thorpej (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) 254 1.67 thorpej 255 1.185 pooka static bool config_initialized = false; /* config_init() has been called. */ 256 1.74 thorpej 257 1.80 thorpej static int config_do_twiddle; 258 1.176 ad static callout_t config_twiddle_ch; 259 1.80 thorpej 260 1.182 pooka static void sysctl_detach_setup(struct sysctllog **); 261 1.182 pooka 262 1.237 pgoyette int no_devmon_insert(const char *, prop_dictionary_t); 263 1.237 pgoyette int (*devmon_insert_vec)(const char *, prop_dictionary_t) = no_devmon_insert; 264 1.237 pgoyette 265 1.204 pooka typedef int (*cfdriver_fn)(struct cfdriver *); 266 1.204 pooka static int 267 1.204 pooka frob_cfdrivervec(struct cfdriver * const *cfdriverv, 268 1.204 pooka cfdriver_fn drv_do, cfdriver_fn drv_undo, 269 1.204 pooka const char *style, bool dopanic) 270 1.204 pooka { 271 1.226 christos void (*pr)(const char *, ...) __printflike(1, 2) = 272 1.255 joerg dopanic ? panic : printf; 273 1.229 martin int i, error = 0, e2 __diagused; 274 1.204 pooka 275 1.204 pooka for (i = 0; cfdriverv[i] != NULL; i++) { 276 1.204 pooka if ((error = drv_do(cfdriverv[i])) != 0) { 277 1.204 pooka pr("configure: `%s' driver %s failed: %d", 278 1.204 pooka cfdriverv[i]->cd_name, style, error); 279 1.204 pooka goto bad; 280 1.204 pooka } 281 1.204 pooka } 282 1.204 pooka 283 1.204 pooka KASSERT(error == 0); 284 1.204 pooka return 0; 285 1.204 pooka 286 1.204 pooka bad: 287 1.204 pooka printf("\n"); 288 1.204 pooka for (i--; i >= 0; i--) { 289 1.204 pooka e2 = drv_undo(cfdriverv[i]); 290 1.204 pooka KASSERT(e2 == 0); 291 1.204 pooka } 292 1.204 pooka 293 1.204 pooka return error; 294 1.204 pooka } 295 1.204 pooka 296 1.204 pooka typedef int (*cfattach_fn)(const char *, struct cfattach *); 297 1.204 pooka static int 298 1.204 pooka frob_cfattachvec(const struct cfattachinit *cfattachv, 299 1.204 pooka cfattach_fn att_do, cfattach_fn att_undo, 300 1.204 pooka const char *style, bool dopanic) 301 1.204 pooka { 302 1.204 pooka const struct cfattachinit *cfai = NULL; 303 1.226 christos void (*pr)(const char *, ...) __printflike(1, 2) = 304 1.255 joerg dopanic ? panic : printf; 305 1.229 martin int j = 0, error = 0, e2 __diagused; 306 1.204 pooka 307 1.204 pooka for (cfai = &cfattachv[0]; cfai->cfai_name != NULL; cfai++) { 308 1.204 pooka for (j = 0; cfai->cfai_list[j] != NULL; j++) { 309 1.204 pooka if ((error = att_do(cfai->cfai_name, 310 1.214 mbalmer cfai->cfai_list[j])) != 0) { 311 1.204 pooka pr("configure: attachment `%s' " 312 1.204 pooka "of `%s' driver %s failed: %d", 313 1.204 pooka cfai->cfai_list[j]->ca_name, 314 1.204 pooka cfai->cfai_name, style, error); 315 1.204 pooka goto bad; 316 1.204 pooka } 317 1.204 pooka } 318 1.204 pooka } 319 1.204 pooka 320 1.204 pooka KASSERT(error == 0); 321 1.204 pooka return 0; 322 1.204 pooka 323 1.204 pooka bad: 324 1.204 pooka /* 325 1.204 pooka * Rollback in reverse order. dunno if super-important, but 326 1.204 pooka * do that anyway. Although the code looks a little like 327 1.204 pooka * someone did a little integration (in the math sense). 328 1.204 pooka */ 329 1.204 pooka printf("\n"); 330 1.204 pooka if (cfai) { 331 1.204 pooka bool last; 332 1.204 pooka 333 1.204 pooka for (last = false; last == false; ) { 334 1.204 pooka if (cfai == &cfattachv[0]) 335 1.204 pooka last = true; 336 1.204 pooka for (j--; j >= 0; j--) { 337 1.204 pooka e2 = att_undo(cfai->cfai_name, 338 1.204 pooka cfai->cfai_list[j]); 339 1.204 pooka KASSERT(e2 == 0); 340 1.204 pooka } 341 1.204 pooka if (!last) { 342 1.204 pooka cfai--; 343 1.204 pooka for (j = 0; cfai->cfai_list[j] != NULL; j++) 344 1.204 pooka ; 345 1.204 pooka } 346 1.204 pooka } 347 1.204 pooka } 348 1.204 pooka 349 1.204 pooka return error; 350 1.204 pooka } 351 1.204 pooka 352 1.20 cgd /* 353 1.74 thorpej * Initialize the autoconfiguration data structures. Normally this 354 1.74 thorpej * is done by configure(), but some platforms need to do this very 355 1.74 thorpej * early (to e.g. initialize the console). 356 1.20 cgd */ 357 1.20 cgd void 358 1.74 thorpej config_init(void) 359 1.20 cgd { 360 1.67 thorpej 361 1.185 pooka KASSERT(config_initialized == false); 362 1.74 thorpej 363 1.257 mlelstv mutex_init(&alldevs_lock, MUTEX_DEFAULT, IPL_VM); 364 1.136 dyoung 365 1.151 ad mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE); 366 1.151 ad cv_init(&config_misc_cv, "cfgmisc"); 367 1.151 ad 368 1.176 ad callout_init(&config_twiddle_ch, CALLOUT_MPSAFE); 369 1.176 ad 370 1.204 pooka frob_cfdrivervec(cfdriver_list_initial, 371 1.204 pooka config_cfdriver_attach, NULL, "bootstrap", true); 372 1.204 pooka frob_cfattachvec(cfattachinit, 373 1.204 pooka config_cfattach_attach, NULL, "bootstrap", true); 374 1.20 cgd 375 1.65 thorpej initcftable.ct_cfdata = cfdata; 376 1.65 thorpej TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list); 377 1.185 pooka 378 1.270 riastrad rnd_attach_source(&rnd_autoconf_source, "autoconf", RND_TYPE_UNKNOWN, 379 1.270 riastrad RND_FLAG_COLLECT_TIME); 380 1.270 riastrad 381 1.185 pooka config_initialized = true; 382 1.185 pooka } 383 1.185 pooka 384 1.204 pooka /* 385 1.204 pooka * Init or fini drivers and attachments. Either all or none 386 1.204 pooka * are processed (via rollback). It would be nice if this were 387 1.204 pooka * atomic to outside consumers, but with the current state of 388 1.204 pooka * locking ... 389 1.204 pooka */ 390 1.204 pooka int 391 1.204 pooka config_init_component(struct cfdriver * const *cfdriverv, 392 1.204 pooka const struct cfattachinit *cfattachv, struct cfdata *cfdatav) 393 1.204 pooka { 394 1.204 pooka int error; 395 1.204 pooka 396 1.285 riastrad KERNEL_LOCK(1, NULL); 397 1.282 riastrad 398 1.204 pooka if ((error = frob_cfdrivervec(cfdriverv, 399 1.204 pooka config_cfdriver_attach, config_cfdriver_detach, "init", false))!= 0) 400 1.285 riastrad goto out; 401 1.204 pooka if ((error = frob_cfattachvec(cfattachv, 402 1.204 pooka config_cfattach_attach, config_cfattach_detach, 403 1.204 pooka "init", false)) != 0) { 404 1.204 pooka frob_cfdrivervec(cfdriverv, 405 1.204 pooka config_cfdriver_detach, NULL, "init rollback", true); 406 1.285 riastrad goto out; 407 1.204 pooka } 408 1.204 pooka if ((error = config_cfdata_attach(cfdatav, 1)) != 0) { 409 1.204 pooka frob_cfattachvec(cfattachv, 410 1.204 pooka config_cfattach_detach, NULL, "init rollback", true); 411 1.204 pooka frob_cfdrivervec(cfdriverv, 412 1.204 pooka config_cfdriver_detach, NULL, "init rollback", true); 413 1.285 riastrad goto out; 414 1.204 pooka } 415 1.204 pooka 416 1.285 riastrad /* Success! */ 417 1.285 riastrad error = 0; 418 1.285 riastrad 419 1.285 riastrad out: KERNEL_UNLOCK_ONE(NULL); 420 1.285 riastrad return error; 421 1.204 pooka } 422 1.204 pooka 423 1.204 pooka int 424 1.204 pooka config_fini_component(struct cfdriver * const *cfdriverv, 425 1.204 pooka const struct cfattachinit *cfattachv, struct cfdata *cfdatav) 426 1.204 pooka { 427 1.204 pooka int error; 428 1.204 pooka 429 1.285 riastrad KERNEL_LOCK(1, NULL); 430 1.282 riastrad 431 1.204 pooka if ((error = config_cfdata_detach(cfdatav)) != 0) 432 1.285 riastrad goto out; 433 1.204 pooka if ((error = frob_cfattachvec(cfattachv, 434 1.204 pooka config_cfattach_detach, config_cfattach_attach, 435 1.204 pooka "fini", false)) != 0) { 436 1.204 pooka if (config_cfdata_attach(cfdatav, 0) != 0) 437 1.204 pooka panic("config_cfdata fini rollback failed"); 438 1.285 riastrad goto out; 439 1.204 pooka } 440 1.204 pooka if ((error = frob_cfdrivervec(cfdriverv, 441 1.204 pooka config_cfdriver_detach, config_cfdriver_attach, 442 1.204 pooka "fini", false)) != 0) { 443 1.204 pooka frob_cfattachvec(cfattachv, 444 1.204 pooka config_cfattach_attach, NULL, "fini rollback", true); 445 1.204 pooka if (config_cfdata_attach(cfdatav, 0) != 0) 446 1.204 pooka panic("config_cfdata fini rollback failed"); 447 1.285 riastrad goto out; 448 1.204 pooka } 449 1.204 pooka 450 1.285 riastrad /* Success! */ 451 1.285 riastrad error = 0; 452 1.285 riastrad 453 1.285 riastrad out: KERNEL_UNLOCK_ONE(NULL); 454 1.285 riastrad return error; 455 1.204 pooka } 456 1.204 pooka 457 1.185 pooka void 458 1.185 pooka config_init_mi(void) 459 1.185 pooka { 460 1.185 pooka 461 1.185 pooka if (!config_initialized) 462 1.185 pooka config_init(); 463 1.185 pooka 464 1.182 pooka sysctl_detach_setup(NULL); 465 1.74 thorpej } 466 1.74 thorpej 467 1.126 dyoung void 468 1.126 dyoung config_deferred(device_t dev) 469 1.126 dyoung { 470 1.282 riastrad 471 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 472 1.282 riastrad 473 1.126 dyoung config_process_deferred(&deferred_config_queue, dev); 474 1.126 dyoung config_process_deferred(&interrupt_config_queue, dev); 475 1.207 tsutsui config_process_deferred(&mountroot_config_queue, dev); 476 1.126 dyoung } 477 1.126 dyoung 478 1.142 ad static void 479 1.142 ad config_interrupts_thread(void *cookie) 480 1.142 ad { 481 1.142 ad struct deferred_config *dc; 482 1.267 jdolecek device_t dev; 483 1.142 ad 484 1.266 jdolecek mutex_enter(&config_misc_lock); 485 1.142 ad while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) { 486 1.142 ad TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue); 487 1.266 jdolecek mutex_exit(&config_misc_lock); 488 1.266 jdolecek 489 1.267 jdolecek dev = dc->dc_dev; 490 1.267 jdolecek (*dc->dc_func)(dev); 491 1.267 jdolecek if (!device_pmf_is_registered(dev)) 492 1.267 jdolecek aprint_debug_dev(dev, 493 1.265 msaitoh "WARNING: power management not supported\n"); 494 1.267 jdolecek config_pending_decr(dev); 495 1.159 matt kmem_free(dc, sizeof(*dc)); 496 1.266 jdolecek 497 1.266 jdolecek mutex_enter(&config_misc_lock); 498 1.142 ad } 499 1.266 jdolecek mutex_exit(&config_misc_lock); 500 1.266 jdolecek 501 1.142 ad kthread_exit(0); 502 1.142 ad } 503 1.142 ad 504 1.74 thorpej void 505 1.222 matt config_create_interruptthreads(void) 506 1.74 thorpej { 507 1.180 pooka int i; 508 1.144 ad 509 1.142 ad for (i = 0; i < interrupt_config_threads; i++) { 510 1.266 jdolecek (void)kthread_create(PRI_NONE, 0/*XXXSMP */, NULL, 511 1.223 matt config_interrupts_thread, NULL, NULL, "configintr"); 512 1.142 ad } 513 1.20 cgd } 514 1.20 cgd 515 1.207 tsutsui static void 516 1.207 tsutsui config_mountroot_thread(void *cookie) 517 1.207 tsutsui { 518 1.207 tsutsui struct deferred_config *dc; 519 1.207 tsutsui 520 1.266 jdolecek mutex_enter(&config_misc_lock); 521 1.207 tsutsui while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) { 522 1.207 tsutsui TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue); 523 1.266 jdolecek mutex_exit(&config_misc_lock); 524 1.266 jdolecek 525 1.207 tsutsui (*dc->dc_func)(dc->dc_dev); 526 1.207 tsutsui kmem_free(dc, sizeof(*dc)); 527 1.266 jdolecek 528 1.266 jdolecek mutex_enter(&config_misc_lock); 529 1.207 tsutsui } 530 1.266 jdolecek mutex_exit(&config_misc_lock); 531 1.266 jdolecek 532 1.207 tsutsui kthread_exit(0); 533 1.207 tsutsui } 534 1.207 tsutsui 535 1.207 tsutsui void 536 1.222 matt config_create_mountrootthreads(void) 537 1.207 tsutsui { 538 1.207 tsutsui int i; 539 1.207 tsutsui 540 1.208 tsutsui if (!root_is_mounted) 541 1.208 tsutsui root_is_mounted = true; 542 1.208 tsutsui 543 1.234 mrg mountroot_config_lwpids_size = sizeof(mountroot_config_lwpids) * 544 1.234 mrg mountroot_config_threads; 545 1.234 mrg mountroot_config_lwpids = kmem_alloc(mountroot_config_lwpids_size, 546 1.234 mrg KM_NOSLEEP); 547 1.234 mrg KASSERT(mountroot_config_lwpids); 548 1.207 tsutsui for (i = 0; i < mountroot_config_threads; i++) { 549 1.234 mrg mountroot_config_lwpids[i] = 0; 550 1.266 jdolecek (void)kthread_create(PRI_NONE, KTHREAD_MUSTJOIN/* XXXSMP */, 551 1.266 jdolecek NULL, config_mountroot_thread, NULL, 552 1.234 mrg &mountroot_config_lwpids[i], 553 1.234 mrg "configroot"); 554 1.234 mrg } 555 1.234 mrg } 556 1.234 mrg 557 1.234 mrg void 558 1.234 mrg config_finalize_mountroot(void) 559 1.234 mrg { 560 1.234 mrg int i, error; 561 1.234 mrg 562 1.234 mrg for (i = 0; i < mountroot_config_threads; i++) { 563 1.234 mrg if (mountroot_config_lwpids[i] == 0) 564 1.234 mrg continue; 565 1.234 mrg 566 1.234 mrg error = kthread_join(mountroot_config_lwpids[i]); 567 1.234 mrg if (error) 568 1.234 mrg printf("%s: thread %x joined with error %d\n", 569 1.234 mrg __func__, i, error); 570 1.207 tsutsui } 571 1.234 mrg kmem_free(mountroot_config_lwpids, mountroot_config_lwpids_size); 572 1.207 tsutsui } 573 1.207 tsutsui 574 1.1 glass /* 575 1.149 jmcneill * Announce device attach/detach to userland listeners. 576 1.149 jmcneill */ 577 1.237 pgoyette 578 1.237 pgoyette int 579 1.237 pgoyette no_devmon_insert(const char *name, prop_dictionary_t p) 580 1.237 pgoyette { 581 1.237 pgoyette 582 1.237 pgoyette return ENODEV; 583 1.237 pgoyette } 584 1.237 pgoyette 585 1.149 jmcneill static void 586 1.149 jmcneill devmon_report_device(device_t dev, bool isattach) 587 1.149 jmcneill { 588 1.269 macallan prop_dictionary_t ev, dict = device_properties(dev); 589 1.149 jmcneill const char *parent; 590 1.149 jmcneill const char *what; 591 1.269 macallan const char *where; 592 1.149 jmcneill device_t pdev = device_parent(dev); 593 1.149 jmcneill 594 1.237 pgoyette /* If currently no drvctl device, just return */ 595 1.237 pgoyette if (devmon_insert_vec == no_devmon_insert) 596 1.237 pgoyette return; 597 1.237 pgoyette 598 1.149 jmcneill ev = prop_dictionary_create(); 599 1.149 jmcneill if (ev == NULL) 600 1.149 jmcneill return; 601 1.149 jmcneill 602 1.149 jmcneill what = (isattach ? "device-attach" : "device-detach"); 603 1.149 jmcneill parent = (pdev == NULL ? "root" : device_xname(pdev)); 604 1.272 jmcneill if (prop_dictionary_get_string(dict, "location", &where)) { 605 1.272 jmcneill prop_dictionary_set_string(ev, "location", where); 606 1.269 macallan aprint_debug("ev: %s %s at %s in [%s]\n", 607 1.269 macallan what, device_xname(dev), parent, where); 608 1.269 macallan } 609 1.272 jmcneill if (!prop_dictionary_set_string(ev, "device", device_xname(dev)) || 610 1.272 jmcneill !prop_dictionary_set_string(ev, "parent", parent)) { 611 1.149 jmcneill prop_object_release(ev); 612 1.149 jmcneill return; 613 1.149 jmcneill } 614 1.149 jmcneill 615 1.237 pgoyette if ((*devmon_insert_vec)(what, ev) != 0) 616 1.237 pgoyette prop_object_release(ev); 617 1.149 jmcneill } 618 1.149 jmcneill 619 1.149 jmcneill /* 620 1.67 thorpej * Add a cfdriver to the system. 621 1.67 thorpej */ 622 1.67 thorpej int 623 1.67 thorpej config_cfdriver_attach(struct cfdriver *cd) 624 1.67 thorpej { 625 1.67 thorpej struct cfdriver *lcd; 626 1.67 thorpej 627 1.67 thorpej /* Make sure this driver isn't already in the system. */ 628 1.67 thorpej LIST_FOREACH(lcd, &allcfdrivers, cd_list) { 629 1.67 thorpej if (STREQ(lcd->cd_name, cd->cd_name)) 630 1.175 cegger return EEXIST; 631 1.67 thorpej } 632 1.67 thorpej 633 1.76 thorpej LIST_INIT(&cd->cd_attach); 634 1.67 thorpej LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list); 635 1.67 thorpej 636 1.175 cegger return 0; 637 1.67 thorpej } 638 1.67 thorpej 639 1.67 thorpej /* 640 1.67 thorpej * Remove a cfdriver from the system. 641 1.67 thorpej */ 642 1.67 thorpej int 643 1.67 thorpej config_cfdriver_detach(struct cfdriver *cd) 644 1.67 thorpej { 645 1.198 dyoung struct alldevs_foray af; 646 1.198 dyoung int i, rc = 0; 647 1.67 thorpej 648 1.198 dyoung config_alldevs_enter(&af); 649 1.67 thorpej /* Make sure there are no active instances. */ 650 1.67 thorpej for (i = 0; i < cd->cd_ndevs; i++) { 651 1.187 dyoung if (cd->cd_devs[i] != NULL) { 652 1.187 dyoung rc = EBUSY; 653 1.187 dyoung break; 654 1.187 dyoung } 655 1.67 thorpej } 656 1.198 dyoung config_alldevs_exit(&af); 657 1.187 dyoung 658 1.187 dyoung if (rc != 0) 659 1.187 dyoung return rc; 660 1.67 thorpej 661 1.76 thorpej /* ...and no attachments loaded. */ 662 1.76 thorpej if (LIST_EMPTY(&cd->cd_attach) == 0) 663 1.175 cegger return EBUSY; 664 1.76 thorpej 665 1.67 thorpej LIST_REMOVE(cd, cd_list); 666 1.67 thorpej 667 1.67 thorpej KASSERT(cd->cd_devs == NULL); 668 1.67 thorpej 669 1.175 cegger return 0; 670 1.67 thorpej } 671 1.67 thorpej 672 1.67 thorpej /* 673 1.67 thorpej * Look up a cfdriver by name. 674 1.67 thorpej */ 675 1.78 isaki struct cfdriver * 676 1.67 thorpej config_cfdriver_lookup(const char *name) 677 1.67 thorpej { 678 1.67 thorpej struct cfdriver *cd; 679 1.69 thorpej 680 1.67 thorpej LIST_FOREACH(cd, &allcfdrivers, cd_list) { 681 1.67 thorpej if (STREQ(cd->cd_name, name)) 682 1.175 cegger return cd; 683 1.67 thorpej } 684 1.67 thorpej 685 1.175 cegger return NULL; 686 1.67 thorpej } 687 1.67 thorpej 688 1.67 thorpej /* 689 1.76 thorpej * Add a cfattach to the specified driver. 690 1.76 thorpej */ 691 1.76 thorpej int 692 1.76 thorpej config_cfattach_attach(const char *driver, struct cfattach *ca) 693 1.76 thorpej { 694 1.76 thorpej struct cfattach *lca; 695 1.76 thorpej struct cfdriver *cd; 696 1.76 thorpej 697 1.76 thorpej cd = config_cfdriver_lookup(driver); 698 1.76 thorpej if (cd == NULL) 699 1.175 cegger return ESRCH; 700 1.76 thorpej 701 1.76 thorpej /* Make sure this attachment isn't already on this driver. */ 702 1.76 thorpej LIST_FOREACH(lca, &cd->cd_attach, ca_list) { 703 1.76 thorpej if (STREQ(lca->ca_name, ca->ca_name)) 704 1.175 cegger return EEXIST; 705 1.76 thorpej } 706 1.76 thorpej 707 1.76 thorpej LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list); 708 1.76 thorpej 709 1.175 cegger return 0; 710 1.76 thorpej } 711 1.76 thorpej 712 1.76 thorpej /* 713 1.76 thorpej * Remove a cfattach from the specified driver. 714 1.76 thorpej */ 715 1.76 thorpej int 716 1.76 thorpej config_cfattach_detach(const char *driver, struct cfattach *ca) 717 1.76 thorpej { 718 1.198 dyoung struct alldevs_foray af; 719 1.76 thorpej struct cfdriver *cd; 720 1.102 thorpej device_t dev; 721 1.198 dyoung int i, rc = 0; 722 1.76 thorpej 723 1.76 thorpej cd = config_cfdriver_lookup(driver); 724 1.76 thorpej if (cd == NULL) 725 1.175 cegger return ESRCH; 726 1.76 thorpej 727 1.198 dyoung config_alldevs_enter(&af); 728 1.76 thorpej /* Make sure there are no active instances. */ 729 1.76 thorpej for (i = 0; i < cd->cd_ndevs; i++) { 730 1.76 thorpej if ((dev = cd->cd_devs[i]) == NULL) 731 1.76 thorpej continue; 732 1.187 dyoung if (dev->dv_cfattach == ca) { 733 1.187 dyoung rc = EBUSY; 734 1.187 dyoung break; 735 1.187 dyoung } 736 1.76 thorpej } 737 1.198 dyoung config_alldevs_exit(&af); 738 1.187 dyoung 739 1.187 dyoung if (rc != 0) 740 1.187 dyoung return rc; 741 1.76 thorpej 742 1.76 thorpej LIST_REMOVE(ca, ca_list); 743 1.76 thorpej 744 1.175 cegger return 0; 745 1.76 thorpej } 746 1.76 thorpej 747 1.76 thorpej /* 748 1.76 thorpej * Look up a cfattach by name. 749 1.76 thorpej */ 750 1.76 thorpej static struct cfattach * 751 1.76 thorpej config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname) 752 1.76 thorpej { 753 1.76 thorpej struct cfattach *ca; 754 1.76 thorpej 755 1.76 thorpej LIST_FOREACH(ca, &cd->cd_attach, ca_list) { 756 1.76 thorpej if (STREQ(ca->ca_name, atname)) 757 1.175 cegger return ca; 758 1.76 thorpej } 759 1.76 thorpej 760 1.175 cegger return NULL; 761 1.76 thorpej } 762 1.76 thorpej 763 1.76 thorpej /* 764 1.76 thorpej * Look up a cfattach by driver/attachment name. 765 1.76 thorpej */ 766 1.76 thorpej struct cfattach * 767 1.76 thorpej config_cfattach_lookup(const char *name, const char *atname) 768 1.76 thorpej { 769 1.76 thorpej struct cfdriver *cd; 770 1.76 thorpej 771 1.76 thorpej cd = config_cfdriver_lookup(name); 772 1.76 thorpej if (cd == NULL) 773 1.175 cegger return NULL; 774 1.76 thorpej 775 1.175 cegger return config_cfattach_lookup_cd(cd, atname); 776 1.76 thorpej } 777 1.76 thorpej 778 1.76 thorpej /* 779 1.1 glass * Apply the matching function and choose the best. This is used 780 1.1 glass * a few times and we want to keep the code small. 781 1.1 glass */ 782 1.16 mycroft static void 783 1.102 thorpej mapply(struct matchinfo *m, cfdata_t cf) 784 1.1 glass { 785 1.50 augustss int pri; 786 1.1 glass 787 1.99 drochner if (m->fn != NULL) { 788 1.99 drochner pri = (*m->fn)(m->parent, cf, m->locs, m->aux); 789 1.90 drochner } else { 790 1.100 drochner pri = config_match(m->parent, cf, m->aux); 791 1.3 glass } 792 1.1 glass if (pri > m->pri) { 793 1.25 cgd m->match = cf; 794 1.1 glass m->pri = pri; 795 1.1 glass } 796 1.1 glass } 797 1.1 glass 798 1.98 drochner int 799 1.102 thorpej config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux) 800 1.98 drochner { 801 1.98 drochner const struct cfiattrdata *ci; 802 1.98 drochner const struct cflocdesc *cl; 803 1.98 drochner int nlocs, i; 804 1.98 drochner 805 1.201 dyoung ci = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver); 806 1.98 drochner KASSERT(ci); 807 1.98 drochner nlocs = ci->ci_loclen; 808 1.154 drochner KASSERT(!nlocs || locs); 809 1.98 drochner for (i = 0; i < nlocs; i++) { 810 1.98 drochner cl = &ci->ci_locdesc[i]; 811 1.233 uebayasi if (cl->cld_defaultstr != NULL && 812 1.233 uebayasi cf->cf_loc[i] == cl->cld_default) 813 1.233 uebayasi continue; 814 1.233 uebayasi if (cf->cf_loc[i] == locs[i]) 815 1.233 uebayasi continue; 816 1.233 uebayasi return 0; 817 1.98 drochner } 818 1.98 drochner 819 1.175 cegger return config_match(parent, cf, aux); 820 1.98 drochner } 821 1.98 drochner 822 1.1 glass /* 823 1.96 drochner * Helper function: check whether the driver supports the interface attribute 824 1.96 drochner * and return its descriptor structure. 825 1.91 drochner */ 826 1.96 drochner static const struct cfiattrdata * 827 1.96 drochner cfdriver_get_iattr(const struct cfdriver *cd, const char *ia) 828 1.91 drochner { 829 1.96 drochner const struct cfiattrdata * const *cpp; 830 1.91 drochner 831 1.91 drochner if (cd->cd_attrs == NULL) 832 1.175 cegger return 0; 833 1.91 drochner 834 1.91 drochner for (cpp = cd->cd_attrs; *cpp; cpp++) { 835 1.96 drochner if (STREQ((*cpp)->ci_name, ia)) { 836 1.91 drochner /* Match. */ 837 1.175 cegger return *cpp; 838 1.91 drochner } 839 1.91 drochner } 840 1.175 cegger return 0; 841 1.91 drochner } 842 1.91 drochner 843 1.295 tnn static int __diagused 844 1.295 tnn cfdriver_iattr_count(const struct cfdriver *cd) 845 1.278 thorpej { 846 1.278 thorpej const struct cfiattrdata * const *cpp; 847 1.278 thorpej int i; 848 1.278 thorpej 849 1.278 thorpej if (cd->cd_attrs == NULL) 850 1.278 thorpej return 0; 851 1.278 thorpej 852 1.278 thorpej for (i = 0, cpp = cd->cd_attrs; *cpp; cpp++) { 853 1.278 thorpej i++; 854 1.278 thorpej } 855 1.278 thorpej return i; 856 1.278 thorpej } 857 1.278 thorpej 858 1.91 drochner /* 859 1.96 drochner * Lookup an interface attribute description by name. 860 1.96 drochner * If the driver is given, consider only its supported attributes. 861 1.96 drochner */ 862 1.96 drochner const struct cfiattrdata * 863 1.96 drochner cfiattr_lookup(const char *name, const struct cfdriver *cd) 864 1.96 drochner { 865 1.96 drochner const struct cfdriver *d; 866 1.96 drochner const struct cfiattrdata *ia; 867 1.96 drochner 868 1.96 drochner if (cd) 869 1.175 cegger return cfdriver_get_iattr(cd, name); 870 1.96 drochner 871 1.96 drochner LIST_FOREACH(d, &allcfdrivers, cd_list) { 872 1.96 drochner ia = cfdriver_get_iattr(d, name); 873 1.96 drochner if (ia) 874 1.175 cegger return ia; 875 1.96 drochner } 876 1.175 cegger return 0; 877 1.96 drochner } 878 1.96 drochner 879 1.96 drochner /* 880 1.66 thorpej * Determine if `parent' is a potential parent for a device spec based 881 1.66 thorpej * on `cfp'. 882 1.66 thorpej */ 883 1.66 thorpej static int 884 1.102 thorpej cfparent_match(const device_t parent, const struct cfparent *cfp) 885 1.66 thorpej { 886 1.67 thorpej struct cfdriver *pcd; 887 1.70 thorpej 888 1.70 thorpej /* We don't match root nodes here. */ 889 1.70 thorpej if (cfp == NULL) 890 1.175 cegger return 0; 891 1.66 thorpej 892 1.77 thorpej pcd = parent->dv_cfdriver; 893 1.67 thorpej KASSERT(pcd != NULL); 894 1.67 thorpej 895 1.66 thorpej /* 896 1.66 thorpej * First, ensure this parent has the correct interface 897 1.66 thorpej * attribute. 898 1.66 thorpej */ 899 1.96 drochner if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr)) 900 1.175 cegger return 0; 901 1.66 thorpej 902 1.66 thorpej /* 903 1.66 thorpej * If no specific parent device instance was specified (i.e. 904 1.66 thorpej * we're attaching to the attribute only), we're done! 905 1.66 thorpej */ 906 1.66 thorpej if (cfp->cfp_parent == NULL) 907 1.175 cegger return 1; 908 1.66 thorpej 909 1.66 thorpej /* 910 1.66 thorpej * Check the parent device's name. 911 1.66 thorpej */ 912 1.71 thorpej if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0) 913 1.175 cegger return 0; /* not the same parent */ 914 1.66 thorpej 915 1.66 thorpej /* 916 1.66 thorpej * Make sure the unit number matches. 917 1.66 thorpej */ 918 1.77 thorpej if (cfp->cfp_unit == DVUNIT_ANY || /* wildcard */ 919 1.66 thorpej cfp->cfp_unit == parent->dv_unit) 920 1.175 cegger return 1; 921 1.66 thorpej 922 1.66 thorpej /* Unit numbers don't match. */ 923 1.175 cegger return 0; 924 1.68 thorpej } 925 1.68 thorpej 926 1.68 thorpej /* 927 1.90 drochner * Helper for config_cfdata_attach(): check all devices whether it could be 928 1.90 drochner * parent any attachment in the config data table passed, and rescan. 929 1.90 drochner */ 930 1.90 drochner static void 931 1.90 drochner rescan_with_cfdata(const struct cfdata *cf) 932 1.90 drochner { 933 1.102 thorpej device_t d; 934 1.90 drochner const struct cfdata *cf1; 935 1.136 dyoung deviter_t di; 936 1.243 msaitoh 937 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 938 1.90 drochner 939 1.90 drochner /* 940 1.164 ad * "alldevs" is likely longer than a modules's cfdata, so make it 941 1.90 drochner * the outer loop. 942 1.90 drochner */ 943 1.136 dyoung for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) { 944 1.90 drochner 945 1.90 drochner if (!(d->dv_cfattach->ca_rescan)) 946 1.90 drochner continue; 947 1.90 drochner 948 1.90 drochner for (cf1 = cf; cf1->cf_name; cf1++) { 949 1.90 drochner 950 1.90 drochner if (!cfparent_match(d, cf1->cf_pspec)) 951 1.90 drochner continue; 952 1.90 drochner 953 1.90 drochner (*d->dv_cfattach->ca_rescan)(d, 954 1.201 dyoung cfdata_ifattr(cf1), cf1->cf_loc); 955 1.209 jruoho 956 1.209 jruoho config_deferred(d); 957 1.90 drochner } 958 1.90 drochner } 959 1.136 dyoung deviter_release(&di); 960 1.90 drochner } 961 1.90 drochner 962 1.90 drochner /* 963 1.90 drochner * Attach a supplemental config data table and rescan potential 964 1.90 drochner * parent devices if required. 965 1.90 drochner */ 966 1.90 drochner int 967 1.102 thorpej config_cfdata_attach(cfdata_t cf, int scannow) 968 1.90 drochner { 969 1.90 drochner struct cftable *ct; 970 1.90 drochner 971 1.285 riastrad KERNEL_LOCK(1, NULL); 972 1.282 riastrad 973 1.159 matt ct = kmem_alloc(sizeof(*ct), KM_SLEEP); 974 1.90 drochner ct->ct_cfdata = cf; 975 1.90 drochner TAILQ_INSERT_TAIL(&allcftables, ct, ct_list); 976 1.90 drochner 977 1.90 drochner if (scannow) 978 1.90 drochner rescan_with_cfdata(cf); 979 1.90 drochner 980 1.288 skrll KERNEL_UNLOCK_ONE(NULL); 981 1.285 riastrad 982 1.175 cegger return 0; 983 1.90 drochner } 984 1.90 drochner 985 1.90 drochner /* 986 1.90 drochner * Helper for config_cfdata_detach: check whether a device is 987 1.90 drochner * found through any attachment in the config data table. 988 1.90 drochner */ 989 1.90 drochner static int 990 1.224 chs dev_in_cfdata(device_t d, cfdata_t cf) 991 1.90 drochner { 992 1.90 drochner const struct cfdata *cf1; 993 1.90 drochner 994 1.90 drochner for (cf1 = cf; cf1->cf_name; cf1++) 995 1.90 drochner if (d->dv_cfdata == cf1) 996 1.175 cegger return 1; 997 1.90 drochner 998 1.175 cegger return 0; 999 1.90 drochner } 1000 1.90 drochner 1001 1.90 drochner /* 1002 1.90 drochner * Detach a supplemental config data table. Detach all devices found 1003 1.90 drochner * through that table (and thus keeping references to it) before. 1004 1.90 drochner */ 1005 1.90 drochner int 1006 1.102 thorpej config_cfdata_detach(cfdata_t cf) 1007 1.90 drochner { 1008 1.102 thorpej device_t d; 1009 1.136 dyoung int error = 0; 1010 1.90 drochner struct cftable *ct; 1011 1.136 dyoung deviter_t di; 1012 1.90 drochner 1013 1.285 riastrad KERNEL_LOCK(1, NULL); 1014 1.285 riastrad 1015 1.136 dyoung for (d = deviter_first(&di, DEVITER_F_RW); d != NULL; 1016 1.136 dyoung d = deviter_next(&di)) { 1017 1.136 dyoung if (!dev_in_cfdata(d, cf)) 1018 1.136 dyoung continue; 1019 1.136 dyoung if ((error = config_detach(d, 0)) != 0) 1020 1.136 dyoung break; 1021 1.136 dyoung } 1022 1.136 dyoung deviter_release(&di); 1023 1.136 dyoung if (error) { 1024 1.136 dyoung aprint_error_dev(d, "unable to detach instance\n"); 1025 1.285 riastrad goto out; 1026 1.90 drochner } 1027 1.90 drochner 1028 1.90 drochner TAILQ_FOREACH(ct, &allcftables, ct_list) { 1029 1.90 drochner if (ct->ct_cfdata == cf) { 1030 1.90 drochner TAILQ_REMOVE(&allcftables, ct, ct_list); 1031 1.159 matt kmem_free(ct, sizeof(*ct)); 1032 1.285 riastrad error = 0; 1033 1.285 riastrad goto out; 1034 1.90 drochner } 1035 1.90 drochner } 1036 1.90 drochner 1037 1.90 drochner /* not found -- shouldn't happen */ 1038 1.285 riastrad error = EINVAL; 1039 1.285 riastrad 1040 1.285 riastrad out: KERNEL_UNLOCK_ONE(NULL); 1041 1.285 riastrad return error; 1042 1.90 drochner } 1043 1.90 drochner 1044 1.90 drochner /* 1045 1.68 thorpej * Invoke the "match" routine for a cfdata entry on behalf of 1046 1.278 thorpej * an external caller, usually a direct config "submatch" routine. 1047 1.68 thorpej */ 1048 1.68 thorpej int 1049 1.102 thorpej config_match(device_t parent, cfdata_t cf, void *aux) 1050 1.68 thorpej { 1051 1.76 thorpej struct cfattach *ca; 1052 1.76 thorpej 1053 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 1054 1.282 riastrad 1055 1.76 thorpej ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); 1056 1.76 thorpej if (ca == NULL) { 1057 1.76 thorpej /* No attachment for this entry, oh well. */ 1058 1.175 cegger return 0; 1059 1.76 thorpej } 1060 1.68 thorpej 1061 1.175 cegger return (*ca->ca_match)(parent, cf, aux); 1062 1.66 thorpej } 1063 1.66 thorpej 1064 1.66 thorpej /* 1065 1.278 thorpej * Invoke the "probe" routine for a cfdata entry on behalf of 1066 1.278 thorpej * an external caller, usually an indirect config "search" routine. 1067 1.278 thorpej */ 1068 1.278 thorpej int 1069 1.278 thorpej config_probe(device_t parent, cfdata_t cf, void *aux) 1070 1.278 thorpej { 1071 1.278 thorpej /* 1072 1.278 thorpej * This is currently a synonym for config_match(), but this 1073 1.278 thorpej * is an implementation detail; "match" and "probe" routines 1074 1.278 thorpej * have different behaviors. 1075 1.278 thorpej * 1076 1.278 thorpej * XXX config_probe() should return a bool, because there is 1077 1.278 thorpej * XXX no match score for probe -- it's either there or it's 1078 1.278 thorpej * XXX not, but some ports abuse the return value as a way 1079 1.278 thorpej * XXX to attach "critical" devices before "non-critical" 1080 1.278 thorpej * XXX devices. 1081 1.278 thorpej */ 1082 1.278 thorpej return config_match(parent, cf, aux); 1083 1.278 thorpej } 1084 1.278 thorpej 1085 1.289 thorpej static struct cfargs_internal * 1086 1.289 thorpej cfargs_canonicalize(const struct cfargs * const cfargs, 1087 1.289 thorpej struct cfargs_internal * const store) 1088 1.289 thorpej { 1089 1.289 thorpej struct cfargs_internal *args = store; 1090 1.278 thorpej 1091 1.289 thorpej memset(args, 0, sizeof(*args)); 1092 1.278 thorpej 1093 1.289 thorpej /* If none specified, are all-NULL pointers are good. */ 1094 1.289 thorpej if (cfargs == NULL) { 1095 1.289 thorpej return args; 1096 1.289 thorpej } 1097 1.278 thorpej 1098 1.289 thorpej /* 1099 1.289 thorpej * Only one arguments version is recognized at this time. 1100 1.289 thorpej */ 1101 1.289 thorpej if (cfargs->cfargs_version != CFARGS_VERSION) { 1102 1.289 thorpej panic("cfargs_canonicalize: unknown version %lu\n", 1103 1.289 thorpej (unsigned long)cfargs->cfargs_version); 1104 1.289 thorpej } 1105 1.278 thorpej 1106 1.289 thorpej /* 1107 1.289 thorpej * submatch and search are mutually-exclusive. 1108 1.289 thorpej */ 1109 1.289 thorpej if (cfargs->submatch != NULL && cfargs->search != NULL) { 1110 1.289 thorpej panic("cfargs_canonicalize: submatch and search are " 1111 1.289 thorpej "mutually-exclusive"); 1112 1.289 thorpej } 1113 1.289 thorpej if (cfargs->submatch != NULL) { 1114 1.289 thorpej args->submatch = cfargs->submatch; 1115 1.289 thorpej } else if (cfargs->search != NULL) { 1116 1.289 thorpej args->search = cfargs->search; 1117 1.289 thorpej } 1118 1.278 thorpej 1119 1.289 thorpej args->iattr = cfargs->iattr; 1120 1.289 thorpej args->locators = cfargs->locators; 1121 1.289 thorpej args->devhandle = cfargs->devhandle; 1122 1.278 thorpej 1123 1.289 thorpej return args; 1124 1.278 thorpej } 1125 1.278 thorpej 1126 1.278 thorpej /* 1127 1.1 glass * Iterate over all potential children of some device, calling the given 1128 1.1 glass * function (default being the child's match function) for each one. 1129 1.1 glass * Nonzero returns are matches; the highest value returned is considered 1130 1.1 glass * the best match. Return the `found child' if we got a match, or NULL 1131 1.1 glass * otherwise. The `aux' pointer is simply passed on through. 1132 1.1 glass * 1133 1.1 glass * Note that this function is designed so that it can be used to apply 1134 1.1 glass * an arbitrary function to all potential children (its return value 1135 1.1 glass * can be ignored). 1136 1.1 glass */ 1137 1.289 thorpej static cfdata_t 1138 1.289 thorpej config_search_internal(device_t parent, void *aux, 1139 1.289 thorpej const struct cfargs_internal * const args) 1140 1.90 drochner { 1141 1.90 drochner struct cftable *ct; 1142 1.102 thorpej cfdata_t cf; 1143 1.90 drochner struct matchinfo m; 1144 1.90 drochner 1145 1.90 drochner KASSERT(config_initialized); 1146 1.307 riastrad KASSERTMSG((!args->iattr || 1147 1.307 riastrad cfdriver_get_iattr(parent->dv_cfdriver, args->iattr)), 1148 1.307 riastrad "%s searched for child at interface attribute %s," 1149 1.307 riastrad " but device %s(4) has no such interface attribute in config(5)", 1150 1.307 riastrad device_xname(parent), args->iattr, 1151 1.307 riastrad parent->dv_cfdriver->cd_name); 1152 1.307 riastrad KASSERTMSG((args->iattr || 1153 1.307 riastrad cfdriver_iattr_count(parent->dv_cfdriver) < 2), 1154 1.307 riastrad "%s searched for child without interface attribute," 1155 1.307 riastrad " needed to disambiguate among the %d declared for in %s(4)" 1156 1.307 riastrad " in config(5)", 1157 1.307 riastrad device_xname(parent), 1158 1.307 riastrad cfdriver_iattr_count(parent->dv_cfdriver), 1159 1.307 riastrad parent->dv_cfdriver->cd_name); 1160 1.90 drochner 1161 1.289 thorpej m.fn = args->submatch; /* N.B. union */ 1162 1.1 glass m.parent = parent; 1163 1.289 thorpej m.locs = args->locators; 1164 1.25 cgd m.aux = aux; 1165 1.14 mycroft m.match = NULL; 1166 1.1 glass m.pri = 0; 1167 1.65 thorpej 1168 1.65 thorpej TAILQ_FOREACH(ct, &allcftables, ct_list) { 1169 1.67 thorpej for (cf = ct->ct_cfdata; cf->cf_name; cf++) { 1170 1.90 drochner 1171 1.90 drochner /* We don't match root nodes here. */ 1172 1.90 drochner if (!cf->cf_pspec) 1173 1.90 drochner continue; 1174 1.90 drochner 1175 1.65 thorpej /* 1176 1.65 thorpej * Skip cf if no longer eligible, otherwise scan 1177 1.65 thorpej * through parents for one matching `parent', and 1178 1.65 thorpej * try match function. 1179 1.65 thorpej */ 1180 1.65 thorpej if (cf->cf_fstate == FSTATE_FOUND) 1181 1.65 thorpej continue; 1182 1.65 thorpej if (cf->cf_fstate == FSTATE_DNOTFOUND || 1183 1.65 thorpej cf->cf_fstate == FSTATE_DSTAR) 1184 1.65 thorpej continue; 1185 1.90 drochner 1186 1.90 drochner /* 1187 1.90 drochner * If an interface attribute was specified, 1188 1.90 drochner * consider only children which attach to 1189 1.90 drochner * that attribute. 1190 1.90 drochner */ 1191 1.289 thorpej if (args->iattr != NULL && 1192 1.289 thorpej !STREQ(args->iattr, cfdata_ifattr(cf))) 1193 1.90 drochner continue; 1194 1.90 drochner 1195 1.66 thorpej if (cfparent_match(parent, cf->cf_pspec)) 1196 1.66 thorpej mapply(&m, cf); 1197 1.65 thorpej } 1198 1.1 glass } 1199 1.297 riastrad rnd_add_uint32(&rnd_autoconf_source, 0); 1200 1.175 cegger return m.match; 1201 1.1 glass } 1202 1.1 glass 1203 1.102 thorpej cfdata_t 1204 1.289 thorpej config_search(device_t parent, void *aux, const struct cfargs *cfargs) 1205 1.102 thorpej { 1206 1.278 thorpej cfdata_t cf; 1207 1.289 thorpej struct cfargs_internal store; 1208 1.102 thorpej 1209 1.289 thorpej cf = config_search_internal(parent, aux, 1210 1.289 thorpej cfargs_canonicalize(cfargs, &store)); 1211 1.278 thorpej 1212 1.278 thorpej return cf; 1213 1.102 thorpej } 1214 1.102 thorpej 1215 1.16 mycroft /* 1216 1.1 glass * Find the given root device. 1217 1.1 glass * This is much like config_search, but there is no parent. 1218 1.65 thorpej * Don't bother with multiple cfdata tables; the root node 1219 1.65 thorpej * must always be in the initial table. 1220 1.1 glass */ 1221 1.102 thorpej cfdata_t 1222 1.95 drochner config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux) 1223 1.1 glass { 1224 1.102 thorpej cfdata_t cf; 1225 1.84 matt const short *p; 1226 1.1 glass struct matchinfo m; 1227 1.1 glass 1228 1.99 drochner m.fn = fn; 1229 1.1 glass m.parent = ROOT; 1230 1.25 cgd m.aux = aux; 1231 1.14 mycroft m.match = NULL; 1232 1.1 glass m.pri = 0; 1233 1.114 christos m.locs = 0; 1234 1.1 glass /* 1235 1.1 glass * Look at root entries for matching name. We do not bother 1236 1.1 glass * with found-state here since only one root should ever be 1237 1.1 glass * searched (and it must be done first). 1238 1.1 glass */ 1239 1.1 glass for (p = cfroots; *p >= 0; p++) { 1240 1.1 glass cf = &cfdata[*p]; 1241 1.67 thorpej if (strcmp(cf->cf_name, rootname) == 0) 1242 1.16 mycroft mapply(&m, cf); 1243 1.1 glass } 1244 1.175 cegger return m.match; 1245 1.1 glass } 1246 1.1 glass 1247 1.280 thorpej static const char * const msgs[] = { 1248 1.280 thorpej [QUIET] = "", 1249 1.280 thorpej [UNCONF] = " not configured\n", 1250 1.280 thorpej [UNSUPP] = " unsupported\n", 1251 1.280 thorpej }; 1252 1.1 glass 1253 1.1 glass /* 1254 1.1 glass * The given `aux' argument describes a device that has been found 1255 1.1 glass * on the given parent, but not necessarily configured. Locate the 1256 1.18 cgd * configuration data for that device (using the submatch function 1257 1.18 cgd * provided, or using candidates' cd_match configuration driver 1258 1.218 dyoung * functions) and attach it, and return its device_t. If the device was 1259 1.218 dyoung * not configured, call the given `print' function and return NULL. 1260 1.1 glass */ 1261 1.279 thorpej device_t 1262 1.311 riastrad config_found_acquire(device_t parent, void *aux, cfprint_t print, 1263 1.289 thorpej const struct cfargs * const cfargs) 1264 1.90 drochner { 1265 1.102 thorpej cfdata_t cf; 1266 1.289 thorpej struct cfargs_internal store; 1267 1.289 thorpej const struct cfargs_internal * const args = 1268 1.289 thorpej cfargs_canonicalize(cfargs, &store); 1269 1.311 riastrad device_t dev; 1270 1.311 riastrad 1271 1.311 riastrad KERNEL_LOCK(1, NULL); 1272 1.278 thorpej 1273 1.289 thorpej cf = config_search_internal(parent, aux, args); 1274 1.278 thorpej if (cf != NULL) { 1275 1.311 riastrad dev = config_attach_internal(parent, cf, aux, print, args); 1276 1.311 riastrad goto out; 1277 1.278 thorpej } 1278 1.90 drochner 1279 1.90 drochner if (print) { 1280 1.176 ad if (config_do_twiddle && cold) 1281 1.90 drochner twiddle(); 1282 1.280 thorpej 1283 1.280 thorpej const int pret = (*print)(aux, device_xname(parent)); 1284 1.280 thorpej KASSERT(pret >= 0); 1285 1.280 thorpej KASSERT(pret < __arraycount(msgs)); 1286 1.280 thorpej KASSERT(msgs[pret] != NULL); 1287 1.280 thorpej aprint_normal("%s", msgs[pret]); 1288 1.90 drochner } 1289 1.105 jmcneill 1290 1.311 riastrad dev = NULL; 1291 1.311 riastrad 1292 1.311 riastrad out: KERNEL_UNLOCK_ONE(NULL); 1293 1.311 riastrad return dev; 1294 1.311 riastrad } 1295 1.311 riastrad 1296 1.311 riastrad /* 1297 1.311 riastrad * config_found(parent, aux, print, cfargs) 1298 1.311 riastrad * 1299 1.311 riastrad * Legacy entry point for callers whose use of the returned 1300 1.311 riastrad * device_t is not delimited by device_release. 1301 1.311 riastrad * 1302 1.311 riastrad * The caller is required to hold the kernel lock as a fragile 1303 1.311 riastrad * defence against races. 1304 1.311 riastrad * 1305 1.311 riastrad * Callers should ignore the return value or be converted to 1306 1.311 riastrad * config_found_acquire with a matching device_release once they 1307 1.311 riastrad * have finished with the returned device_t. 1308 1.311 riastrad */ 1309 1.311 riastrad device_t 1310 1.311 riastrad config_found(device_t parent, void *aux, cfprint_t print, 1311 1.311 riastrad const struct cfargs * const cfargs) 1312 1.311 riastrad { 1313 1.311 riastrad device_t dev; 1314 1.311 riastrad 1315 1.311 riastrad KASSERT(KERNEL_LOCKED_P()); 1316 1.311 riastrad 1317 1.311 riastrad dev = config_found_acquire(parent, aux, print, cfargs); 1318 1.311 riastrad if (dev == NULL) 1319 1.311 riastrad return NULL; 1320 1.311 riastrad device_release(dev); 1321 1.311 riastrad 1322 1.311 riastrad return dev; 1323 1.90 drochner } 1324 1.90 drochner 1325 1.1 glass /* 1326 1.1 glass * As above, but for root devices. 1327 1.1 glass */ 1328 1.102 thorpej device_t 1329 1.52 cgd config_rootfound(const char *rootname, void *aux) 1330 1.1 glass { 1331 1.102 thorpej cfdata_t cf; 1332 1.281 riastrad device_t dev = NULL; 1333 1.25 cgd 1334 1.281 riastrad KERNEL_LOCK(1, NULL); 1335 1.220 plunky if ((cf = config_rootsearch(NULL, rootname, aux)) != NULL) 1336 1.289 thorpej dev = config_attach(ROOT, cf, aux, NULL, CFARGS_NONE); 1337 1.281 riastrad else 1338 1.281 riastrad aprint_error("root device %s not configured\n", rootname); 1339 1.281 riastrad KERNEL_UNLOCK_ONE(NULL); 1340 1.281 riastrad return dev; 1341 1.1 glass } 1342 1.1 glass 1343 1.1 glass /* just like sprintf(buf, "%d") except that it works from the end */ 1344 1.1 glass static char * 1345 1.51 cgd number(char *ep, int n) 1346 1.1 glass { 1347 1.1 glass 1348 1.1 glass *--ep = 0; 1349 1.1 glass while (n >= 10) { 1350 1.1 glass *--ep = (n % 10) + '0'; 1351 1.1 glass n /= 10; 1352 1.1 glass } 1353 1.1 glass *--ep = n + '0'; 1354 1.175 cegger return ep; 1355 1.1 glass } 1356 1.1 glass 1357 1.1 glass /* 1358 1.59 augustss * Expand the size of the cd_devs array if necessary. 1359 1.187 dyoung * 1360 1.257 mlelstv * The caller must hold alldevs_lock. config_makeroom() may release and 1361 1.257 mlelstv * re-acquire alldevs_lock, so callers should re-check conditions such 1362 1.257 mlelstv * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom() 1363 1.187 dyoung * returns. 1364 1.59 augustss */ 1365 1.117 drochner static void 1366 1.59 augustss config_makeroom(int n, struct cfdriver *cd) 1367 1.59 augustss { 1368 1.232 matt int ondevs, nndevs; 1369 1.190 dyoung device_t *osp, *nsp; 1370 1.59 augustss 1371 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 1372 1.257 mlelstv alldevs_nwrite++; 1373 1.187 dyoung 1374 1.310 riastrad /* XXX arithmetic overflow */ 1375 1.232 matt for (nndevs = MAX(4, cd->cd_ndevs); nndevs <= n; nndevs += nndevs) 1376 1.190 dyoung ; 1377 1.190 dyoung 1378 1.190 dyoung while (n >= cd->cd_ndevs) { 1379 1.190 dyoung /* 1380 1.190 dyoung * Need to expand the array. 1381 1.190 dyoung */ 1382 1.232 matt ondevs = cd->cd_ndevs; 1383 1.190 dyoung osp = cd->cd_devs; 1384 1.190 dyoung 1385 1.251 riastrad /* 1386 1.257 mlelstv * Release alldevs_lock around allocation, which may 1387 1.190 dyoung * sleep. 1388 1.190 dyoung */ 1389 1.257 mlelstv mutex_exit(&alldevs_lock); 1390 1.273 jdolecek nsp = kmem_alloc(sizeof(device_t) * nndevs, KM_SLEEP); 1391 1.257 mlelstv mutex_enter(&alldevs_lock); 1392 1.190 dyoung 1393 1.251 riastrad /* 1394 1.251 riastrad * If another thread moved the array while we did 1395 1.257 mlelstv * not hold alldevs_lock, try again. 1396 1.190 dyoung */ 1397 1.308 riastrad if (cd->cd_devs != osp || cd->cd_ndevs != ondevs) { 1398 1.257 mlelstv mutex_exit(&alldevs_lock); 1399 1.273 jdolecek kmem_free(nsp, sizeof(device_t) * nndevs); 1400 1.257 mlelstv mutex_enter(&alldevs_lock); 1401 1.190 dyoung continue; 1402 1.190 dyoung } 1403 1.59 augustss 1404 1.273 jdolecek memset(nsp + ondevs, 0, sizeof(device_t) * (nndevs - ondevs)); 1405 1.232 matt if (ondevs != 0) 1406 1.273 jdolecek memcpy(nsp, cd->cd_devs, sizeof(device_t) * ondevs); 1407 1.190 dyoung 1408 1.232 matt cd->cd_ndevs = nndevs; 1409 1.190 dyoung cd->cd_devs = nsp; 1410 1.232 matt if (ondevs != 0) { 1411 1.257 mlelstv mutex_exit(&alldevs_lock); 1412 1.273 jdolecek kmem_free(osp, sizeof(device_t) * ondevs); 1413 1.257 mlelstv mutex_enter(&alldevs_lock); 1414 1.206 dyoung } 1415 1.59 augustss } 1416 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 1417 1.257 mlelstv alldevs_nwrite--; 1418 1.59 augustss } 1419 1.59 augustss 1420 1.190 dyoung /* 1421 1.190 dyoung * Put dev into the devices list. 1422 1.190 dyoung */ 1423 1.117 drochner static void 1424 1.117 drochner config_devlink(device_t dev) 1425 1.117 drochner { 1426 1.117 drochner 1427 1.257 mlelstv mutex_enter(&alldevs_lock); 1428 1.117 drochner 1429 1.190 dyoung KASSERT(device_cfdriver(dev)->cd_devs[dev->dv_unit] == dev); 1430 1.190 dyoung 1431 1.257 mlelstv dev->dv_add_gen = alldevs_gen; 1432 1.136 dyoung /* It is safe to add a device to the tail of the list while 1433 1.187 dyoung * readers and writers are in the list. 1434 1.136 dyoung */ 1435 1.257 mlelstv TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); 1436 1.257 mlelstv mutex_exit(&alldevs_lock); 1437 1.117 drochner } 1438 1.117 drochner 1439 1.190 dyoung static void 1440 1.190 dyoung config_devfree(device_t dev) 1441 1.190 dyoung { 1442 1.286 riastrad 1443 1.271 thorpej KASSERT(dev->dv_flags & DVF_PRIV_ALLOC); 1444 1.286 riastrad KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending); 1445 1.190 dyoung 1446 1.190 dyoung if (dev->dv_cfattach->ca_devsize > 0) 1447 1.190 dyoung kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize); 1448 1.271 thorpej kmem_free(dev, sizeof(*dev)); 1449 1.190 dyoung } 1450 1.190 dyoung 1451 1.187 dyoung /* 1452 1.257 mlelstv * Caller must hold alldevs_lock. 1453 1.187 dyoung */ 1454 1.117 drochner static void 1455 1.190 dyoung config_devunlink(device_t dev, struct devicelist *garbage) 1456 1.117 drochner { 1457 1.190 dyoung struct device_garbage *dg = &dev->dv_garbage; 1458 1.190 dyoung cfdriver_t cd = device_cfdriver(dev); 1459 1.190 dyoung int i; 1460 1.187 dyoung 1461 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 1462 1.286 riastrad KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending); 1463 1.117 drochner 1464 1.190 dyoung /* Unlink from device list. Link to garbage list. */ 1465 1.257 mlelstv TAILQ_REMOVE(&alldevs, dev, dv_list); 1466 1.190 dyoung TAILQ_INSERT_TAIL(garbage, dev, dv_list); 1467 1.117 drochner 1468 1.117 drochner /* Remove from cfdriver's array. */ 1469 1.117 drochner cd->cd_devs[dev->dv_unit] = NULL; 1470 1.117 drochner 1471 1.117 drochner /* 1472 1.190 dyoung * If the device now has no units in use, unlink its softc array. 1473 1.117 drochner */ 1474 1.159 matt for (i = 0; i < cd->cd_ndevs; i++) { 1475 1.117 drochner if (cd->cd_devs[i] != NULL) 1476 1.187 dyoung break; 1477 1.187 dyoung } 1478 1.190 dyoung /* Nothing found. Unlink, now. Deallocate, later. */ 1479 1.187 dyoung if (i == cd->cd_ndevs) { 1480 1.190 dyoung dg->dg_ndevs = cd->cd_ndevs; 1481 1.190 dyoung dg->dg_devs = cd->cd_devs; 1482 1.187 dyoung cd->cd_devs = NULL; 1483 1.187 dyoung cd->cd_ndevs = 0; 1484 1.187 dyoung } 1485 1.190 dyoung } 1486 1.187 dyoung 1487 1.190 dyoung static void 1488 1.190 dyoung config_devdelete(device_t dev) 1489 1.190 dyoung { 1490 1.190 dyoung struct device_garbage *dg = &dev->dv_garbage; 1491 1.190 dyoung device_lock_t dvl = device_getlock(dev); 1492 1.187 dyoung 1493 1.286 riastrad KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending); 1494 1.286 riastrad 1495 1.190 dyoung if (dg->dg_devs != NULL) 1496 1.273 jdolecek kmem_free(dg->dg_devs, sizeof(device_t) * dg->dg_ndevs); 1497 1.187 dyoung 1498 1.298 riastrad localcount_fini(dev->dv_localcount); 1499 1.298 riastrad kmem_free(dev->dv_localcount, sizeof(*dev->dv_localcount)); 1500 1.298 riastrad 1501 1.187 dyoung cv_destroy(&dvl->dvl_cv); 1502 1.187 dyoung mutex_destroy(&dvl->dvl_mtx); 1503 1.187 dyoung 1504 1.187 dyoung KASSERT(dev->dv_properties != NULL); 1505 1.187 dyoung prop_object_release(dev->dv_properties); 1506 1.187 dyoung 1507 1.197 rmind if (dev->dv_activity_handlers) 1508 1.197 rmind panic("%s with registered handlers", __func__); 1509 1.187 dyoung 1510 1.187 dyoung if (dev->dv_locators) { 1511 1.187 dyoung size_t amount = *--dev->dv_locators; 1512 1.187 dyoung kmem_free(dev->dv_locators, amount); 1513 1.117 drochner } 1514 1.197 rmind 1515 1.190 dyoung config_devfree(dev); 1516 1.190 dyoung } 1517 1.190 dyoung 1518 1.190 dyoung static int 1519 1.190 dyoung config_unit_nextfree(cfdriver_t cd, cfdata_t cf) 1520 1.190 dyoung { 1521 1.296 riastrad int unit = cf->cf_unit; 1522 1.190 dyoung 1523 1.309 riastrad KASSERT(mutex_owned(&alldevs_lock)); 1524 1.309 riastrad 1525 1.296 riastrad if (unit < 0) 1526 1.296 riastrad return -1; 1527 1.190 dyoung if (cf->cf_fstate == FSTATE_STAR) { 1528 1.296 riastrad for (; unit < cd->cd_ndevs; unit++) 1529 1.190 dyoung if (cd->cd_devs[unit] == NULL) 1530 1.190 dyoung break; 1531 1.190 dyoung /* 1532 1.190 dyoung * unit is now the unit of the first NULL device pointer, 1533 1.190 dyoung * or max(cd->cd_ndevs,cf->cf_unit). 1534 1.190 dyoung */ 1535 1.190 dyoung } else { 1536 1.190 dyoung if (unit < cd->cd_ndevs && cd->cd_devs[unit] != NULL) 1537 1.190 dyoung unit = -1; 1538 1.190 dyoung } 1539 1.190 dyoung return unit; 1540 1.190 dyoung } 1541 1.190 dyoung 1542 1.190 dyoung static int 1543 1.190 dyoung config_unit_alloc(device_t dev, cfdriver_t cd, cfdata_t cf) 1544 1.190 dyoung { 1545 1.198 dyoung struct alldevs_foray af; 1546 1.198 dyoung int unit; 1547 1.187 dyoung 1548 1.198 dyoung config_alldevs_enter(&af); 1549 1.190 dyoung for (;;) { 1550 1.190 dyoung unit = config_unit_nextfree(cd, cf); 1551 1.190 dyoung if (unit == -1) 1552 1.190 dyoung break; 1553 1.190 dyoung if (unit < cd->cd_ndevs) { 1554 1.190 dyoung cd->cd_devs[unit] = dev; 1555 1.190 dyoung dev->dv_unit = unit; 1556 1.190 dyoung break; 1557 1.190 dyoung } 1558 1.190 dyoung config_makeroom(unit, cd); 1559 1.190 dyoung } 1560 1.198 dyoung config_alldevs_exit(&af); 1561 1.187 dyoung 1562 1.190 dyoung return unit; 1563 1.117 drochner } 1564 1.187 dyoung 1565 1.117 drochner static device_t 1566 1.289 thorpej config_devalloc(const device_t parent, const cfdata_t cf, 1567 1.289 thorpej const struct cfargs_internal * const args) 1568 1.25 cgd { 1569 1.190 dyoung cfdriver_t cd; 1570 1.190 dyoung cfattach_t ca; 1571 1.50 augustss size_t lname, lunit; 1572 1.52 cgd const char *xunit; 1573 1.189 pooka int myunit; 1574 1.25 cgd char num[10]; 1575 1.117 drochner device_t dev; 1576 1.120 joerg void *dev_private; 1577 1.96 drochner const struct cfiattrdata *ia; 1578 1.174 dyoung device_lock_t dvl; 1579 1.25 cgd 1580 1.67 thorpej cd = config_cfdriver_lookup(cf->cf_name); 1581 1.117 drochner if (cd == NULL) 1582 1.175 cegger return NULL; 1583 1.76 thorpej 1584 1.76 thorpej ca = config_cfattach_lookup_cd(cd, cf->cf_atname); 1585 1.117 drochner if (ca == NULL) 1586 1.175 cegger return NULL; 1587 1.76 thorpej 1588 1.25 cgd /* get memory for all device vars */ 1589 1.271 thorpej KASSERT(ca->ca_flags & DVF_PRIV_ALLOC); 1590 1.132 matt if (ca->ca_devsize > 0) { 1591 1.166 ad dev_private = kmem_zalloc(ca->ca_devsize, KM_SLEEP); 1592 1.132 matt } else { 1593 1.132 matt dev_private = NULL; 1594 1.132 matt } 1595 1.271 thorpej dev = kmem_zalloc(sizeof(*dev), KM_SLEEP); 1596 1.120 joerg 1597 1.289 thorpej dev->dv_handle = args->devhandle; 1598 1.278 thorpej 1599 1.202 dyoung dev->dv_class = cd->cd_class; 1600 1.202 dyoung dev->dv_cfdata = cf; 1601 1.202 dyoung dev->dv_cfdriver = cd; 1602 1.202 dyoung dev->dv_cfattach = ca; 1603 1.202 dyoung dev->dv_activity_count = 0; 1604 1.202 dyoung dev->dv_activity_handlers = NULL; 1605 1.202 dyoung dev->dv_private = dev_private; 1606 1.202 dyoung dev->dv_flags = ca->ca_flags; /* inherit flags from class */ 1607 1.298 riastrad dev->dv_attaching = curlwp; 1608 1.202 dyoung 1609 1.190 dyoung myunit = config_unit_alloc(dev, cd, cf); 1610 1.190 dyoung if (myunit == -1) { 1611 1.190 dyoung config_devfree(dev); 1612 1.190 dyoung return NULL; 1613 1.190 dyoung } 1614 1.190 dyoung 1615 1.190 dyoung /* compute length of name and decimal expansion of unit number */ 1616 1.190 dyoung lname = strlen(cd->cd_name); 1617 1.190 dyoung xunit = number(&num[sizeof(num)], myunit); 1618 1.190 dyoung lunit = &num[sizeof(num)] - xunit; 1619 1.190 dyoung if (lname + lunit > sizeof(dev->dv_xname)) 1620 1.289 thorpej panic("config_devalloc: device name too long"); 1621 1.190 dyoung 1622 1.174 dyoung dvl = device_getlock(dev); 1623 1.174 dyoung 1624 1.174 dyoung mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE); 1625 1.174 dyoung cv_init(&dvl->dvl_cv, "pmfsusp"); 1626 1.174 dyoung 1627 1.31 perry memcpy(dev->dv_xname, cd->cd_name, lname); 1628 1.31 perry memcpy(dev->dv_xname + lname, xunit, lunit); 1629 1.25 cgd dev->dv_parent = parent; 1630 1.124 jmcneill if (parent != NULL) 1631 1.124 jmcneill dev->dv_depth = parent->dv_depth + 1; 1632 1.124 jmcneill else 1633 1.124 jmcneill dev->dv_depth = 0; 1634 1.202 dyoung dev->dv_flags |= DVF_ACTIVE; /* always initially active */ 1635 1.289 thorpej if (args->locators) { 1636 1.96 drochner KASSERT(parent); /* no locators at root */ 1637 1.201 dyoung ia = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver); 1638 1.159 matt dev->dv_locators = 1639 1.273 jdolecek kmem_alloc(sizeof(int) * (ia->ci_loclen + 1), KM_SLEEP); 1640 1.273 jdolecek *dev->dv_locators++ = sizeof(int) * (ia->ci_loclen + 1); 1641 1.289 thorpej memcpy(dev->dv_locators, args->locators, 1642 1.289 thorpej sizeof(int) * ia->ci_loclen); 1643 1.90 drochner } 1644 1.112 thorpej dev->dv_properties = prop_dictionary_create(); 1645 1.112 thorpej KASSERT(dev->dv_properties != NULL); 1646 1.29 thorpej 1647 1.272 jmcneill prop_dictionary_set_string_nocopy(dev->dv_properties, 1648 1.150 jmcneill "device-driver", dev->dv_cfdriver->cd_name); 1649 1.150 jmcneill prop_dictionary_set_uint16(dev->dv_properties, 1650 1.150 jmcneill "device-unit", dev->dv_unit); 1651 1.236 joerg if (parent != NULL) { 1652 1.272 jmcneill prop_dictionary_set_string(dev->dv_properties, 1653 1.236 joerg "device-parent", device_xname(parent)); 1654 1.236 joerg } 1655 1.150 jmcneill 1656 1.298 riastrad dev->dv_localcount = kmem_zalloc(sizeof(*dev->dv_localcount), 1657 1.298 riastrad KM_SLEEP); 1658 1.298 riastrad localcount_init(dev->dv_localcount); 1659 1.298 riastrad 1660 1.221 pgoyette if (dev->dv_cfdriver->cd_attrs != NULL) 1661 1.221 pgoyette config_add_attrib_dict(dev); 1662 1.221 pgoyette 1663 1.175 cegger return dev; 1664 1.117 drochner } 1665 1.117 drochner 1666 1.117 drochner /* 1667 1.221 pgoyette * Create an array of device attach attributes and add it 1668 1.221 pgoyette * to the device's dv_properties dictionary. 1669 1.221 pgoyette * 1670 1.221 pgoyette * <key>interface-attributes</key> 1671 1.221 pgoyette * <array> 1672 1.221 pgoyette * <dict> 1673 1.221 pgoyette * <key>attribute-name</key> 1674 1.221 pgoyette * <string>foo</string> 1675 1.221 pgoyette * <key>locators</key> 1676 1.221 pgoyette * <array> 1677 1.221 pgoyette * <dict> 1678 1.221 pgoyette * <key>loc-name</key> 1679 1.221 pgoyette * <string>foo-loc1</string> 1680 1.221 pgoyette * </dict> 1681 1.221 pgoyette * <dict> 1682 1.221 pgoyette * <key>loc-name</key> 1683 1.221 pgoyette * <string>foo-loc2</string> 1684 1.221 pgoyette * <key>default</key> 1685 1.221 pgoyette * <string>foo-loc2-default</string> 1686 1.221 pgoyette * </dict> 1687 1.221 pgoyette * ... 1688 1.221 pgoyette * </array> 1689 1.221 pgoyette * </dict> 1690 1.221 pgoyette * ... 1691 1.221 pgoyette * </array> 1692 1.221 pgoyette */ 1693 1.221 pgoyette 1694 1.221 pgoyette static void 1695 1.221 pgoyette config_add_attrib_dict(device_t dev) 1696 1.221 pgoyette { 1697 1.221 pgoyette int i, j; 1698 1.221 pgoyette const struct cfiattrdata *ci; 1699 1.221 pgoyette prop_dictionary_t attr_dict, loc_dict; 1700 1.221 pgoyette prop_array_t attr_array, loc_array; 1701 1.221 pgoyette 1702 1.221 pgoyette if ((attr_array = prop_array_create()) == NULL) 1703 1.221 pgoyette return; 1704 1.221 pgoyette 1705 1.221 pgoyette for (i = 0; ; i++) { 1706 1.221 pgoyette if ((ci = dev->dv_cfdriver->cd_attrs[i]) == NULL) 1707 1.221 pgoyette break; 1708 1.221 pgoyette if ((attr_dict = prop_dictionary_create()) == NULL) 1709 1.221 pgoyette break; 1710 1.272 jmcneill prop_dictionary_set_string_nocopy(attr_dict, "attribute-name", 1711 1.221 pgoyette ci->ci_name); 1712 1.221 pgoyette 1713 1.221 pgoyette /* Create an array of the locator names and defaults */ 1714 1.221 pgoyette 1715 1.221 pgoyette if (ci->ci_loclen != 0 && 1716 1.221 pgoyette (loc_array = prop_array_create()) != NULL) { 1717 1.221 pgoyette for (j = 0; j < ci->ci_loclen; j++) { 1718 1.221 pgoyette loc_dict = prop_dictionary_create(); 1719 1.221 pgoyette if (loc_dict == NULL) 1720 1.221 pgoyette continue; 1721 1.272 jmcneill prop_dictionary_set_string_nocopy(loc_dict, 1722 1.221 pgoyette "loc-name", ci->ci_locdesc[j].cld_name); 1723 1.221 pgoyette if (ci->ci_locdesc[j].cld_defaultstr != NULL) 1724 1.272 jmcneill prop_dictionary_set_string_nocopy( 1725 1.221 pgoyette loc_dict, "default", 1726 1.221 pgoyette ci->ci_locdesc[j].cld_defaultstr); 1727 1.221 pgoyette prop_array_set(loc_array, j, loc_dict); 1728 1.221 pgoyette prop_object_release(loc_dict); 1729 1.221 pgoyette } 1730 1.221 pgoyette prop_dictionary_set_and_rel(attr_dict, "locators", 1731 1.221 pgoyette loc_array); 1732 1.221 pgoyette } 1733 1.221 pgoyette prop_array_add(attr_array, attr_dict); 1734 1.221 pgoyette prop_object_release(attr_dict); 1735 1.221 pgoyette } 1736 1.221 pgoyette if (i == 0) 1737 1.221 pgoyette prop_object_release(attr_array); 1738 1.221 pgoyette else 1739 1.221 pgoyette prop_dictionary_set_and_rel(dev->dv_properties, 1740 1.221 pgoyette "interface-attributes", attr_array); 1741 1.221 pgoyette 1742 1.221 pgoyette return; 1743 1.221 pgoyette } 1744 1.221 pgoyette 1745 1.221 pgoyette /* 1746 1.117 drochner * Attach a found device. 1747 1.311 riastrad * 1748 1.311 riastrad * Returns the device referenced, to be released with device_release. 1749 1.117 drochner */ 1750 1.289 thorpej static device_t 1751 1.289 thorpej config_attach_internal(device_t parent, cfdata_t cf, void *aux, cfprint_t print, 1752 1.289 thorpej const struct cfargs_internal * const args) 1753 1.117 drochner { 1754 1.117 drochner device_t dev; 1755 1.117 drochner struct cftable *ct; 1756 1.117 drochner const char *drvname; 1757 1.283 riastrad bool deferred; 1758 1.117 drochner 1759 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 1760 1.282 riastrad 1761 1.289 thorpej dev = config_devalloc(parent, cf, args); 1762 1.117 drochner if (!dev) 1763 1.117 drochner panic("config_attach: allocation of device softc failed"); 1764 1.117 drochner 1765 1.117 drochner /* XXX redundant - see below? */ 1766 1.117 drochner if (cf->cf_fstate != FSTATE_STAR) { 1767 1.117 drochner KASSERT(cf->cf_fstate == FSTATE_NOTFOUND); 1768 1.117 drochner cf->cf_fstate = FSTATE_FOUND; 1769 1.117 drochner } 1770 1.117 drochner 1771 1.117 drochner config_devlink(dev); 1772 1.117 drochner 1773 1.176 ad if (config_do_twiddle && cold) 1774 1.80 thorpej twiddle(); 1775 1.80 thorpej else 1776 1.80 thorpej aprint_naive("Found "); 1777 1.80 thorpej /* 1778 1.80 thorpej * We want the next two printfs for normal, verbose, and quiet, 1779 1.80 thorpej * but not silent (in which case, we're twiddling, instead). 1780 1.80 thorpej */ 1781 1.80 thorpej if (parent == ROOT) { 1782 1.143 cegger aprint_naive("%s (root)", device_xname(dev)); 1783 1.143 cegger aprint_normal("%s (root)", device_xname(dev)); 1784 1.80 thorpej } else { 1785 1.243 msaitoh aprint_naive("%s at %s", device_xname(dev), 1786 1.243 msaitoh device_xname(parent)); 1787 1.243 msaitoh aprint_normal("%s at %s", device_xname(dev), 1788 1.243 msaitoh device_xname(parent)); 1789 1.25 cgd if (print) 1790 1.52 cgd (void) (*print)(aux, NULL); 1791 1.25 cgd } 1792 1.25 cgd 1793 1.25 cgd /* 1794 1.25 cgd * Before attaching, clobber any unfound devices that are 1795 1.45 cgd * otherwise identical. 1796 1.117 drochner * XXX code above is redundant? 1797 1.25 cgd */ 1798 1.117 drochner drvname = dev->dv_cfdriver->cd_name; 1799 1.65 thorpej TAILQ_FOREACH(ct, &allcftables, ct_list) { 1800 1.67 thorpej for (cf = ct->ct_cfdata; cf->cf_name; cf++) { 1801 1.117 drochner if (STREQ(cf->cf_name, drvname) && 1802 1.65 thorpej cf->cf_unit == dev->dv_unit) { 1803 1.65 thorpej if (cf->cf_fstate == FSTATE_NOTFOUND) 1804 1.65 thorpej cf->cf_fstate = FSTATE_FOUND; 1805 1.65 thorpej } 1806 1.25 cgd } 1807 1.65 thorpej } 1808 1.25 cgd device_register(dev, aux); 1809 1.124 jmcneill 1810 1.149 jmcneill /* Let userland know */ 1811 1.149 jmcneill devmon_report_device(dev, true); 1812 1.149 jmcneill 1813 1.298 riastrad /* 1814 1.298 riastrad * Prevent detach until the driver's attach function, and all 1815 1.298 riastrad * deferred actions, have finished. 1816 1.298 riastrad */ 1817 1.283 riastrad config_pending_incr(dev); 1818 1.298 riastrad 1819 1.311 riastrad /* 1820 1.311 riastrad * Prevent concurrent detach from destroying the device_t until 1821 1.311 riastrad * the caller has released the device. 1822 1.311 riastrad */ 1823 1.311 riastrad device_acquire(dev); 1824 1.311 riastrad 1825 1.298 riastrad /* Call the driver's attach function. */ 1826 1.117 drochner (*dev->dv_cfattach->ca_attach)(parent, dev, aux); 1827 1.298 riastrad 1828 1.298 riastrad /* 1829 1.298 riastrad * Allow other threads to acquire references to the device now 1830 1.298 riastrad * that the driver's attach function is done. 1831 1.298 riastrad */ 1832 1.298 riastrad mutex_enter(&config_misc_lock); 1833 1.298 riastrad KASSERT(dev->dv_attaching == curlwp); 1834 1.298 riastrad dev->dv_attaching = NULL; 1835 1.298 riastrad cv_broadcast(&config_misc_cv); 1836 1.298 riastrad mutex_exit(&config_misc_lock); 1837 1.298 riastrad 1838 1.298 riastrad /* 1839 1.298 riastrad * Synchronous parts of attach are done. Allow detach, unless 1840 1.298 riastrad * the driver's attach function scheduled deferred actions. 1841 1.298 riastrad */ 1842 1.283 riastrad config_pending_decr(dev); 1843 1.124 jmcneill 1844 1.283 riastrad mutex_enter(&config_misc_lock); 1845 1.283 riastrad deferred = (dev->dv_pending != 0); 1846 1.283 riastrad mutex_exit(&config_misc_lock); 1847 1.283 riastrad 1848 1.283 riastrad if (!deferred && !device_pmf_is_registered(dev)) 1849 1.264 msaitoh aprint_debug_dev(dev, 1850 1.264 msaitoh "WARNING: power management not supported\n"); 1851 1.124 jmcneill 1852 1.42 thorpej config_process_deferred(&deferred_config_queue, dev); 1853 1.196 martin 1854 1.196 martin device_register_post_config(dev, aux); 1855 1.297 riastrad rnd_add_uint32(&rnd_autoconf_source, 0); 1856 1.175 cegger return dev; 1857 1.25 cgd } 1858 1.29 thorpej 1859 1.102 thorpej device_t 1860 1.311 riastrad config_attach_acquire(device_t parent, cfdata_t cf, void *aux, cfprint_t print, 1861 1.311 riastrad const struct cfargs *cfargs) 1862 1.311 riastrad { 1863 1.311 riastrad struct cfargs_internal store; 1864 1.311 riastrad device_t dev; 1865 1.311 riastrad 1866 1.311 riastrad KERNEL_LOCK(1, NULL); 1867 1.311 riastrad dev = config_attach_internal(parent, cf, aux, print, 1868 1.311 riastrad cfargs_canonicalize(cfargs, &store)); 1869 1.311 riastrad KERNEL_UNLOCK_ONE(NULL); 1870 1.311 riastrad 1871 1.311 riastrad return dev; 1872 1.311 riastrad } 1873 1.311 riastrad 1874 1.311 riastrad /* 1875 1.311 riastrad * config_attach(parent, cf, aux, print, cfargs) 1876 1.311 riastrad * 1877 1.311 riastrad * Legacy entry point for callers whose use of the returned 1878 1.311 riastrad * device_t is not delimited by device_release. 1879 1.311 riastrad * 1880 1.311 riastrad * The caller is required to hold the kernel lock as a fragile 1881 1.311 riastrad * defence against races. 1882 1.311 riastrad * 1883 1.311 riastrad * Callers should ignore the return value or be converted to 1884 1.311 riastrad * config_attach_acquire with a matching device_release once they 1885 1.311 riastrad * have finished with the returned device_t. 1886 1.311 riastrad */ 1887 1.311 riastrad device_t 1888 1.278 thorpej config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print, 1889 1.289 thorpej const struct cfargs *cfargs) 1890 1.102 thorpej { 1891 1.311 riastrad device_t dev; 1892 1.102 thorpej 1893 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 1894 1.282 riastrad 1895 1.311 riastrad dev = config_attach_acquire(parent, cf, aux, print, cfargs); 1896 1.311 riastrad if (dev == NULL) 1897 1.311 riastrad return NULL; 1898 1.311 riastrad device_release(dev); 1899 1.311 riastrad 1900 1.311 riastrad return dev; 1901 1.102 thorpej } 1902 1.102 thorpej 1903 1.29 thorpej /* 1904 1.77 thorpej * As above, but for pseudo-devices. Pseudo-devices attached in this 1905 1.77 thorpej * way are silently inserted into the device tree, and their children 1906 1.77 thorpej * attached. 1907 1.77 thorpej * 1908 1.77 thorpej * Note that because pseudo-devices are attached silently, any information 1909 1.77 thorpej * the attach routine wishes to print should be prefixed with the device 1910 1.77 thorpej * name by the attach routine. 1911 1.77 thorpej */ 1912 1.102 thorpej device_t 1913 1.311 riastrad config_attach_pseudo_acquire(cfdata_t cf, void *aux) 1914 1.77 thorpej { 1915 1.102 thorpej device_t dev; 1916 1.77 thorpej 1917 1.285 riastrad KERNEL_LOCK(1, NULL); 1918 1.282 riastrad 1919 1.289 thorpej struct cfargs_internal args = { }; 1920 1.289 thorpej dev = config_devalloc(ROOT, cf, &args); 1921 1.117 drochner if (!dev) 1922 1.285 riastrad goto out; 1923 1.77 thorpej 1924 1.117 drochner /* XXX mark busy in cfdata */ 1925 1.77 thorpej 1926 1.170 dyoung if (cf->cf_fstate != FSTATE_STAR) { 1927 1.170 dyoung KASSERT(cf->cf_fstate == FSTATE_NOTFOUND); 1928 1.170 dyoung cf->cf_fstate = FSTATE_FOUND; 1929 1.170 dyoung } 1930 1.170 dyoung 1931 1.117 drochner config_devlink(dev); 1932 1.77 thorpej 1933 1.77 thorpej #if 0 /* XXXJRT not yet */ 1934 1.77 thorpej device_register(dev, NULL); /* like a root node */ 1935 1.77 thorpej #endif 1936 1.225 mlelstv 1937 1.225 mlelstv /* Let userland know */ 1938 1.225 mlelstv devmon_report_device(dev, true); 1939 1.225 mlelstv 1940 1.298 riastrad /* 1941 1.298 riastrad * Prevent detach until the driver's attach function, and all 1942 1.298 riastrad * deferred actions, have finished. 1943 1.298 riastrad */ 1944 1.283 riastrad config_pending_incr(dev); 1945 1.298 riastrad 1946 1.311 riastrad /* 1947 1.311 riastrad * Prevent concurrent detach from destroying the device_t until 1948 1.311 riastrad * the caller has released the device. 1949 1.311 riastrad */ 1950 1.311 riastrad device_acquire(dev); 1951 1.311 riastrad 1952 1.298 riastrad /* Call the driver's attach function. */ 1953 1.311 riastrad (*dev->dv_cfattach->ca_attach)(ROOT, dev, aux); 1954 1.298 riastrad 1955 1.298 riastrad /* 1956 1.298 riastrad * Allow other threads to acquire references to the device now 1957 1.298 riastrad * that the driver's attach function is done. 1958 1.298 riastrad */ 1959 1.298 riastrad mutex_enter(&config_misc_lock); 1960 1.298 riastrad KASSERT(dev->dv_attaching == curlwp); 1961 1.298 riastrad dev->dv_attaching = NULL; 1962 1.298 riastrad cv_broadcast(&config_misc_cv); 1963 1.298 riastrad mutex_exit(&config_misc_lock); 1964 1.298 riastrad 1965 1.298 riastrad /* 1966 1.298 riastrad * Synchronous parts of attach are done. Allow detach, unless 1967 1.298 riastrad * the driver's attach function scheduled deferred actions. 1968 1.298 riastrad */ 1969 1.283 riastrad config_pending_decr(dev); 1970 1.225 mlelstv 1971 1.77 thorpej config_process_deferred(&deferred_config_queue, dev); 1972 1.285 riastrad 1973 1.285 riastrad out: KERNEL_UNLOCK_ONE(NULL); 1974 1.175 cegger return dev; 1975 1.77 thorpej } 1976 1.77 thorpej 1977 1.77 thorpej /* 1978 1.311 riastrad * config_attach_pseudo(cf) 1979 1.311 riastrad * 1980 1.311 riastrad * Legacy entry point for callers whose use of the returned 1981 1.311 riastrad * device_t is not delimited by device_release. 1982 1.311 riastrad * 1983 1.311 riastrad * The caller is required to hold the kernel lock as a fragile 1984 1.311 riastrad * defence against races. 1985 1.311 riastrad * 1986 1.311 riastrad * Callers should ignore the return value or be converted to 1987 1.311 riastrad * config_attach_pseudo_acquire with a matching device_release 1988 1.311 riastrad * once they have finished with the returned device_t. As a 1989 1.311 riastrad * bonus, config_attach_pseudo_acquire can pass a non-null aux 1990 1.311 riastrad * argument into the driver's attach routine. 1991 1.311 riastrad */ 1992 1.311 riastrad device_t 1993 1.311 riastrad config_attach_pseudo(cfdata_t cf) 1994 1.311 riastrad { 1995 1.311 riastrad device_t dev; 1996 1.311 riastrad 1997 1.311 riastrad dev = config_attach_pseudo_acquire(cf, NULL); 1998 1.311 riastrad if (dev == NULL) 1999 1.311 riastrad return dev; 2000 1.311 riastrad device_release(dev); 2001 1.311 riastrad 2002 1.311 riastrad return dev; 2003 1.311 riastrad } 2004 1.311 riastrad 2005 1.311 riastrad /* 2006 1.257 mlelstv * Caller must hold alldevs_lock. 2007 1.197 rmind */ 2008 1.197 rmind static void 2009 1.197 rmind config_collect_garbage(struct devicelist *garbage) 2010 1.197 rmind { 2011 1.197 rmind device_t dv; 2012 1.197 rmind 2013 1.197 rmind KASSERT(!cpu_intr_p()); 2014 1.197 rmind KASSERT(!cpu_softintr_p()); 2015 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 2016 1.197 rmind 2017 1.257 mlelstv while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) { 2018 1.257 mlelstv TAILQ_FOREACH(dv, &alldevs, dv_list) { 2019 1.197 rmind if (dv->dv_del_gen != 0) 2020 1.197 rmind break; 2021 1.197 rmind } 2022 1.197 rmind if (dv == NULL) { 2023 1.257 mlelstv alldevs_garbage = false; 2024 1.197 rmind break; 2025 1.197 rmind } 2026 1.197 rmind config_devunlink(dv, garbage); 2027 1.197 rmind } 2028 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 2029 1.197 rmind } 2030 1.197 rmind 2031 1.197 rmind static void 2032 1.197 rmind config_dump_garbage(struct devicelist *garbage) 2033 1.197 rmind { 2034 1.197 rmind device_t dv; 2035 1.197 rmind 2036 1.197 rmind while ((dv = TAILQ_FIRST(garbage)) != NULL) { 2037 1.197 rmind TAILQ_REMOVE(garbage, dv, dv_list); 2038 1.197 rmind config_devdelete(dv); 2039 1.197 rmind } 2040 1.197 rmind } 2041 1.197 rmind 2042 1.283 riastrad static int 2043 1.283 riastrad config_detach_enter(device_t dev) 2044 1.283 riastrad { 2045 1.302 riastrad struct lwp *l __diagused; 2046 1.298 riastrad int error = 0; 2047 1.283 riastrad 2048 1.283 riastrad mutex_enter(&config_misc_lock); 2049 1.298 riastrad 2050 1.298 riastrad /* 2051 1.298 riastrad * Wait until attach has fully completed, and until any 2052 1.298 riastrad * concurrent detach (e.g., drvctl racing with USB event 2053 1.298 riastrad * thread) has completed. 2054 1.298 riastrad * 2055 1.298 riastrad * Caller must hold alldevs_nread or alldevs_nwrite (e.g., via 2056 1.298 riastrad * deviter) to ensure the winner of the race doesn't free the 2057 1.298 riastrad * device leading the loser of the race into use-after-free. 2058 1.298 riastrad * 2059 1.298 riastrad * XXX Not all callers do this! 2060 1.298 riastrad */ 2061 1.298 riastrad while (dev->dv_pending || dev->dv_detaching) { 2062 1.283 riastrad KASSERTMSG(dev->dv_detaching != curlwp, 2063 1.283 riastrad "recursively detaching %s", device_xname(dev)); 2064 1.283 riastrad error = cv_wait_sig(&config_misc_cv, &config_misc_lock); 2065 1.283 riastrad if (error) 2066 1.298 riastrad goto out; 2067 1.283 riastrad } 2068 1.283 riastrad 2069 1.298 riastrad /* 2070 1.298 riastrad * Attach has completed, and no other concurrent detach is 2071 1.298 riastrad * running. Claim the device for detaching. This will cause 2072 1.298 riastrad * all new attempts to acquire references to block. 2073 1.298 riastrad */ 2074 1.302 riastrad KASSERTMSG((l = dev->dv_attaching) == NULL, 2075 1.305 riastrad "lwp %ld [%s] @ %p attaching %s", 2076 1.305 riastrad (long)l->l_lid, (l->l_name ? l->l_name : l->l_proc->p_comm), l, 2077 1.305 riastrad device_xname(dev)); 2078 1.302 riastrad KASSERTMSG((l = dev->dv_detaching) == NULL, 2079 1.305 riastrad "lwp %ld [%s] @ %p detaching %s", 2080 1.305 riastrad (long)l->l_lid, (l->l_name ? l->l_name : l->l_proc->p_comm), l, 2081 1.305 riastrad device_xname(dev)); 2082 1.298 riastrad dev->dv_detaching = curlwp; 2083 1.298 riastrad 2084 1.298 riastrad out: mutex_exit(&config_misc_lock); 2085 1.283 riastrad return error; 2086 1.283 riastrad } 2087 1.283 riastrad 2088 1.283 riastrad static void 2089 1.283 riastrad config_detach_exit(device_t dev) 2090 1.283 riastrad { 2091 1.302 riastrad struct lwp *l __diagused; 2092 1.283 riastrad 2093 1.283 riastrad mutex_enter(&config_misc_lock); 2094 1.305 riastrad KASSERTMSG(dev->dv_detaching != NULL, "not detaching %s", 2095 1.305 riastrad device_xname(dev)); 2096 1.302 riastrad KASSERTMSG((l = dev->dv_detaching) == curlwp, 2097 1.305 riastrad "lwp %ld [%s] @ %p detaching %s", 2098 1.305 riastrad (long)l->l_lid, (l->l_name ? l->l_name : l->l_proc->p_comm), l, 2099 1.305 riastrad device_xname(dev)); 2100 1.283 riastrad dev->dv_detaching = NULL; 2101 1.283 riastrad cv_broadcast(&config_misc_cv); 2102 1.283 riastrad mutex_exit(&config_misc_lock); 2103 1.283 riastrad } 2104 1.283 riastrad 2105 1.197 rmind /* 2106 1.33 thorpej * Detach a device. Optionally forced (e.g. because of hardware 2107 1.33 thorpej * removal) and quiet. Returns zero if successful, non-zero 2108 1.33 thorpej * (an error code) otherwise. 2109 1.33 thorpej * 2110 1.33 thorpej * Note that this code wants to be run from a process context, so 2111 1.33 thorpej * that the detach can sleep to allow processes which have a device 2112 1.33 thorpej * open to run and unwind their stacks. 2113 1.311 riastrad * 2114 1.311 riastrad * Caller must hold a reference with device_acquire or 2115 1.311 riastrad * device_lookup_acquire. 2116 1.33 thorpej */ 2117 1.33 thorpej int 2118 1.311 riastrad config_detach_release(device_t dev, int flags) 2119 1.33 thorpej { 2120 1.198 dyoung struct alldevs_foray af; 2121 1.65 thorpej struct cftable *ct; 2122 1.102 thorpej cfdata_t cf; 2123 1.73 thorpej const struct cfattach *ca; 2124 1.33 thorpej struct cfdriver *cd; 2125 1.252 riastrad device_t d __diagused; 2126 1.241 skrll int rv = 0; 2127 1.33 thorpej 2128 1.287 riastrad KERNEL_LOCK(1, NULL); 2129 1.282 riastrad 2130 1.161 christos cf = dev->dv_cfdata; 2131 1.252 riastrad KASSERTMSG((cf == NULL || cf->cf_fstate == FSTATE_FOUND || 2132 1.252 riastrad cf->cf_fstate == FSTATE_STAR), 2133 1.252 riastrad "config_detach: %s: bad device fstate: %d", 2134 1.252 riastrad device_xname(dev), cf ? cf->cf_fstate : -1); 2135 1.252 riastrad 2136 1.77 thorpej cd = dev->dv_cfdriver; 2137 1.67 thorpej KASSERT(cd != NULL); 2138 1.76 thorpej 2139 1.77 thorpej ca = dev->dv_cfattach; 2140 1.76 thorpej KASSERT(ca != NULL); 2141 1.33 thorpej 2142 1.283 riastrad /* 2143 1.283 riastrad * Only one detach at a time, please -- and not until fully 2144 1.283 riastrad * attached. 2145 1.283 riastrad */ 2146 1.283 riastrad rv = config_detach_enter(dev); 2147 1.311 riastrad device_release(dev); 2148 1.287 riastrad if (rv) { 2149 1.287 riastrad KERNEL_UNLOCK_ONE(NULL); 2150 1.283 riastrad return rv; 2151 1.287 riastrad } 2152 1.283 riastrad 2153 1.257 mlelstv mutex_enter(&alldevs_lock); 2154 1.187 dyoung if (dev->dv_del_gen != 0) { 2155 1.257 mlelstv mutex_exit(&alldevs_lock); 2156 1.187 dyoung #ifdef DIAGNOSTIC 2157 1.187 dyoung printf("%s: %s is already detached\n", __func__, 2158 1.187 dyoung device_xname(dev)); 2159 1.187 dyoung #endif /* DIAGNOSTIC */ 2160 1.283 riastrad config_detach_exit(dev); 2161 1.287 riastrad KERNEL_UNLOCK_ONE(NULL); 2162 1.187 dyoung return ENOENT; 2163 1.187 dyoung } 2164 1.257 mlelstv alldevs_nwrite++; 2165 1.257 mlelstv mutex_exit(&alldevs_lock); 2166 1.136 dyoung 2167 1.300 riastrad /* 2168 1.300 riastrad * Call the driver's .ca_detach function, unless it has none or 2169 1.300 riastrad * we are skipping it because it's unforced shutdown time and 2170 1.300 riastrad * the driver didn't ask to detach on shutdown. 2171 1.300 riastrad */ 2172 1.174 dyoung if (!detachall && 2173 1.174 dyoung (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN && 2174 1.174 dyoung (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) { 2175 1.183 dyoung rv = EOPNOTSUPP; 2176 1.187 dyoung } else if (ca->ca_detach != NULL) { 2177 1.187 dyoung rv = (*ca->ca_detach)(dev, flags); 2178 1.187 dyoung } else 2179 1.187 dyoung rv = EOPNOTSUPP; 2180 1.33 thorpej 2181 1.306 riastrad KASSERTMSG(!dev->dv_detach_done, "%s detached twice, error=%d", 2182 1.306 riastrad device_xname(dev), rv); 2183 1.306 riastrad 2184 1.33 thorpej /* 2185 1.187 dyoung * If it was not possible to detach the device, then we either 2186 1.187 dyoung * panic() (for the forced but failed case), or return an error. 2187 1.33 thorpej */ 2188 1.300 riastrad if (rv) { 2189 1.299 riastrad /* 2190 1.300 riastrad * Detach failed -- likely EOPNOTSUPP or EBUSY. Driver 2191 1.300 riastrad * must not have called config_detach_commit. 2192 1.299 riastrad */ 2193 1.306 riastrad KASSERTMSG(!dev->dv_detach_committed, 2194 1.306 riastrad "%s committed to detaching and then backed out, error=%d", 2195 1.306 riastrad device_xname(dev), rv); 2196 1.300 riastrad if (flags & DETACH_FORCE) { 2197 1.300 riastrad panic("config_detach: forced detach of %s failed (%d)", 2198 1.300 riastrad device_xname(dev), rv); 2199 1.300 riastrad } 2200 1.187 dyoung goto out; 2201 1.33 thorpej } 2202 1.33 thorpej 2203 1.33 thorpej /* 2204 1.33 thorpej * The device has now been successfully detached. 2205 1.33 thorpej */ 2206 1.306 riastrad dev->dv_detach_done = true; 2207 1.33 thorpej 2208 1.298 riastrad /* 2209 1.300 riastrad * If .ca_detach didn't commit to detach, then do that for it. 2210 1.300 riastrad * This wakes any pending device_lookup_acquire calls so they 2211 1.300 riastrad * will fail. 2212 1.300 riastrad */ 2213 1.300 riastrad config_detach_commit(dev); 2214 1.300 riastrad 2215 1.300 riastrad /* 2216 1.300 riastrad * If it was possible to detach the device, ensure that the 2217 1.300 riastrad * device is deactivated. 2218 1.300 riastrad */ 2219 1.300 riastrad dev->dv_flags &= ~DVF_ACTIVE; /* XXXSMP */ 2220 1.300 riastrad 2221 1.300 riastrad /* 2222 1.298 riastrad * Wait for all device_lookup_acquire references -- mostly, for 2223 1.298 riastrad * all attempts to open the device -- to drain. It is the 2224 1.298 riastrad * responsibility of .ca_detach to ensure anything with open 2225 1.298 riastrad * references will be interrupted and release them promptly, 2226 1.298 riastrad * not block indefinitely. All new attempts to acquire 2227 1.299 riastrad * references will fail, as config_detach_commit has arranged 2228 1.299 riastrad * by now. 2229 1.298 riastrad */ 2230 1.298 riastrad mutex_enter(&config_misc_lock); 2231 1.298 riastrad localcount_drain(dev->dv_localcount, 2232 1.298 riastrad &config_misc_cv, &config_misc_lock); 2233 1.298 riastrad mutex_exit(&config_misc_lock); 2234 1.298 riastrad 2235 1.149 jmcneill /* Let userland know */ 2236 1.149 jmcneill devmon_report_device(dev, false); 2237 1.149 jmcneill 2238 1.33 thorpej #ifdef DIAGNOSTIC 2239 1.33 thorpej /* 2240 1.33 thorpej * Sanity: If you're successfully detached, you should have no 2241 1.33 thorpej * children. (Note that because children must be attached 2242 1.33 thorpej * after parents, we only need to search the latter part of 2243 1.33 thorpej * the list.) 2244 1.33 thorpej */ 2245 1.284 riastrad mutex_enter(&alldevs_lock); 2246 1.33 thorpej for (d = TAILQ_NEXT(dev, dv_list); d != NULL; 2247 1.48 enami d = TAILQ_NEXT(d, dv_list)) { 2248 1.187 dyoung if (d->dv_parent == dev && d->dv_del_gen == 0) { 2249 1.48 enami printf("config_detach: detached device %s" 2250 1.243 msaitoh " has children %s\n", device_xname(dev), 2251 1.243 msaitoh device_xname(d)); 2252 1.48 enami panic("config_detach"); 2253 1.48 enami } 2254 1.33 thorpej } 2255 1.284 riastrad mutex_exit(&alldevs_lock); 2256 1.33 thorpej #endif 2257 1.33 thorpej 2258 1.90 drochner /* notify the parent that the child is gone */ 2259 1.90 drochner if (dev->dv_parent) { 2260 1.102 thorpej device_t p = dev->dv_parent; 2261 1.90 drochner if (p->dv_cfattach->ca_childdetached) 2262 1.90 drochner (*p->dv_cfattach->ca_childdetached)(p, dev); 2263 1.90 drochner } 2264 1.90 drochner 2265 1.33 thorpej /* 2266 1.33 thorpej * Mark cfdata to show that the unit can be reused, if possible. 2267 1.33 thorpej */ 2268 1.65 thorpej TAILQ_FOREACH(ct, &allcftables, ct_list) { 2269 1.67 thorpej for (cf = ct->ct_cfdata; cf->cf_name; cf++) { 2270 1.67 thorpej if (STREQ(cf->cf_name, cd->cd_name)) { 2271 1.65 thorpej if (cf->cf_fstate == FSTATE_FOUND && 2272 1.65 thorpej cf->cf_unit == dev->dv_unit) 2273 1.65 thorpej cf->cf_fstate = FSTATE_NOTFOUND; 2274 1.65 thorpej } 2275 1.33 thorpej } 2276 1.33 thorpej } 2277 1.33 thorpej 2278 1.77 thorpej if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0) 2279 1.136 dyoung aprint_normal_dev(dev, "detached\n"); 2280 1.33 thorpej 2281 1.136 dyoung out: 2282 1.283 riastrad config_detach_exit(dev); 2283 1.283 riastrad 2284 1.198 dyoung config_alldevs_enter(&af); 2285 1.257 mlelstv KASSERT(alldevs_nwrite != 0); 2286 1.257 mlelstv --alldevs_nwrite; 2287 1.211 dyoung if (rv == 0 && dev->dv_del_gen == 0) { 2288 1.257 mlelstv if (alldevs_nwrite == 0 && alldevs_nread == 0) 2289 1.211 dyoung config_devunlink(dev, &af.af_garbage); 2290 1.211 dyoung else { 2291 1.257 mlelstv dev->dv_del_gen = alldevs_gen; 2292 1.257 mlelstv alldevs_garbage = true; 2293 1.211 dyoung } 2294 1.211 dyoung } 2295 1.198 dyoung config_alldevs_exit(&af); 2296 1.187 dyoung 2297 1.287 riastrad KERNEL_UNLOCK_ONE(NULL); 2298 1.287 riastrad 2299 1.136 dyoung return rv; 2300 1.33 thorpej } 2301 1.33 thorpej 2302 1.299 riastrad /* 2303 1.311 riastrad * config_detach(dev, flags) 2304 1.311 riastrad * 2305 1.311 riastrad * Legacy entry point for callers that have not acquired a 2306 1.311 riastrad * reference to dev. 2307 1.311 riastrad * 2308 1.311 riastrad * The caller is required to hold the kernel lock as a fragile 2309 1.311 riastrad * defence against races. 2310 1.311 riastrad * 2311 1.311 riastrad * Callers should be converted to use device_acquire under a lock 2312 1.311 riastrad * taken also by .ca_childdetached to synchronize access to the 2313 1.311 riastrad * device_t, and then config_detach_release ouside the lock. 2314 1.311 riastrad * Alternatively, most drivers detach children only in their own 2315 1.311 riastrad * detach routines, which can be done with config_detach_children 2316 1.311 riastrad * instead. 2317 1.311 riastrad */ 2318 1.311 riastrad int 2319 1.311 riastrad config_detach(device_t dev, int flags) 2320 1.311 riastrad { 2321 1.311 riastrad 2322 1.311 riastrad device_acquire(dev); 2323 1.311 riastrad return config_detach_release(dev, flags); 2324 1.311 riastrad } 2325 1.311 riastrad 2326 1.311 riastrad /* 2327 1.299 riastrad * config_detach_commit(dev) 2328 1.299 riastrad * 2329 1.299 riastrad * Issued by a driver's .ca_detach routine to notify anyone 2330 1.299 riastrad * waiting in device_lookup_acquire that the driver is committed 2331 1.299 riastrad * to detaching the device, which allows device_lookup_acquire to 2332 1.299 riastrad * wake up and fail immediately. 2333 1.299 riastrad * 2334 1.299 riastrad * Safe to call multiple times -- idempotent. Must be called 2335 1.299 riastrad * during config_detach_enter/exit. Safe to use with 2336 1.299 riastrad * device_lookup because the device is not actually removed from 2337 1.299 riastrad * the table until after config_detach_exit. 2338 1.299 riastrad */ 2339 1.299 riastrad void 2340 1.299 riastrad config_detach_commit(device_t dev) 2341 1.299 riastrad { 2342 1.302 riastrad struct lwp *l __diagused; 2343 1.299 riastrad 2344 1.299 riastrad mutex_enter(&config_misc_lock); 2345 1.305 riastrad KASSERTMSG(dev->dv_detaching != NULL, "not detaching %s", 2346 1.305 riastrad device_xname(dev)); 2347 1.302 riastrad KASSERTMSG((l = dev->dv_detaching) == curlwp, 2348 1.305 riastrad "lwp %ld [%s] @ %p detaching %s", 2349 1.305 riastrad (long)l->l_lid, (l->l_name ? l->l_name : l->l_proc->p_comm), l, 2350 1.305 riastrad device_xname(dev)); 2351 1.306 riastrad dev->dv_detach_committed = true; 2352 1.299 riastrad cv_broadcast(&config_misc_cv); 2353 1.299 riastrad mutex_exit(&config_misc_lock); 2354 1.299 riastrad } 2355 1.299 riastrad 2356 1.126 dyoung int 2357 1.126 dyoung config_detach_children(device_t parent, int flags) 2358 1.126 dyoung { 2359 1.130 drochner device_t dv; 2360 1.136 dyoung deviter_t di; 2361 1.136 dyoung int error = 0; 2362 1.126 dyoung 2363 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 2364 1.282 riastrad 2365 1.136 dyoung for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL; 2366 1.136 dyoung dv = deviter_next(&di)) { 2367 1.136 dyoung if (device_parent(dv) != parent) 2368 1.136 dyoung continue; 2369 1.136 dyoung if ((error = config_detach(dv, flags)) != 0) 2370 1.130 drochner break; 2371 1.136 dyoung } 2372 1.136 dyoung deviter_release(&di); 2373 1.130 drochner return error; 2374 1.126 dyoung } 2375 1.126 dyoung 2376 1.178 dyoung device_t 2377 1.178 dyoung shutdown_first(struct shutdown_state *s) 2378 1.178 dyoung { 2379 1.178 dyoung if (!s->initialized) { 2380 1.178 dyoung deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST); 2381 1.178 dyoung s->initialized = true; 2382 1.178 dyoung } 2383 1.178 dyoung return shutdown_next(s); 2384 1.178 dyoung } 2385 1.178 dyoung 2386 1.178 dyoung device_t 2387 1.178 dyoung shutdown_next(struct shutdown_state *s) 2388 1.178 dyoung { 2389 1.178 dyoung device_t dv; 2390 1.178 dyoung 2391 1.178 dyoung while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv)) 2392 1.178 dyoung ; 2393 1.178 dyoung 2394 1.178 dyoung if (dv == NULL) 2395 1.178 dyoung s->initialized = false; 2396 1.178 dyoung 2397 1.178 dyoung return dv; 2398 1.178 dyoung } 2399 1.178 dyoung 2400 1.178 dyoung bool 2401 1.178 dyoung config_detach_all(int how) 2402 1.178 dyoung { 2403 1.178 dyoung static struct shutdown_state s; 2404 1.178 dyoung device_t curdev; 2405 1.178 dyoung bool progress = false; 2406 1.242 bouyer int flags; 2407 1.178 dyoung 2408 1.281 riastrad KERNEL_LOCK(1, NULL); 2409 1.281 riastrad 2410 1.239 christos if ((how & (RB_NOSYNC|RB_DUMP)) != 0) 2411 1.281 riastrad goto out; 2412 1.178 dyoung 2413 1.242 bouyer if ((how & RB_POWERDOWN) == RB_POWERDOWN) 2414 1.242 bouyer flags = DETACH_SHUTDOWN | DETACH_POWEROFF; 2415 1.242 bouyer else 2416 1.242 bouyer flags = DETACH_SHUTDOWN; 2417 1.242 bouyer 2418 1.178 dyoung for (curdev = shutdown_first(&s); curdev != NULL; 2419 1.178 dyoung curdev = shutdown_next(&s)) { 2420 1.178 dyoung aprint_debug(" detaching %s, ", device_xname(curdev)); 2421 1.242 bouyer if (config_detach(curdev, flags) == 0) { 2422 1.178 dyoung progress = true; 2423 1.178 dyoung aprint_debug("success."); 2424 1.178 dyoung } else 2425 1.178 dyoung aprint_debug("failed."); 2426 1.178 dyoung } 2427 1.281 riastrad 2428 1.281 riastrad out: KERNEL_UNLOCK_ONE(NULL); 2429 1.178 dyoung return progress; 2430 1.178 dyoung } 2431 1.178 dyoung 2432 1.187 dyoung static bool 2433 1.187 dyoung device_is_ancestor_of(device_t ancestor, device_t descendant) 2434 1.187 dyoung { 2435 1.187 dyoung device_t dv; 2436 1.187 dyoung 2437 1.187 dyoung for (dv = descendant; dv != NULL; dv = device_parent(dv)) { 2438 1.187 dyoung if (device_parent(dv) == ancestor) 2439 1.187 dyoung return true; 2440 1.187 dyoung } 2441 1.187 dyoung return false; 2442 1.187 dyoung } 2443 1.187 dyoung 2444 1.33 thorpej int 2445 1.102 thorpej config_deactivate(device_t dev) 2446 1.33 thorpej { 2447 1.187 dyoung deviter_t di; 2448 1.187 dyoung const struct cfattach *ca; 2449 1.187 dyoung device_t descendant; 2450 1.187 dyoung int s, rv = 0, oflags; 2451 1.33 thorpej 2452 1.187 dyoung for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST); 2453 1.187 dyoung descendant != NULL; 2454 1.187 dyoung descendant = deviter_next(&di)) { 2455 1.187 dyoung if (dev != descendant && 2456 1.187 dyoung !device_is_ancestor_of(dev, descendant)) 2457 1.187 dyoung continue; 2458 1.187 dyoung 2459 1.187 dyoung if ((descendant->dv_flags & DVF_ACTIVE) == 0) 2460 1.187 dyoung continue; 2461 1.33 thorpej 2462 1.187 dyoung ca = descendant->dv_cfattach; 2463 1.187 dyoung oflags = descendant->dv_flags; 2464 1.187 dyoung 2465 1.187 dyoung descendant->dv_flags &= ~DVF_ACTIVE; 2466 1.187 dyoung if (ca->ca_activate == NULL) 2467 1.187 dyoung continue; 2468 1.187 dyoung s = splhigh(); 2469 1.187 dyoung rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE); 2470 1.187 dyoung splx(s); 2471 1.187 dyoung if (rv != 0) 2472 1.187 dyoung descendant->dv_flags = oflags; 2473 1.33 thorpej } 2474 1.187 dyoung deviter_release(&di); 2475 1.175 cegger return rv; 2476 1.33 thorpej } 2477 1.33 thorpej 2478 1.33 thorpej /* 2479 1.29 thorpej * Defer the configuration of the specified device until all 2480 1.29 thorpej * of its parent's devices have been attached. 2481 1.29 thorpej */ 2482 1.29 thorpej void 2483 1.102 thorpej config_defer(device_t dev, void (*func)(device_t)) 2484 1.29 thorpej { 2485 1.29 thorpej struct deferred_config *dc; 2486 1.29 thorpej 2487 1.29 thorpej if (dev->dv_parent == NULL) 2488 1.29 thorpej panic("config_defer: can't defer config of a root device"); 2489 1.29 thorpej 2490 1.266 jdolecek dc = kmem_alloc(sizeof(*dc), KM_SLEEP); 2491 1.266 jdolecek 2492 1.266 jdolecek config_pending_incr(dev); 2493 1.266 jdolecek 2494 1.266 jdolecek mutex_enter(&config_misc_lock); 2495 1.29 thorpej #ifdef DIAGNOSTIC 2496 1.266 jdolecek struct deferred_config *odc; 2497 1.266 jdolecek TAILQ_FOREACH(odc, &deferred_config_queue, dc_queue) { 2498 1.266 jdolecek if (odc->dc_dev == dev) 2499 1.29 thorpej panic("config_defer: deferred twice"); 2500 1.29 thorpej } 2501 1.29 thorpej #endif 2502 1.29 thorpej dc->dc_dev = dev; 2503 1.29 thorpej dc->dc_func = func; 2504 1.29 thorpej TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue); 2505 1.266 jdolecek mutex_exit(&config_misc_lock); 2506 1.29 thorpej } 2507 1.29 thorpej 2508 1.29 thorpej /* 2509 1.42 thorpej * Defer some autoconfiguration for a device until after interrupts 2510 1.42 thorpej * are enabled. 2511 1.42 thorpej */ 2512 1.42 thorpej void 2513 1.102 thorpej config_interrupts(device_t dev, void (*func)(device_t)) 2514 1.42 thorpej { 2515 1.42 thorpej struct deferred_config *dc; 2516 1.42 thorpej 2517 1.42 thorpej /* 2518 1.42 thorpej * If interrupts are enabled, callback now. 2519 1.42 thorpej */ 2520 1.43 thorpej if (cold == 0) { 2521 1.42 thorpej (*func)(dev); 2522 1.42 thorpej return; 2523 1.42 thorpej } 2524 1.42 thorpej 2525 1.266 jdolecek dc = kmem_alloc(sizeof(*dc), KM_SLEEP); 2526 1.266 jdolecek 2527 1.266 jdolecek config_pending_incr(dev); 2528 1.266 jdolecek 2529 1.266 jdolecek mutex_enter(&config_misc_lock); 2530 1.42 thorpej #ifdef DIAGNOSTIC 2531 1.266 jdolecek struct deferred_config *odc; 2532 1.266 jdolecek TAILQ_FOREACH(odc, &interrupt_config_queue, dc_queue) { 2533 1.266 jdolecek if (odc->dc_dev == dev) 2534 1.42 thorpej panic("config_interrupts: deferred twice"); 2535 1.42 thorpej } 2536 1.42 thorpej #endif 2537 1.42 thorpej dc->dc_dev = dev; 2538 1.42 thorpej dc->dc_func = func; 2539 1.42 thorpej TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue); 2540 1.266 jdolecek mutex_exit(&config_misc_lock); 2541 1.42 thorpej } 2542 1.42 thorpej 2543 1.42 thorpej /* 2544 1.207 tsutsui * Defer some autoconfiguration for a device until after root file system 2545 1.207 tsutsui * is mounted (to load firmware etc). 2546 1.207 tsutsui */ 2547 1.207 tsutsui void 2548 1.207 tsutsui config_mountroot(device_t dev, void (*func)(device_t)) 2549 1.207 tsutsui { 2550 1.207 tsutsui struct deferred_config *dc; 2551 1.207 tsutsui 2552 1.207 tsutsui /* 2553 1.207 tsutsui * If root file system is mounted, callback now. 2554 1.207 tsutsui */ 2555 1.208 tsutsui if (root_is_mounted) { 2556 1.207 tsutsui (*func)(dev); 2557 1.207 tsutsui return; 2558 1.207 tsutsui } 2559 1.207 tsutsui 2560 1.266 jdolecek dc = kmem_alloc(sizeof(*dc), KM_SLEEP); 2561 1.266 jdolecek 2562 1.266 jdolecek mutex_enter(&config_misc_lock); 2563 1.207 tsutsui #ifdef DIAGNOSTIC 2564 1.266 jdolecek struct deferred_config *odc; 2565 1.266 jdolecek TAILQ_FOREACH(odc, &mountroot_config_queue, dc_queue) { 2566 1.266 jdolecek if (odc->dc_dev == dev) 2567 1.207 tsutsui panic("%s: deferred twice", __func__); 2568 1.207 tsutsui } 2569 1.207 tsutsui #endif 2570 1.207 tsutsui 2571 1.207 tsutsui dc->dc_dev = dev; 2572 1.207 tsutsui dc->dc_func = func; 2573 1.207 tsutsui TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue); 2574 1.266 jdolecek mutex_exit(&config_misc_lock); 2575 1.207 tsutsui } 2576 1.207 tsutsui 2577 1.207 tsutsui /* 2578 1.42 thorpej * Process a deferred configuration queue. 2579 1.29 thorpej */ 2580 1.29 thorpej static void 2581 1.243 msaitoh config_process_deferred(struct deferred_config_head *queue, device_t parent) 2582 1.29 thorpej { 2583 1.266 jdolecek struct deferred_config *dc; 2584 1.29 thorpej 2585 1.282 riastrad KASSERT(KERNEL_LOCKED_P()); 2586 1.282 riastrad 2587 1.266 jdolecek mutex_enter(&config_misc_lock); 2588 1.266 jdolecek dc = TAILQ_FIRST(queue); 2589 1.266 jdolecek while (dc) { 2590 1.42 thorpej if (parent == NULL || dc->dc_dev->dv_parent == parent) { 2591 1.42 thorpej TAILQ_REMOVE(queue, dc, dc_queue); 2592 1.266 jdolecek mutex_exit(&config_misc_lock); 2593 1.266 jdolecek 2594 1.29 thorpej (*dc->dc_func)(dc->dc_dev); 2595 1.228 christos config_pending_decr(dc->dc_dev); 2596 1.159 matt kmem_free(dc, sizeof(*dc)); 2597 1.266 jdolecek 2598 1.266 jdolecek mutex_enter(&config_misc_lock); 2599 1.266 jdolecek /* Restart, queue might have changed */ 2600 1.266 jdolecek dc = TAILQ_FIRST(queue); 2601 1.266 jdolecek } else { 2602 1.266 jdolecek dc = TAILQ_NEXT(dc, dc_queue); 2603 1.29 thorpej } 2604 1.29 thorpej } 2605 1.266 jdolecek mutex_exit(&config_misc_lock); 2606 1.47 thorpej } 2607 1.47 thorpej 2608 1.47 thorpej /* 2609 1.47 thorpej * Manipulate the config_pending semaphore. 2610 1.47 thorpej */ 2611 1.47 thorpej void 2612 1.228 christos config_pending_incr(device_t dev) 2613 1.47 thorpej { 2614 1.47 thorpej 2615 1.151 ad mutex_enter(&config_misc_lock); 2616 1.274 riastrad KASSERTMSG(dev->dv_pending < INT_MAX, 2617 1.274 riastrad "%s: excess config_pending_incr", device_xname(dev)); 2618 1.274 riastrad if (dev->dv_pending++ == 0) 2619 1.274 riastrad TAILQ_INSERT_TAIL(&config_pending, dev, dv_pending_list); 2620 1.228 christos #ifdef DEBUG_AUTOCONF 2621 1.274 riastrad printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending); 2622 1.228 christos #endif 2623 1.151 ad mutex_exit(&config_misc_lock); 2624 1.47 thorpej } 2625 1.47 thorpej 2626 1.47 thorpej void 2627 1.228 christos config_pending_decr(device_t dev) 2628 1.47 thorpej { 2629 1.47 thorpej 2630 1.151 ad mutex_enter(&config_misc_lock); 2631 1.274 riastrad KASSERTMSG(dev->dv_pending > 0, 2632 1.274 riastrad "%s: excess config_pending_decr", device_xname(dev)); 2633 1.283 riastrad if (--dev->dv_pending == 0) { 2634 1.274 riastrad TAILQ_REMOVE(&config_pending, dev, dv_pending_list); 2635 1.283 riastrad cv_broadcast(&config_misc_cv); 2636 1.283 riastrad } 2637 1.228 christos #ifdef DEBUG_AUTOCONF 2638 1.274 riastrad printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending); 2639 1.228 christos #endif 2640 1.151 ad mutex_exit(&config_misc_lock); 2641 1.75 thorpej } 2642 1.75 thorpej 2643 1.75 thorpej /* 2644 1.75 thorpej * Register a "finalization" routine. Finalization routines are 2645 1.75 thorpej * called iteratively once all real devices have been found during 2646 1.75 thorpej * autoconfiguration, for as long as any one finalizer has done 2647 1.75 thorpej * any work. 2648 1.75 thorpej */ 2649 1.75 thorpej int 2650 1.102 thorpej config_finalize_register(device_t dev, int (*fn)(device_t)) 2651 1.75 thorpej { 2652 1.75 thorpej struct finalize_hook *f; 2653 1.281 riastrad int error = 0; 2654 1.281 riastrad 2655 1.281 riastrad KERNEL_LOCK(1, NULL); 2656 1.75 thorpej 2657 1.75 thorpej /* 2658 1.75 thorpej * If finalization has already been done, invoke the 2659 1.75 thorpej * callback function now. 2660 1.75 thorpej */ 2661 1.75 thorpej if (config_finalize_done) { 2662 1.75 thorpej while ((*fn)(dev) != 0) 2663 1.75 thorpej /* loop */ ; 2664 1.281 riastrad goto out; 2665 1.75 thorpej } 2666 1.75 thorpej 2667 1.75 thorpej /* Ensure this isn't already on the list. */ 2668 1.75 thorpej TAILQ_FOREACH(f, &config_finalize_list, f_list) { 2669 1.281 riastrad if (f->f_func == fn && f->f_dev == dev) { 2670 1.281 riastrad error = EEXIST; 2671 1.281 riastrad goto out; 2672 1.281 riastrad } 2673 1.75 thorpej } 2674 1.75 thorpej 2675 1.159 matt f = kmem_alloc(sizeof(*f), KM_SLEEP); 2676 1.75 thorpej f->f_func = fn; 2677 1.75 thorpej f->f_dev = dev; 2678 1.75 thorpej TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list); 2679 1.75 thorpej 2680 1.281 riastrad /* Success! */ 2681 1.281 riastrad error = 0; 2682 1.281 riastrad 2683 1.281 riastrad out: KERNEL_UNLOCK_ONE(NULL); 2684 1.281 riastrad return error; 2685 1.75 thorpej } 2686 1.75 thorpej 2687 1.75 thorpej void 2688 1.75 thorpej config_finalize(void) 2689 1.75 thorpej { 2690 1.75 thorpej struct finalize_hook *f; 2691 1.142 ad struct pdevinit *pdev; 2692 1.142 ad extern struct pdevinit pdevinit[]; 2693 1.314 riastrad unsigned t0 = getticks(); 2694 1.142 ad int errcnt, rv; 2695 1.142 ad 2696 1.142 ad /* 2697 1.142 ad * Now that device driver threads have been created, wait for 2698 1.142 ad * them to finish any deferred autoconfiguration. 2699 1.142 ad */ 2700 1.151 ad mutex_enter(&config_misc_lock); 2701 1.274 riastrad while (!TAILQ_EMPTY(&config_pending)) { 2702 1.314 riastrad const unsigned t1 = getticks(); 2703 1.290 jmcneill 2704 1.314 riastrad if (t1 - t0 >= hz) { 2705 1.314 riastrad void (*pr)(const char *, ...) __printflike(1,2); 2706 1.314 riastrad device_t dev; 2707 1.314 riastrad 2708 1.314 riastrad if (t1 - t0 >= 60*hz) { 2709 1.314 riastrad pr = aprint_normal; 2710 1.314 riastrad t0 = t1; 2711 1.314 riastrad } else { 2712 1.314 riastrad pr = aprint_debug; 2713 1.314 riastrad } 2714 1.314 riastrad 2715 1.314 riastrad (*pr)("waiting for devices:"); 2716 1.290 jmcneill TAILQ_FOREACH(dev, &config_pending, dv_pending_list) 2717 1.314 riastrad (*pr)(" %s", device_xname(dev)); 2718 1.314 riastrad (*pr)("\n"); 2719 1.290 jmcneill } 2720 1.314 riastrad 2721 1.314 riastrad (void)cv_timedwait(&config_misc_cv, &config_misc_lock, 2722 1.314 riastrad mstohz(1000)); 2723 1.274 riastrad } 2724 1.151 ad mutex_exit(&config_misc_lock); 2725 1.142 ad 2726 1.167 ad KERNEL_LOCK(1, NULL); 2727 1.167 ad 2728 1.142 ad /* Attach pseudo-devices. */ 2729 1.142 ad for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++) 2730 1.142 ad (*pdev->pdev_attach)(pdev->pdev_count); 2731 1.75 thorpej 2732 1.75 thorpej /* Run the hooks until none of them does any work. */ 2733 1.75 thorpej do { 2734 1.75 thorpej rv = 0; 2735 1.75 thorpej TAILQ_FOREACH(f, &config_finalize_list, f_list) 2736 1.75 thorpej rv |= (*f->f_func)(f->f_dev); 2737 1.75 thorpej } while (rv != 0); 2738 1.75 thorpej 2739 1.75 thorpej config_finalize_done = 1; 2740 1.75 thorpej 2741 1.75 thorpej /* Now free all the hooks. */ 2742 1.75 thorpej while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) { 2743 1.75 thorpej TAILQ_REMOVE(&config_finalize_list, f, f_list); 2744 1.159 matt kmem_free(f, sizeof(*f)); 2745 1.79 thorpej } 2746 1.142 ad 2747 1.167 ad KERNEL_UNLOCK_ONE(NULL); 2748 1.167 ad 2749 1.142 ad errcnt = aprint_get_error_count(); 2750 1.142 ad if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 && 2751 1.142 ad (boothowto & AB_VERBOSE) == 0) { 2752 1.176 ad mutex_enter(&config_misc_lock); 2753 1.142 ad if (config_do_twiddle) { 2754 1.142 ad config_do_twiddle = 0; 2755 1.169 ad printf_nolog(" done.\n"); 2756 1.142 ad } 2757 1.176 ad mutex_exit(&config_misc_lock); 2758 1.247 msaitoh } 2759 1.247 msaitoh if (errcnt != 0) { 2760 1.247 msaitoh printf("WARNING: %d error%s while detecting hardware; " 2761 1.247 msaitoh "check system log.\n", errcnt, 2762 1.247 msaitoh errcnt == 1 ? "" : "s"); 2763 1.142 ad } 2764 1.79 thorpej } 2765 1.79 thorpej 2766 1.176 ad void 2767 1.222 matt config_twiddle_init(void) 2768 1.180 pooka { 2769 1.180 pooka 2770 1.180 pooka if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) { 2771 1.180 pooka config_do_twiddle = 1; 2772 1.180 pooka } 2773 1.180 pooka callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL); 2774 1.180 pooka } 2775 1.180 pooka 2776 1.180 pooka void 2777 1.176 ad config_twiddle_fn(void *cookie) 2778 1.176 ad { 2779 1.176 ad 2780 1.176 ad mutex_enter(&config_misc_lock); 2781 1.176 ad if (config_do_twiddle) { 2782 1.176 ad twiddle(); 2783 1.176 ad callout_schedule(&config_twiddle_ch, mstohz(100)); 2784 1.176 ad } 2785 1.176 ad mutex_exit(&config_misc_lock); 2786 1.176 ad } 2787 1.176 ad 2788 1.187 dyoung static void 2789 1.198 dyoung config_alldevs_enter(struct alldevs_foray *af) 2790 1.198 dyoung { 2791 1.198 dyoung TAILQ_INIT(&af->af_garbage); 2792 1.257 mlelstv mutex_enter(&alldevs_lock); 2793 1.198 dyoung config_collect_garbage(&af->af_garbage); 2794 1.243 msaitoh } 2795 1.198 dyoung 2796 1.198 dyoung static void 2797 1.198 dyoung config_alldevs_exit(struct alldevs_foray *af) 2798 1.198 dyoung { 2799 1.257 mlelstv mutex_exit(&alldevs_lock); 2800 1.198 dyoung config_dump_garbage(&af->af_garbage); 2801 1.198 dyoung } 2802 1.198 dyoung 2803 1.104 thorpej /* 2804 1.107 thorpej * device_lookup: 2805 1.107 thorpej * 2806 1.107 thorpej * Look up a device instance for a given driver. 2807 1.298 riastrad * 2808 1.298 riastrad * Caller is responsible for ensuring the device's state is 2809 1.298 riastrad * stable, either by holding a reference already obtained with 2810 1.298 riastrad * device_lookup_acquire or by otherwise ensuring the device is 2811 1.298 riastrad * attached and can't be detached (e.g., holding an open device 2812 1.298 riastrad * node and ensuring *_detach calls vdevgone). 2813 1.298 riastrad * 2814 1.298 riastrad * XXX Find a way to assert this. 2815 1.298 riastrad * 2816 1.298 riastrad * Safe for use up to and including interrupt context at IPL_VM. 2817 1.298 riastrad * Never sleeps. 2818 1.107 thorpej */ 2819 1.156 drochner device_t 2820 1.107 thorpej device_lookup(cfdriver_t cd, int unit) 2821 1.107 thorpej { 2822 1.187 dyoung device_t dv; 2823 1.107 thorpej 2824 1.257 mlelstv mutex_enter(&alldevs_lock); 2825 1.107 thorpej if (unit < 0 || unit >= cd->cd_ndevs) 2826 1.187 dyoung dv = NULL; 2827 1.191 dyoung else if ((dv = cd->cd_devs[unit]) != NULL && dv->dv_del_gen != 0) 2828 1.191 dyoung dv = NULL; 2829 1.257 mlelstv mutex_exit(&alldevs_lock); 2830 1.187 dyoung 2831 1.187 dyoung return dv; 2832 1.107 thorpej } 2833 1.107 thorpej 2834 1.107 thorpej /* 2835 1.191 dyoung * device_lookup_private: 2836 1.140 matt * 2837 1.191 dyoung * Look up a softc instance for a given driver. 2838 1.140 matt */ 2839 1.140 matt void * 2840 1.140 matt device_lookup_private(cfdriver_t cd, int unit) 2841 1.140 matt { 2842 1.140 matt 2843 1.198 dyoung return device_private(device_lookup(cd, unit)); 2844 1.140 matt } 2845 1.140 matt 2846 1.140 matt /* 2847 1.298 riastrad * device_lookup_acquire: 2848 1.298 riastrad * 2849 1.298 riastrad * Look up a device instance for a given driver, and return a 2850 1.298 riastrad * reference to it that must be released by device_release. 2851 1.298 riastrad * 2852 1.298 riastrad * => If the device is still attaching, blocks until *_attach has 2853 1.298 riastrad * returned. 2854 1.298 riastrad * 2855 1.298 riastrad * => If the device is detaching, blocks until *_detach has 2856 1.298 riastrad * returned. May succeed or fail in that case, depending on 2857 1.298 riastrad * whether *_detach has backed out (EBUSY) or committed to 2858 1.298 riastrad * detaching. 2859 1.298 riastrad * 2860 1.298 riastrad * May sleep. 2861 1.298 riastrad */ 2862 1.298 riastrad device_t 2863 1.298 riastrad device_lookup_acquire(cfdriver_t cd, int unit) 2864 1.298 riastrad { 2865 1.298 riastrad device_t dv; 2866 1.298 riastrad 2867 1.298 riastrad ASSERT_SLEEPABLE(); 2868 1.298 riastrad 2869 1.298 riastrad /* XXX This should have a pserialized fast path -- TBD. */ 2870 1.298 riastrad mutex_enter(&config_misc_lock); 2871 1.298 riastrad mutex_enter(&alldevs_lock); 2872 1.298 riastrad retry: if (unit < 0 || unit >= cd->cd_ndevs || 2873 1.298 riastrad (dv = cd->cd_devs[unit]) == NULL || 2874 1.299 riastrad dv->dv_del_gen != 0 || 2875 1.306 riastrad dv->dv_detach_committed) { 2876 1.298 riastrad dv = NULL; 2877 1.298 riastrad } else { 2878 1.298 riastrad /* 2879 1.298 riastrad * Wait for the device to stabilize, if attaching or 2880 1.298 riastrad * detaching. Either way we must wait for *_attach or 2881 1.298 riastrad * *_detach to complete, and either way we must retry: 2882 1.298 riastrad * even if detaching, *_detach might fail (EBUSY) so 2883 1.298 riastrad * the device may still be there. 2884 1.298 riastrad */ 2885 1.298 riastrad if ((dv->dv_attaching != NULL && dv->dv_attaching != curlwp) || 2886 1.298 riastrad dv->dv_detaching != NULL) { 2887 1.298 riastrad mutex_exit(&alldevs_lock); 2888 1.298 riastrad cv_wait(&config_misc_cv, &config_misc_lock); 2889 1.298 riastrad mutex_enter(&alldevs_lock); 2890 1.298 riastrad goto retry; 2891 1.298 riastrad } 2892 1.311 riastrad device_acquire(dv); 2893 1.298 riastrad } 2894 1.298 riastrad mutex_exit(&alldevs_lock); 2895 1.298 riastrad mutex_exit(&config_misc_lock); 2896 1.298 riastrad 2897 1.298 riastrad return dv; 2898 1.298 riastrad } 2899 1.298 riastrad 2900 1.298 riastrad /* 2901 1.311 riastrad * device_acquire: 2902 1.311 riastrad * 2903 1.311 riastrad * Acquire a reference to a device. It is the caller's 2904 1.311 riastrad * responsibility to ensure that the device's .ca_detach routine 2905 1.311 riastrad * cannot return before calling this. Caller must release the 2906 1.311 riastrad * reference with device_release or config_detach_release. 2907 1.311 riastrad */ 2908 1.311 riastrad void 2909 1.311 riastrad device_acquire(device_t dv) 2910 1.311 riastrad { 2911 1.311 riastrad 2912 1.311 riastrad /* 2913 1.311 riastrad * No lock because the caller has promised that this can't 2914 1.311 riastrad * change concurrently with device_acquire. 2915 1.311 riastrad */ 2916 1.311 riastrad KASSERTMSG(!dv->dv_detach_done, "%s", 2917 1.311 riastrad dv == NULL ? "(null)" : device_xname(dv)); 2918 1.311 riastrad localcount_acquire(dv->dv_localcount); 2919 1.311 riastrad } 2920 1.311 riastrad 2921 1.311 riastrad /* 2922 1.298 riastrad * device_release: 2923 1.298 riastrad * 2924 1.311 riastrad * Release a reference to a device acquired with device_acquire or 2925 1.298 riastrad * device_lookup_acquire. 2926 1.298 riastrad */ 2927 1.298 riastrad void 2928 1.298 riastrad device_release(device_t dv) 2929 1.298 riastrad { 2930 1.298 riastrad 2931 1.298 riastrad localcount_release(dv->dv_localcount, 2932 1.298 riastrad &config_misc_cv, &config_misc_lock); 2933 1.298 riastrad } 2934 1.298 riastrad 2935 1.298 riastrad /* 2936 1.131 joerg * device_find_by_xname: 2937 1.131 joerg * 2938 1.131 joerg * Returns the device of the given name or NULL if it doesn't exist. 2939 1.131 joerg */ 2940 1.131 joerg device_t 2941 1.131 joerg device_find_by_xname(const char *name) 2942 1.131 joerg { 2943 1.131 joerg device_t dv; 2944 1.136 dyoung deviter_t di; 2945 1.131 joerg 2946 1.136 dyoung for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) { 2947 1.131 joerg if (strcmp(device_xname(dv), name) == 0) 2948 1.131 joerg break; 2949 1.131 joerg } 2950 1.136 dyoung deviter_release(&di); 2951 1.131 joerg 2952 1.131 joerg return dv; 2953 1.131 joerg } 2954 1.131 joerg 2955 1.131 joerg /* 2956 1.131 joerg * device_find_by_driver_unit: 2957 1.131 joerg * 2958 1.131 joerg * Returns the device of the given driver name and unit or 2959 1.131 joerg * NULL if it doesn't exist. 2960 1.131 joerg */ 2961 1.131 joerg device_t 2962 1.131 joerg device_find_by_driver_unit(const char *name, int unit) 2963 1.131 joerg { 2964 1.131 joerg struct cfdriver *cd; 2965 1.131 joerg 2966 1.131 joerg if ((cd = config_cfdriver_lookup(name)) == NULL) 2967 1.131 joerg return NULL; 2968 1.131 joerg return device_lookup(cd, unit); 2969 1.131 joerg } 2970 1.131 joerg 2971 1.276 thorpej static bool 2972 1.276 thorpej match_strcmp(const char * const s1, const char * const s2) 2973 1.276 thorpej { 2974 1.276 thorpej return strcmp(s1, s2) == 0; 2975 1.276 thorpej } 2976 1.276 thorpej 2977 1.276 thorpej static bool 2978 1.276 thorpej match_pmatch(const char * const s1, const char * const s2) 2979 1.276 thorpej { 2980 1.276 thorpej return pmatch(s1, s2, NULL) == 2; 2981 1.276 thorpej } 2982 1.276 thorpej 2983 1.276 thorpej static bool 2984 1.276 thorpej strarray_match_internal(const char ** const strings, 2985 1.276 thorpej unsigned int const nstrings, const char * const str, 2986 1.276 thorpej unsigned int * const indexp, 2987 1.276 thorpej bool (*match_fn)(const char *, const char *)) 2988 1.276 thorpej { 2989 1.276 thorpej unsigned int i; 2990 1.276 thorpej 2991 1.276 thorpej if (strings == NULL || nstrings == 0) { 2992 1.277 thorpej return false; 2993 1.276 thorpej } 2994 1.276 thorpej 2995 1.276 thorpej for (i = 0; i < nstrings; i++) { 2996 1.276 thorpej if ((*match_fn)(strings[i], str)) { 2997 1.276 thorpej *indexp = i; 2998 1.276 thorpej return true; 2999 1.276 thorpej } 3000 1.276 thorpej } 3001 1.276 thorpej 3002 1.276 thorpej return false; 3003 1.276 thorpej } 3004 1.276 thorpej 3005 1.276 thorpej static int 3006 1.276 thorpej strarray_match(const char ** const strings, unsigned int const nstrings, 3007 1.276 thorpej const char * const str) 3008 1.276 thorpej { 3009 1.276 thorpej unsigned int idx; 3010 1.276 thorpej 3011 1.276 thorpej if (strarray_match_internal(strings, nstrings, str, &idx, 3012 1.276 thorpej match_strcmp)) { 3013 1.276 thorpej return (int)(nstrings - idx); 3014 1.276 thorpej } 3015 1.276 thorpej return 0; 3016 1.276 thorpej } 3017 1.276 thorpej 3018 1.276 thorpej static int 3019 1.276 thorpej strarray_pmatch(const char ** const strings, unsigned int const nstrings, 3020 1.276 thorpej const char * const pattern) 3021 1.276 thorpej { 3022 1.276 thorpej unsigned int idx; 3023 1.276 thorpej 3024 1.276 thorpej if (strarray_match_internal(strings, nstrings, pattern, &idx, 3025 1.276 thorpej match_pmatch)) { 3026 1.276 thorpej return (int)(nstrings - idx); 3027 1.276 thorpej } 3028 1.276 thorpej return 0; 3029 1.276 thorpej } 3030 1.276 thorpej 3031 1.276 thorpej static int 3032 1.276 thorpej device_compatible_match_strarray_internal( 3033 1.276 thorpej const char **device_compats, int ndevice_compats, 3034 1.276 thorpej const struct device_compatible_entry *driver_compats, 3035 1.276 thorpej const struct device_compatible_entry **matching_entryp, 3036 1.276 thorpej int (*match_fn)(const char **, unsigned int, const char *)) 3037 1.276 thorpej { 3038 1.276 thorpej const struct device_compatible_entry *dce = NULL; 3039 1.276 thorpej int rv; 3040 1.276 thorpej 3041 1.276 thorpej if (ndevice_compats == 0 || device_compats == NULL || 3042 1.276 thorpej driver_compats == NULL) 3043 1.276 thorpej return 0; 3044 1.276 thorpej 3045 1.276 thorpej for (dce = driver_compats; dce->compat != NULL; dce++) { 3046 1.276 thorpej rv = (*match_fn)(device_compats, ndevice_compats, dce->compat); 3047 1.276 thorpej if (rv != 0) { 3048 1.276 thorpej if (matching_entryp != NULL) { 3049 1.276 thorpej *matching_entryp = dce; 3050 1.276 thorpej } 3051 1.276 thorpej return rv; 3052 1.276 thorpej } 3053 1.276 thorpej } 3054 1.276 thorpej return 0; 3055 1.276 thorpej } 3056 1.276 thorpej 3057 1.131 joerg /* 3058 1.258 thorpej * device_compatible_match: 3059 1.258 thorpej * 3060 1.258 thorpej * Match a driver's "compatible" data against a device's 3061 1.276 thorpej * "compatible" strings. Returns resulted weighted by 3062 1.276 thorpej * which device "compatible" string was matched. 3063 1.276 thorpej */ 3064 1.276 thorpej int 3065 1.276 thorpej device_compatible_match(const char **device_compats, int ndevice_compats, 3066 1.276 thorpej const struct device_compatible_entry *driver_compats) 3067 1.276 thorpej { 3068 1.276 thorpej return device_compatible_match_strarray_internal(device_compats, 3069 1.276 thorpej ndevice_compats, driver_compats, NULL, strarray_match); 3070 1.276 thorpej } 3071 1.276 thorpej 3072 1.276 thorpej /* 3073 1.276 thorpej * device_compatible_pmatch: 3074 1.276 thorpej * 3075 1.276 thorpej * Like device_compatible_match(), but uses pmatch(9) to compare 3076 1.276 thorpej * the device "compatible" strings against patterns in the 3077 1.276 thorpej * driver's "compatible" data. 3078 1.258 thorpej */ 3079 1.276 thorpej int 3080 1.276 thorpej device_compatible_pmatch(const char **device_compats, int ndevice_compats, 3081 1.276 thorpej const struct device_compatible_entry *driver_compats) 3082 1.276 thorpej { 3083 1.276 thorpej return device_compatible_match_strarray_internal(device_compats, 3084 1.276 thorpej ndevice_compats, driver_compats, NULL, strarray_pmatch); 3085 1.276 thorpej } 3086 1.276 thorpej 3087 1.275 thorpej static int 3088 1.276 thorpej device_compatible_match_strlist_internal( 3089 1.276 thorpej const char * const device_compats, size_t const device_compatsize, 3090 1.275 thorpej const struct device_compatible_entry *driver_compats, 3091 1.276 thorpej const struct device_compatible_entry **matching_entryp, 3092 1.276 thorpej int (*match_fn)(const char *, size_t, const char *)) 3093 1.258 thorpej { 3094 1.258 thorpej const struct device_compatible_entry *dce = NULL; 3095 1.276 thorpej int rv; 3096 1.258 thorpej 3097 1.276 thorpej if (device_compats == NULL || device_compatsize == 0 || 3098 1.258 thorpej driver_compats == NULL) 3099 1.261 thorpej return 0; 3100 1.276 thorpej 3101 1.276 thorpej for (dce = driver_compats; dce->compat != NULL; dce++) { 3102 1.276 thorpej rv = (*match_fn)(device_compats, device_compatsize, 3103 1.276 thorpej dce->compat); 3104 1.276 thorpej if (rv != 0) { 3105 1.276 thorpej if (matching_entryp != NULL) { 3106 1.276 thorpej *matching_entryp = dce; 3107 1.258 thorpej } 3108 1.276 thorpej return rv; 3109 1.258 thorpej } 3110 1.258 thorpej } 3111 1.261 thorpej return 0; 3112 1.258 thorpej } 3113 1.258 thorpej 3114 1.276 thorpej /* 3115 1.276 thorpej * device_compatible_match_strlist: 3116 1.276 thorpej * 3117 1.276 thorpej * Like device_compatible_match(), but take the device 3118 1.276 thorpej * "compatible" strings as an OpenFirmware-style string 3119 1.276 thorpej * list. 3120 1.276 thorpej */ 3121 1.275 thorpej int 3122 1.276 thorpej device_compatible_match_strlist( 3123 1.276 thorpej const char * const device_compats, size_t const device_compatsize, 3124 1.276 thorpej const struct device_compatible_entry *driver_compats) 3125 1.276 thorpej { 3126 1.276 thorpej return device_compatible_match_strlist_internal(device_compats, 3127 1.276 thorpej device_compatsize, driver_compats, NULL, strlist_match); 3128 1.276 thorpej } 3129 1.276 thorpej 3130 1.276 thorpej /* 3131 1.276 thorpej * device_compatible_pmatch_strlist: 3132 1.276 thorpej * 3133 1.276 thorpej * Like device_compatible_pmatch(), but take the device 3134 1.276 thorpej * "compatible" strings as an OpenFirmware-style string 3135 1.276 thorpej * list. 3136 1.276 thorpej */ 3137 1.276 thorpej int 3138 1.276 thorpej device_compatible_pmatch_strlist( 3139 1.276 thorpej const char * const device_compats, size_t const device_compatsize, 3140 1.276 thorpej const struct device_compatible_entry *driver_compats) 3141 1.275 thorpej { 3142 1.276 thorpej return device_compatible_match_strlist_internal(device_compats, 3143 1.276 thorpej device_compatsize, driver_compats, NULL, strlist_pmatch); 3144 1.275 thorpej } 3145 1.275 thorpej 3146 1.277 thorpej static int 3147 1.277 thorpej device_compatible_match_id_internal( 3148 1.277 thorpej uintptr_t const id, uintptr_t const mask, uintptr_t const sentinel_id, 3149 1.277 thorpej const struct device_compatible_entry *driver_compats, 3150 1.277 thorpej const struct device_compatible_entry **matching_entryp) 3151 1.277 thorpej { 3152 1.277 thorpej const struct device_compatible_entry *dce = NULL; 3153 1.277 thorpej 3154 1.277 thorpej if (mask == 0) 3155 1.277 thorpej return 0; 3156 1.277 thorpej 3157 1.277 thorpej for (dce = driver_compats; dce->id != sentinel_id; dce++) { 3158 1.277 thorpej if ((id & mask) == dce->id) { 3159 1.277 thorpej if (matching_entryp != NULL) { 3160 1.277 thorpej *matching_entryp = dce; 3161 1.277 thorpej } 3162 1.277 thorpej return 1; 3163 1.277 thorpej } 3164 1.277 thorpej } 3165 1.277 thorpej return 0; 3166 1.277 thorpej } 3167 1.277 thorpej 3168 1.277 thorpej /* 3169 1.277 thorpej * device_compatible_match_id: 3170 1.277 thorpej * 3171 1.277 thorpej * Like device_compatible_match(), but takes a single 3172 1.277 thorpej * unsigned integer device ID. 3173 1.277 thorpej */ 3174 1.277 thorpej int 3175 1.277 thorpej device_compatible_match_id( 3176 1.277 thorpej uintptr_t const id, uintptr_t const sentinel_id, 3177 1.277 thorpej const struct device_compatible_entry *driver_compats) 3178 1.277 thorpej { 3179 1.277 thorpej return device_compatible_match_id_internal(id, (uintptr_t)-1, 3180 1.277 thorpej sentinel_id, driver_compats, NULL); 3181 1.277 thorpej } 3182 1.277 thorpej 3183 1.275 thorpej /* 3184 1.275 thorpej * device_compatible_lookup: 3185 1.275 thorpej * 3186 1.275 thorpej * Look up and return the device_compatible_entry, using the 3187 1.275 thorpej * same matching criteria used by device_compatible_match(). 3188 1.275 thorpej */ 3189 1.275 thorpej const struct device_compatible_entry * 3190 1.275 thorpej device_compatible_lookup(const char **device_compats, int ndevice_compats, 3191 1.275 thorpej const struct device_compatible_entry *driver_compats) 3192 1.275 thorpej { 3193 1.275 thorpej const struct device_compatible_entry *dce; 3194 1.275 thorpej 3195 1.276 thorpej if (device_compatible_match_strarray_internal(device_compats, 3196 1.276 thorpej ndevice_compats, driver_compats, &dce, strarray_match)) { 3197 1.276 thorpej return dce; 3198 1.276 thorpej } 3199 1.276 thorpej return NULL; 3200 1.276 thorpej } 3201 1.276 thorpej 3202 1.276 thorpej /* 3203 1.276 thorpej * device_compatible_plookup: 3204 1.276 thorpej * 3205 1.276 thorpej * Look up and return the device_compatible_entry, using the 3206 1.276 thorpej * same matching criteria used by device_compatible_pmatch(). 3207 1.276 thorpej */ 3208 1.276 thorpej const struct device_compatible_entry * 3209 1.276 thorpej device_compatible_plookup(const char **device_compats, int ndevice_compats, 3210 1.276 thorpej const struct device_compatible_entry *driver_compats) 3211 1.276 thorpej { 3212 1.276 thorpej const struct device_compatible_entry *dce; 3213 1.276 thorpej 3214 1.276 thorpej if (device_compatible_match_strarray_internal(device_compats, 3215 1.276 thorpej ndevice_compats, driver_compats, &dce, strarray_pmatch)) { 3216 1.276 thorpej return dce; 3217 1.276 thorpej } 3218 1.276 thorpej return NULL; 3219 1.276 thorpej } 3220 1.276 thorpej 3221 1.276 thorpej /* 3222 1.276 thorpej * device_compatible_lookup_strlist: 3223 1.276 thorpej * 3224 1.276 thorpej * Like device_compatible_lookup(), but take the device 3225 1.276 thorpej * "compatible" strings as an OpenFirmware-style string 3226 1.276 thorpej * list. 3227 1.276 thorpej */ 3228 1.276 thorpej const struct device_compatible_entry * 3229 1.276 thorpej device_compatible_lookup_strlist( 3230 1.276 thorpej const char * const device_compats, size_t const device_compatsize, 3231 1.276 thorpej const struct device_compatible_entry *driver_compats) 3232 1.276 thorpej { 3233 1.276 thorpej const struct device_compatible_entry *dce; 3234 1.276 thorpej 3235 1.276 thorpej if (device_compatible_match_strlist_internal(device_compats, 3236 1.276 thorpej device_compatsize, driver_compats, &dce, strlist_match)) { 3237 1.276 thorpej return dce; 3238 1.276 thorpej } 3239 1.276 thorpej return NULL; 3240 1.276 thorpej } 3241 1.276 thorpej 3242 1.276 thorpej /* 3243 1.276 thorpej * device_compatible_plookup_strlist: 3244 1.276 thorpej * 3245 1.276 thorpej * Like device_compatible_plookup(), but take the device 3246 1.276 thorpej * "compatible" strings as an OpenFirmware-style string 3247 1.276 thorpej * list. 3248 1.276 thorpej */ 3249 1.276 thorpej const struct device_compatible_entry * 3250 1.276 thorpej device_compatible_plookup_strlist( 3251 1.276 thorpej const char * const device_compats, size_t const device_compatsize, 3252 1.276 thorpej const struct device_compatible_entry *driver_compats) 3253 1.276 thorpej { 3254 1.276 thorpej const struct device_compatible_entry *dce; 3255 1.276 thorpej 3256 1.276 thorpej if (device_compatible_match_strlist_internal(device_compats, 3257 1.276 thorpej device_compatsize, driver_compats, &dce, strlist_pmatch)) { 3258 1.275 thorpej return dce; 3259 1.275 thorpej } 3260 1.275 thorpej return NULL; 3261 1.275 thorpej } 3262 1.275 thorpej 3263 1.258 thorpej /* 3264 1.277 thorpej * device_compatible_lookup_id: 3265 1.277 thorpej * 3266 1.277 thorpej * Like device_compatible_lookup(), but takes a single 3267 1.277 thorpej * unsigned integer device ID. 3268 1.277 thorpej */ 3269 1.277 thorpej const struct device_compatible_entry * 3270 1.277 thorpej device_compatible_lookup_id( 3271 1.277 thorpej uintptr_t const id, uintptr_t const sentinel_id, 3272 1.277 thorpej const struct device_compatible_entry *driver_compats) 3273 1.277 thorpej { 3274 1.277 thorpej const struct device_compatible_entry *dce; 3275 1.277 thorpej 3276 1.277 thorpej if (device_compatible_match_id_internal(id, (uintptr_t)-1, 3277 1.277 thorpej sentinel_id, driver_compats, &dce)) { 3278 1.277 thorpej return dce; 3279 1.277 thorpej } 3280 1.277 thorpej return NULL; 3281 1.277 thorpej } 3282 1.277 thorpej 3283 1.277 thorpej /* 3284 1.124 jmcneill * Power management related functions. 3285 1.124 jmcneill */ 3286 1.124 jmcneill 3287 1.124 jmcneill bool 3288 1.124 jmcneill device_pmf_is_registered(device_t dev) 3289 1.124 jmcneill { 3290 1.124 jmcneill return (dev->dv_flags & DVF_POWER_HANDLERS) != 0; 3291 1.124 jmcneill } 3292 1.124 jmcneill 3293 1.124 jmcneill bool 3294 1.203 dyoung device_pmf_driver_suspend(device_t dev, const pmf_qual_t *qual) 3295 1.124 jmcneill { 3296 1.124 jmcneill if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0) 3297 1.124 jmcneill return true; 3298 1.124 jmcneill if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0) 3299 1.124 jmcneill return false; 3300 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER && 3301 1.183 dyoung dev->dv_driver_suspend != NULL && 3302 1.195 dyoung !(*dev->dv_driver_suspend)(dev, qual)) 3303 1.124 jmcneill return false; 3304 1.124 jmcneill 3305 1.124 jmcneill dev->dv_flags |= DVF_DRIVER_SUSPENDED; 3306 1.124 jmcneill return true; 3307 1.124 jmcneill } 3308 1.124 jmcneill 3309 1.124 jmcneill bool 3310 1.203 dyoung device_pmf_driver_resume(device_t dev, const pmf_qual_t *qual) 3311 1.124 jmcneill { 3312 1.124 jmcneill if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0) 3313 1.124 jmcneill return true; 3314 1.124 jmcneill if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0) 3315 1.124 jmcneill return false; 3316 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER && 3317 1.183 dyoung dev->dv_driver_resume != NULL && 3318 1.195 dyoung !(*dev->dv_driver_resume)(dev, qual)) 3319 1.124 jmcneill return false; 3320 1.124 jmcneill 3321 1.124 jmcneill dev->dv_flags &= ~DVF_DRIVER_SUSPENDED; 3322 1.124 jmcneill return true; 3323 1.124 jmcneill } 3324 1.124 jmcneill 3325 1.133 drochner bool 3326 1.133 drochner device_pmf_driver_shutdown(device_t dev, int how) 3327 1.133 drochner { 3328 1.133 drochner 3329 1.133 drochner if (*dev->dv_driver_shutdown != NULL && 3330 1.133 drochner !(*dev->dv_driver_shutdown)(dev, how)) 3331 1.133 drochner return false; 3332 1.133 drochner return true; 3333 1.133 drochner } 3334 1.133 drochner 3335 1.303 riastrad void 3336 1.124 jmcneill device_pmf_driver_register(device_t dev, 3337 1.203 dyoung bool (*suspend)(device_t, const pmf_qual_t *), 3338 1.203 dyoung bool (*resume)(device_t, const pmf_qual_t *), 3339 1.133 drochner bool (*shutdown)(device_t, int)) 3340 1.124 jmcneill { 3341 1.303 riastrad 3342 1.124 jmcneill dev->dv_driver_suspend = suspend; 3343 1.124 jmcneill dev->dv_driver_resume = resume; 3344 1.133 drochner dev->dv_driver_shutdown = shutdown; 3345 1.124 jmcneill dev->dv_flags |= DVF_POWER_HANDLERS; 3346 1.124 jmcneill } 3347 1.124 jmcneill 3348 1.124 jmcneill void 3349 1.124 jmcneill device_pmf_driver_deregister(device_t dev) 3350 1.124 jmcneill { 3351 1.174 dyoung device_lock_t dvl = device_getlock(dev); 3352 1.157 drochner 3353 1.124 jmcneill dev->dv_driver_suspend = NULL; 3354 1.124 jmcneill dev->dv_driver_resume = NULL; 3355 1.139 dyoung 3356 1.174 dyoung mutex_enter(&dvl->dvl_mtx); 3357 1.124 jmcneill dev->dv_flags &= ~DVF_POWER_HANDLERS; 3358 1.174 dyoung while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) { 3359 1.139 dyoung /* Wake a thread that waits for the lock. That 3360 1.139 dyoung * thread will fail to acquire the lock, and then 3361 1.139 dyoung * it will wake the next thread that waits for the 3362 1.139 dyoung * lock, or else it will wake us. 3363 1.139 dyoung */ 3364 1.174 dyoung cv_signal(&dvl->dvl_cv); 3365 1.139 dyoung pmflock_debug(dev, __func__, __LINE__); 3366 1.174 dyoung cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx); 3367 1.139 dyoung pmflock_debug(dev, __func__, __LINE__); 3368 1.139 dyoung } 3369 1.174 dyoung mutex_exit(&dvl->dvl_mtx); 3370 1.124 jmcneill } 3371 1.124 jmcneill 3372 1.304 riastrad void 3373 1.124 jmcneill device_pmf_driver_child_register(device_t dev) 3374 1.124 jmcneill { 3375 1.124 jmcneill device_t parent = device_parent(dev); 3376 1.124 jmcneill 3377 1.124 jmcneill if (parent == NULL || parent->dv_driver_child_register == NULL) 3378 1.304 riastrad return; 3379 1.304 riastrad (*parent->dv_driver_child_register)(dev); 3380 1.124 jmcneill } 3381 1.124 jmcneill 3382 1.124 jmcneill void 3383 1.124 jmcneill device_pmf_driver_set_child_register(device_t dev, 3384 1.304 riastrad void (*child_register)(device_t)) 3385 1.124 jmcneill { 3386 1.124 jmcneill dev->dv_driver_child_register = child_register; 3387 1.124 jmcneill } 3388 1.124 jmcneill 3389 1.139 dyoung static void 3390 1.139 dyoung pmflock_debug(device_t dev, const char *func, int line) 3391 1.139 dyoung { 3392 1.292 riastrad #ifdef PMFLOCK_DEBUG 3393 1.174 dyoung device_lock_t dvl = device_getlock(dev); 3394 1.292 riastrad const char *curlwp_name; 3395 1.292 riastrad 3396 1.292 riastrad if (curlwp->l_name != NULL) 3397 1.292 riastrad curlwp_name = curlwp->l_name; 3398 1.292 riastrad else 3399 1.292 riastrad curlwp_name = curlwp->l_proc->p_comm; 3400 1.139 dyoung 3401 1.243 msaitoh aprint_debug_dev(dev, 3402 1.243 msaitoh "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n", func, line, 3403 1.292 riastrad curlwp_name, dvl->dvl_nlock, dvl->dvl_nwait, dev->dv_flags); 3404 1.292 riastrad #endif /* PMFLOCK_DEBUG */ 3405 1.139 dyoung } 3406 1.139 dyoung 3407 1.139 dyoung static bool 3408 1.183 dyoung device_pmf_lock1(device_t dev) 3409 1.139 dyoung { 3410 1.174 dyoung device_lock_t dvl = device_getlock(dev); 3411 1.139 dyoung 3412 1.155 dyoung while (device_pmf_is_registered(dev) && 3413 1.174 dyoung dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) { 3414 1.174 dyoung dvl->dvl_nwait++; 3415 1.183 dyoung pmflock_debug(dev, __func__, __LINE__); 3416 1.174 dyoung cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx); 3417 1.183 dyoung pmflock_debug(dev, __func__, __LINE__); 3418 1.174 dyoung dvl->dvl_nwait--; 3419 1.139 dyoung } 3420 1.139 dyoung if (!device_pmf_is_registered(dev)) { 3421 1.183 dyoung pmflock_debug(dev, __func__, __LINE__); 3422 1.139 dyoung /* We could not acquire the lock, but some other thread may 3423 1.139 dyoung * wait for it, also. Wake that thread. 3424 1.139 dyoung */ 3425 1.174 dyoung cv_signal(&dvl->dvl_cv); 3426 1.139 dyoung return false; 3427 1.139 dyoung } 3428 1.174 dyoung dvl->dvl_nlock++; 3429 1.174 dyoung dvl->dvl_holder = curlwp; 3430 1.183 dyoung pmflock_debug(dev, __func__, __LINE__); 3431 1.139 dyoung return true; 3432 1.139 dyoung } 3433 1.139 dyoung 3434 1.139 dyoung bool 3435 1.183 dyoung device_pmf_lock(device_t dev) 3436 1.139 dyoung { 3437 1.139 dyoung bool rc; 3438 1.174 dyoung device_lock_t dvl = device_getlock(dev); 3439 1.139 dyoung 3440 1.174 dyoung mutex_enter(&dvl->dvl_mtx); 3441 1.183 dyoung rc = device_pmf_lock1(dev); 3442 1.174 dyoung mutex_exit(&dvl->dvl_mtx); 3443 1.139 dyoung 3444 1.139 dyoung return rc; 3445 1.139 dyoung } 3446 1.139 dyoung 3447 1.139 dyoung void 3448 1.183 dyoung device_pmf_unlock(device_t dev) 3449 1.139 dyoung { 3450 1.174 dyoung device_lock_t dvl = device_getlock(dev); 3451 1.139 dyoung 3452 1.174 dyoung KASSERT(dvl->dvl_nlock > 0); 3453 1.174 dyoung mutex_enter(&dvl->dvl_mtx); 3454 1.174 dyoung if (--dvl->dvl_nlock == 0) 3455 1.174 dyoung dvl->dvl_holder = NULL; 3456 1.174 dyoung cv_signal(&dvl->dvl_cv); 3457 1.183 dyoung pmflock_debug(dev, __func__, __LINE__); 3458 1.174 dyoung mutex_exit(&dvl->dvl_mtx); 3459 1.139 dyoung } 3460 1.139 dyoung 3461 1.174 dyoung device_lock_t 3462 1.174 dyoung device_getlock(device_t dev) 3463 1.139 dyoung { 3464 1.174 dyoung return &dev->dv_lock; 3465 1.139 dyoung } 3466 1.139 dyoung 3467 1.124 jmcneill void * 3468 1.124 jmcneill device_pmf_bus_private(device_t dev) 3469 1.124 jmcneill { 3470 1.124 jmcneill return dev->dv_bus_private; 3471 1.124 jmcneill } 3472 1.124 jmcneill 3473 1.124 jmcneill bool 3474 1.203 dyoung device_pmf_bus_suspend(device_t dev, const pmf_qual_t *qual) 3475 1.124 jmcneill { 3476 1.124 jmcneill if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0) 3477 1.124 jmcneill return true; 3478 1.124 jmcneill if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 || 3479 1.124 jmcneill (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0) 3480 1.124 jmcneill return false; 3481 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS && 3482 1.183 dyoung dev->dv_bus_suspend != NULL && 3483 1.195 dyoung !(*dev->dv_bus_suspend)(dev, qual)) 3484 1.124 jmcneill return false; 3485 1.124 jmcneill 3486 1.124 jmcneill dev->dv_flags |= DVF_BUS_SUSPENDED; 3487 1.124 jmcneill return true; 3488 1.124 jmcneill } 3489 1.124 jmcneill 3490 1.124 jmcneill bool 3491 1.203 dyoung device_pmf_bus_resume(device_t dev, const pmf_qual_t *qual) 3492 1.124 jmcneill { 3493 1.124 jmcneill if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0) 3494 1.124 jmcneill return true; 3495 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS && 3496 1.183 dyoung dev->dv_bus_resume != NULL && 3497 1.195 dyoung !(*dev->dv_bus_resume)(dev, qual)) 3498 1.124 jmcneill return false; 3499 1.124 jmcneill 3500 1.124 jmcneill dev->dv_flags &= ~DVF_BUS_SUSPENDED; 3501 1.124 jmcneill return true; 3502 1.124 jmcneill } 3503 1.124 jmcneill 3504 1.133 drochner bool 3505 1.133 drochner device_pmf_bus_shutdown(device_t dev, int how) 3506 1.133 drochner { 3507 1.133 drochner 3508 1.133 drochner if (*dev->dv_bus_shutdown != NULL && 3509 1.133 drochner !(*dev->dv_bus_shutdown)(dev, how)) 3510 1.133 drochner return false; 3511 1.133 drochner return true; 3512 1.133 drochner } 3513 1.133 drochner 3514 1.124 jmcneill void 3515 1.124 jmcneill device_pmf_bus_register(device_t dev, void *priv, 3516 1.203 dyoung bool (*suspend)(device_t, const pmf_qual_t *), 3517 1.203 dyoung bool (*resume)(device_t, const pmf_qual_t *), 3518 1.133 drochner bool (*shutdown)(device_t, int), void (*deregister)(device_t)) 3519 1.124 jmcneill { 3520 1.124 jmcneill dev->dv_bus_private = priv; 3521 1.124 jmcneill dev->dv_bus_resume = resume; 3522 1.124 jmcneill dev->dv_bus_suspend = suspend; 3523 1.133 drochner dev->dv_bus_shutdown = shutdown; 3524 1.124 jmcneill dev->dv_bus_deregister = deregister; 3525 1.124 jmcneill } 3526 1.124 jmcneill 3527 1.124 jmcneill void 3528 1.124 jmcneill device_pmf_bus_deregister(device_t dev) 3529 1.124 jmcneill { 3530 1.124 jmcneill if (dev->dv_bus_deregister == NULL) 3531 1.124 jmcneill return; 3532 1.124 jmcneill (*dev->dv_bus_deregister)(dev); 3533 1.124 jmcneill dev->dv_bus_private = NULL; 3534 1.124 jmcneill dev->dv_bus_suspend = NULL; 3535 1.124 jmcneill dev->dv_bus_resume = NULL; 3536 1.124 jmcneill dev->dv_bus_deregister = NULL; 3537 1.124 jmcneill } 3538 1.124 jmcneill 3539 1.124 jmcneill void * 3540 1.124 jmcneill device_pmf_class_private(device_t dev) 3541 1.124 jmcneill { 3542 1.124 jmcneill return dev->dv_class_private; 3543 1.124 jmcneill } 3544 1.124 jmcneill 3545 1.124 jmcneill bool 3546 1.203 dyoung device_pmf_class_suspend(device_t dev, const pmf_qual_t *qual) 3547 1.124 jmcneill { 3548 1.124 jmcneill if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0) 3549 1.124 jmcneill return true; 3550 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS && 3551 1.183 dyoung dev->dv_class_suspend != NULL && 3552 1.195 dyoung !(*dev->dv_class_suspend)(dev, qual)) 3553 1.124 jmcneill return false; 3554 1.124 jmcneill 3555 1.124 jmcneill dev->dv_flags |= DVF_CLASS_SUSPENDED; 3556 1.124 jmcneill return true; 3557 1.124 jmcneill } 3558 1.124 jmcneill 3559 1.124 jmcneill bool 3560 1.203 dyoung device_pmf_class_resume(device_t dev, const pmf_qual_t *qual) 3561 1.124 jmcneill { 3562 1.124 jmcneill if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0) 3563 1.124 jmcneill return true; 3564 1.124 jmcneill if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 || 3565 1.124 jmcneill (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0) 3566 1.124 jmcneill return false; 3567 1.195 dyoung if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS && 3568 1.183 dyoung dev->dv_class_resume != NULL && 3569 1.195 dyoung !(*dev->dv_class_resume)(dev, qual)) 3570 1.124 jmcneill return false; 3571 1.124 jmcneill 3572 1.124 jmcneill dev->dv_flags &= ~DVF_CLASS_SUSPENDED; 3573 1.124 jmcneill return true; 3574 1.124 jmcneill } 3575 1.124 jmcneill 3576 1.124 jmcneill void 3577 1.124 jmcneill device_pmf_class_register(device_t dev, void *priv, 3578 1.203 dyoung bool (*suspend)(device_t, const pmf_qual_t *), 3579 1.203 dyoung bool (*resume)(device_t, const pmf_qual_t *), 3580 1.124 jmcneill void (*deregister)(device_t)) 3581 1.124 jmcneill { 3582 1.124 jmcneill dev->dv_class_private = priv; 3583 1.124 jmcneill dev->dv_class_suspend = suspend; 3584 1.124 jmcneill dev->dv_class_resume = resume; 3585 1.124 jmcneill dev->dv_class_deregister = deregister; 3586 1.124 jmcneill } 3587 1.124 jmcneill 3588 1.124 jmcneill void 3589 1.124 jmcneill device_pmf_class_deregister(device_t dev) 3590 1.124 jmcneill { 3591 1.124 jmcneill if (dev->dv_class_deregister == NULL) 3592 1.124 jmcneill return; 3593 1.124 jmcneill (*dev->dv_class_deregister)(dev); 3594 1.124 jmcneill dev->dv_class_private = NULL; 3595 1.124 jmcneill dev->dv_class_suspend = NULL; 3596 1.124 jmcneill dev->dv_class_resume = NULL; 3597 1.124 jmcneill dev->dv_class_deregister = NULL; 3598 1.124 jmcneill } 3599 1.124 jmcneill 3600 1.124 jmcneill bool 3601 1.124 jmcneill device_active(device_t dev, devactive_t type) 3602 1.124 jmcneill { 3603 1.124 jmcneill size_t i; 3604 1.124 jmcneill 3605 1.124 jmcneill if (dev->dv_activity_count == 0) 3606 1.124 jmcneill return false; 3607 1.124 jmcneill 3608 1.160 matt for (i = 0; i < dev->dv_activity_count; ++i) { 3609 1.160 matt if (dev->dv_activity_handlers[i] == NULL) 3610 1.160 matt break; 3611 1.124 jmcneill (*dev->dv_activity_handlers[i])(dev, type); 3612 1.160 matt } 3613 1.124 jmcneill 3614 1.124 jmcneill return true; 3615 1.124 jmcneill } 3616 1.124 jmcneill 3617 1.124 jmcneill bool 3618 1.124 jmcneill device_active_register(device_t dev, void (*handler)(device_t, devactive_t)) 3619 1.124 jmcneill { 3620 1.124 jmcneill void (**new_handlers)(device_t, devactive_t); 3621 1.124 jmcneill void (**old_handlers)(device_t, devactive_t); 3622 1.159 matt size_t i, old_size, new_size; 3623 1.124 jmcneill int s; 3624 1.124 jmcneill 3625 1.124 jmcneill old_handlers = dev->dv_activity_handlers; 3626 1.159 matt old_size = dev->dv_activity_count; 3627 1.124 jmcneill 3628 1.240 mlelstv KASSERT(old_size == 0 || old_handlers != NULL); 3629 1.240 mlelstv 3630 1.159 matt for (i = 0; i < old_size; ++i) { 3631 1.159 matt KASSERT(old_handlers[i] != handler); 3632 1.159 matt if (old_handlers[i] == NULL) { 3633 1.159 matt old_handlers[i] = handler; 3634 1.159 matt return true; 3635 1.159 matt } 3636 1.124 jmcneill } 3637 1.124 jmcneill 3638 1.159 matt new_size = old_size + 4; 3639 1.273 jdolecek new_handlers = kmem_alloc(sizeof(void *) * new_size, KM_SLEEP); 3640 1.124 jmcneill 3641 1.240 mlelstv for (i = 0; i < old_size; ++i) 3642 1.240 mlelstv new_handlers[i] = old_handlers[i]; 3643 1.159 matt new_handlers[old_size] = handler; 3644 1.240 mlelstv for (i = old_size+1; i < new_size; ++i) 3645 1.240 mlelstv new_handlers[i] = NULL; 3646 1.124 jmcneill 3647 1.124 jmcneill s = splhigh(); 3648 1.124 jmcneill dev->dv_activity_count = new_size; 3649 1.124 jmcneill dev->dv_activity_handlers = new_handlers; 3650 1.124 jmcneill splx(s); 3651 1.124 jmcneill 3652 1.240 mlelstv if (old_size > 0) 3653 1.273 jdolecek kmem_free(old_handlers, sizeof(void *) * old_size); 3654 1.124 jmcneill 3655 1.124 jmcneill return true; 3656 1.124 jmcneill } 3657 1.124 jmcneill 3658 1.124 jmcneill void 3659 1.124 jmcneill device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t)) 3660 1.124 jmcneill { 3661 1.124 jmcneill void (**old_handlers)(device_t, devactive_t); 3662 1.159 matt size_t i, old_size; 3663 1.124 jmcneill int s; 3664 1.124 jmcneill 3665 1.124 jmcneill old_handlers = dev->dv_activity_handlers; 3666 1.159 matt old_size = dev->dv_activity_count; 3667 1.124 jmcneill 3668 1.159 matt for (i = 0; i < old_size; ++i) { 3669 1.124 jmcneill if (old_handlers[i] == handler) 3670 1.124 jmcneill break; 3671 1.159 matt if (old_handlers[i] == NULL) 3672 1.159 matt return; /* XXX panic? */ 3673 1.124 jmcneill } 3674 1.124 jmcneill 3675 1.159 matt if (i == old_size) 3676 1.124 jmcneill return; /* XXX panic? */ 3677 1.124 jmcneill 3678 1.159 matt for (; i < old_size - 1; ++i) { 3679 1.159 matt if ((old_handlers[i] = old_handlers[i + 1]) != NULL) 3680 1.159 matt continue; 3681 1.124 jmcneill 3682 1.159 matt if (i == 0) { 3683 1.159 matt s = splhigh(); 3684 1.159 matt dev->dv_activity_count = 0; 3685 1.159 matt dev->dv_activity_handlers = NULL; 3686 1.159 matt splx(s); 3687 1.273 jdolecek kmem_free(old_handlers, sizeof(void *) * old_size); 3688 1.159 matt } 3689 1.159 matt return; 3690 1.124 jmcneill } 3691 1.159 matt old_handlers[i] = NULL; 3692 1.124 jmcneill } 3693 1.136 dyoung 3694 1.187 dyoung /* Return true iff the device_t `dev' exists at generation `gen'. */ 3695 1.187 dyoung static bool 3696 1.187 dyoung device_exists_at(device_t dv, devgen_t gen) 3697 1.187 dyoung { 3698 1.187 dyoung return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) && 3699 1.187 dyoung dv->dv_add_gen <= gen; 3700 1.187 dyoung } 3701 1.187 dyoung 3702 1.187 dyoung static bool 3703 1.187 dyoung deviter_visits(const deviter_t *di, device_t dv) 3704 1.187 dyoung { 3705 1.187 dyoung return device_exists_at(dv, di->di_gen); 3706 1.187 dyoung } 3707 1.187 dyoung 3708 1.136 dyoung /* 3709 1.136 dyoung * Device Iteration 3710 1.136 dyoung * 3711 1.136 dyoung * deviter_t: a device iterator. Holds state for a "walk" visiting 3712 1.136 dyoung * each device_t's in the device tree. 3713 1.136 dyoung * 3714 1.136 dyoung * deviter_init(di, flags): initialize the device iterator `di' 3715 1.136 dyoung * to "walk" the device tree. deviter_next(di) will return 3716 1.136 dyoung * the first device_t in the device tree, or NULL if there are 3717 1.136 dyoung * no devices. 3718 1.136 dyoung * 3719 1.136 dyoung * `flags' is one or more of DEVITER_F_RW, indicating that the 3720 1.136 dyoung * caller intends to modify the device tree by calling 3721 1.136 dyoung * config_detach(9) on devices in the order that the iterator 3722 1.136 dyoung * returns them; DEVITER_F_ROOT_FIRST, asking for the devices 3723 1.136 dyoung * nearest the "root" of the device tree to be returned, first; 3724 1.136 dyoung * DEVITER_F_LEAVES_FIRST, asking for the devices furthest from 3725 1.136 dyoung * the root of the device tree, first; and DEVITER_F_SHUTDOWN, 3726 1.136 dyoung * indicating both that deviter_init() should not respect any 3727 1.136 dyoung * locks on the device tree, and that deviter_next(di) may run 3728 1.136 dyoung * in more than one LWP before the walk has finished. 3729 1.136 dyoung * 3730 1.136 dyoung * Only one DEVITER_F_RW iterator may be in the device tree at 3731 1.136 dyoung * once. 3732 1.136 dyoung * 3733 1.136 dyoung * DEVITER_F_SHUTDOWN implies DEVITER_F_RW. 3734 1.136 dyoung * 3735 1.136 dyoung * Results are undefined if the flags DEVITER_F_ROOT_FIRST and 3736 1.136 dyoung * DEVITER_F_LEAVES_FIRST are used in combination. 3737 1.136 dyoung * 3738 1.136 dyoung * deviter_first(di, flags): initialize the device iterator `di' 3739 1.136 dyoung * and return the first device_t in the device tree, or NULL 3740 1.136 dyoung * if there are no devices. The statement 3741 1.136 dyoung * 3742 1.136 dyoung * dv = deviter_first(di); 3743 1.136 dyoung * 3744 1.136 dyoung * is shorthand for 3745 1.136 dyoung * 3746 1.136 dyoung * deviter_init(di); 3747 1.136 dyoung * dv = deviter_next(di); 3748 1.136 dyoung * 3749 1.136 dyoung * deviter_next(di): return the next device_t in the device tree, 3750 1.136 dyoung * or NULL if there are no more devices. deviter_next(di) 3751 1.136 dyoung * is undefined if `di' was not initialized with deviter_init() or 3752 1.136 dyoung * deviter_first(). 3753 1.136 dyoung * 3754 1.136 dyoung * deviter_release(di): stops iteration (subsequent calls to 3755 1.136 dyoung * deviter_next() will return NULL), releases any locks and 3756 1.136 dyoung * resources held by the device iterator. 3757 1.136 dyoung * 3758 1.136 dyoung * Device iteration does not return device_t's in any particular 3759 1.136 dyoung * order. An iterator will never return the same device_t twice. 3760 1.136 dyoung * Device iteration is guaranteed to complete---i.e., if deviter_next(di) 3761 1.136 dyoung * is called repeatedly on the same `di', it will eventually return 3762 1.136 dyoung * NULL. It is ok to attach/detach devices during device iteration. 3763 1.136 dyoung */ 3764 1.136 dyoung void 3765 1.136 dyoung deviter_init(deviter_t *di, deviter_flags_t flags) 3766 1.136 dyoung { 3767 1.136 dyoung device_t dv; 3768 1.136 dyoung 3769 1.187 dyoung memset(di, 0, sizeof(*di)); 3770 1.187 dyoung 3771 1.187 dyoung if ((flags & DEVITER_F_SHUTDOWN) != 0) 3772 1.136 dyoung flags |= DEVITER_F_RW; 3773 1.187 dyoung 3774 1.257 mlelstv mutex_enter(&alldevs_lock); 3775 1.187 dyoung if ((flags & DEVITER_F_RW) != 0) 3776 1.257 mlelstv alldevs_nwrite++; 3777 1.187 dyoung else 3778 1.257 mlelstv alldevs_nread++; 3779 1.257 mlelstv di->di_gen = alldevs_gen++; 3780 1.136 dyoung di->di_flags = flags; 3781 1.136 dyoung 3782 1.136 dyoung switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) { 3783 1.136 dyoung case DEVITER_F_LEAVES_FIRST: 3784 1.257 mlelstv TAILQ_FOREACH(dv, &alldevs, dv_list) { 3785 1.187 dyoung if (!deviter_visits(di, dv)) 3786 1.187 dyoung continue; 3787 1.136 dyoung di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth); 3788 1.187 dyoung } 3789 1.136 dyoung break; 3790 1.136 dyoung case DEVITER_F_ROOT_FIRST: 3791 1.257 mlelstv TAILQ_FOREACH(dv, &alldevs, dv_list) { 3792 1.187 dyoung if (!deviter_visits(di, dv)) 3793 1.187 dyoung continue; 3794 1.136 dyoung di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth); 3795 1.187 dyoung } 3796 1.136 dyoung break; 3797 1.136 dyoung default: 3798 1.136 dyoung break; 3799 1.136 dyoung } 3800 1.136 dyoung 3801 1.136 dyoung deviter_reinit(di); 3802 1.257 mlelstv mutex_exit(&alldevs_lock); 3803 1.136 dyoung } 3804 1.136 dyoung 3805 1.136 dyoung static void 3806 1.136 dyoung deviter_reinit(deviter_t *di) 3807 1.136 dyoung { 3808 1.248 riastrad 3809 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 3810 1.136 dyoung if ((di->di_flags & DEVITER_F_RW) != 0) 3811 1.257 mlelstv di->di_prev = TAILQ_LAST(&alldevs, devicelist); 3812 1.136 dyoung else 3813 1.257 mlelstv di->di_prev = TAILQ_FIRST(&alldevs); 3814 1.136 dyoung } 3815 1.136 dyoung 3816 1.136 dyoung device_t 3817 1.136 dyoung deviter_first(deviter_t *di, deviter_flags_t flags) 3818 1.136 dyoung { 3819 1.248 riastrad 3820 1.136 dyoung deviter_init(di, flags); 3821 1.136 dyoung return deviter_next(di); 3822 1.136 dyoung } 3823 1.136 dyoung 3824 1.136 dyoung static device_t 3825 1.187 dyoung deviter_next2(deviter_t *di) 3826 1.136 dyoung { 3827 1.136 dyoung device_t dv; 3828 1.136 dyoung 3829 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 3830 1.248 riastrad 3831 1.136 dyoung dv = di->di_prev; 3832 1.136 dyoung 3833 1.136 dyoung if (dv == NULL) 3834 1.191 dyoung return NULL; 3835 1.191 dyoung 3836 1.191 dyoung if ((di->di_flags & DEVITER_F_RW) != 0) 3837 1.136 dyoung di->di_prev = TAILQ_PREV(dv, devicelist, dv_list); 3838 1.136 dyoung else 3839 1.136 dyoung di->di_prev = TAILQ_NEXT(dv, dv_list); 3840 1.136 dyoung 3841 1.136 dyoung return dv; 3842 1.136 dyoung } 3843 1.136 dyoung 3844 1.187 dyoung static device_t 3845 1.187 dyoung deviter_next1(deviter_t *di) 3846 1.187 dyoung { 3847 1.187 dyoung device_t dv; 3848 1.187 dyoung 3849 1.257 mlelstv KASSERT(mutex_owned(&alldevs_lock)); 3850 1.248 riastrad 3851 1.187 dyoung do { 3852 1.187 dyoung dv = deviter_next2(di); 3853 1.187 dyoung } while (dv != NULL && !deviter_visits(di, dv)); 3854 1.187 dyoung 3855 1.187 dyoung return dv; 3856 1.187 dyoung } 3857 1.187 dyoung 3858 1.136 dyoung device_t 3859 1.136 dyoung deviter_next(deviter_t *di) 3860 1.136 dyoung { 3861 1.136 dyoung device_t dv = NULL; 3862 1.136 dyoung 3863 1.257 mlelstv mutex_enter(&alldevs_lock); 3864 1.136 dyoung switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) { 3865 1.136 dyoung case 0: 3866 1.248 riastrad dv = deviter_next1(di); 3867 1.248 riastrad break; 3868 1.136 dyoung case DEVITER_F_LEAVES_FIRST: 3869 1.136 dyoung while (di->di_curdepth >= 0) { 3870 1.136 dyoung if ((dv = deviter_next1(di)) == NULL) { 3871 1.136 dyoung di->di_curdepth--; 3872 1.136 dyoung deviter_reinit(di); 3873 1.136 dyoung } else if (dv->dv_depth == di->di_curdepth) 3874 1.136 dyoung break; 3875 1.136 dyoung } 3876 1.248 riastrad break; 3877 1.136 dyoung case DEVITER_F_ROOT_FIRST: 3878 1.136 dyoung while (di->di_curdepth <= di->di_maxdepth) { 3879 1.136 dyoung if ((dv = deviter_next1(di)) == NULL) { 3880 1.136 dyoung di->di_curdepth++; 3881 1.136 dyoung deviter_reinit(di); 3882 1.136 dyoung } else if (dv->dv_depth == di->di_curdepth) 3883 1.136 dyoung break; 3884 1.136 dyoung } 3885 1.248 riastrad break; 3886 1.136 dyoung default: 3887 1.248 riastrad break; 3888 1.136 dyoung } 3889 1.257 mlelstv mutex_exit(&alldevs_lock); 3890 1.248 riastrad 3891 1.248 riastrad return dv; 3892 1.136 dyoung } 3893 1.136 dyoung 3894 1.136 dyoung void 3895 1.136 dyoung deviter_release(deviter_t *di) 3896 1.136 dyoung { 3897 1.136 dyoung bool rw = (di->di_flags & DEVITER_F_RW) != 0; 3898 1.136 dyoung 3899 1.257 mlelstv mutex_enter(&alldevs_lock); 3900 1.187 dyoung if (rw) 3901 1.257 mlelstv --alldevs_nwrite; 3902 1.187 dyoung else 3903 1.257 mlelstv --alldevs_nread; 3904 1.187 dyoung /* XXX wake a garbage-collection thread */ 3905 1.257 mlelstv mutex_exit(&alldevs_lock); 3906 1.136 dyoung } 3907 1.174 dyoung 3908 1.201 dyoung const char * 3909 1.201 dyoung cfdata_ifattr(const struct cfdata *cf) 3910 1.201 dyoung { 3911 1.201 dyoung return cf->cf_pspec->cfp_iattr; 3912 1.201 dyoung } 3913 1.201 dyoung 3914 1.193 dyoung bool 3915 1.193 dyoung ifattr_match(const char *snull, const char *t) 3916 1.193 dyoung { 3917 1.193 dyoung return (snull == NULL) || strcmp(snull, t) == 0; 3918 1.193 dyoung } 3919 1.193 dyoung 3920 1.192 dyoung void 3921 1.192 dyoung null_childdetached(device_t self, device_t child) 3922 1.192 dyoung { 3923 1.192 dyoung /* do nothing */ 3924 1.192 dyoung } 3925 1.192 dyoung 3926 1.182 pooka static void 3927 1.182 pooka sysctl_detach_setup(struct sysctllog **clog) 3928 1.174 dyoung { 3929 1.174 dyoung 3930 1.230 pooka sysctl_createv(clog, 0, NULL, NULL, 3931 1.174 dyoung CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 3932 1.205 jruoho CTLTYPE_BOOL, "detachall", 3933 1.174 dyoung SYSCTL_DESCR("Detach all devices at shutdown"), 3934 1.174 dyoung NULL, 0, &detachall, 0, 3935 1.230 pooka CTL_KERN, CTL_CREATE, CTL_EOL); 3936 1.174 dyoung } 3937