Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.2.2.2
      1 /*	$NetBSD: bcm2835_intr.c,v 1.2.2.2 2017/12/03 11:35:52 jdolecek Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012, 2015 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.2.2.2 2017/12/03 11:35:52 jdolecek 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/proc.h>
     44 
     45 #include <machine/intr.h>
     46 
     47 #include <arm/locore.h>
     48 
     49 #include <arm/pic/picvar.h>
     50 #include <arm/cortex/gtmr_var.h>
     51 
     52 #include <arm/broadcom/bcm_amba.h>
     53 #include <arm/broadcom/bcm2835reg.h>
     54 #include <arm/broadcom/bcm2835var.h>
     55 
     56 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     57 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     58 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     59 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     60 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     61     size_t);
     62 
     63 #if defined(BCM2836)
     64 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     65 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     66 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     67 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     68 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     69     size_t);
     70 #ifdef MULTIPROCESSOR
     71 int bcm2836mp_ipi_handler(void *);
     72 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     73 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     74 #endif
     75 #endif
     76 
     77 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     78 static void bcm2835_icu_attach(device_t, device_t, void *);
     79 
     80 static struct pic_ops bcm2835_picops = {
     81 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     82 	.pic_block_irqs = bcm2835_pic_block_irqs,
     83 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     84 	.pic_establish_irq = bcm2835_pic_establish_irq,
     85 	.pic_source_name = bcm2835_pic_source_name,
     86 };
     87 
     88 struct pic_softc bcm2835_pic = {
     89 	.pic_ops = &bcm2835_picops,
     90 	.pic_maxsources = BCM2835_NIRQ,
     91 	.pic_name = "bcm2835 pic",
     92 };
     93 
     94 #if defined(BCM2836)
     95 static struct pic_ops bcm2836mp_picops = {
     96 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
     97 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
     98 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
     99 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    100 	.pic_source_name = bcm2836mp_pic_source_name,
    101 #if defined(MULTIPROCESSOR)
    102 	.pic_cpu_init = bcm2836mp_cpu_init,
    103 	.pic_ipi_send = bcm2836mp_send_ipi,
    104 #endif
    105 };
    106 
    107 struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
    108 	[0 ... BCM2836_NCPUS - 1] = {
    109 		.pic_ops = &bcm2836mp_picops,
    110 		.pic_maxsources = BCM2836_NIRQPERCPU,
    111 		.pic_name = "bcm2836 pic",
    112 	}
    113 };
    114 #endif
    115 
    116 struct bcm2835icu_softc {
    117 	device_t		sc_dev;
    118 	bus_space_tag_t		sc_iot;
    119 	bus_space_handle_t	sc_ioh;
    120 	struct pic_softc	*sc_pic;
    121 };
    122 
    123 struct bcm2835icu_softc *bcmicu_sc;
    124 
    125 #define read_bcm2835reg(o)	\
    126 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    127 
    128 #define write_bcm2835reg(o, v)	\
    129 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    130 
    131 
    132 #define bcm2835_barrier() \
    133 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    134 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    135 
    136 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    137 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    138 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    139 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    140 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    141 	"dma0",		"dma1",		"dma2",		"dma3",
    142 	"dma4",		"dma5",		"dma6",		"dma7",
    143 	"dma8",		"dma9",		"dma10",	"dma11",
    144 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    145 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    146 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    147 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    148 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    149 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    150 	"gpio[3]",	"i2c",		"spi",		"pcm",
    151 	"sdhost",	"uart",		"(unused 58)",	"(unused 59)",
    152 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    153 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    154 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    155 };
    156 
    157 #if defined(BCM2836)
    158 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
    159 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    160 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    161 };
    162 #endif
    163 
    164 #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    165 
    166 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    167 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    168 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    169 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    170 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    171 
    172 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    173     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    174 
    175 static int
    176 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    177 {
    178 	struct amba_attach_args *aaa = aux;
    179 
    180 	if (strcmp(aaa->aaa_name, "icu") != 0)
    181 		return 0;
    182 
    183 	return 1;
    184 }
    185 
    186 static void
    187 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    188 {
    189 	struct bcm2835icu_softc *sc = device_private(self);
    190 	struct amba_attach_args *aaa = aux;
    191 
    192 	sc->sc_dev = self;
    193 	sc->sc_iot = aaa->aaa_iot;
    194 	sc->sc_pic = &bcm2835_pic;
    195 
    196 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    197 	    &sc->sc_ioh)) {
    198 		aprint_error_dev(self, "unable to map device\n");
    199 		return;
    200 	}
    201 
    202 	bcmicu_sc = sc;
    203 
    204 #if defined(BCM2836)
    205 #if defined(MULTIPROCESSOR)
    206 	aprint_normal(": Multiprocessor");
    207 	bcm2836mp_intr_init(curcpu());
    208 #else
    209 	pic_add(&bcm2836mp_pic[0], BCM2836_INT_BASECPUN(0));
    210 #endif
    211 #endif /* BCM2836 */
    212 	pic_add(sc->sc_pic, BCM2835_INT_BASE);
    213 
    214 	aprint_normal("\n");
    215 }
    216 
    217 void
    218 bcm2835_irq_handler(void *frame)
    219 {
    220 	struct cpu_info * const ci = curcpu();
    221 	const int oldipl = ci->ci_cpl;
    222 	const cpuid_t cpuid = ci->ci_cpuid;
    223 	const uint32_t oldipl_mask = __BIT(oldipl);
    224 	int ipl_mask = 0;
    225 
    226 	ci->ci_data.cpu_nintr++;
    227 
    228 	bcm2835_barrier();
    229 	if (cpuid == 0) {
    230 		ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    231 	}
    232 #if defined(BCM2836)
    233 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
    234 #endif
    235 
    236 	/*
    237 	 * Record the pending_ipls and deliver them if we can.
    238 	 */
    239 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    240 		pic_do_pending_ints(I32_bit, oldipl, frame);
    241 }
    242 
    243 static void
    244 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    245     uint32_t irq_mask)
    246 {
    247 
    248 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    249 	bcm2835_barrier();
    250 }
    251 
    252 static void
    253 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    254     uint32_t irq_mask)
    255 {
    256 
    257 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    258 	bcm2835_barrier();
    259 }
    260 
    261 /*
    262  * Called with interrupts disabled
    263  */
    264 static int
    265 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    266 {
    267 	int ipl = 0;
    268 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    269 
    270 	bcm2835_barrier();
    271 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    272 	if (bpending == 0)
    273 		return 0;
    274 
    275 	armirq = bpending & BCM2835_INTBIT_ARM;
    276 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    277 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    278 
    279 	if (armirq) {
    280 		ipl |= pic_mark_pending_sources(pic,
    281 		    BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
    282 	}
    283 
    284 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    285 		uint32_t pending1;
    286 
    287 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    288 		ipl |= pic_mark_pending_sources(pic,
    289 		    BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
    290 	}
    291 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    292 		uint32_t pending2;
    293 
    294 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    295 		ipl |= pic_mark_pending_sources(pic,
    296 		    BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
    297 	}
    298 
    299 	return ipl;
    300 }
    301 
    302 static void
    303 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    304 {
    305 
    306 	/* Nothing really*/
    307 	KASSERT(is->is_irq < BCM2835_NIRQ);
    308 	KASSERT(is->is_type == IST_LEVEL);
    309 }
    310 
    311 static void
    312 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    313 {
    314 
    315 	strlcpy(buf, bcm2835_sources[irq], len);
    316 }
    317 
    318 
    319 #if defined(BCM2836)
    320 
    321 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    322 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,4)
    323 
    324 #define	BCM2836MP_ALL_IRQS	\
    325     (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
    326 
    327 static void
    328 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    329     uint32_t irq_mask)
    330 {
    331 	struct cpu_info * const ci = curcpu();
    332 	const cpuid_t cpuid = ci->ci_cpuid;
    333 
    334 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    335 	KASSERT(irqbase == 0);
    336 
    337 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    338 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    339 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    340 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    341 		val |= mask;
    342 		bus_space_write_4(al_iot, al_ioh,
    343 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    344 		    val);
    345 		bus_space_barrier(al_iot, al_ioh,
    346 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    347 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    348 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    349 	}
    350 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    351 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    352 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    353 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    354 		val |= mask;
    355 		bus_space_write_4(al_iot, al_ioh,
    356 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    357 		    val);
    358 		bus_space_barrier(al_iot, al_ioh,
    359 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    360 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    361 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    362 	}
    363 
    364 	return;
    365 }
    366 
    367 static void
    368 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    369     uint32_t irq_mask)
    370 {
    371 	struct cpu_info * const ci = curcpu();
    372 	const cpuid_t cpuid = ci->ci_cpuid;
    373 
    374 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    375 	KASSERT(irqbase == 0);
    376 
    377 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    378 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    379 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    380 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    381 		val &= ~mask;
    382 		bus_space_write_4(al_iot, al_ioh,
    383 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    384 		    val);
    385 	}
    386 	if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    387 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    388 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    389 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    390 		val &= ~mask;
    391 		bus_space_write_4(al_iot, al_ioh,
    392 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    393 		    val);
    394 	}
    395 
    396 	bcm2835_barrier();
    397 	return;
    398 }
    399 
    400 static int
    401 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    402 {
    403 	struct cpu_info * const ci = curcpu();
    404 	const cpuid_t cpuid = ci->ci_cpuid;
    405 	uint32_t lpending;
    406 	int ipl = 0;
    407 
    408 	KASSERT(pic == &bcm2836mp_pic[cpuid]);
    409 
    410 	bcm2835_barrier();
    411 
    412 	lpending = bus_space_read_4(al_iot, al_ioh,
    413 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    414 
    415 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    416 	if (lpending & BCM2836MP_ALL_IRQS) {
    417 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
    418 		    lpending & BCM2836MP_ALL_IRQS);
    419 	}
    420 
    421 	return ipl;
    422 }
    423 
    424 static void
    425 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    426 {
    427 	/* Nothing really*/
    428 	KASSERT(is->is_irq >= 0);
    429 	KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
    430 }
    431 
    432 static void
    433 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    434 {
    435 
    436 	irq %= BCM2836_NIRQPERCPU;
    437 	strlcpy(buf, bcm2836mp_sources[irq], len);
    438 }
    439 
    440 
    441 #ifdef MULTIPROCESSOR
    442 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
    443 {
    444 
    445 	/* Enable IRQ and not FIQ */
    446 	bus_space_write_4(al_iot, al_ioh,
    447 	    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
    448 }
    449 
    450 
    451 static void
    452 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
    453 {
    454 	KASSERT(pic != NULL);
    455 	KASSERT(pic != &bcm2835_pic);
    456 	KASSERT(pic->pic_cpus != NULL);
    457 
    458 	const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
    459 
    460 	bus_space_write_4(al_iot, al_ioh,
    461 	    BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
    462 }
    463 
    464 int
    465 bcm2836mp_ipi_handler(void *priv)
    466 {
    467 	const struct cpu_info *ci = curcpu();
    468 	const cpuid_t cpuid = ci->ci_cpuid;
    469 	uint32_t ipimask, bit;
    470 
    471 	ipimask = bus_space_read_4(al_iot, al_ioh,
    472 	    BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
    473 	bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_MAILBOX0_CLRN(cpuid),
    474 	    ipimask);
    475 
    476 	while ((bit = ffs(ipimask)) > 0) {
    477 		const u_int ipi = bit - 1;
    478 		switch (ipi) {
    479 		case IPI_AST:
    480 			pic_ipi_ast(priv);
    481 			break;
    482 		case IPI_NOP:
    483 			pic_ipi_nop(priv);
    484 			break;
    485 #ifdef __HAVE_PREEMPTION
    486 		case IPI_KPREEMPT:
    487 			pic_ipi_kpreempt(priv);
    488 			break;
    489 #endif
    490 		case IPI_XCALL:
    491 			pic_ipi_xcall(priv);
    492 			break;
    493 		case IPI_GENERIC:
    494 			pic_ipi_generic(priv);
    495 			break;
    496 		case IPI_SHOOTDOWN:
    497 			pic_ipi_shootdown(priv);
    498 			break;
    499 #ifdef DDB
    500 		case IPI_DDB:
    501 			pic_ipi_ddb(priv);
    502 			break;
    503 #endif
    504 		}
    505 		ipimask &= ~__BIT(ipi);
    506 	}
    507 
    508 	return 1;
    509 }
    510 
    511 void
    512 bcm2836mp_intr_init(struct cpu_info *ci)
    513 {
    514 	const cpuid_t cpuid = ci->ci_cpuid;
    515 	struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
    516 
    517 	pic->pic_cpus = ci->ci_kcpuset;
    518 	pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
    519 
    520 	intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
    521 	    IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
    522 
    523 	/* clock interrupt will attach with gtmr */
    524 	if (cpuid == 0)
    525 		return;
    526 
    527 	intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
    528 	    IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
    529 
    530 }
    531 #endif
    532 
    533 #endif
    534