1139804Simp/*- 21541Srgrimes * Copyright (c) 1992, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This software was developed by the Computer Systems Engineering group 61541Srgrimes * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 71541Srgrimes * contributed to Berkeley. 81541Srgrimes * 91541Srgrimes * Redistribution and use in source and binary forms, with or without 101541Srgrimes * modification, are permitted provided that the following conditions 111541Srgrimes * are met: 121541Srgrimes * 1. Redistributions of source code must retain the above copyright 131541Srgrimes * notice, this list of conditions and the following disclaimer. 141541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer in the 161541Srgrimes * documentation and/or other materials provided with the distribution. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)subr_autoconf.c 8.1 (Berkeley) 6/10/93 341541Srgrimes * 351541Srgrimes */ 361541Srgrimes 37116182Sobrien#include <sys/cdefs.h> 38116182Sobrien__FBSDID("$FreeBSD$"); 39116182Sobrien 40180610Srwatson#include "opt_ddb.h" 41180610Srwatson 421541Srgrimes#include <sys/param.h> 4329680Sgibbs#include <sys/kernel.h> 44180616Srwatson#include <sys/linker.h> 45160509Sjhb#include <sys/lock.h> 46160509Sjhb#include <sys/mutex.h> 4729680Sgibbs#include <sys/systm.h> 481541Srgrimes 491541Srgrimes/* 501541Srgrimes * Autoconfiguration subroutines. 511541Srgrimes */ 521541Srgrimes 531541Srgrimes/* 5429680Sgibbs * "Interrupt driven config" functions. 5529680Sgibbs */ 5660938Sjakestatic TAILQ_HEAD(, intr_config_hook) intr_config_hook_list = 5729680Sgibbs TAILQ_HEAD_INITIALIZER(intr_config_hook_list); 58211236Sgibbsstatic struct intr_config_hook *next_to_notify; 59160509Sjhbstatic struct mtx intr_config_hook_lock; 60160509SjhbMTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF); 6129680Sgibbs 6229680Sgibbs/* ARGSUSED */ 63211236Sgibbsstatic void run_interrupt_driven_config_hooks(void); 64160509Sjhb 65180616Srwatson/* 66180616Srwatson * If we wait too long for an interrupt-driven config hook to return, print 67180616Srwatson * a diagnostic. 68180616Srwatson */ 69180616Srwatson#define WARNING_INTERVAL_SECS 60 7029680Sgibbsstatic void 71180616Srwatsonrun_interrupt_driven_config_hooks_warning(int warned) 72180616Srwatson{ 73180616Srwatson struct intr_config_hook *hook_entry; 74180616Srwatson char namebuf[64]; 75180616Srwatson long offset; 76180616Srwatson 77180673Srwatson if (warned < 6) { 78180673Srwatson printf("run_interrupt_driven_hooks: still waiting after %d " 79180673Srwatson "seconds for", warned * WARNING_INTERVAL_SECS); 80180673Srwatson TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) { 81180673Srwatson if (linker_search_symbol_name( 82180673Srwatson (caddr_t)hook_entry->ich_func, namebuf, 83180673Srwatson sizeof(namebuf), &offset) == 0) 84180673Srwatson printf(" %s", namebuf); 85180673Srwatson else 86180673Srwatson printf(" %p", hook_entry->ich_func); 87180673Srwatson } 88180673Srwatson printf("\n"); 89180616Srwatson } 90180673Srwatson KASSERT(warned < 6, 91180673Srwatson ("run_interrupt_driven_config_hooks: waited too long")); 92180616Srwatson} 93180616Srwatson 94180616Srwatsonstatic void 95211236Sgibbsrun_interrupt_driven_config_hooks() 9629680Sgibbs{ 97211236Sgibbs static int running; 98211236Sgibbs struct intr_config_hook *hook_entry; 9929680Sgibbs 100160509Sjhb mtx_lock(&intr_config_hook_lock); 101211236Sgibbs 102211236Sgibbs /* 103211236Sgibbs * If hook processing is already active, any newly 104211236Sgibbs * registered hooks will eventually be notified. 105211236Sgibbs * Let the currently running session issue these 106211236Sgibbs * notifications. 107211236Sgibbs */ 108211236Sgibbs if (running != 0) { 109160509Sjhb mtx_unlock(&intr_config_hook_lock); 110211236Sgibbs return; 111211236Sgibbs } 112211236Sgibbs running = 1; 113211236Sgibbs 114211236Sgibbs while (next_to_notify != NULL) { 115211236Sgibbs hook_entry = next_to_notify; 116211236Sgibbs next_to_notify = TAILQ_NEXT(hook_entry, ich_links); 117211236Sgibbs mtx_unlock(&intr_config_hook_lock); 11851684Sn_hibma (*hook_entry->ich_func)(hook_entry->ich_arg); 119160509Sjhb mtx_lock(&intr_config_hook_lock); 12029680Sgibbs } 12129680Sgibbs 122211236Sgibbs running = 0; 123211236Sgibbs mtx_unlock(&intr_config_hook_lock); 124211236Sgibbs} 125211236Sgibbs 126211236Sgibbsstatic void 127211236Sgibbsboot_run_interrupt_driven_config_hooks(void *dummy) 128211236Sgibbs{ 129211236Sgibbs int warned; 130211236Sgibbs 131211236Sgibbs run_interrupt_driven_config_hooks(); 132211236Sgibbs 133211236Sgibbs /* Block boot processing until all hooks are disestablished. */ 134211236Sgibbs mtx_lock(&intr_config_hook_lock); 135180616Srwatson warned = 0; 13651684Sn_hibma while (!TAILQ_EMPTY(&intr_config_hook_list)) { 137180616Srwatson if (msleep(&intr_config_hook_list, &intr_config_hook_lock, 138217075Sjhb 0, "conifhk", WARNING_INTERVAL_SECS * hz) == 139180673Srwatson EWOULDBLOCK) { 140180616Srwatson mtx_unlock(&intr_config_hook_lock); 141180616Srwatson warned++; 142180616Srwatson run_interrupt_driven_config_hooks_warning(warned); 143180616Srwatson mtx_lock(&intr_config_hook_lock); 144180616Srwatson } 14529680Sgibbs } 146160509Sjhb mtx_unlock(&intr_config_hook_lock); 14729680Sgibbs} 148211236Sgibbs 14929680SgibbsSYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, 150211236Sgibbs boot_run_interrupt_driven_config_hooks, NULL); 15129680Sgibbs 15229680Sgibbs/* 15329680Sgibbs * Register a hook that will be called after "cold" 15429680Sgibbs * autoconfiguration is complete and interrupts can 15529680Sgibbs * be used to complete initialization. 15629680Sgibbs */ 15729680Sgibbsint 158188059Simpconfig_intrhook_establish(struct intr_config_hook *hook) 15929680Sgibbs{ 16029680Sgibbs struct intr_config_hook *hook_entry; 16129680Sgibbs 162160509Sjhb mtx_lock(&intr_config_hook_lock); 163160509Sjhb TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) 16429680Sgibbs if (hook_entry == hook) 16529680Sgibbs break; 16629680Sgibbs if (hook_entry != NULL) { 167160509Sjhb mtx_unlock(&intr_config_hook_lock); 16829680Sgibbs printf("config_intrhook_establish: establishing an " 16929680Sgibbs "already established hook.\n"); 17029680Sgibbs return (1); 17129680Sgibbs } 17229680Sgibbs TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links); 173211236Sgibbs if (next_to_notify == NULL) 174211236Sgibbs next_to_notify = hook; 175160509Sjhb mtx_unlock(&intr_config_hook_lock); 17629680Sgibbs if (cold == 0) 177211236Sgibbs /* 178211236Sgibbs * XXX Call from a task since not all drivers expect 179211236Sgibbs * to be re-entered at the time a hook is established. 180211236Sgibbs */ 18145739Speter /* XXX Sufficient for modules loaded after initial config??? */ 182211236Sgibbs run_interrupt_driven_config_hooks(); 18329680Sgibbs return (0); 18429680Sgibbs} 18529680Sgibbs 18629680Sgibbsvoid 187188059Simpconfig_intrhook_disestablish(struct intr_config_hook *hook) 18829680Sgibbs{ 18929680Sgibbs struct intr_config_hook *hook_entry; 19029680Sgibbs 191160509Sjhb mtx_lock(&intr_config_hook_lock); 192160509Sjhb TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) 19329680Sgibbs if (hook_entry == hook) 19429680Sgibbs break; 19529680Sgibbs if (hook_entry == NULL) 19629680Sgibbs panic("config_intrhook_disestablish: disestablishing an " 19729680Sgibbs "unestablished hook"); 19829680Sgibbs 199211236Sgibbs if (next_to_notify == hook) 200211236Sgibbs next_to_notify = TAILQ_NEXT(hook, ich_links); 20129680Sgibbs TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links); 202160509Sjhb 20329680Sgibbs /* Wakeup anyone watching the list */ 20429680Sgibbs wakeup(&intr_config_hook_list); 205160509Sjhb mtx_unlock(&intr_config_hook_lock); 20629680Sgibbs} 207180610Srwatson 208180610Srwatson#ifdef DDB 209180610Srwatson#include <ddb/ddb.h> 210180610Srwatson 211180610SrwatsonDB_SHOW_COMMAND(conifhk, db_show_conifhk) 212180610Srwatson{ 213180610Srwatson struct intr_config_hook *hook_entry; 214180610Srwatson char namebuf[64]; 215180610Srwatson long offset; 216180610Srwatson 217180610Srwatson TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) { 218180610Srwatson if (linker_ddb_search_symbol_name( 219180610Srwatson (caddr_t)hook_entry->ich_func, namebuf, sizeof(namebuf), 220180610Srwatson &offset) == 0) { 221180610Srwatson db_printf("hook: %p at %s+%#lx arg: %p\n", 222180610Srwatson hook_entry->ich_func, namebuf, offset, 223180610Srwatson hook_entry->ich_arg); 224180610Srwatson } else { 225180610Srwatson db_printf("hook: %p at ??+?? arg %p\n", 226180610Srwatson hook_entry->ich_func, hook_entry->ich_arg); 227180610Srwatson } 228180610Srwatson } 229180610Srwatson} 230180610Srwatson#endif /* DDB */ 231