1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratories. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)subr_autoconf.c 8.1 (Berkeley) 6/10/93 39 * 40 * $FreeBSD: src/sys/kern/subr_autoconf.c,v 1.14 1999/10/05 21:19:41 n_hibma Exp $ 41 * $DragonFly: src/sys/kern/subr_autoconf.c,v 1.9 2007/07/28 23:24:33 dillon Exp $ 42 */ 43 44 #include <sys/param.h> 45 #include <sys/kernel.h> 46 #include <sys/systm.h> 47 #include <sys/thread.h> 48 #include <sys/thread2.h> 49 50 /* 51 * Autoconfiguration subroutines. 52 */ 53 54 /* 55 * "Interrupt driven config" functions. 56 */ 57 static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list = 58 TAILQ_HEAD_INITIALIZER(intr_config_hook_list); 59 60 61 /* ARGSUSED */ 62 static void run_interrupt_driven_config_hooks (void *dummy); 63 static int ran_config_hooks; 64 65 static void 66 run_interrupt_driven_config_hooks(void *dummy) 67 { 68 struct intr_config_hook *hook_entry; 69 int waiting; 70 71 waiting = 0; 72 73 ran_config_hooks = 1; 74 while (!TAILQ_EMPTY(&intr_config_hook_list)) { 75 TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) { 76 if (hook_entry->ich_ran == 0) { 77 hook_entry->ich_ran = 1; 78 (*hook_entry->ich_func)(hook_entry->ich_arg); 79 break; 80 } 81 } 82 if (hook_entry) 83 continue; 84 if (TAILQ_EMPTY(&intr_config_hook_list)) 85 break; 86 87 if (waiting >= 20 && (waiting % 10) == 0) { 88 crit_enter(); 89 kprintf("**WARNING** waiting for the following device " 90 "to finish configuring:\n"); 91 TAILQ_FOREACH(hook_entry, &intr_config_hook_list, 92 ich_links) { 93 kprintf(" %s:\tfunc=%p arg=%p\n", 94 (hook_entry->ich_desc ? 95 hook_entry->ich_desc : "?"), 96 hook_entry->ich_func, 97 hook_entry->ich_arg); 98 } 99 crit_exit(); 100 if (waiting >= 60) { 101 kprintf("Giving up, interrupt routing is " 102 "probably hosed\n"); 103 break; 104 } 105 } 106 tsleep(&intr_config_hook_list, 0, "conifhk", hz); 107 ++waiting; 108 } 109 } 110 SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, 111 run_interrupt_driven_config_hooks, NULL) 112 113 /* 114 * Register a hook that will be called after "cold" 115 * autoconfiguration is complete and interrupts can 116 * be used to complete initialization. 117 */ 118 int 119 config_intrhook_establish(struct intr_config_hook *hook) 120 { 121 struct intr_config_hook *hook_entry; 122 123 for (hook_entry = TAILQ_FIRST(&intr_config_hook_list); 124 hook_entry != NULL; 125 hook_entry = TAILQ_NEXT(hook_entry, ich_links)) { 126 if (hook_entry == hook) 127 break; 128 if (hook_entry->ich_order > hook->ich_order) 129 break; 130 } 131 if (hook_entry == hook) { 132 kprintf("config_intrhook_establish: establishing an " 133 "already established hook.\n"); 134 return (1); 135 } 136 hook->ich_ran = 0; 137 if (hook_entry) 138 TAILQ_INSERT_BEFORE(hook_entry, hook, ich_links); 139 else 140 TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links); 141 142 /* 143 * Late hook, run immediately. 144 */ 145 if (ran_config_hooks) 146 run_interrupt_driven_config_hooks(NULL); 147 return (0); 148 } 149 150 void 151 config_intrhook_disestablish(struct intr_config_hook *hook) 152 { 153 struct intr_config_hook *hook_entry; 154 155 for (hook_entry = TAILQ_FIRST(&intr_config_hook_list); 156 hook_entry != NULL; 157 hook_entry = TAILQ_NEXT(hook_entry, ich_links)) 158 if (hook_entry == hook) 159 break; 160 if (hook_entry == NULL) 161 panic("config_intrhook_disestablish: disestablishing an " 162 "unestablished hook"); 163 164 TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links); 165 /* Wakeup anyone watching the list */ 166 wakeup(&intr_config_hook_list); 167 } 168