xref: /netbsd/sys/arch/arm/broadcom/bcm2835_intr.c (revision 68447a06)
1 /*	$NetBSD: bcm2835_intr.c,v 1.29 2019/12/26 11:09:11 skrll 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.29 2019/12/26 11:09:11 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/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 register the
895 	 * interupt 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