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