[rtems-libbsd commit] CONFIG_INTRHOOK(9): Port to RTEMS

Sebastian Huber sebh at rtems.org
Tue Sep 25 08:02:22 UTC 2018


Module:    rtems-libbsd
Branch:    master
Commit:    b42dea9e51579ee27f1e063e75b936fec6c55141
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=b42dea9e51579ee27f1e063e75b936fec6c55141

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Sep 25 09:27:50 2018 +0200

CONFIG_INTRHOOK(9): Port to RTEMS

Some device drivers (e.g. MMC) need a complex intialization with working
callouts.  Remove the dummy CONFIG_INTRHOOK() implementation and replace
it with the real one from FreeBSD.  Make sure TIMEOUT(9) services work
at this point.

Update #3525.

---

 freebsd/sys/kern/init_main.c                 |   4 +
 freebsd/sys/kern/kern_timeout.c              |  12 +-
 freebsd/sys/kern/subr_autoconf.c             | 282 +++++++++++++++++++++++++++
 libbsd.py                                    |   2 +-
 rtemsbsd/rtems/rtems-kernel-configintrhook.c |  58 ------
 5 files changed, 297 insertions(+), 61 deletions(-)

diff --git a/freebsd/sys/kern/init_main.c b/freebsd/sys/kern/init_main.c
index fa4951d..43eaea5 100644
--- a/freebsd/sys/kern/init_main.c
+++ b/freebsd/sys/kern/init_main.c
@@ -350,8 +350,12 @@ restart:
 
 	TSEXIT();	/* Here so we don't overlap with start_init. */
 
+#ifndef __rtems__
 	mtx_assert(&Giant, MA_OWNED | MA_NOTRECURSED);
 	mtx_unlock(&Giant);
+#else /* __rtems__ */
+	/* Giant is unlocked in rtems_bsd_timeout_init_late() */
+#endif /* __rtems__ */
 
 #ifndef __rtems__
 	/*
diff --git a/freebsd/sys/kern/kern_timeout.c b/freebsd/sys/kern/kern_timeout.c
index d33c158..8ef42c9 100644
--- a/freebsd/sys/kern/kern_timeout.c
+++ b/freebsd/sys/kern/kern_timeout.c
@@ -326,7 +326,15 @@ rtems_bsd_timeout_init_late(void *unused)
 	rtems_status_code sc;
 	rtems_id id;
 
-	(void) unused;
+	(void)unused;
+
+	/*
+	 * Giant unlock moved from mi_startup() to here.  We have to unlock the
+	 * Giant lock earlier, since otherwise deadlocks with non-mpsafe
+	 * callouts may occur.
+	 */
+	mtx_assert(&Giant, MA_OWNED | MA_NOTRECURSED);
+	mtx_unlock(&Giant);
 
 	sc = rtems_timer_create(rtems_build_name('_', 'C', 'L', 'O'), &id);
 	BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
@@ -338,7 +346,7 @@ rtems_bsd_timeout_init_late(void *unused)
 SYSINIT(rtems_bsd_timeout_early, SI_SUB_VM, SI_ORDER_FIRST,
     rtems_bsd_timeout_init_early, NULL);
 
