Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/fdt Add fdt_intr_mask() / fdt_intr_unmask() function...
details: https://anonhg.NetBSD.org/src/rev/1de775837474
branches: trunk
changeset: 1007379:1de775837474
user: thorpej <thorpej%NetBSD.org@localhost>
date: Sun Feb 16 20:28:18 2020 +0000
description:
Add fdt_intr_mask() / fdt_intr_unmask() functions, for masking and
unmasking invididual interrupt sources (similar to acpi_intr_mask()
and acpi_intr_unmask()).
diffstat:
sys/dev/fdt/fdt_intr.c | 143 +++++++++++++++++++++++++++++++++++++++++++-----
sys/dev/fdt/fdt_subr.c | 9 ++-
sys/dev/fdt/fdtvar.h | 6 +-
3 files changed, 139 insertions(+), 19 deletions(-)
diffs (274 lines):
diff -r 2e419d21926a -r 1de775837474 sys/dev/fdt/fdt_intr.c
--- a/sys/dev/fdt/fdt_intr.c Sun Feb 16 17:45:11 2020 +0000
+++ b/sys/dev/fdt/fdt_intr.c Sun Feb 16 20:28:18 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fdt_intr.c,v 1.24 2019/12/31 20:47:05 jmcneill Exp $ */
+/* $NetBSD: fdt_intr.c,v 1.25 2020/02/16 20:28:18 thorpej Exp $ */
/*-
* Copyright (c) 2015-2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,15 +27,19 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_intr.c,v 1.24 2019/12/31 20:47:05 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_intr.c,v 1.25 2020/02/16 20:28:18 thorpej Exp $");
#include <sys/param.h>
+#include <sys/atomic.h>
#include <sys/bus.h>
#include <sys/kmem.h>
#include <sys/queue.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
#include <libfdt.h>
#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/fdt_private.h>
struct fdtbus_interrupt_controller {
device_t ic_dev;
@@ -53,14 +57,26 @@
void *c_ih;
LIST_ENTRY(fdtbus_interrupt_cookie) c_next;
+ uint32_t c_refcnt;
};
static LIST_HEAD(, fdtbus_interrupt_cookie) fdtbus_interrupt_cookies =
LIST_HEAD_INITIALIZER(fdtbus_interrupt_cookies);
+static kmutex_t fdtbus_interrupt_cookie_mutex;
+static kcondvar_t fdtbus_interrupt_cookie_wait;
+static bool fdtbus_interrupt_cookies_wanted;
static const u_int * get_specifier_by_index(int, int, int *);
static const u_int * get_specifier_from_map(int, const u_int *, int *);
+void
+fdtbus_intr_init(void)
+{
+
+ mutex_init(&fdtbus_interrupt_cookie_mutex, MUTEX_SPIN, IPL_HIGH);
+ cv_init(&fdtbus_interrupt_cookie_wait, "fdtintr");
+}
+
/*
* Find the interrupt controller for a given node. This function will either
* return the phandle of the interrupt controller for this node, or the phandle
@@ -130,6 +146,37 @@
return 0;
}
+static struct fdtbus_interrupt_cookie *
+fdtbus_get_interrupt_cookie(void *cookie)
+{
+ struct fdtbus_interrupt_cookie *c;
+
+ mutex_enter(&fdtbus_interrupt_cookie_mutex);
+ LIST_FOREACH(c, &fdtbus_interrupt_cookies, c_next) {
+ if (c->c_ih == cookie) {
+ c->c_refcnt++;
+ KASSERT(c->c_refcnt > 0);
+ break;
+ }
+ }
+ mutex_exit(&fdtbus_interrupt_cookie_mutex);
+ return c;
+}
+
+static void
+fdtbus_put_interrupt_cookie(struct fdtbus_interrupt_cookie *c)
+{
+
+ mutex_enter(&fdtbus_interrupt_cookie_mutex);
+ KASSERT(c->c_refcnt > 0);
+ c->c_refcnt--;
+ if (fdtbus_interrupt_cookies_wanted) {
+ fdtbus_interrupt_cookies_wanted = false;
+ cv_signal(&fdtbus_interrupt_cookie_wait);
+ }
+ mutex_exit(&fdtbus_interrupt_cookie_mutex);
+}
+
void *
fdtbus_intr_establish(int phandle, u_int index, int ipl, int flags,
int (*func)(void *), void *arg)
@@ -173,13 +220,29 @@
return NULL;
}
+ c = kmem_zalloc(sizeof(*c), KM_SLEEP);
+ c->c_ic = ic;
+ mutex_enter(&fdtbus_interrupt_cookie_mutex);
+ LIST_INSERT_HEAD(&fdtbus_interrupt_cookies, c, c_next);
+ mutex_exit(&fdtbus_interrupt_cookie_mutex);
+
+ /*
+ * XXX This leaves a small window where the handler is registered
+ * (and thus could be called) before the cookie on the list has a
+ * valid lookup key (and thus can be found). This will cause a
+ * panic in fdt_intr_mask() if that is called from the handler before
+ * this situation is resolved. For now we just cross our fingers
+ * and hope that the device won't actually interrupt until we return.
+ */
ih = ic->ic_funcs->establish(ic->ic_dev, __UNCONST(specifier),
ipl, flags, func, arg);
if (ih != NULL) {
- c = kmem_alloc(sizeof(*c), KM_SLEEP);
- c->c_ic = ic;
- c->c_ih = ih;
- LIST_INSERT_HEAD(&fdtbus_interrupt_cookies, c, c_next);
+ atomic_store_release(&c->c_ih, ih);
+ } else {
+ mutex_enter(&fdtbus_interrupt_cookie_mutex);
+ LIST_REMOVE(c, c_next);
+ mutex_exit(&fdtbus_interrupt_cookie_mutex);
+ kmem_free(c, sizeof(*c));
}
return ih;
@@ -188,22 +251,70 @@
void
fdtbus_intr_disestablish(int phandle, void *cookie)
{
- struct fdtbus_interrupt_controller *ic = NULL;
+ struct fdtbus_interrupt_cookie *c;
+
+ if ((c = fdtbus_get_interrupt_cookie(cookie)) == NULL) {
+ panic("%s: interrupt handle not valid", __func__);
+ }
+
+ const struct fdtbus_interrupt_controller *ic = c->c_ic;
+ ic->ic_funcs->disestablish(ic->ic_dev, cookie);
+
+ /*
+ * Wait for any dangling references other than ours to
+ * drain away.
+ */
+ mutex_enter(&fdtbus_interrupt_cookie_mutex);
+ while (c->c_refcnt != 1) {
+ KASSERT(c->c_refcnt > 0);
+ fdtbus_interrupt_cookies_wanted = true;
+ cv_wait(&fdtbus_interrupt_cookie_wait,
+ &fdtbus_interrupt_cookie_mutex);
+ }
+ LIST_REMOVE(c, c_next);
+ mutex_exit(&fdtbus_interrupt_cookie_mutex);
+
+ kmem_free(c, sizeof(*c));
+}
+
+void
+fdtbus_intr_mask(int phandle, void *cookie)
+{
struct fdtbus_interrupt_cookie *c;
- LIST_FOREACH(c, &fdtbus_interrupt_cookies, c_next) {
- if (c->c_ih == cookie) {
- ic = c->c_ic;
- LIST_REMOVE(c, c_next);
- kmem_free(c, sizeof(*c));
- break;
- }
+ if ((c = fdtbus_get_interrupt_cookie(cookie)) == NULL) {
+ panic("%s: interrupt handle not valid", __func__);
+ }
+
+ struct fdtbus_interrupt_controller * const ic = c->c_ic;
+
+ if (ic->ic_funcs->mask == NULL) {
+ panic("%s: no 'mask' method for %s", __func__,
+ device_xname(ic->ic_dev));
}
- if (ic == NULL)
+ ic->ic_funcs->mask(ic->ic_dev, cookie);
+ fdtbus_put_interrupt_cookie(c);
+}
+
+void
+fdtbus_intr_unmask(int phandle, void *cookie)
+{
+ struct fdtbus_interrupt_cookie *c;
+
+ if ((c = fdtbus_get_interrupt_cookie(cookie)) == NULL) {
panic("%s: interrupt handle not valid", __func__);
+ }
- return ic->ic_funcs->disestablish(ic->ic_dev, cookie);
+ struct fdtbus_interrupt_controller * const ic = c->c_ic;
+
+ if (ic->ic_funcs->unmask == NULL) {
+ panic("%s: no 'unmask' method for %s", __func__,
+ device_xname(ic->ic_dev));
+ }
+
+ ic->ic_funcs->unmask(ic->ic_dev, cookie);
+ fdtbus_put_interrupt_cookie(c);
}
bool
diff -r 2e419d21926a -r 1de775837474 sys/dev/fdt/fdt_subr.c
--- a/sys/dev/fdt/fdt_subr.c Sun Feb 16 17:45:11 2020 +0000
+++ b/sys/dev/fdt/fdt_subr.c Sun Feb 16 20:28:18 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fdt_subr.c,v 1.32 2020/02/16 14:56:52 thorpej Exp $ */
+/* $NetBSD: fdt_subr.c,v 1.33 2020/02/16 20:28:18 thorpej Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.32 2020/02/16 14:56:52 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.33 2020/02/16 20:28:18 thorpej Exp $");
#include "opt_fdt.h"
@@ -36,6 +36,7 @@
#include <libfdt.h>
#include <dev/fdt/fdtvar.h>
+#include <dev/fdt/fdt_private.h>
static const void *fdt_data;
@@ -50,6 +51,10 @@
return false;
}
fdt_data = data;
+
+ /* Now that we have a FDT blob, initialize other bits that need it. */
+ fdtbus_intr_init();
+
return true;
}
diff -r 2e419d21926a -r 1de775837474 sys/dev/fdt/fdtvar.h
--- a/sys/dev/fdt/fdtvar.h Sun Feb 16 17:45:11 2020 +0000
+++ b/sys/dev/fdt/fdtvar.h Sun Feb 16 20:28:18 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fdtvar.h,v 1.58 2020/02/16 14:56:52 thorpej Exp $ */
+/* $NetBSD: fdtvar.h,v 1.59 2020/02/16 20:28:18 thorpej Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -76,6 +76,8 @@
int (*)(void *), void *);
void (*disestablish)(device_t, void *);
bool (*intrstr)(device_t, u_int *, char *, size_t);
+ void (*mask)(device_t, void *);
+ void (*unmask)(device_t, void *);
};
struct fdtbus_i2c_controller_func {
@@ -316,6 +318,8 @@
int (*func)(void *), void *arg);
void * fdtbus_intr_establish_raw(int, const u_int *, int, int,
int (*func)(void *), void *arg);
+void fdtbus_intr_mask(int, void *);
+void fdtbus_intr_unmask(int, void *);
void fdtbus_intr_disestablish(int, void *);
bool fdtbus_intr_str(int, u_int, char *, size_t);
bool fdtbus_intr_str_raw(int, const u_int *, char *, size_t);
Home |
Main Index |
Thread Index |
Old Index