Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/sunxi Provide a back-end for fdt_intr_mask() / ...
details: https://anonhg.NetBSD.org/src/rev/3499b9e12e37
branches: trunk
changeset: 744909:3499b9e12e37
user: thorpej <thorpej%NetBSD.org@localhost>
date: Sun Feb 16 20:29:36 2020 +0000
description:
Provide a back-end for fdt_intr_mask() / fdt_intr_unmask().
diffstat:
sys/arch/arm/sunxi/sunxi_nmi.c | 118 +++++++++++++++++++++++++++++++++-------
1 files changed, 97 insertions(+), 21 deletions(-)
diffs (220 lines):
diff -r 0bc3e26cd731 -r 3499b9e12e37 sys/arch/arm/sunxi/sunxi_nmi.c
--- a/sys/arch/arm/sunxi/sunxi_nmi.c Sun Feb 16 20:28:18 2020 +0000
+++ b/sys/arch/arm/sunxi/sunxi_nmi.c Sun Feb 16 20:29:36 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_nmi.c,v 1.4 2020/01/07 10:20:07 skrll Exp $ */
+/* $NetBSD: sunxi_nmi.c,v 1.5 2020/02/16 20:29:36 thorpej Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
#define _INTR_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_nmi.c,v 1.4 2020/01/07 10:20:07 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_nmi.c,v 1.5 2020/02/16 20:29:36 thorpej Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -37,6 +37,8 @@
#include <sys/intr.h>
#include <sys/kernel.h>
#include <sys/systm.h>
+#include <sys/atomic.h>
+#include <sys/mutex.h>
#include <sys/lwp.h>
#include <dev/fdt/fdtvar.h>
@@ -99,10 +101,12 @@
bus_space_handle_t sc_bsh;
int sc_phandle;
+ kmutex_t sc_intr_lock;
+
const struct sunxi_nmi_config *sc_config;
- int (*sc_func)(void *);
- void *sc_arg;
+ struct intrsource sc_is;
+ void *sc_ih;
};
#define NMI_READ(sc, reg) \
@@ -148,11 +152,17 @@
sunxi_nmi_intr(void *priv)
{
struct sunxi_nmi_softc * const sc = priv;
+ int (*func)(void *);
int rv = 0;
- if (sc->sc_func)
- rv = sc->sc_func(sc->sc_arg);
+ func = atomic_load_acquire(&sc->sc_is.is_func);
+ if (func)
+ rv = func(sc->sc_is.is_arg);
+ /*
+ * We don't serialize access to this register because we're the
+ * only thing fiddling wth it.
+ */
sunxi_nmi_irq_ack(sc);
return rv;
@@ -164,19 +174,13 @@
{
struct sunxi_nmi_softc * const sc = device_private(dev);
u_int irq_type;
+ int ist;
/* 1st cell is the interrupt number */
const u_int irq = be32toh(specifier[0]);
/* 2nd cell is polarity */
const u_int pol = be32toh(specifier[1]);
- if (sc->sc_func != NULL) {
-#ifdef DIAGNOSTIC
- device_printf(dev, "%s in use\n", sc->sc_config->name);
-#endif
- return NULL;
- }
-
if (irq != 0) {
#ifdef DIAGNOSTIC
device_printf(dev, "IRQ %u is invalid\n", irq);
@@ -187,42 +191,100 @@
switch (pol & 0x7) {
case 1: /* IRQ_TYPE_EDGE_RISING */
irq_type = NMI_CTRL_IRQ_HIGH_EDGE;
+ ist = IST_EDGE;
break;
case 2: /* IRQ_TYPE_EDGE_FALLING */
irq_type = NMI_CTRL_IRQ_LOW_EDGE;
+ ist = IST_EDGE;
break;
case 3: /* IRQ_TYPE_LEVEL_HIGH */
irq_type = NMI_CTRL_IRQ_HIGH_LEVEL;
+ ist = IST_LEVEL;
break;
case 4: /* IRQ_TYPE_LEVEL_LOW */
irq_type = NMI_CTRL_IRQ_LOW_LEVEL;
+ ist = IST_LEVEL;
break;
default:
irq_type = NMI_CTRL_IRQ_LOW_LEVEL;
+ ist = IST_LEVEL;
break;
}
- sc->sc_func = func;
- sc->sc_arg = arg;
+ mutex_enter(&sc->sc_intr_lock);
+
+ if (atomic_load_relaxed(&sc->sc_is.is_func) != NULL) {
+ mutex_exit(&sc->sc_intr_lock);
+#ifdef DIAGNOSTIC
+ device_printf(dev, "%s in use\n", sc->sc_config->name);
+#endif
+ return NULL;
+ }
+ sc->sc_is.is_arg = arg;
+ atomic_store_release(&sc->sc_is.is_func, func);
+
+ sc->sc_is.is_type = ist;
+ sc->sc_is.is_ipl = ipl;
+ sc->sc_is.is_mpsafe = (flags & FDT_INTR_MPSAFE) ? true : false;
+
+ mutex_exit(&sc->sc_intr_lock);
+
+ sc->sc_ih = fdtbus_intr_establish(sc->sc_phandle, 0, ipl, flags,
+ sunxi_nmi_intr, sc);
+
+ mutex_enter(&sc->sc_intr_lock);
sunxi_nmi_irq_set_type(sc, irq_type);
sunxi_nmi_irq_enable(sc, true);
+ mutex_exit(&sc->sc_intr_lock);
- return fdtbus_intr_establish(sc->sc_phandle, 0, ipl, flags,
- sunxi_nmi_intr, sc);
+ return &sc->sc_is;
+}
+
+static void
+sunxi_nmi_fdt_mask(device_t dev, void *ih __unused)
+{
+ struct sunxi_nmi_softc * const sc = device_private(dev);
+
+ mutex_enter(&sc->sc_intr_lock);
+ if (sc->sc_is.is_mask_count++ == 0) {
+ sunxi_nmi_irq_enable(sc, false);
+ }
+ mutex_exit(&sc->sc_intr_lock);
+}
+
+static void
+sunxi_nmi_fdt_unmask(device_t dev, void *ih __unused)
+{
+ struct sunxi_nmi_softc * const sc = device_private(dev);
+
+ mutex_enter(&sc->sc_intr_lock);
+ if (sc->sc_is.is_mask_count-- == 1) {
+ sunxi_nmi_irq_enable(sc, true);
+ }
+ mutex_exit(&sc->sc_intr_lock);
}
static void
sunxi_nmi_fdt_disestablish(device_t dev, void *ih)
{
struct sunxi_nmi_softc * const sc = device_private(dev);
+ struct intrsource * const is = ih;
- sunxi_nmi_irq_enable(sc, false);
+ KASSERT(is == &sc->sc_is);
- fdtbus_intr_disestablish(sc->sc_phandle, ih);
+ mutex_enter(&sc->sc_intr_lock);
+ sunxi_nmi_irq_enable(sc, false);
+ is->is_mask_count = 0;
+ mutex_exit(&sc->sc_intr_lock);
- sc->sc_func = NULL;
- sc->sc_arg = NULL;
+ fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih);
+ sc->sc_ih = NULL;
+
+ mutex_enter(&sc->sc_intr_lock);
+ is->is_arg = NULL;
+ is->is_func = NULL;
+ mutex_exit(&sc->sc_intr_lock);
}
static bool
@@ -239,6 +301,8 @@
.establish = sunxi_nmi_fdt_establish,
.disestablish = sunxi_nmi_fdt_disestablish,
.intrstr = sunxi_nmi_fdt_intrstr,
+ .mask = sunxi_nmi_fdt_mask,
+ .unmask = sunxi_nmi_fdt_unmask,
};
static int
@@ -276,6 +340,18 @@
aprint_naive("\n");
aprint_normal(": %s\n", sc->sc_config->name);
+ mutex_init(&sc->sc_intr_lock, MUTEX_SPIN, IPL_HIGH);
+
+ /*
+ * Normally it's assumed that an intrsource can be passed to
+ * interrupt_distribute(). We're providing our own that's
+ * independent of our parent PIC, but because we will leave
+ * the intrsource::is_pic field NULL, the right thing
+ * (i.e. nothing) will happen in interrupt_distribute().
+ */
+ snprintf(sc->sc_is.is_source, sizeof(sc->sc_is.is_source),
+ "%s", sc->sc_config->name);
+
sunxi_nmi_irq_enable(sc, false);
sunxi_nmi_irq_ack(sc);
Home |
Main Index |
Thread Index |
Old Index