-SYSINIT(rtems_bsd_timeout_late, SI_SUB_LAST, SI_ORDER_FIRST,
+SYSINIT(rtems_bsd_timeout_late, SI_SUB_KICK_SCHEDULER, SI_ORDER_FIRST,
     rtems_bsd_timeout_init_late, NULL);
 
 static void
diff --git a/freebsd/sys/kern/subr_autoconf.c b/freebsd/sys/kern/subr_autoconf.c
new file mode 100644
index 0000000..33087b0
--- /dev/null
+++ b/freebsd/sys/kern/subr_autoconf.c
@@ -0,0 +1,282 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)subr_autoconf.c	8.1 (Berkeley) 6/10/93
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_ddb.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+/*
+ * Autoconfiguration subroutines.
+ */
+
+/*
+ * "Interrupt driven config" functions.
+ */
+static TAILQ_HEAD(, intr_config_hook) intr_config_hook_list =
+	TAILQ_HEAD_INITIALIZER(intr_config_hook_list);
+static struct intr_config_hook *next_to_notify;
+static struct mtx intr_config_hook_lock;
+MTX_SYSINIT(intr_config_hook, &intr_config_hook_lock, "intr config", MTX_DEF);
+
+/* ARGSUSED */
+static void run_interrupt_driven_config_hooks(void);
+
+/*
+ * Private data and a shim function for implementing config_interhook_oneshot().
+ */
+struct oneshot_config_hook {
+	struct intr_config_hook 
+			och_hook;		/* Must be first */
+	ich_func_t	och_func;
+	void		*och_arg;
+};
+
+static void
+config_intrhook_oneshot_func(void *arg)
+{
+	struct oneshot_config_hook *ohook;
+
+	ohook = arg;
+	ohook->och_func(ohook->och_arg);
+	config_intrhook_disestablish(&ohook->och_hook);
+	free(ohook, M_DEVBUF);
+}
+
+/*
+ * If we wait too long for an interrupt-driven config hook to return, print
+ * a diagnostic.
+ */
+#define	WARNING_INTERVAL_SECS	60
+static void
+run_interrupt_driven_config_hooks_warning(int warned)
+{
+	struct intr_config_hook *hook_entry;
+#ifndef __rtems__
+	char namebuf[64];
+	long offset;
+#endif /* __rtems__ */
+
+	if (warned < 6) {
+		printf("run_interrupt_driven_hooks: still waiting after %d "
+		    "seconds for", warned * WARNING_INTERVAL_SECS);
+		TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
+#ifndef __rtems__
+			if (linker_search_symbol_name(
+			    (caddr_t)hook_entry->ich_func, namebuf,
+			    sizeof(namebuf), &offset) == 0)
+				printf(" %s", namebuf);
+			else
+#endif /* __rtems__ */
+				printf(" %p", hook_entry->ich_func);
+		}
+		printf("\n");
+	}
+	KASSERT(warned < 6,
+	    ("run_interrupt_driven_config_hooks: waited too long"));
+}
+
+static void
+run_interrupt_driven_config_hooks()
+{
+	static int running;
+	struct intr_config_hook *hook_entry;
+
+	mtx_lock(&intr_config_hook_lock);
+
+	/*
+	 * If hook processing is already active, any newly
+	 * registered hooks will eventually be notified.
+	 * Let the currently running session issue these
+	 * notifications.
+	 */
+	if (running != 0) {
+		mtx_unlock(&intr_config_hook_lock);
+		return;
+	}
+	running = 1;
+
+	while (next_to_notify != NULL) {
+		hook_entry = next_to_notify;
+		next_to_notify = TAILQ_NEXT(hook_entry, ich_links);
+		mtx_unlock(&intr_config_hook_lock);
+		(*hook_entry->ich_func)(hook_entry->ich_arg);
+		mtx_lock(&intr_config_hook_lock);
+	}
+
+	running = 0;
+	mtx_unlock(&intr_config_hook_lock);
+}
+
+static void
+boot_run_interrupt_driven_config_hooks(void *dummy)
+{
+	int warned;
+
+	run_interrupt_driven_config_hooks();
+
+	/* Block boot processing until all hooks are disestablished. */
+	TSWAIT("config hooks");
+	mtx_lock(&intr_config_hook_lock);
+	warned = 0;
+	while (!TAILQ_EMPTY(&intr_config_hook_list)) {
+		if (msleep(&intr_config_hook_list, &intr_config_hook_lock,
+		    0, "conifhk", WARNING_INTERVAL_SECS * hz) ==
+		    EWOULDBLOCK) {
+			mtx_unlock(&intr_config_hook_lock);
+			warned++;
+			run_interrupt_driven_config_hooks_warning(warned);
+			mtx_lock(&intr_config_hook_lock);
+		}
+	}
+	mtx_unlock(&intr_config_hook_lock);
+	TSUNWAIT("config hooks");
+}
+
+SYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
+	boot_run_interrupt_driven_config_hooks, NULL);
+
+/*
+ * Register a hook that will be called after "cold"
+ * autoconfiguration is complete and interrupts can
+ * be used to complete initialization.
+ */
+int
+config_intrhook_establish(struct intr_config_hook *hook)
+{
+	struct intr_config_hook *hook_entry;
+
+	TSHOLD("config hooks");
+	mtx_lock(&intr_config_hook_lock);
+	TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
+		if (hook_entry == hook)
+			break;
+	if (hook_entry != NULL) {
+		mtx_unlock(&intr_config_hook_lock);
+		printf("config_intrhook_establish: establishing an "
+		       "already established hook.\n");
+		return (1);
+	}
+	TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links);
+	if (next_to_notify == NULL)
+		next_to_notify = hook;
+	mtx_unlock(&intr_config_hook_lock);
+#ifndef __rtems__
+	if (cold == 0)
+		/*
+		 * XXX Call from a task since not all drivers expect
+		 *     to be re-entered at the time a hook is established.
+		 */
+		/* XXX Sufficient for modules loaded after initial config??? */
+		run_interrupt_driven_config_hooks();	
+#endif /* __rtems__ */
+	return (0);
+}
+
+/*
+ * Register a hook function that is automatically unregistered after it runs.
+ */
+void
+config_intrhook_oneshot(ich_func_t func, void *arg)
+{
+	struct oneshot_config_hook *ohook;
+
+	ohook = malloc(sizeof(*ohook), M_DEVBUF, M_WAITOK);
+	ohook->och_func = func;
+	ohook->och_arg  = arg;
+	ohook->och_hook.ich_func = config_intrhook_oneshot_func;
+	ohook->och_hook.ich_arg  = ohook;
+	config_intrhook_establish(&ohook->och_hook);
+}
+
+void
+config_intrhook_disestablish(struct intr_config_hook *hook)
+{
+	struct intr_config_hook *hook_entry;
+
+	mtx_lock(&intr_config_hook_lock);
+	TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links)
+		if (hook_entry == hook)
+			break;
+	if (hook_entry == NULL)
+		panic("config_intrhook_disestablish: disestablishing an "
+		      "unestablished hook");
+
+	if (next_to_notify == hook)
+		next_to_notify = TAILQ_NEXT(hook, ich_links);
+	TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
+	TSRELEASE("config hooks");
+
+	/* Wakeup anyone watching the list */
+	wakeup(&intr_config_hook_list);
+	mtx_unlock(&intr_config_hook_lock);
+}
+
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(conifhk, db_show_conifhk)
+{
+	struct intr_config_hook *hook_entry;
+	char namebuf[64];
+	long offset;
+
+	TAILQ_FOREACH(hook_entry, &intr_config_hook_list, ich_links) {
+		if (linker_ddb_search_symbol_name(
+		    (caddr_t)hook_entry->ich_func, namebuf, sizeof(namebuf),
+		    &offset) == 0) {
+			db_printf("hook: %p at %s+%#lx arg: %p\n",
+			    hook_entry->ich_func, namebuf, offset,
+			    hook_entry->ich_arg);
+		} else {
+			db_printf("hook: %p at ??+?? arg %p\n",
+			    hook_entry->ich_func, hook_entry->ich_arg);
+		}
+	}
+}
+#endif /* DDB */
diff --git a/libbsd.py b/libbsd.py
index f50de8d..a066b37 100644
--- a/libbsd.py
+++ b/libbsd.py
@@ -250,7 +250,6 @@ class rtems(builder.Module):
                 'rtems/rtems-kernel-bus-root.c',
                 'rtems/rtems-kernel-cam.c',
                 'rtems/rtems-kernel-chunk.c',
