Module Name:    src
Committed By:   thorpej
Date:           Sun Feb 16 20:28:18 UTC 2020

Modified Files:
        src/sys/dev/fdt: fdt_intr.c fdt_subr.c fdtvar.h

Log Message:
Add fdt_intr_mask() / fdt_intr_unmask() functions, for masking and
unmasking invididual interrupt sources (similar to acpi_intr_mask()
and acpi_intr_unmask()).


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sys/dev/fdt/fdt_intr.c
cvs rdiff -u -r1.32 -r1.33 src/sys/dev/fdt/fdt_subr.c
cvs rdiff -u -r1.58 -r1.59 src/sys/dev/fdt/fdtvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/fdt/fdt_intr.c
diff -u src/sys/dev/fdt/fdt_intr.c:1.24 src/sys/dev/fdt/fdt_intr.c:1.25
--- src/sys/dev/fdt/fdt_intr.c:1.24	Tue Dec 31 20:47:05 2019
+++ src/sys/dev/fdt/fdt_intr.c	Sun Feb 16 20:28:18 2020
@@ -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 <[email protected]>
@@ -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 @@ struct fdtbus_interrupt_cookie {
 	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 @@ fdtbus_register_interrupt_controller(dev
 	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 @@ fdtbus_intr_establish_raw(int ihandle, c
 		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 @@ fdtbus_intr_establish_raw(int ihandle, c
 void
 fdtbus_intr_disestablish(int phandle, void *cookie)
 {
-	struct fdtbus_interrupt_controller *ic = NULL;
 	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__);
 	}
 
-	if (ic == NULL)
+	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;
+
+	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));
+	}
+
+	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__);
+	}
+
+	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));
+	}
 
-	return ic->ic_funcs->disestablish(ic->ic_dev, cookie);
+	ic->ic_funcs->unmask(ic->ic_dev, cookie);
+	fdtbus_put_interrupt_cookie(c);
 }
 
 bool

Index: src/sys/dev/fdt/fdt_subr.c
diff -u src/sys/dev/fdt/fdt_subr.c:1.32 src/sys/dev/fdt/fdt_subr.c:1.33
--- src/sys/dev/fdt/fdt_subr.c:1.32	Sun Feb 16 14:56:52 2020
+++ src/sys/dev/fdt/fdt_subr.c	Sun Feb 16 20:28:18 2020
@@ -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 <[email protected]>
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v
 
 #include <libfdt.h>
 #include <dev/fdt/fdtvar.h>
+#include <dev/fdt/fdt_private.h>
 
 static const void *fdt_data;
 
@@ -50,6 +51,10 @@ fdtbus_init(const void *data)
 		return false;
 	}
 	fdt_data = data;
+
+	/* Now that we have a FDT blob, initialize other bits that need it. */
+	fdtbus_intr_init();
+
 	return true;
 }
 

Index: src/sys/dev/fdt/fdtvar.h
diff -u src/sys/dev/fdt/fdtvar.h:1.58 src/sys/dev/fdt/fdtvar.h:1.59
--- src/sys/dev/fdt/fdtvar.h:1.58	Sun Feb 16 14:56:52 2020
+++ src/sys/dev/fdt/fdtvar.h	Sun Feb 16 20:28:18 2020
@@ -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 <[email protected]>
@@ -76,6 +76,8 @@ struct fdtbus_interrupt_controller_func 
 			     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 @@ void *		fdtbus_intr_establish_byname(int
 		    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);

Reply via email to