Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/subr_autoconf.c
Show All 39 Lines | |||||
#include "opt_ddb.h" | #include "opt_ddb.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/sysctl.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
/* | /* | ||||
* Autoconfiguration subroutines. | * Autoconfiguration subroutines. | ||||
*/ | */ | ||||
/* | /* | ||||
* "Interrupt driven config" functions. | * "Interrupt driven config" functions. | ||||
*/ | */ | ||||
static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list = | static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list = | ||||
TAILQ_HEAD_INITIALIZER(intr_config_hook_list); | TAILQ_HEAD_INITIALIZER(intr_config_hook_list); | ||||
static struct intr_config_hook *next_to_notify; | static struct intr_config_hook *next_to_notify; | ||||
static struct mtx intr_config_hook_lock; | static struct mtx intr_config_hook_lock; | ||||
MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF); | MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF); | ||||
SYSCTL_NODE(_kern, OID_AUTO, autoconf, CTLFLAG_RW, 0, ""); | |||||
#define WARNING_INTERVAL_SECS 60 | |||||
static int intrhook_interval_secs = WARNING_INTERVAL_SECS; | |||||
SYSCTL_INT(_kern_autoconf, OID_AUTO, intrhook_seconds, CTLFLAG_RDTUN, | |||||
&intrhook_interval_secs, 0, "Intrhook loop timeout in seconds"); | |||||
#define WARNING_INTERVAL_LOOPS 5 | |||||
static int intrhook_interval_loops = WARNING_INTERVAL_LOOPS; | |||||
SYSCTL_INT(_kern_autoconf, OID_AUTO, intrhook_loops, CTLFLAG_RDTUN, | |||||
&intrhook_interval_loops, 0, "Intrhook loop count"); | |||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
static void run_interrupt_driven_config_hooks(void); | static void run_interrupt_driven_config_hooks(void); | ||||
/* | /* | ||||
* Private data and a shim function for implementing config_interhook_oneshot(). | * Private data and a shim function for implementing config_interhook_oneshot(). | ||||
*/ | */ | ||||
struct oneshot_config_hook { | struct oneshot_config_hook { | ||||
struct intr_config_hook | struct intr_config_hook | ||||
Show All 12 Lines | config_intrhook_oneshot_func(void *arg) | ||||
config_intrhook_disestablish(&ohook->och_hook); | config_intrhook_disestablish(&ohook->och_hook); | ||||
free(ohook, M_DEVBUF); | free(ohook, M_DEVBUF); | ||||
} | } | ||||
/* | /* | ||||
* If we wait too long for an interrupt-driven config hook to return, print | * If we wait too long for an interrupt-driven config hook to return, print | ||||
* a diagnostic. | * a diagnostic. | ||||
*/ | */ | ||||
#define WARNING_INTERVAL_SECS 60 | |||||
static void | static void | ||||
run_interrupt_driven_config_hooks_warning(int warned) | run_interrupt_driven_config_hooks_warning(int warned) | ||||
{ | { | ||||
struct intr_config_hook *hook_entry; | struct intr_config_hook *hook_entry; | ||||
char namebuf[64]; | char namebuf[64]; | ||||
long offset; | long offset; | ||||
if (warned < 6) { | if (warned < intrhook_interval_loops) { | ||||
printf("run_interrupt_driven_hooks: still waiting after %d " | printf("run_interrupt_driven_hooks: still waiting after %d " | ||||
"seconds for", warned * WARNING_INTERVAL_SECS); | "seconds for", warned * intrhook_interval_secs); | ||||
TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) { | TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) { | ||||
if (linker_search_symbol_name( | if (linker_search_symbol_name( | ||||
(caddr_t)hook_entry->ich_func, namebuf, | (caddr_t)hook_entry->ich_func, namebuf, | ||||
sizeof(namebuf), &offset) == 0) | sizeof(namebuf), &offset) == 0) | ||||
printf(" %s", namebuf); | printf(" %s", namebuf); | ||||
else | else | ||||
printf(" %p", hook_entry->ich_func); | printf(" %p", hook_entry->ich_func); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
KASSERT(warned < 6, | |||||
KASSERT(warned < intrhook_interval_loops, | |||||
("run_interrupt_driven_config_hooks: waited too long")); | ("run_interrupt_driven_config_hooks: waited too long")); | ||||
} | } | ||||
static void | static void | ||||
run_interrupt_driven_config_hooks() | run_interrupt_driven_config_hooks() | ||||
{ | { | ||||
static int running; | static int running; | ||||
struct intr_config_hook *hook_entry; | struct intr_config_hook *hook_entry; | ||||
Show All 30 Lines | boot_run_interrupt_driven_config_hooks(void *dummy) | ||||
int warned; | int warned; | ||||
run_interrupt_driven_config_hooks(); | run_interrupt_driven_config_hooks(); | ||||
/* Block boot processing until all hooks are disestablished. */ | /* Block boot processing until all hooks are disestablished. */ | ||||
mtx_lock(&intr_config_hook_lock); | mtx_lock(&intr_config_hook_lock); | ||||
warned = 0; | warned = 0; | ||||
while (!TAILQ_EMPTY(&intr_config_hook_list)) { | while (!TAILQ_EMPTY(&intr_config_hook_list)) { | ||||
if (warned >= intrhook_interval_loops) { | |||||
/* | |||||
* Allow the system to break out early rather than risk | |||||
* never making progress. | |||||
*/ | |||||
if (warned == 0) | |||||
run_interrupt_driven_config_hooks_warning(warned); | |||||
printf("Continuing with boot\n"); | |||||
break; | |||||
} | |||||
if (msleep(&intr_config_hook_list, &intr_config_hook_lock, | if (msleep(&intr_config_hook_list, &intr_config_hook_lock, | ||||
0, "conifhk", WARNING_INTERVAL_SECS * hz) == | 0, "conifhk", intrhook_interval_secs * hz) == | ||||
EWOULDBLOCK) { | EWOULDBLOCK) { | ||||
mtx_unlock(&intr_config_hook_lock); | mtx_unlock(&intr_config_hook_lock); | ||||
warned++; | run_interrupt_driven_config_hooks_warning(warned++); | ||||
run_interrupt_driven_config_hooks_warning(warned); | |||||
mtx_lock(&intr_config_hook_lock); | mtx_lock(&intr_config_hook_lock); | ||||
} | } | ||||
} | } | ||||
mtx_unlock(&intr_config_hook_lock); | mtx_unlock(&intr_config_hook_lock); | ||||
} | } | ||||
SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, | SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST, | ||||
boot_run_interrupt_driven_config_hooks, NULL); | boot_run_interrupt_driven_config_hooks, NULL); | ||||
▲ Show 20 Lines • Show All 96 Lines • Show Last 20 Lines |