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