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