bcm2835_intr.c revision 1.21 1 /* $NetBSD: bcm2835_intr.c,v 1.21 2019/09/25 16:48:06 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.21 2019/09/25 16:48:06 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 bcm2836mp_icu_fdt_decode_irq(u_int *);
91 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
92 int (*)(void *), void *);
93 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
94 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
95
96 static int bcm2835_icu_match(device_t, cfdata_t, void *);
97 static void bcm2835_icu_attach(device_t, device_t, void *);
98
99 static void
100 bcm2835_set_priority(struct pic_softc *pic, int ipl)
101 {
102 }
103
104 static struct pic_ops bcm2835_picops = {
105 .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
106 .pic_block_irqs = bcm2835_pic_block_irqs,
107 .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
108 .pic_establish_irq = bcm2835_pic_establish_irq,
109 .pic_source_name = bcm2835_pic_source_name,
110 .pic_set_priority = bcm2835_set_priority,
111 };
112
113 static struct pic_softc bcm2835_pic = {
114 .pic_ops = &bcm2835_picops,
115 .pic_maxsources = BCM2835_NIRQ,
116 .pic_name = "bcm2835 pic",
117 };
118
119 static struct pic_ops bcm2836mp_picops = {
120 .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
121 .pic_block_irqs = bcm2836mp_pic_block_irqs,
122 .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
123 .pic_establish_irq = bcm2836mp_pic_establish_irq,
124 .pic_source_name = bcm2836mp_pic_source_name,
125 #if defined(MULTIPROCESSOR)
126 .pic_cpu_init = bcm2836mp_cpu_init,
127 .pic_ipi_send = bcm2836mp_send_ipi,
128 #endif
129 };
130
131 static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
132 [0 ... BCM2836_NCPUS - 1] = {
133 .pic_ops = &bcm2836mp_picops,
134 .pic_maxsources = BCM2836_NIRQPERCPU,
135 .pic_name = "bcm2836 pic",
136 }
137 };
138
139 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
140 .establish = bcm2835_icu_fdt_establish,
141 .disestablish = bcm2835_icu_fdt_disestablish,
142 .intrstr = bcm2835_icu_fdt_intrstr
143 };
144
145 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
146 .establish = bcm2836mp_icu_fdt_establish,
147 .disestablish = bcm2836mp_icu_fdt_disestablish,
148 .intrstr = bcm2836mp_icu_fdt_intrstr
149 };
150
151 struct bcm2836mp_interrupt {
152 bool bi_done;
153 TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
154 int bi_irq;
155 int bi_ipl;
156 int bi_flags;
157 int (*bi_func)(void *);
158 void *bi_arg;
159 void *bi_ihs[BCM2836_NCPUS];
160 };
161
162 static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
163 TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
164
165 struct bcm2835icu_softc {
166 device_t sc_dev;
167 bus_space_tag_t sc_iot;
168 bus_space_handle_t sc_ioh;
169
170 int sc_phandle;
171 };
172
173 struct bcm2835icu_softc *bcml1icu_sc;
174 struct bcm2835icu_softc *bcmicu_sc;
175
176 #define read_bcm2835reg(o) \
177 bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
178
179 #define write_bcm2835reg(o, v) \
180 bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
181
182
183 #define bcm2835_barrier() \
184 bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
185 BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
186
187 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
188 "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
189 "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
190 "(unused 8)", "usb", "(unused 10)", "(unused 11)",
191 "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
192 "dma0", "dma1", "dma2", "dma3",
193 "dma4", "dma5", "dma6", "dma7",
194 "dma8", "dma9", "dma10", "dma11",
195 "dma12", "aux", "(unused 30)", "(unused 31)",
196 "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
197 "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
198 "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
199 "(unused 44)", "pwa0", "pwa1", "(unused 47)",
200 "smi", "gpio[0]", "gpio[1]", "gpio[2]",
201 "gpio[3]", "i2c", "spi", "pcm",
202 "sdhost", "uart", "(unused 58)", "(unused 59)",
203 "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
204 "Timer", "Mailbox", "Doorbell0", "Doorbell1",
205 "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
206 };
207
208 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
209 "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
210 "mailbox0", "mailbox1", "mailbox2", "mailbox3",
211 "gpu", "pmu"
212 };
213
214 #define BCM2836_INTBIT_GPUPENDING __BIT(8)
215
216 #define BCM2835_INTBIT_PENDING1 __BIT(8)
217 #define BCM2835_INTBIT_PENDING2 __BIT(9)
218 #define BCM2835_INTBIT_ARM __BITS(0,7)
219 #define BCM2835_INTBIT_GPU0 __BITS(10,14)
220 #define BCM2835_INTBIT_GPU1 __BITS(15,20)
221
222 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
223 bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
224
225 static int
226 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
227 {
228 const char * const compatible[] = {
229 "brcm,bcm2708-armctrl-ic",
230 "brcm,bcm2709-armctrl-ic",
231 "brcm,bcm2835-armctrl-ic",
232 "brcm,bcm2836-armctrl-ic",
233 "brcm,bcm2836-l1-intc",
234 NULL
235 };
236 struct fdt_attach_args * const faa = aux;
237
238 return of_match_compatible(faa->faa_phandle, compatible);
239 }
240
241 static void
242 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
243 {
244 struct bcm2835icu_softc * const sc = device_private(self);
245 struct fdt_attach_args * const faa = aux;
246 struct fdtbus_interrupt_controller_func *ifuncs;
247 const int phandle = faa->faa_phandle;
248 bus_addr_t addr;
249 bus_size_t size;
250 bus_space_handle_t ioh;
251 int error;
252
253 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
254 aprint_error(": couldn't get registers\n");
255 return;
256 }
257
258 sc->sc_dev = self;
259 sc->sc_iot = faa->faa_bst;
260
261 if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
262 aprint_error(": couldn't map device\n");
263 return;
264 }
265
266 sc->sc_ioh = ioh;
267 sc->sc_phandle = phandle;
268
269 const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
270 if (of_match_compatible(faa->faa_phandle, local_intc)) {
271 #if defined(MULTIPROCESSOR)
272 aprint_normal(": Multiprocessor");
273 #endif
274 bcml1icu_sc = sc;
275
276 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
277 BCM2836_LOCAL_CONTROL, 0);
278 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
279 BCM2836_LOCAL_PRESCALER, 0x80000000);
280
281 ifuncs = &bcm2836mpicu_fdt_funcs;
282
283 bcm2836mp_intr_init(self, curcpu());
284 arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
285 } else {
286 if (bcml1icu_sc == NULL)
287 arm_fdt_irq_set_handler(bcm2835_irq_handler);
288 bcmicu_sc = sc;
289 sc->sc_ioh = ioh;
290 sc->sc_phandle = phandle;
291 pic_add(&bcm2835_pic, BCM2835_INT_BASE);
292 ifuncs = &bcm2835icu_fdt_funcs;
293 }
294
295 error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
296 if (error != 0) {
297 aprint_error(": couldn't register with fdtbus: %d\n", error);
298 return;
299 }
300 aprint_normal("\n");
301 }
302
303 static void
304 bcm2835_irq_handler(void *frame)
305 {
306 struct cpu_info * const ci = curcpu();
307 const int oldipl = ci->ci_cpl;
308 const cpuid_t cpuid = ci->ci_core_id;
309 const uint32_t oldipl_mask = __BIT(oldipl);
310 int ipl_mask = 0;
311
312 ci->ci_data.cpu_nintr++;
313
314 bcm2835_barrier();
315 if (cpuid == 0) {
316 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
317 }
318 #if defined(SOC_BCM2836)
319 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
320 #endif
321
322 /*
323 * Record the pending_ipls and deliver them if we can.
324 */
325 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
326 pic_do_pending_ints(I32_bit, oldipl, frame);
327 }
328
329 static void
330 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
331 uint32_t irq_mask)
332 {
333
334 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
335 bcm2835_barrier();
336 }
337
338 static void
339 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
340 uint32_t irq_mask)
341 {
342
343 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
344 bcm2835_barrier();
345 }
346
347 /*
348 * Called with interrupts disabled
349 */
350 static int
351 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
352 {
353 int ipl = 0;
354 uint32_t bpending, gpu0irq, gpu1irq, armirq;
355
356 bcm2835_barrier();
357 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
358 if (bpending == 0)
359 return 0;
360
361 armirq = bpending & BCM2835_INTBIT_ARM;
362 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
363 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
364
365 if (armirq) {
366 ipl |= pic_mark_pending_sources(pic,
367 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
368 }
369
370 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
371 uint32_t pending1;
372
373 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
374 ipl |= pic_mark_pending_sources(pic,
375 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
376 }
377 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
378 uint32_t pending2;
379
380 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
381 ipl |= pic_mark_pending_sources(pic,
382 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
383 }
384
385 return ipl;
386 }
387
388 static void
389 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
390 {
391
392 /* Nothing really*/
393 KASSERT(is->is_irq < BCM2835_NIRQ);
394 KASSERT(is->is_type == IST_LEVEL);
395 }
396
397 static void
398 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
399 {
400
401 strlcpy(buf, bcm2835_sources[irq], len);
402 }
403
404 static int
405 bcm2835_icu_fdt_decode_irq(u_int *specifier)
406 {
407 u_int base;
408
409 if (!specifier)
410 return -1;
411
412 /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
413 /* 2nd cell is the irq relative to that bank */
414
415 const u_int bank = be32toh(specifier[0]);
416 switch (bank) {
417 case 0:
418 base = BCM2835_INT_BASICBASE;
419 break;
420 case 1:
421 base = BCM2835_INT_GPU0BASE;
422 break;
423 case 2:
424 base = BCM2835_INT_GPU1BASE;
425 break;
426 default:
427 return -1;
428 }
429 const u_int off = be32toh(specifier[1]);
430
431 return base + off;
432 }
433
434 static void *
435 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
436 int (*func)(void *), void *arg)
437 {
438 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
439 int irq;
440
441 irq = bcm2835_icu_fdt_decode_irq(specifier);
442 if (irq == -1)
443 return NULL;
444
445 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
446 }
447
448 static void
449 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
450 {
451 intr_disestablish(ih);
452 }
453
454 static bool
455 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
456 {
457 int irq;
458
459 irq = bcm2835_icu_fdt_decode_irq(specifier);
460 if (irq == -1)
461 return false;
462
463 snprintf(buf, buflen, "icu irq %d", irq);
464
465 return true;
466 }
467
468 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
469 #define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
470 #define BCM2836MP_GPU_IRQ __BIT(8)
471 #define BCM2836MP_PMU_IRQ __BIT(9)
472 #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
473
474 static void
475 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
476 uint32_t irq_mask)
477 {
478 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
479 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
480 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
481
482 KASSERT(irqbase == 0);
483
484 if (irq_mask & BCM2836MP_TIMER_IRQS) {
485 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
486 uint32_t val = bus_space_read_4(iot, ioh,
487 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
488 val |= mask;
489 bus_space_write_4(iot, ioh,
490 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
491 val);
492 bus_space_barrier(iot, ioh,
493 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
494 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
495 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
496 }
497 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
498 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
499 uint32_t val = bus_space_read_4(iot, ioh,
500 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
501 val |= mask;
502 bus_space_write_4(iot, ioh,
503 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
504 val);
505 bus_space_barrier(iot, ioh,
506 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
507 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
508 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
509 }
510 if (irq_mask & BCM2836MP_PMU_IRQ) {
511 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
512 __BIT(cpuid));
513 bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
514 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
515 }
516
517 return;
518 }
519
520 static void
521 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
522 uint32_t irq_mask)
523 {
524 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
525 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
526 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
527
528 KASSERT(irqbase == 0);
529
530 if (irq_mask & BCM2836MP_TIMER_IRQS) {
531 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
532 uint32_t val = bus_space_read_4(iot, ioh,
533 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
534 val &= ~mask;
535 bus_space_write_4(iot, ioh,
536 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
537 val);
538 }
539 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
540 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
541 uint32_t val = bus_space_read_4(iot, ioh,
542 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
543 val &= ~mask;
544 bus_space_write_4(iot, ioh,
545 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
546 val);
547 }
548 if (irq_mask & BCM2836MP_PMU_IRQ) {
549 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
550 __BIT(cpuid));
551 }
552
553 bcm2835_barrier();
554 return;
555 }
556
557 static int
558 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
559 {
560 struct cpu_info * const ci = curcpu();
561 const cpuid_t cpuid = ci->ci_core_id;
562 uint32_t lpending;
563 int ipl = 0;
564
565 KASSERT(pic == &bcm2836mp_pic[cpuid]);
566
567 bcm2835_barrier();
568
569 lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
570 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
571
572 lpending &= ~BCM2836_INTBIT_GPUPENDING;
573 if (lpending & BCM2836MP_ALL_IRQS) {
574 ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
575 lpending & BCM2836MP_ALL_IRQS);
576 }
577
578 return ipl;
579 }
580
581 static void
582 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
583 {
584 /* Nothing really*/
585 KASSERT(is->is_irq >= 0);
586 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
587 }
588
589 static void
590 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
591 {
592
593 irq %= BCM2836_NIRQPERCPU;
594 strlcpy(buf, bcm2836mp_sources[irq], len);
595 }
596
597
598 #if defined(MULTIPROCESSOR)
599 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
600 {
601
602 /* Enable IRQ and not FIQ */
603 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
604 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
605 }
606
607 static void
608 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
609 {
610 KASSERT(pic != NULL);
611 KASSERT(pic != &bcm2835_pic);
612 KASSERT(pic->pic_cpus != NULL);
613
614 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
615
616 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
617 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
618 }
619
620 int
621 bcm2836mp_ipi_handler(void *priv)
622 {
623 const struct cpu_info *ci = curcpu();
624 const cpuid_t cpuid = ci->ci_core_id;
625 uint32_t ipimask, bit;
626
627 ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
628 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
629 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
630 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
631
632 while ((bit = ffs(ipimask)) > 0) {
633 const u_int ipi = bit - 1;
634 switch (ipi) {
635 case IPI_AST:
636 pic_ipi_ast(priv);
637 break;
638 case IPI_NOP:
639 pic_ipi_nop(priv);
640 break;
641 #ifdef __HAVE_PREEMPTION
642 case IPI_KPREEMPT:
643 pic_ipi_kpreempt(priv);
644 break;
645 #endif
646 case IPI_XCALL:
647 pic_ipi_xcall(priv);
648 break;
649 case IPI_GENERIC:
650 pic_ipi_generic(priv);
651 break;
652 case IPI_SHOOTDOWN:
653 pic_ipi_shootdown(priv);
654 break;
655 #ifdef DDB
656 case IPI_DDB:
657 pic_ipi_ddb(priv);
658 break;
659 #endif
660 }
661 ipimask &= ~__BIT(ipi);
662 }
663
664 return 1;
665 }
666 #endif
667
668 static void
669 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
670 {
671 const cpuid_t cpuid = ci->ci_core_id;
672 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
673
674 #if defined(MULTIPROCESSOR)
675 pic->pic_cpus = ci->ci_kcpuset;
676
677 /*
678 * Append "#n" to avoid duplication of .pic_name[]
679 * It should be a unique id for intr_get_source()
680 */
681 char suffix[sizeof("#00000")];
682 snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
683 strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
684 #endif
685 pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
686
687 #if defined(MULTIPROCESSOR)
688 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
689 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
690
691 struct bcm2836mp_interrupt *bip;
692 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
693 if (bip->bi_done)
694 continue;
695
696 const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
697 void *ih = intr_establish(irq, bip->bi_ipl,
698 IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
699
700 bip->bi_ihs[cpuid] = ih;
701 }
702 #endif
703 }
704
705 static int
706 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
707 {
708 if (!specifier)
709 return -1;
710 return be32toh(specifier[0]);
711 }
712
713 static void *
714 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
715 int (*func)(void *), void *arg)
716 {
717 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
718 struct bcm2836mp_interrupt *bip;
719 void *ih;
720
721 int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
722 if (irq == -1)
723 return NULL;
724
725 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
726 if (irq == bip->bi_irq)
727 return NULL;
728 }
729
730 bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
731 if (bip == NULL)
732 return NULL;
733
734 bip->bi_done = false;
735 bip->bi_irq = irq;
736 bip->bi_ipl = ipl;
737 bip->bi_flags = IST_LEVEL | iflags;
738 bip->bi_func = func;
739 bip->bi_arg = arg;
740
741 /*
742 * If we're not cold and the BPs have been started then we can register the
743 * interupt for all CPUs now, e.g. PMU
744 */
745 if (!cold) {
746 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
747 ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
748 IST_LEVEL | iflags, func, arg);
749 if (!ih) {
750 kmem_free(bip, sizeof(*bip));
751 return NULL;
752 }
753 bip->bi_ihs[cpuid] = ih;
754
755 }
756 bip->bi_done = true;
757 ih = bip->bi_ihs[0];
758 goto done;
759 }
760
761 /*
762 * Otherwise we can only establish the interrupt for the BP and
763 * delay until bcm2836mp_intr_init is called for each AP, e.g.
764 * gtmr
765 */
766 ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
767 IST_LEVEL | iflags, func, arg);
768 if (!ih) {
769 kmem_free(bip, sizeof(*bip));
770 return NULL;
771 }
772
773 bip->bi_ihs[0] = ih;
774 for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
775 bip->bi_ihs[cpuid] = NULL;
776
777 done:
778 TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
779
780 /*
781 * Return the intr_establish handle for cpu 0 for API compatibility.
782 * Any cpu would do here as these sources don't support set_affinity
783 * when the handle is used in interrupt_distribute(9)
784 */
785 return ih;
786 }
787
788 static void
789 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
790 {
791 struct bcm2836mp_interrupt *bip;
792
793 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
794 if (bip->bi_ihs[0] == ih)
795 break;
796 }
797
798 if (bip == NULL)
799 return;
800
801 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
802 intr_disestablish(bip->bi_ihs[cpuid]);
803
804 TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
805
806 kmem_free(bip, sizeof(*bip));
807 }
808
809 static bool
810 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
811 size_t buflen)
812 {
813 int irq;
814
815 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
816 if (irq == -1)
817 return false;
818
819 snprintf(buf, buflen, "local_intc irq %d", irq);
820
821 return true;
822 }
823