Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/broadcom There are some devices on the bcm283x ...
details: https://anonhg.NetBSD.org/src/rev/546ee5605edc
branches: trunk
changeset: 465553:546ee5605edc
user: thorpej <thorpej%NetBSD.org@localhost>
date: Thu Nov 28 01:08:06 2019 +0000
description:
There are some devices on the bcm283x that share IRQs (notably, the i2c
controllers), but the generic ARM PIC code doesn't support this. Add a
workaround inspired by the GICv3 driver (thanks Jared for pointint it out).
diffstat:
sys/arch/arm/broadcom/bcm2835_intr.c | 115 +++++++++++++++++++++++++++++++++-
1 files changed, 110 insertions(+), 5 deletions(-)
diffs (169 lines):
diff -r 5aa29c554872 -r 546ee5605edc sys/arch/arm/broadcom/bcm2835_intr.c
--- a/sys/arch/arm/broadcom/bcm2835_intr.c Thu Nov 28 00:18:36 2019 +0000
+++ b/sys/arch/arm/broadcom/bcm2835_intr.c Thu Nov 28 01:08:06 2019 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: bcm2835_intr.c,v 1.24 2019/09/25 16:57:10 skrll Exp $ */
+/* $NetBSD: bcm2835_intr.c,v 1.25 2019/11/28 01:08:06 thorpej Exp $ */
/*-
- * Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
+ * Copyright (c) 2012, 2015, 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.24 2019/09/25 16:57:10 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.25 2019/11/28 01:08:06 thorpej Exp $");
#define _INTR_PRIVATE
@@ -87,6 +87,8 @@
static void bcm2835_icu_fdt_disestablish(device_t, void *);
static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
+static int bcm2835_icu_intr(void *);
+
static int bcm2836mp_icu_fdt_decode_irq(u_int *);
static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
int (*)(void *), void *);
@@ -162,11 +164,35 @@
static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
+struct bcm2835icu_irqhandler;
+struct bcm2835icu_irq;
+struct bcm2835icu_softc;
+
+struct bcm2835icu_irqhandler {
+ struct bcm2835icu_irq *ih_irq;
+ int (*ih_fn)(void *);
+ void *ih_arg;
+ TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
+};
+
+struct bcm2835icu_irq {
+ struct bcm2835icu_softc *intr_sc;
+ void *intr_ih;
+ void *intr_arg;
+ int intr_refcnt;
+ int intr_ipl;
+ int intr_irq;
+ int intr_mpsafe;
+ TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
+};
+
struct bcm2835icu_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
+ struct bcm2835icu_irq *sc_irq[BCM2835_NIRQ];
+
int sc_phandle;
};
@@ -437,6 +463,9 @@
bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
int (*func)(void *), void *arg)
{
+ struct bcm2835icu_softc * const sc = device_private(dev);
+ struct bcm2835icu_irq *firq;
+ struct bcm2835icu_irqhandler *firqh;
int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
int irq;
@@ -444,13 +473,89 @@
if (irq == -1)
return NULL;
- return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
+ firq = sc->sc_irq[irq];
+ if (firq == NULL) {
+ firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
+ firq->intr_sc = sc;
+ firq->intr_refcnt = 0;
+ firq->intr_arg = arg;
+ firq->intr_ipl = ipl;
+ firq->intr_mpsafe = iflags;
+ firq->intr_irq = irq;
+ TAILQ_INIT(&firq->intr_handlers);
+ if (arg == NULL) {
+ firq->intr_ih = intr_establish(irq, ipl,
+ IST_LEVEL | iflags, func, NULL);
+ } else {
+ firq->intr_ih = intr_establish(irq, ipl,
+ IST_LEVEL | iflags, bcm2835_icu_intr, firq);
+ }
+ if (firq->intr_ih == NULL) {
+ kmem_free(firq, sizeof(*firq));
+ return NULL;
+ }
+ sc->sc_irq[irq] = firq;
+ } else {
+ if (firq->intr_arg == NULL || arg == NULL) {
+ device_printf(dev,
+ "cannot share irq with NULL-arg handler\n");
+ return NULL;
+ }
+ if (firq->intr_ipl != ipl) {
+ device_printf(dev,
+ "cannot share irq with different ipl\n");
+ return NULL;
+ }
+ if (firq->intr_mpsafe != iflags) {
+ device_printf(dev,
+ "cannot share irq between mpsafe/non-mpsafe\n");
+ return NULL;
+ }
+ }
+
+ firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
+ firqh->ih_irq = firq;
+ firqh->ih_fn = func;
+ firqh->ih_arg = arg;
+ TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
+
+ return firqh;
}
static void
bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
{
- intr_disestablish(ih);
+ struct bcm2835icu_softc * const sc = device_private(dev);
+ struct bcm2835icu_irqhandler *firqh = ih;
+ struct bcm2835icu_irq *firq = firqh->ih_irq;
+
+ KASSERT(firq->intr_refcnt > 0);
+
+ /* XXX */
+ if (firq->intr_refcnt > 1)
+ panic("%s: cannot disestablish shared irq", __func__);
+
+ intr_disestablish(firq->intr_ih);
+
+ TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
+ kmem_free(firqh, sizeof(*firqh));
+
+ sc->sc_irq[firq->intr_irq] = NULL;
+ kmem_free(firq, sizeof(*firq));
+}
+
+static int
+bcm2835_icu_intr(void *priv)
+{
+ struct bcm2835icu_irq *firq = priv;
+ struct bcm2835icu_irqhandler *firqh;
+ int handled = 0;
+
+ TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
+ handled |= firqh->ih_fn(firqh->ih_arg);
+ }
+
+ return handled;
}
static bool
Home |
Main Index |
Thread Index |
Old Index