-                'rtems/rtems-kernel-configintrhook.c',
                 'rtems/rtems-kernel-delay.c',
                 'rtems/rtems-kernel-epoch.c',
                 'rtems/rtems-kernel-get-file.c',
@@ -536,6 +535,7 @@ class base(builder.Module):
                 'sys/kern/kern_time.c',
                 'sys/kern/kern_timeout.c',
                 'sys/kern/kern_uuid.c',
+                'sys/kern/subr_autoconf.c',
                 'sys/kern/subr_blist.c',
                 'sys/kern/subr_bufring.c',
                 'sys/kern/subr_bus.c',
diff --git a/rtemsbsd/rtems/rtems-kernel-configintrhook.c b/rtemsbsd/rtems/rtems-kernel-configintrhook.c
deleted file mode 100644
index 7ff4e40..0000000
--- a/rtemsbsd/rtems/rtems-kernel-configintrhook.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * @file
- *
- * @ingroup rtems_bsd_rtems
- *
- * @brief TODO.
- */
-
-/*
- * Copyright (c) 2011 embedded brains GmbH.  All rights reserved.
- *
- *  embedded brains GmbH
- *  Dornierstr. 4
- *  82178 Puchheim
- *  Germany
- *  <info at embedded-brains.de>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <machine/rtems-bsd-kernel-space.h>
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/kernel.h>
-
-int
-config_intrhook_establish(struct intr_config_hook *hook)
-{
-	(*hook->ich_func)(hook->ich_arg);
-
-	return (0);
-}
-
-void
-config_intrhook_disestablish(struct intr_config_hook *hook)
-{
-	/* Do nothing */
-}



More information about the vc mailing list