bcm2835_intr.c revision 1.24 1 /* $NetBSD: bcm2835_intr.c,v 1.24 2019/09/25 16:57:10 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.24 2019/09/25 16:57:10 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 static struct bcm2835icu_softc *bcml1icu_sc;
174 static 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 KASSERT(cpuid < BCM2836_NCPUS);
313
314 ci->ci_data.cpu_nintr++;
315
316 bcm2835_barrier();
317 if (cpuid == 0) {
318 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
319 }
320 #if defined(SOC_BCM2836)
321 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
322 #endif
323
324 /*
325 * Record the pending_ipls and deliver them if we can.
326 */
327 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
328 pic_do_pending_ints(I32_bit, oldipl, frame);
329 }
330
331 static void
332 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
333 uint32_t irq_mask)
334 {
335
336 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
337 bcm2835_barrier();
338 }
339
340 static void
341 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
342 uint32_t irq_mask)
343 {
344
345 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
346 bcm2835_barrier();
347 }
348
349 /*
350 * Called with interrupts disabled
351 */
352 static int
353 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
354 {
355 int ipl = 0;
356 uint32_t bpending, gpu0irq, gpu1irq, armirq;
357
358 bcm2835_barrier();
359 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
360 if (bpending == 0)
361 return 0;
362
363 armirq = bpending & BCM2835_INTBIT_ARM;
364 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
365 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
366
367 if (armirq) {
368 ipl |= pic_mark_pending_sources(pic,
369 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
370 }
371
372 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
373 uint32_t pending1;
374
375 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
376 ipl |= pic_mark_pending_sources(pic,
377 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
378 }
379 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
380 uint32_t pending2;
381
382 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
383 ipl |= pic_mark_pending_sources(pic,
384 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
385 }
386
387 return ipl;
388 }
389
390 static void
391 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
392 {
393
394 /* Nothing really*/
395 KASSERT(is->is_irq < BCM2835_NIRQ);
396 KASSERT(is->is_type == IST_LEVEL);
397 }
398
399 static void
400 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
401 {
402
403 strlcpy(buf, bcm2835_sources[irq], len);
404 }
405
406 static int
407 bcm2835_icu_fdt_decode_irq(u_int *specifier)
408 {
409 u_int base;
410
411 if (!specifier)
412 return -1;
413
414 /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
415 /* 2nd cell is the irq relative to that bank */
416
417 const u_int bank = be32toh(specifier[0]);
418 switch (bank) {
419 case 0:
420 base = BCM2835_INT_BASICBASE;
421 break;
422 case 1:
423 base = BCM2835_INT_GPU0BASE;
424 break;
425 case 2:
426 base = BCM2835_INT_GPU1BASE;
427 break;
428 default:
429 return -1;
430 }
431 const u_int off = be32toh(specifier[1]);
432
433 return base + off;
434 }
435
436 static void *
437 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
438 int (*func)(void *), void *arg)
439 {
440 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
441 int irq;
442
443 irq = bcm2835_icu_fdt_decode_irq(specifier);
444 if (irq == -1)
445 return NULL;
446
447 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
448 }
449
450 static void
451 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
452 {
453 intr_disestablish(ih);
454 }
455
456 static bool
457 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
458 {
459 int irq;
460
461 irq = bcm2835_icu_fdt_decode_irq(specifier);
462 if (irq == -1)
463 return false;
464
465 snprintf(buf, buflen, "icu irq %d", irq);
466
467 return true;
468 }
469
470 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
471 #define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
472 #define BCM2836MP_GPU_IRQ __BIT(8)
473 #define BCM2836MP_PMU_IRQ __BIT(9)
474 #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
475
476 static void
477 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
478 uint32_t irq_mask)
479 {
480 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
481 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
482 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
483
484 KASSERT(cpuid < BCM2836_NCPUS);
485 KASSERT(irqbase == 0);
486
487 if (irq_mask & BCM2836MP_TIMER_IRQS) {
488 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
489 uint32_t val = bus_space_read_4(iot, ioh,
490 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
491 val |= mask;
492 bus_space_write_4(iot, ioh,
493 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
494 val);
495 bus_space_barrier(iot, ioh,
496 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
497 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
498 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
499 }
500 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
501 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
502 uint32_t val = bus_space_read_4(iot, ioh,
503 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
504 val |= mask;
505 bus_space_write_4(iot, ioh,
506 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
507 val);
508 bus_space_barrier(iot, ioh,
509 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
510 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
511 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
512 }
513 if (irq_mask & BCM2836MP_PMU_IRQ) {
514 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
515 __BIT(cpuid));
516 bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
517 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
518 }
519
520 return;
521 }
522
523 static void
524 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
525 uint32_t irq_mask)
526 {
527 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
528 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
529 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
530
531 KASSERT(cpuid < BCM2836_NCPUS);
532 KASSERT(irqbase == 0);
533
534 if (irq_mask & BCM2836MP_TIMER_IRQS) {
535 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
536 uint32_t val = bus_space_read_4(iot, ioh,
537 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
538 val &= ~mask;
539 bus_space_write_4(iot, ioh,
540 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
541 val);
542 }
543 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
544 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
545 uint32_t val = bus_space_read_4(iot, ioh,
546 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
547 val &= ~mask;
548 bus_space_write_4(iot, ioh,
549 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
550 val);
551 }
552 if (irq_mask & BCM2836MP_PMU_IRQ) {
553 bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
554 __BIT(cpuid));
555 }
556
557 bcm2835_barrier();
558 return;
559 }
560
561 static int
562 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
563 {
564 struct cpu_info * const ci = curcpu();
565 const cpuid_t cpuid = ci->ci_core_id;
566 uint32_t lpending;
567 int ipl = 0;
568
569 KASSERT(cpuid < BCM2836_NCPUS);
570 KASSERT(pic == &bcm2836mp_pic[cpuid]);
571
572 bcm2835_barrier();
573
574 lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
575 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
576
577 lpending &= ~BCM2836_INTBIT_GPUPENDING;
578 if (lpending & BCM2836MP_ALL_IRQS) {
579 ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
580 lpending & BCM2836MP_ALL_IRQS);
581 }
582
583 return ipl;
584 }
585
586 static void
587 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
588 {
589 /* Nothing really*/
590 KASSERT(is->is_irq >= 0);
591 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
592 }
593
594 static void
595 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
596 {
597
598 irq %= BCM2836_NIRQPERCPU;
599 strlcpy(buf, bcm2836mp_sources[irq], len);
600 }
601
602
603 #if defined(MULTIPROCESSOR)
604 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
605 {
606 const cpuid_t cpuid = ci->ci_core_id;
607
608 KASSERT(cpuid < BCM2836_NCPUS);
609
610 /* Enable IRQ and not FIQ */
611 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
612 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid), 1);
613 }
614
615 static void
616 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
617 {
618 KASSERT(pic != NULL);
619 KASSERT(pic != &bcm2835_pic);
620 KASSERT(pic->pic_cpus != NULL);
621
622 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
623 KASSERT(cpuid < BCM2836_NCPUS);
624
625 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
626 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
627 }
628
629 int
630 bcm2836mp_ipi_handler(void *priv)
631 {
632 const struct cpu_info *ci = curcpu();
633 const cpuid_t cpuid = ci->ci_core_id;
634 uint32_t ipimask, bit;
635
636 KASSERT(cpuid < BCM2836_NCPUS);
637
638 ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
639 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
640 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
641 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
642
643 while ((bit = ffs(ipimask)) > 0) {
644 const u_int ipi = bit - 1;
645 switch (ipi) {
646 case IPI_AST:
647 pic_ipi_ast(priv);
648 break;
649 case IPI_NOP:
650 pic_ipi_nop(priv);
651 break;
652 #ifdef __HAVE_PREEMPTION
653 case IPI_KPREEMPT:
654 pic_ipi_kpreempt(priv);
655 break;
656 #endif
657 case IPI_XCALL:
658 pic_ipi_xcall(priv);
659 break;
660 case IPI_GENERIC:
661 pic_ipi_generic(priv);
662 break;
663 case IPI_SHOOTDOWN:
664 pic_ipi_shootdown(priv);
665 break;
666 #ifdef DDB
667 case IPI_DDB:
668 pic_ipi_ddb(priv);
669 break;
670 #endif
671 }
672 ipimask &= ~__BIT(ipi);
673 }
674
675 return 1;
676 }
677 #endif
678
679 static void
680 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
681 {
682 const cpuid_t cpuid = ci->ci_core_id;
683 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
684
685 KASSERT(cpuid < BCM2836_NCPUS);
686
687 #if defined(MULTIPROCESSOR)
688 pic->pic_cpus = ci->ci_kcpuset;
689
690 /*
691 * Append "#n" to avoid duplication of .pic_name[]
692 * It should be a unique id for intr_get_source()
693 */
694 char suffix[sizeof("#00000")];
695 snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
696 strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
697 #endif
698 pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
699
700 #if defined(MULTIPROCESSOR)
701 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
702 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
703
704 struct bcm2836mp_interrupt *bip;
705 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
706 if (bip->bi_done)
707 continue;
708
709 const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
710 void *ih = intr_establish(irq, bip->bi_ipl,
711 IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
712
713 bip->bi_ihs[cpuid] = ih;
714 }
715 #endif
716 }
717
718 static int
719 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
720 {
721
722 if (!specifier)
723 return -1;
724 return be32toh(specifier[0]);
725 }
726
727 static void *
728 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
729 int (*func)(void *), void *arg)
730 {
731 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
732 struct bcm2836mp_interrupt *bip;
733 void *ih;
734
735 int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
736 if (irq == -1)
737 return NULL;
738
739 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
740 if (irq == bip->bi_irq)
741 return NULL;
742 }
743
744 bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
745 if (bip == NULL)
746 return NULL;
747
748 bip->bi_done = false;
749 bip->bi_irq = irq;
750 bip->bi_ipl = ipl;
751 bip->bi_flags = IST_LEVEL | iflags;
752 bip->bi_func = func;
753 bip->bi_arg = arg;
754
755 /*
756 * If we're not cold and the BPs have been started then we can register the
757 * interupt for all CPUs now, e.g. PMU
758 */
759 if (!cold) {
760 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
761 ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
762 IST_LEVEL | iflags, func, arg);
763 if (!ih) {
764 kmem_free(bip, sizeof(*bip));
765 return NULL;
766 }
767 bip->bi_ihs[cpuid] = ih;
768
769 }
770 bip->bi_done = true;
771 ih = bip->bi_ihs[0];
772 goto done;
773 }
774
775 /*
776 * Otherwise we can only establish the interrupt for the BP and
777 * delay until bcm2836mp_intr_init is called for each AP, e.g.
778 * gtmr
779 */
780 ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
781 IST_LEVEL | iflags, func, arg);
782 if (!ih) {
783 kmem_free(bip, sizeof(*bip));
784 return NULL;
785 }
786
787 bip->bi_ihs[0] = ih;
788 for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
789 bip->bi_ihs[cpuid] = NULL;
790
791 done:
792 TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
793
794 /*
795 * Return the intr_establish handle for cpu 0 for API compatibility.
796 * Any cpu would do here as these sources don't support set_affinity
797 * when the handle is used in interrupt_distribute(9)
798 */
799 return ih;
800 }
801
802 static void
803 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
804 {
805 struct bcm2836mp_interrupt *bip;
806
807 TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
808 if (bip->bi_ihs[0] == ih)
809 break;
810 }
811
812 if (bip == NULL)
813 return;
814
815 for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
816 intr_disestablish(bip->bi_ihs[cpuid]);
817
818 TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
819
820 kmem_free(bip, sizeof(*bip));
821 }
822
823 static bool
824 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
825 size_t buflen)
826 {
827 int irq;
828
829 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
830 if (irq == -1)
831 return false;
832
833 snprintf(buf, buflen, "local_intc irq %d", irq);
834
835 return true;
836 }
837