The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_autoconf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)subr_autoconf.c     8.1 (Berkeley) 6/10/93
   34  *
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/11.2/sys/kern/subr_autoconf.c 331722 2018-03-29 02:50:57Z eadler $");
   39 
   40 #include "opt_ddb.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/kernel.h>
   44 #include <sys/linker.h>
   45 #include <sys/lock.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mutex.h>
   48 #include <sys/systm.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 static struct intr_config_hook *next_to_notify;
   60 static struct mtx intr_config_hook_lock;
   61 MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF);
   62 
   63 /* ARGSUSED */
   64 static void run_interrupt_driven_config_hooks(void);
   65 
   66 /*
   67  * Private data and a shim function for implementing config_interhook_oneshot().
   68  */
   69 struct oneshot_config_hook {
   70         struct intr_config_hook 
   71                         och_hook;               /* Must be first */
   72         ich_func_t      och_func;
   73         void            *och_arg;
   74 };
   75 
   76 static void
   77 config_intrhook_oneshot_func(void *arg)
   78 {
   79         struct oneshot_config_hook *ohook;
   80 
   81         ohook = arg;
   82         ohook->och_func(ohook->och_arg);
   83         config_intrhook_disestablish(&ohook->och_hook);
   84         free(ohook, M_DEVBUF);
   85 }
   86 
   87 /*
   88  * If we wait too long for an interrupt-driven config hook to return, print
   89  * a diagnostic.
   90  */
   91 #define WARNING_INTERVAL_SECS   60
   92 static void
   93 run_interrupt_driven_config_hooks_warning(int warned)
   94 {
   95         struct intr_config_hook *hook_entry;
   96         char namebuf[64];
   97         long offset;
   98 
   99         if (warned < 6) {
  100                 printf("run_interrupt_driven_hooks: still waiting after %d "
  101                     "seconds for", warned * WARNING_INTERVAL_SECS);
  102                 TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
  103                         if (linker_search_symbol_name(
  104                             (caddr_t)hook_entry->ich_func, namebuf,
  105                             sizeof(namebuf), &offset) == 0)
  106                                 printf(" %s", namebuf);
  107                         else
  108                                 printf(" %p", hook_entry->ich_func);
  109                 }
  110                 printf("\n");
  111         }
  112         KASSERT(warned < 6,
  113             ("run_interrupt_driven_config_hooks: waited too long"));
  114 }
  115 
  116 static void
  117 run_interrupt_driven_config_hooks()
  118 {
  119         static int running;
  120         struct intr_config_hook *hook_entry;
  121 
  122         mtx_lock(&intr_config_hook_lock);
  123 
  124         /*
  125          * If hook processing is already active, any newly
  126          * registered hooks will eventually be notified.
  127          * Let the currently running session issue these
  128          * notifications.
  129          */
  130         if (running != 0) {
  131                 mtx_unlock(&intr_config_hook_lock);
  132                 return;
  133         }
  134         running = 1;
  135 
  136         while (next_to_notify != NULL) {
  137                 hook_entry = next_to_notify;
  138                 next_to_notify = TAILQ_NEXT(hook_entry, ich_links);
  139                 mtx_unlock(&intr_config_hook_lock);
  140                 (*hook_entry->ich_func)(hook_entry->ich_arg);
  141                 mtx_lock(&intr_config_hook_lock);
  142         }
  143 
  144         running = 0;
  145         mtx_unlock(&intr_config_hook_lock);
  146 }
  147 
  148 static void
  149 boot_run_interrupt_driven_config_hooks(void *dummy)
  150 {
  151         int warned;
  152 
  153         run_interrupt_driven_config_hooks();
  154 
  155         /* Block boot processing until all hooks are disestablished. */
  156         mtx_lock(&intr_config_hook_lock);
  157         warned = 0;
  158         while (!TAILQ_EMPTY(&intr_config_hook_list)) {
  159                 if (msleep(&intr_config_hook_list, &intr_config_hook_lock,
  160                     0, "conifhk", WARNING_INTERVAL_SECS * hz) ==
  161                     EWOULDBLOCK) {
  162                         mtx_unlock(&intr_config_hook_lock);
  163                         warned++;
  164                         run_interrupt_driven_config_hooks_warning(warned);
  165                         mtx_lock(&intr_config_hook_lock);
  166                 }
  167         }
  168         mtx_unlock(&intr_config_hook_lock);
  169 }
  170 
  171 SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
  172         boot_run_interrupt_driven_config_hooks, NULL);
  173 
  174 /*
  175  * Register a hook that will be called after "cold"
  176  * autoconfiguration is complete and interrupts can
  177  * be used to complete initialization.
  178  */
  179 int
  180 config_intrhook_establish(struct intr_config_hook *hook)
  181 {
  182         struct intr_config_hook *hook_entry;
  183 
  184         mtx_lock(&intr_config_hook_lock);
  185         TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
  186                 if (hook_entry == hook)
  187                         break;
  188         if (hook_entry != NULL) {
  189                 mtx_unlock(&intr_config_hook_lock);
  190                 printf("config_intrhook_establish: establishing an "
  191                        "already established hook.\n");
  192                 return (1);
  193         }
  194         TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links);
  195         if (next_to_notify == NULL)
  196                 next_to_notify = hook;
  197         mtx_unlock(&intr_config_hook_lock);
  198         if (cold == 0)
  199                 /*
  200                  * XXX Call from a task since not all drivers expect
  201                  *     to be re-entered at the time a hook is established.
  202                  */
  203                 /* XXX Sufficient for modules loaded after initial config??? */
  204                 run_interrupt_driven_config_hooks();    
  205         return (0);
  206 }
  207 
  208 /*
  209  * Register a hook function that is automatically unregistered after it runs.
  210  */
  211 void
  212 config_intrhook_oneshot(ich_func_t func, void *arg)
  213 {
  214         struct oneshot_config_hook *ohook;
  215 
  216         ohook = malloc(sizeof(*ohook), M_DEVBUF, M_WAITOK);
  217         ohook->och_func = func;
  218         ohook->och_arg  = arg;
  219         ohook->och_hook.ich_func = config_intrhook_oneshot_func;
  220         ohook->och_hook.ich_arg  = ohook;
  221         config_intrhook_establish(&ohook->och_hook);
  222 }
  223 
  224 void
  225 config_intrhook_disestablish(struct intr_config_hook *hook)
  226 {
  227         struct intr_config_hook *hook_entry;
  228 
  229         mtx_lock(&intr_config_hook_lock);
  230         TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
  231                 if (hook_entry == hook)
  232                         break;
  233         if (hook_entry == NULL)
  234                 panic("config_intrhook_disestablish: disestablishing an "
  235                       "unestablished hook");
  236 
  237         if (next_to_notify == hook)
  238                 next_to_notify = TAILQ_NEXT(hook, ich_links);
  239         TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
  240 
  241         /* Wakeup anyone watching the list */
  242         wakeup(&intr_config_hook_list);
  243         mtx_unlock(&intr_config_hook_lock);
  244 }
  245 
  246 #ifdef DDB
  247 #include <ddb/ddb.h>
  248 
  249 DB_SHOW_COMMAND(conifhk, db_show_conifhk)
  250 {
  251         struct intr_config_hook *hook_entry;
  252         char namebuf[64];
  253         long offset;
  254 
  255         TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
  256                 if (linker_ddb_search_symbol_name(
  257                     (caddr_t)hook_entry->ich_func, namebuf, sizeof(namebuf),
  258                     &offset) == 0) {
  259                         db_printf("hook: %p at %s+%#lx arg: %p\n",
  260                             hook_entry->ich_func, namebuf, offset,
  261                             hook_entry->ich_arg);
  262                 } else {
  263                         db_printf("hook: %p at ??+?? arg %p\n",
  264                             hook_entry->ich_func, hook_entry->ich_arg);
  265                 }
  266         }
  267 }
  268 #endif /* DDB */

Cache object: c1551f7a6e6af8a0b68577a116604321


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.