Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.37
      1 /*	$NetBSD: bcm2835_intr.c,v 1.37 2021/01/27 03:10:19 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012, 2015, 2019 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Nick Hudson
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.37 2021/01/27 03:10:19 thorpej Exp $");
     34 
     35 #define _INTR_PRIVATE
     36 
     37 #include "opt_bcm283x.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/bus.h>
     41 #include <sys/cpu.h>
     42 #include <sys/device.h>
     43 #include <sys/kernel.h>
     44 #include <sys/kmem.h>
     45 #include <sys/proc.h>
     46 
     47 #include <dev/fdt/fdtvar.h>
     48 
     49 #include <machine/intr.h>
     50 
     51 #include <arm/locore.h>
     52 
     53 #include <arm/pic/picvar.h>
     54 #include <arm/cortex/gtmr_var.h>
     55 
     56 #include <arm/broadcom/bcm2835_intr.h>
     57 #include <arm/broadcom/bcm2835reg.h>
     58 #include <arm/broadcom/bcm2835var.h>
     59 
     60 #include <arm/fdt/arm_fdtvar.h>
     61 
     62 static void bcm2835_irq_handler(void *);
     63 static void bcm2836mp_intr_init(void *, struct cpu_info *);
     64 
     65 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     66 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     67 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     68 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     69 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     70     size_t);
     71 
     72 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     73 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     74 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     75 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     76 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     77     size_t);
     78 #ifdef MULTIPROCESSOR
     79 int bcm2836mp_ipi_handler(void *);
     80 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     81 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     82 #endif
     83 
     84 static int bcm2835_icu_fdt_decode_irq(u_int *);
     85 static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
     86     int (*)(void *), void *, const char *);
     87 static void bcm2835_icu_fdt_disestablish(device_t, void *);
     88 static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     89 
     90 static int bcm2835_icu_intr(void *);
     91 
     92 static int bcm2836mp_icu_fdt_decode_irq(u_int *);
     93 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
     94     int (*)(void *), void *, const char *);
     95 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
     96 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
     97 
     98 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     99 static void bcm2835_icu_attach(device_t, device_t, void *);
    100 
    101 static int bcm2835_int_base;
    102 static int bcm2836mp_int_base[BCM2836_NCPUS];
    103 
    104 #define	BCM2835_INT_BASE		bcm2835_int_base
    105 #define	BCM2836_INT_BASECPUN(n)		bcm2836mp_int_base[(n)]
    106 
    107 static void
    108 bcm2835_set_priority(struct pic_softc *pic, int ipl)
    109 {
    110 }
    111 
    112 static struct pic_ops bcm2835_picops = {
    113 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
    114 	.pic_block_irqs = bcm2835_pic_block_irqs,
    115 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
    116 	.pic_establish_irq = bcm2835_pic_establish_irq,
    117 	.pic_source_name = bcm2835_pic_source_name,
    118 	.pic_set_priority = bcm2835_set_priority,
    119 };
    120 
    121 static struct pic_softc bcm2835_pic = {
    122 	.pic_ops = &bcm2835_picops,
    123 	.pic_maxsources = BCM2835_NIRQ,
    124 	.pic_name = "bcm2835 pic",
    125 };
    126 
    127 static struct pic_ops bcm2836mp_picops = {
    128 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
    129 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
    130 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
    131 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    132 	.pic_source_name = bcm2836mp_pic_source_name,
    133 #if defined(MULTIPROCESSOR)
    134 	.pic_cpu_init = bcm2836mp_cpu_init,
    135 	.pic_ipi_send = bcm2836mp_send_ipi,
    136 #endif
    137 };
    138 
    139 static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
    140 	[0 ... BCM2836_NCPUS - 1] = {
    141 		.pic_ops = &bcm2836mp_picops,
    142 		.pic_maxsources = BCM2836_NIRQPERCPU,
    143 		.pic_name = "bcm2836 pic",
    144 	}
    145 };
    146 
    147 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
    148 	.establish = bcm2835_icu_fdt_establish,
    149 	.disestablish = bcm2835_icu_fdt_disestablish,
    150 	.intrstr = bcm2835_icu_fdt_intrstr
    151 };
    152 
    153 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
    154 	.establish = bcm2836mp_icu_fdt_establish,
    155 	.disestablish = bcm2836mp_icu_fdt_disestablish,
    156 	.intrstr = bcm2836mp_icu_fdt_intrstr
    157 };
    158 
    159 struct bcm2836mp_interrupt {
    160 	bool bi_done;
    161 	TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
    162 	int bi_irq;
    163 	int bi_ipl;
    164 	int bi_flags;
    165 	int (*bi_func)(void *);
    166 	void *bi_arg;
    167 	void *bi_ihs[BCM2836_NCPUS];
    168 };
    169 
    170 static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
    171     TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
    172 
    173 struct bcm2835icu_irqhandler;
    174 struct bcm2835icu_irq;
    175 struct bcm2835icu_softc;
    176 
    177 struct bcm2835icu_irqhandler {
    178 	struct bcm2835icu_irq	*ih_irq;
    179 	int			(*ih_fn)(void *);
    180 	void			*ih_arg;
    181 	TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
    182 };
    183 
    184 struct bcm2835icu_irq {
    185 	struct bcm2835icu_softc	*intr_sc;
    186 	void			*intr_ih;
    187 	void			*intr_arg;
    188 	int			intr_refcnt;
    189 	int			intr_ipl;
    190 	int			intr_irq;
    191 	int			intr_mpsafe;
    192 	TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
    193 };
    194 
    195 struct bcm2835icu_softc {
    196 	device_t		sc_dev;
    197 	bus_space_tag_t		sc_iot;
    198 	bus_space_handle_t	sc_ioh;
    199 
    200 	struct bcm2835icu_irq	*sc_irq[BCM2835_NIRQ];
    201 
    202 	int sc_phandle;
    203 };
    204 
    205 static struct bcm2835icu_softc *bcml1icu_sc;
    206 static struct bcm2835icu_softc *bcmicu_sc;
    207 
    208 #define read_bcm2835reg(o)	\
    209 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    210 
    211 #define write_bcm2835reg(o, v)	\
    212 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    213 
    214 
    215 #define bcm2835_barrier() \
    216 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    217 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    218 
    219 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    220 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    221 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    222 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    223 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    224 	"dma0",		"dma1",		"dma2",		"dma3",
    225 	"dma4",		"dma5",		"dma6",		"dma7",
    226 	"dma8",		"dma9",		"dma10",	"dma11",
    227 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    228 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    229 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    230 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    231 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    232 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    233 	"gpio[3]",	"i2c",		"spi",		"pcm",
    234 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
    235 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    236 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    237 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    238 };
    239 
    240 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
    241 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    242 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    243 	"gpu",		"pmu"
    244 };
    245 
    246 #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    247 
    248 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    249 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    250 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    251 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    252 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    253 
    254 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    255     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    256 
    257 static const struct device_compatible_entry compat_data[] = {
    258 	{ .compat = "brcm,bcm2708-armctrl-ic",	.value = 0 },
    259 	{ .compat = "brcm,bcm2709-armctrl-ic",	.value = 0 },
    260 	{ .compat = "brcm,bcm2835-armctrl-ic",	.value = 0 },
    261 	{ .compat = "brcm,bcm2836-armctrl-ic",	.value = 0 },
    262 	{ .compat = "brcm,bcm2836-l1-intc",	.value = 1 },
    263 	DEVICE_COMPAT_EOL
    264 };
    265 
    266 static int
    267 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    268 {
    269 	struct fdt_attach_args * const faa = aux;
    270 
    271 	return of_compatible_match(faa->faa_phandle, compat_data);
    272 }
    273 
    274 static void
    275 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    276 {
    277 	struct bcm2835icu_softc * const sc = device_private(self);
    278 	struct fdt_attach_args * const faa = aux;
    279 	struct fdtbus_interrupt_controller_func *ifuncs;
    280 	const struct device_compatible_entry *dce;
    281 	const int phandle = faa->faa_phandle;
    282 	bus_addr_t addr;
    283 	bus_size_t size;
    284 	bus_space_handle_t ioh;
    285 	int error;
    286 
    287 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    288 		aprint_error(": couldn't get registers\n");
    289 		return;
    290 	}
    291 
    292 	sc->sc_dev = self;
    293 	sc->sc_iot = faa->faa_bst;
    294 
    295 	if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
    296 		aprint_error(": couldn't map device\n");
    297 		return;
    298 	}
    299 
    300 	sc->sc_ioh = ioh;
    301 	sc->sc_phandle = phandle;
    302 
    303 	dce = of_compatible_lookup(faa->faa_phandle, compat_data);
    304 	KASSERT(dce != NULL);
    305 
    306 	if (dce->value != 0) {
    307 #if defined(MULTIPROCESSOR)
    308 		aprint_normal(": Multiprocessor");
    309 #endif
    310 		bcml1icu_sc = sc;
    311 
    312 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    313 		    BCM2836_LOCAL_CONTROL, 0);
    314 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    315 		    BCM2836_LOCAL_PRESCALER, 0x80000000);
    316 
    317 		ifuncs = &bcm2836mpicu_fdt_funcs;
    318 
    319 		bcm2836mp_intr_init(self, curcpu());
    320 		arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
    321 	} else {
    322 		if (bcml1icu_sc == NULL)
    323 			arm_fdt_irq_set_handler(bcm2835_irq_handler);
    324 		bcmicu_sc = sc;
    325 		sc->sc_ioh = ioh;
    326 		sc->sc_phandle = phandle;
    327 		bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
    328 		ifuncs = &bcm2835icu_fdt_funcs;
    329 	}
    330 
    331 	error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
    332 	if (error != 0) {
    333 		aprint_error(": couldn't register with fdtbus: %d\n", error);
    334 		return;
    335 	}
    336 	aprint_normal("\n");
    337 }
    338 
    339 static void
    340 bcm2835_irq_handler(void *frame)
    341 {
    342 	struct cpu_info * const ci = curcpu();
    343 	const int oldipl = ci->ci_cpl;
    344 	const cpuid_t cpuid = ci->ci_core_id;
    345 	const uint32_t oldipl_mask = __BIT(oldipl);
    346 	int ipl_mask = 0;
    347 
    348 	KASSERT(cpuid < BCM2836_NCPUS);
    349 
    350 	ci->ci_data.cpu_nintr++;
    351 
    352 	bcm2835_barrier();
    353 	if (cpuid == 0) {
    354 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    355 	}
    356 #if defined(SOC_BCM2836)
    357 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    358 #endif
    359 
    360 	/*
    361 	 * Record the pending_ipls and deliver them if we can.
    362 	 */
    363 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    364 		pic_do_pending_ints(I32_bit, oldipl, frame);
    365 }
    366 
    367 static void
    368 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    369     uint32_t irq_mask)
    370 {
    371 
    372 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    373 	bcm2835_barrier();
    374 }
    375 
    376 static void
    377 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    378     uint32_t irq_mask)
    379 {
    380 
    381 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    382 	bcm2835_barrier();
    383 }
    384 
    385 /*
    386  * Called with interrupts disabled
    387  */
    388 static int
    389 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    390 {
    391 	int ipl = 0;
    392 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    393 
    394 	bcm2835_barrier();
    395 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    396 	if (bpending == 0)
    397 		return 0;
    398 
    399 	armirq = bpending & BCM2835_INTBIT_ARM;
    400 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    401 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    402 
    403 	if (armirq) {
    404 		ipl |= pic_mark_pending_sources(pic,
    405 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    406 	}
    407 
    408 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    409 		uint32_t pending1;
    410 
    411 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    412 		ipl |= pic_mark_pending_sources(pic,
    413 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    414 	}
    415 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    416 		uint32_t pending2;
    417 
    418 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    419 		ipl |= pic_mark_pending_sources(pic,
    420 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    421 	}
    422 
    423 	return ipl;
    424 }
    425 
    426 static void
    427 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    428 {
    429 
    430 	/* Nothing really*/
    431 	KASSERT(is->is_irq < BCM2835_NIRQ);
    432 	KASSERT(is->is_type == IST_LEVEL);
    433 }
    434 
    435 static void
    436 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    437 {
    438 
    439 	strlcpy(buf, bcm2835_sources[irq], len);
    440 }
    441 
    442 static int
    443 bcm2835_icu_fdt_decode_irq(u_int *specifier)
    444 {
    445 	u_int base;
    446 
    447 	if (!specifier)
    448 		return -1;
    449 
    450 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
    451 	/* 2nd cell is the irq relative to that bank */
    452 
    453 	const u_int bank = be32toh(specifier[0]);
    454 	switch (bank) {
    455 	case 0:
    456 		base = BCM2835_INT_BASICBASE;
    457 		break;
    458 	case 1:
    459 		base = BCM2835_INT_GPU0BASE;
    460 		break;
    461 	case 2:
    462 		base = BCM2835_INT_GPU1BASE;
    463 		break;
    464 	default:
    465 		return -1;
    466 	}
    467 	const u_int off = be32toh(specifier[1]);
    468 
    469 	return base + off;
    470 }
    471 
    472 static void *
    473 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    474     int (*func)(void *), void *arg, const char *xname)
    475 {
    476 	struct bcm2835icu_softc * const sc = device_private(dev);
    477 	struct bcm2835icu_irq *firq;
    478 	struct bcm2835icu_irqhandler *firqh;
    479 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    480 	int irq, irqidx;
    481 
    482 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    483 	if (irq == -1)
    484 		return NULL;
    485 	irqidx = irq - BCM2835_INT_BASE;
    486 
    487 	KASSERT(irqidx < BCM2835_NIRQ);
    488 
    489 	firq = sc->sc_irq[irqidx];
    490 	if (firq == NULL) {
    491 		firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
    492 		firq->intr_sc = sc;
    493 		firq->intr_refcnt = 0;
    494 		firq->intr_arg = arg;
    495 		firq->intr_ipl = ipl;
    496 		firq->intr_mpsafe = iflags;
    497 		firq->intr_irq = irq;
    498 		TAILQ_INIT(&firq->intr_handlers);
    499 		if (arg == NULL) {
    500 			firq->intr_ih = intr_establish_xname(irq, ipl,
    501 			    IST_LEVEL | iflags, func, NULL, xname);
    502 		} else {
    503 			firq->intr_ih = intr_establish_xname(irq, ipl,
    504 			    IST_LEVEL | iflags, bcm2835_icu_intr, firq, xname);
    505 		}
    506 		if (firq->intr_ih == NULL) {
    507 			kmem_free(firq, sizeof(*firq));
    508 			return NULL;
    509 		}
    510 		sc->sc_irq[irqidx] = firq;
    511 	} else {
    512 		if (firq->intr_arg == NULL || arg == NULL) {
    513 			device_printf(dev,
    514 			    "cannot share irq with NULL-arg handler\n");
    515 			return NULL;
    516 		}
    517 		if (firq->intr_ipl != ipl) {
    518 			device_printf(dev,
    519 			    "cannot share irq with different ipl\n");
    520 			return NULL;
    521 		}
    522 		if (firq->intr_mpsafe != iflags) {
    523 			device_printf(dev,
    524 			    "cannot share irq between mpsafe/non-mpsafe\n");
    525 			return NULL;
    526 		}
    527 	}
    528 
    529 	firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
    530 	firqh->ih_irq = firq;
    531 	firqh->ih_fn = func;
    532 	firqh->ih_arg = arg;
    533 
    534 	firq->intr_refcnt++;
    535 	TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
    536 
    537 	/*
    538 	 * XXX interrupt_distribute(9) assumes that any interrupt
    539 	 * handle can be used as an input to the MD interrupt_distribute
    540 	 * implementationm, so we are forced to return the handle
    541 	 * we got back from intr_establish().  Upshot is that the
    542 	 * input to bcm2835_icu_fdt_disestablish() is ambiguous for
    543 	 * shared IRQs, rendering them un-disestablishable.
    544 	 */
    545 
    546 	return firq->intr_ih;
    547 }
    548 
    549 static void
    550 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
    551 {
    552 	struct bcm2835icu_softc * const sc = device_private(dev);
    553 	struct bcm2835icu_irqhandler *firqh;
    554 	struct bcm2835icu_irq *firq;
    555 	u_int n;
    556 
    557 	for (n = 0; n < BCM2835_NIRQ; n++) {
    558 		firq = sc->sc_irq[n];
    559 		if (firq == NULL || firq->intr_ih != ih)
    560 			continue;
    561 
    562 		KASSERT(firq->intr_refcnt > 0);
    563 		KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
    564 
    565 		/* XXX see above */
    566 		if (firq->intr_refcnt > 1)
    567 			panic("%s: cannot disestablish shared irq", __func__);
    568 
    569 		intr_disestablish(firq->intr_ih);
    570 
    571 		firqh = TAILQ_FIRST(&firq->intr_handlers);
    572 		TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
    573 		kmem_free(firqh, sizeof(*firqh));
    574 
    575 		sc->sc_irq[n] = NULL;
    576 		kmem_free(firq, sizeof(*firq));
    577 
    578 		return;
    579 	}
    580 
    581 	panic("%s: interrupt not established", __func__);
    582 }
    583 
    584 static int
    585 bcm2835_icu_intr(void *priv)
    586 {
    587 	struct bcm2835icu_irq *firq = priv;
    588 	struct bcm2835icu_irqhandler *firqh;
    589 	int handled = 0;
    590 
    591 	TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
    592 		handled |= firqh->ih_fn(firqh->ih_arg);
    593 	}
    594 
    595 	return handled;
    596 }
    597 
    598 static bool
    599 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
    600 {
    601 	int irq;
    602 
    603 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    604 	if (irq == -1)
    605 		return false;
    606 
    607 	snprintf(buf, buflen, "icu irq %d", irq);
    608 
    609 	return true;
    610 }
    611 
    612 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    613 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
    614 #define	BCM2836MP_GPU_IRQ	__BIT(8)
    615 #define	BCM2836MP_PMU_IRQ	__BIT(9)
    616 #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
    617 
    618 static void
    619 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    620     uint32_t irq_mask)
    621 {
    622 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    623 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    624 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    625 
    626 	KASSERT(cpuid < BCM2836_NCPUS);
    627 	KASSERT(irqbase == 0);
    628 
    629 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    630 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    631 		uint32_t val = bus_space_read_4(iot, ioh,
    632 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    633 		val |= mask;
    634 		bus_space_write_4(iot, ioh,
    635 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    636 		    val);
    637 		bus_space_barrier(iot, ioh,
    638 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    639 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    640 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    641 	}
    642 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    643 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    644 		uint32_t val = bus_space_read_4(iot, ioh,
    645 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    646 		val |= mask;
    647 		bus_space_write_4(iot, ioh,
    648 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    649 		    val);
    650 		bus_space_barrier(iot, ioh,
    651 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    652 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    653 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    654 	}
    655 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    656 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
    657 		    __BIT(cpuid));
    658 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
    659 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    660 	}
    661 
    662 	return;
    663 }
    664 
    665 static void
    666 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    667     uint32_t irq_mask)
    668 {
    669 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    670 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    671 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    672 
    673 	KASSERT(cpuid < BCM2836_NCPUS);
    674 	KASSERT(irqbase == 0);
    675 
    676 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    677 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    678 		uint32_t val = bus_space_read_4(iot, ioh,
    679 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    680 		val &= ~mask;
    681 		bus_space_write_4(iot, ioh,
    682 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    683 		    val);
    684 	}
    685 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    686 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    687 		uint32_t val = bus_space_read_4(iot, ioh,
    688 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    689 		val &= ~mask;
    690 		bus_space_write_4(iot, ioh,
    691 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    692 		    val);
    693 	}
    694 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    695 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
    696 		    __BIT(cpuid));
    697 	}
    698 
    699 	bcm2835_barrier();
    700 	return;
    701 }
    702 
    703 static int
    704 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    705 {
    706 	struct cpu_info * const ci = curcpu();
    707 	const cpuid_t cpuid = ci->ci_core_id;
    708 	uint32_t lpending;
    709 	int ipl = 0;
    710 
    711 	KASSERT(cpuid < BCM2836_NCPUS);
    712 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    713 
    714 	bcm2835_barrier();
    715 
    716 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    717 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    718 
    719 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    720 	const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
    721 	if (allirqs) {
    722 		ipl |= pic_mark_pending_sources(pic, 0, allirqs);
    723 	}
    724 
    725 	return ipl;
    726 }
    727 
    728 static void
    729 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    730 {
    731 	/* Nothing really*/
    732 	KASSERT(is->is_irq >= 0);
    733 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    734 }
    735 
    736 static void
    737 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    738 {
    739 
    740 	irq %= BCM2836_NIRQPERCPU;
    741 	strlcpy(buf, bcm2836mp_sources[irq], len);
    742 }
    743 
    744 
    745 #if defined(MULTIPROCESSOR)
    746 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    747 {
    748 	const cpuid_t cpuid = ci->ci_core_id;
    749 
    750 	KASSERT(cpuid < BCM2836_NCPUS);
    751 
    752 	/* Enable IRQ and not FIQ */
    753 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    754 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
    755 }
    756 
    757 static void
    758 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    759 {
    760 	KASSERT(pic != NULL);
    761 	KASSERT(pic != &bcm2835_pic);
    762 	KASSERT(pic->pic_cpus != NULL);
    763 
    764 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    765 	KASSERT(cpuid < BCM2836_NCPUS);
    766 
    767 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    768 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    769 }
    770 
    771 int
    772 bcm2836mp_ipi_handler(void *priv)
    773 {
    774 	const struct cpu_info *ci = curcpu();
    775 	const cpuid_t cpuid = ci->ci_core_id;
    776 	uint32_t ipimask, bit;
    777 
    778 	KASSERT(cpuid < BCM2836_NCPUS);
    779 
    780 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    781 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    782 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    783 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
    784 
    785 	while ((bit = ffs(ipimask)) > 0) {
    786 		const u_int ipi = bit - 1;
    787 		switch (ipi) {
    788 		case IPI_AST:
    789 			pic_ipi_ast(priv);
    790 			break;
    791 		case IPI_NOP:
    792 			pic_ipi_nop(priv);
    793 			break;
    794 #ifdef __HAVE_PREEMPTION
    795 		case IPI_KPREEMPT:
    796 			pic_ipi_kpreempt(priv);
    797 			break;
    798 #endif
    799 		case IPI_XCALL:
    800 			pic_ipi_xcall(priv);
    801 			break;
    802 		case IPI_GENERIC:
    803 			pic_ipi_generic(priv);
    804 			break;
    805 		case IPI_SHOOTDOWN:
    806 			pic_ipi_shootdown(priv);
    807 			break;
    808 #ifdef DDB
    809 		case IPI_DDB:
    810 			pic_ipi_ddb(priv);
    811 			break;
    812 #endif
    813 		}
    814 		ipimask &= ~__BIT(ipi);
    815 	}
    816 
    817 	return 1;
    818 }
    819 #endif
    820 
    821 static void
    822 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
    823 {
    824 	const cpuid_t cpuid = ci->ci_core_id;
    825 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    826 
    827 	KASSERT(cpuid < BCM2836_NCPUS);
    828 
    829 #if defined(MULTIPROCESSOR)
    830 	pic->pic_cpus = ci->ci_kcpuset;
    831 
    832 	/*
    833 	 * Append "#n" to avoid duplication of .pic_name[]
    834 	 * It should be a unique id for intr_get_source()
    835 	 */
    836 	char suffix[sizeof("#00000")];
    837 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
    838 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
    839 #endif
    840 	bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
    841 
    842 #if defined(MULTIPROCESSOR)
    843 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    844 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    845 
    846 	struct bcm2836mp_interrupt *bip;
    847 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    848 		if (bip->bi_done)
    849 			continue;
    850 
    851 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
    852 		void *ih = intr_establish(irq, bip->bi_ipl,
    853 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
    854 
    855 		bip->bi_ihs[cpuid] = ih;
    856 	}
    857 #endif
    858 }
    859 
    860 static int
    861 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
    862 {
    863 
    864 	if (!specifier)
    865 		return -1;
    866 	return be32toh(specifier[0]);
    867 }
    868 
    869 static void *
    870 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    871     int (*func)(void *), void *arg, const char *xname)
    872 {
    873 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    874 	struct bcm2836mp_interrupt *bip;
    875 	void *ih;
    876 
    877 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    878 	if (irq == -1)
    879 		return NULL;
    880 
    881 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    882 		if (irq == bip->bi_irq)
    883 			return NULL;
    884 	}
    885 
    886 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
    887 	if (bip == NULL)
    888 		return NULL;
    889 
    890 	bip->bi_done = false;
    891 	bip->bi_irq = irq;
    892 	bip->bi_ipl = ipl;
    893 	bip->bi_flags = IST_LEVEL | iflags;
    894 	bip->bi_func = func;
    895 	bip->bi_arg = arg;
    896 
    897 	/*
    898 	 * If we're not cold and the BPs have been started then we can
    899 	 * register the interrupt for all CPUs now, e.g. PMU
    900 	 */
    901 	if (!cold) {
    902 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
    903 			ih = intr_establish_xname(
    904 			    BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
    905 			    IST_LEVEL | iflags, func, arg, xname);
    906 			if (!ih) {
    907 				kmem_free(bip, sizeof(*bip));
    908 				return NULL;
    909 			}
    910 			bip->bi_ihs[cpuid] = ih;
    911 
    912 		}
    913 		bip->bi_done = true;
    914 		ih = bip->bi_ihs[0];
    915 		goto done;
    916 	}
    917 
    918 	/*
    919 	 * Otherwise we can only establish the interrupt for the BP and
    920 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
    921 	 * gtmr
    922 	 */
    923 	ih = intr_establish_xname(BCM2836_INT_BASECPUN(0) + irq, ipl,
    924 	    IST_LEVEL | iflags, func, arg, xname);
    925 	if (!ih) {
    926 		kmem_free(bip, sizeof(*bip));
    927 		return NULL;
    928 	}
    929 
    930 	bip->bi_ihs[0] = ih;
    931 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
    932 		bip->bi_ihs[cpuid] = NULL;
    933 
    934 done:
    935 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
    936 
    937 	/*
    938 	 * Return the intr_establish handle for cpu 0 for API compatibility.
    939 	 * Any cpu would do here as these sources don't support set_affinity
    940 	 * when the handle is used in interrupt_distribute(9)
    941 	 */
    942 	return ih;
    943 }
    944 
    945 static void
    946 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
    947 {
    948 	struct bcm2836mp_interrupt *bip;
    949 
    950 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    951 		if (bip->bi_ihs[0] == ih)
    952 			break;
    953 	}
    954 
    955 	if (bip == NULL)
    956 		return;
    957 
    958 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
    959 		intr_disestablish(bip->bi_ihs[cpuid]);
    960 
    961 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
    962 
    963 	kmem_free(bip, sizeof(*bip));
    964 }
    965 
    966 static bool
    967 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
    968     size_t buflen)
    969 {
    970 	int irq;
    971 
    972 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    973 	if (irq == -1)
    974 		return false;
    975 
    976 	snprintf(buf, buflen, "local_intc irq %d", irq);
    977 
    978 	return true;
    979 }
    980