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