Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.15.4.2
      1 /*	$NetBSD: bcm2835_intr.c,v 1.15.4.2 2020/04/08 14:07:28 martin 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.15.4.2 2020/04/08 14:07:28 martin 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 *);
     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 *);
     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 struct bcm2835icu_softc *bcml1icu_sc;
    206 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 int
    258 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    259 {
    260 	const char * const compatible[] = {
    261 	    "brcm,bcm2708-armctrl-ic",
    262 	    "brcm,bcm2709-armctrl-ic",
    263 	    "brcm,bcm2835-armctrl-ic",
    264 	    "brcm,bcm2836-armctrl-ic",
    265 	    "brcm,bcm2836-l1-intc",
    266 	    NULL
    267 	};
    268 	struct fdt_attach_args * const faa = aux;
    269 
    270 	return of_match_compatible(faa->faa_phandle, compatible);
    271 }
    272 
    273 static void
    274 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    275 {
    276 	struct bcm2835icu_softc * const sc = device_private(self);
    277 	struct fdt_attach_args * const faa = aux;
    278 	struct fdtbus_interrupt_controller_func *ifuncs;
    279 	const int phandle = faa->faa_phandle;
    280 	bus_addr_t addr;
    281 	bus_size_t size;
    282 	bus_space_handle_t ioh;
    283 	int error;
    284 
    285 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    286 		aprint_error(": couldn't get registers\n");
    287 		return;
    288 	}
    289 
    290 	sc->sc_dev = self;
    291 	sc->sc_iot = faa->faa_bst;
    292 
    293 	if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
    294 		aprint_error(": couldn't map device\n");
    295 		return;
    296 	}
    297 
    298 	sc->sc_ioh = ioh;
    299 	sc->sc_phandle = phandle;
    300 
    301 	const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
    302 	if (of_match_compatible(faa->faa_phandle, local_intc)) {
    303 #if defined(MULTIPROCESSOR)
    304 		aprint_normal(": Multiprocessor");
    305 #endif
    306 		bcml1icu_sc = sc;
    307 
    308 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    309 		    BCM2836_LOCAL_CONTROL, 0);
    310 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    311 		    BCM2836_LOCAL_PRESCALER, 0x80000000);
    312 
    313 		ifuncs = &bcm2836mpicu_fdt_funcs;
    314 
    315 		bcm2836mp_intr_init(self, curcpu());
    316 		arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
    317 	} else {
    318 		if (bcml1icu_sc == NULL)
    319 			arm_fdt_irq_set_handler(bcm2835_irq_handler);
    320 		bcmicu_sc = sc;
    321 		sc->sc_ioh = ioh;
    322 		sc->sc_phandle = phandle;
    323 		bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
    324 		ifuncs = &bcm2835icu_fdt_funcs;
    325 	}
    326 
    327 	error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
    328 	if (error != 0) {
    329 		aprint_error(": couldn't register with fdtbus: %d\n", error);
    330 		return;
    331 	}
    332 	aprint_normal("\n");
    333 }
    334 
    335 static void
    336 bcm2835_irq_handler(void *frame)
    337 {
    338 	struct cpu_info * const ci = curcpu();
    339 	const int oldipl = ci->ci_cpl;
    340 	const cpuid_t cpuid = ci->ci_core_id;
    341 	const uint32_t oldipl_mask = __BIT(oldipl);
    342 	int ipl_mask = 0;
    343 
    344 	ci->ci_data.cpu_nintr++;
    345 
    346 	bcm2835_barrier();
    347 	if (cpuid == 0) {
    348 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    349 	}
    350 #if defined(SOC_BCM2836)
    351 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    352 #endif
    353 
    354 	/*
    355 	 * Record the pending_ipls and deliver them if we can.
    356 	 */
    357 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    358 		pic_do_pending_ints(I32_bit, oldipl, frame);
    359 }
    360 
    361 static void
    362 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    363     uint32_t irq_mask)
    364 {
    365 
    366 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    367 	bcm2835_barrier();
    368 }
    369 
    370 static void
    371 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    372     uint32_t irq_mask)
    373 {
    374 
    375 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    376 	bcm2835_barrier();
    377 }
    378 
    379 /*
    380  * Called with interrupts disabled
    381  */
    382 static int
    383 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    384 {
    385 	int ipl = 0;
    386 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    387 
    388 	bcm2835_barrier();
    389 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    390 	if (bpending == 0)
    391 		return 0;
    392 
    393 	armirq = bpending & BCM2835_INTBIT_ARM;
    394 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    395 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    396 
    397 	if (armirq) {
    398 		ipl |= pic_mark_pending_sources(pic,
    399 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    400 	}
    401 
    402 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    403 		uint32_t pending1;
    404 
    405 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    406 		ipl |= pic_mark_pending_sources(pic,
    407 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    408 	}
    409 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    410 		uint32_t pending2;
    411 
    412 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    413 		ipl |= pic_mark_pending_sources(pic,
    414 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    415 	}
    416 
    417 	return ipl;
    418 }
    419 
    420 static void
    421 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    422 {
    423 
    424 	/* Nothing really*/
    425 	KASSERT(is->is_irq < BCM2835_NIRQ);
    426 	KASSERT(is->is_type == IST_LEVEL);
    427 }
    428 
    429 static void
    430 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    431 {
    432 
    433 	strlcpy(buf, bcm2835_sources[irq], len);
    434 }
    435 
    436 static int
    437 bcm2835_icu_fdt_decode_irq(u_int *specifier)
    438 {
    439 	u_int base;
    440 
    441 	if (!specifier)
    442 		return -1;
    443 
    444 	/* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
    445 	/* 2nd cell is the irq relative to that bank */
    446 
    447 	const u_int bank = be32toh(specifier[0]);
    448 	switch (bank) {
    449 	case 0:
    450 		base = BCM2835_INT_BASICBASE;
    451 		break;
    452 	case 1:
    453 		base = BCM2835_INT_GPU0BASE;
    454 		break;
    455 	case 2:
    456 		base = BCM2835_INT_GPU1BASE;
    457 		break;
    458 	default:
    459 		return -1;
    460 	}
    461 	const u_int off = be32toh(specifier[1]);
    462 
    463 	return base + off;
    464 }
    465 
    466 static void *
    467 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    468     int (*func)(void *), void *arg)
    469 {
    470 	struct bcm2835icu_softc * const sc = device_private(dev);
    471 	struct bcm2835icu_irq *firq;
    472 	struct bcm2835icu_irqhandler *firqh;
    473 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    474 	int irq, irqidx;
    475 
    476 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    477 	if (irq == -1)
    478 		return NULL;
    479 	irqidx = irq - BCM2835_INT_BASE;
    480 
    481 	KASSERT(irqidx < BCM2835_NIRQ);
    482 
    483 	firq = sc->sc_irq[irqidx];
    484 	if (firq == NULL) {
    485 		firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
    486 		firq->intr_sc = sc;
    487 		firq->intr_refcnt = 0;
    488 		firq->intr_arg = arg;
    489 		firq->intr_ipl = ipl;
    490 		firq->intr_mpsafe = iflags;
    491 		firq->intr_irq = irq;
    492 		TAILQ_INIT(&firq->intr_handlers);
    493 		if (arg == NULL) {
    494 			firq->intr_ih = intr_establish(irq, ipl,
    495 			    IST_LEVEL | iflags, func, NULL);
    496 		} else {
    497 			firq->intr_ih = intr_establish(irq, ipl,
    498 			    IST_LEVEL | iflags, bcm2835_icu_intr, firq);
    499 		}
    500 		if (firq->intr_ih == NULL) {
    501 			kmem_free(firq, sizeof(*firq));
    502 			return NULL;
    503 		}
    504 		sc->sc_irq[irqidx] = firq;
    505 	} else {
    506 		if (firq->intr_arg == NULL || arg == NULL) {
    507 			device_printf(dev,
    508 			    "cannot share irq with NULL-arg handler\n");
    509 			return NULL;
    510 		}
    511 		if (firq->intr_ipl != ipl) {
    512 			device_printf(dev,
    513 			    "cannot share irq with different ipl\n");
    514 			return NULL;
    515 		}
    516 		if (firq->intr_mpsafe != iflags) {
    517 			device_printf(dev,
    518 			    "cannot share irq between mpsafe/non-mpsafe\n");
    519 			return NULL;
    520 		}
    521 	}
    522 
    523 	firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
    524 	firqh->ih_irq = firq;
    525 	firqh->ih_fn = func;
    526 	firqh->ih_arg = arg;
    527 
    528 	firq->intr_refcnt++;
    529 	TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
    530 
    531 	/*
    532 	 * XXX interrupt_distribute(9) assumes that any interrupt
    533 	 * handle can be used as an input to the MD interrupt_distribute
    534 	 * implementationm, so we are forced to return the handle
    535 	 * we got back from intr_establish().  Upshot is that the
    536 	 * input to bcm2835_icu_fdt_disestablish() is ambiguous for
    537 	 * shared IRQs, rendering them un-disestablishable.
    538 	 */
    539 
    540 	return firq->intr_ih;
    541 }
    542 
    543 static void
    544 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
    545 {
    546 	struct bcm2835icu_softc * const sc = device_private(dev);
    547 	struct bcm2835icu_irqhandler *firqh;
    548 	struct bcm2835icu_irq *firq;
    549 	u_int n;
    550 
    551 	for (n = 0; n < BCM2835_NIRQ; n++) {
    552 		firq = sc->sc_irq[n];
    553 		if (firq == NULL || firq->intr_ih != ih)
    554 			continue;
    555 
    556 		KASSERT(firq->intr_refcnt > 0);
    557 		KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
    558 
    559 		/* XXX see above */
    560 		if (firq->intr_refcnt > 1)
    561 			panic("%s: cannot disestablish shared irq", __func__);
    562 
    563 		intr_disestablish(firq->intr_ih);
    564 
    565 		firqh = TAILQ_FIRST(&firq->intr_handlers);
    566 		TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
    567 		kmem_free(firqh, sizeof(*firqh));
    568 
    569 		sc->sc_irq[n] = NULL;
    570 		kmem_free(firq, sizeof(*firq));
    571 
    572 		return;
    573 	}
    574 
    575 	panic("%s: interrupt not established", __func__);
    576 }
    577 
    578 static int
    579 bcm2835_icu_intr(void *priv)
    580 {
    581 	struct bcm2835icu_irq *firq = priv;
    582 	struct bcm2835icu_irqhandler *firqh;
    583 	int handled = 0;
    584 
    585 	TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
    586 		handled |= firqh->ih_fn(firqh->ih_arg);
    587 	}
    588 
    589 	return handled;
    590 }
    591 
    592 static bool
    593 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
    594 {
    595 	int irq;
    596 
    597 	irq = bcm2835_icu_fdt_decode_irq(specifier);
    598 	if (irq == -1)
    599 		return false;
    600 
    601 	snprintf(buf, buflen, "icu irq %d", irq);
    602 
    603 	return true;
    604 }
    605 
    606 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    607 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,7)
    608 #define	BCM2836MP_GPU_IRQ	__BIT(8)
    609 #define	BCM2836MP_PMU_IRQ	__BIT(9)
    610 #define	BCM2836MP_ALL_IRQS	(BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
    611 
    612 static void
    613 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    614     uint32_t irq_mask)
    615 {
    616 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    617 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    618 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    619 
    620 	KASSERT(irqbase == 0);
    621 
    622 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    623 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    624 		uint32_t val = bus_space_read_4(iot, ioh,
    625 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    626 		val |= mask;
    627 		bus_space_write_4(iot, ioh,
    628 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    629 		    val);
    630 		bus_space_barrier(iot, ioh,
    631 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    632 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    633 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    634 	}
    635 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    636 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    637 		uint32_t val = bus_space_read_4(iot, ioh,
    638 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    639 		val |= mask;
    640 		bus_space_write_4(iot, ioh,
    641 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    642 		    val);
    643 		bus_space_barrier(iot, ioh,
    644 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    645 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    646 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    647 	}
    648 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    649 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
    650 		    __BIT(cpuid));
    651 		bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
    652 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    653 	}
    654 
    655 	return;
    656 }
    657 
    658 static void
    659 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    660     uint32_t irq_mask)
    661 {
    662 	const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
    663 	const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
    664 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    665 
    666 	KASSERT(irqbase == 0);
    667 
    668 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    669 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    670 		uint32_t val = bus_space_read_4(iot, ioh,
    671 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    672 		val &= ~mask;
    673 		bus_space_write_4(iot, ioh,
    674 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    675 		    val);
    676 	}
    677 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    678 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    679 		uint32_t val = bus_space_read_4(iot, ioh,
    680 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    681 		val &= ~mask;
    682 		bus_space_write_4(iot, ioh,
    683 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    684 		    val);
    685 	}
    686 	if (irq_mask & BCM2836MP_PMU_IRQ) {
    687 		bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
    688 		     __BIT(cpuid));
    689 	}
    690 
    691 	bcm2835_barrier();
    692 	return;
    693 }
    694 
    695 static int
    696 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    697 {
    698 	struct cpu_info * const ci = curcpu();
    699 	const cpuid_t cpuid = ci->ci_core_id;
    700 	uint32_t lpending;
    701 	int ipl = 0;
    702 
    703 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    704 
    705 	bcm2835_barrier();
    706 
    707 	lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    708 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    709 
    710 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    711 	const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
    712 	if (allirqs) {
    713 		ipl |= pic_mark_pending_sources(pic, 0, allirqs);
    714 	}
    715 
    716 	return ipl;
    717 }
    718 
    719 static void
    720 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    721 {
    722 	/* Nothing really*/
    723 	KASSERT(is->is_irq >= 0);
    724 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    725 }
    726 
    727 static void
    728 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    729 {
    730 
    731 	irq %= BCM2836_NIRQPERCPU;
    732 	strlcpy(buf, bcm2836mp_sources[irq], len);
    733 }
    734 
    735 
    736 #if defined(MULTIPROCESSOR)
    737 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    738 {
    739 
    740 	/* Enable IRQ and not FIQ */
    741 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    742 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
    743 }
    744 
    745 static void
    746 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    747 {
    748 	KASSERT(pic != NULL);
    749 	KASSERT(pic != &bcm2835_pic);
    750 	KASSERT(pic->pic_cpus != NULL);
    751 
    752 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    753 
    754 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    755 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    756 }
    757 
    758 int
    759 bcm2836mp_ipi_handler(void *priv)
    760 {
    761 	const struct cpu_info *ci = curcpu();
    762 	const cpuid_t cpuid = ci->ci_core_id;
    763 	uint32_t ipimask, bit;
    764 
    765 	ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    766 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    767 	bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
    768 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
    769 
    770 	while ((bit = ffs(ipimask)) > 0) {
    771 		const u_int ipi = bit - 1;
    772 		switch (ipi) {
    773 		case IPI_AST:
    774 			pic_ipi_ast(priv);
    775 			break;
    776 		case IPI_NOP:
    777 			pic_ipi_nop(priv);
    778 			break;
    779 #ifdef __HAVE_PREEMPTION
    780 		case IPI_KPREEMPT:
    781 			pic_ipi_kpreempt(priv);
    782 			break;
    783 #endif
    784 		case IPI_XCALL:
    785 			pic_ipi_xcall(priv);
    786 			break;
    787 		case IPI_GENERIC:
    788 			pic_ipi_generic(priv);
    789 			break;
    790 		case IPI_SHOOTDOWN:
    791 			pic_ipi_shootdown(priv);
    792 			break;
    793 #ifdef DDB
    794 		case IPI_DDB:
    795 			pic_ipi_ddb(priv);
    796 			break;
    797 #endif
    798 		}
    799 		ipimask &= ~__BIT(ipi);
    800 	}
    801 
    802 	return 1;
    803 }
    804 #endif
    805 
    806 static void
    807 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
    808 {
    809 	const cpuid_t cpuid = ci->ci_core_id;
    810 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    811 
    812 #if defined(MULTIPROCESSOR)
    813 	pic->pic_cpus = ci->ci_kcpuset;
    814 
    815 	/*
    816 	 * Append "#n" to avoid duplication of .pic_name[]
    817 	 * It should be a unique id for intr_get_source()
    818 	 */
    819 	char suffix[sizeof("#00000")];
    820 	snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
    821 	strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
    822 #endif
    823 	bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
    824 
    825 #if defined(MULTIPROCESSOR)
    826 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    827 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    828 
    829 	struct bcm2836mp_interrupt *bip;
    830 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    831 		if (bip->bi_done)
    832 			continue;
    833 
    834 		const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
    835 		void *ih = intr_establish(irq, bip->bi_ipl,
    836 		    IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
    837 
    838 		bip->bi_ihs[cpuid] = ih;
    839 	}
    840 #endif
    841 }
    842 
    843 static int
    844 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
    845 {
    846 	if (!specifier)
    847 		return -1;
    848 	return be32toh(specifier[0]);
    849 }
    850 
    851 static void *
    852 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
    853     int (*func)(void *), void *arg)
    854 {
    855 	int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
    856 	struct bcm2836mp_interrupt *bip;
    857 	void *ih;
    858 
    859 	int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    860 	if (irq == -1)
    861 		return NULL;
    862 
    863 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    864 		if (irq == bip->bi_irq)
    865 			return NULL;
    866 	}
    867 
    868 	bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
    869 	if (bip == NULL)
    870 		return NULL;
    871 
    872 	bip->bi_done = false;
    873 	bip->bi_irq = irq;
    874 	bip->bi_ipl = ipl;
    875 	bip->bi_flags = IST_LEVEL | iflags;
    876 	bip->bi_func = func;
    877 	bip->bi_arg = arg;
    878 
    879 	/*
    880 	 * If we're not cold and the BPs have been started then we can register the
    881 	 * interupt for all CPUs now, e.g. PMU
    882 	 */
    883 	if (!cold) {
    884 		for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
    885 			ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
    886 			    IST_LEVEL | iflags, func, arg);
    887 			if (!ih) {
    888 				kmem_free(bip, sizeof(*bip));
    889 				return NULL;
    890 			}
    891 			bip->bi_ihs[cpuid] = ih;
    892 
    893 		}
    894 		bip->bi_done = true;
    895 		ih = bip->bi_ihs[0];
    896 		goto done;
    897 	}
    898 
    899 	/*
    900 	 * Otherwise we can only establish the interrupt for the BP and
    901 	 * delay until bcm2836mp_intr_init is called for each AP, e.g.
    902 	 * gtmr
    903 	 */
    904 	ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
    905 	    IST_LEVEL | iflags, func, arg);
    906 	if (!ih) {
    907 		kmem_free(bip, sizeof(*bip));
    908 		return NULL;
    909 	}
    910 
    911 	bip->bi_ihs[0] = ih;
    912 	for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
    913 		bip->bi_ihs[cpuid] = NULL;
    914 
    915 done:
    916 	TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
    917 
    918 	/*
    919 	 * Return the intr_establish handle for cpu 0 for API compatibility.
    920 	 * Any cpu would do here as these sources don't support set_affinity
    921 	 * when the handle is used in interrupt_distribute(9)
    922 	 */
    923 	return ih;
    924 }
    925 
    926 static void
    927 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
    928 {
    929 	struct bcm2836mp_interrupt *bip;
    930 
    931 	TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
    932 		if (bip->bi_ihs[0] == ih)
    933 			break;
    934 	}
    935 
    936 	if (bip == NULL)
    937 		return;
    938 
    939 	for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
    940 		intr_disestablish(bip->bi_ihs[cpuid]);
    941 
    942 	TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
    943 
    944 	kmem_free(bip, sizeof(*bip));
    945 }
    946 
    947 static bool
    948 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
    949     size_t buflen)
    950 {
    951 	int irq;
    952 
    953 	irq = bcm2836mp_icu_fdt_decode_irq(specifier);
    954 	if (irq == -1)
    955 		return false;
    956 
    957 	snprintf(buf, buflen, "local_intc irq %d", irq);
    958 
    959 	return true;
    960 }
    961