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