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