bcm2835_intr.c revision 1.15 1 /* $NetBSD: bcm2835_intr.c,v 1.15 2017/12/10 21:38:26 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.15 2017/12/10 21:38:26 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/proc.h>
44
45 #include <dev/fdt/fdtvar.h>
46
47 #include <machine/intr.h>
48
49 #include <arm/locore.h>
50
51 #include <arm/pic/picvar.h>
52 #include <arm/cortex/gtmr_var.h>
53
54 #include <arm/broadcom/bcm2835_intr.h>
55 #include <arm/broadcom/bcm2835reg.h>
56 #include <arm/broadcom/bcm2835var.h>
57
58 #include <arm/fdt/arm_fdtvar.h>
59
60 static void bcm2835_irq_handler(void *);
61 static void bcm2836mp_intr_init(void *, struct cpu_info *);
62
63 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
64 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
65 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
66 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
67 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
68 size_t);
69
70 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
71 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
72 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
73 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
74 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
75 size_t);
76 #ifdef MULTIPROCESSOR
77 int bcm2836mp_ipi_handler(void *);
78 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
79 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
80 #endif
81
82 static int bcm2835_icu_fdt_decode_irq(u_int *);
83 static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
84 int (*)(void *), void *);
85 static void bcm2835_icu_fdt_disestablish(device_t, void *);
86 static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
87
88 static int bcm2836mp_icu_fdt_decode_irq(u_int *);
89 static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
90 int (*)(void *), void *);
91 static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
92 static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
93
94 static int bcm2835_icu_match(device_t, cfdata_t, void *);
95 static void bcm2835_icu_attach(device_t, device_t, void *);
96
97 static void
98 bcm2835_set_priority(struct pic_softc *pic, int ipl)
99 {
100 }
101
102 static struct pic_ops bcm2835_picops = {
103 .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
104 .pic_block_irqs = bcm2835_pic_block_irqs,
105 .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
106 .pic_establish_irq = bcm2835_pic_establish_irq,
107 .pic_source_name = bcm2835_pic_source_name,
108 .pic_set_priority = bcm2835_set_priority,
109 };
110
111 struct pic_softc bcm2835_pic = {
112 .pic_ops = &bcm2835_picops,
113 .pic_maxsources = BCM2835_NIRQ,
114 .pic_name = "bcm2835 pic",
115 };
116
117 static struct pic_ops bcm2836mp_picops = {
118 .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
119 .pic_block_irqs = bcm2836mp_pic_block_irqs,
120 .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
121 .pic_establish_irq = bcm2836mp_pic_establish_irq,
122 .pic_source_name = bcm2836mp_pic_source_name,
123 #if defined(MULTIPROCESSOR)
124 .pic_cpu_init = bcm2836mp_cpu_init,
125 .pic_ipi_send = bcm2836mp_send_ipi,
126 #endif
127 };
128
129 struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
130 [0 ... BCM2836_NCPUS - 1] = {
131 .pic_ops = &bcm2836mp_picops,
132 .pic_maxsources = BCM2836_NIRQPERCPU,
133 .pic_name = "bcm2836 pic",
134 }
135 };
136
137 static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
138 .establish = bcm2835_icu_fdt_establish,
139 .disestablish = bcm2835_icu_fdt_disestablish,
140 .intrstr = bcm2835_icu_fdt_intrstr
141 };
142
143 static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
144 .establish = bcm2836mp_icu_fdt_establish,
145 .disestablish = bcm2836mp_icu_fdt_disestablish,
146 .intrstr = bcm2836mp_icu_fdt_intrstr
147 };
148
149 struct bcm2835icu_softc {
150 device_t sc_dev;
151 bus_space_tag_t sc_iot;
152 bus_space_handle_t sc_ioh;
153
154 int sc_phandle;
155 };
156
157 struct bcm2835icu_softc *bcml1icu_sc;
158 struct bcm2835icu_softc *bcmicu_sc;
159
160 #define read_bcm2835reg(o) \
161 bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
162
163 #define write_bcm2835reg(o, v) \
164 bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
165
166
167 #define bcm2835_barrier() \
168 bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
169 BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
170
171 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
172 "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
173 "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
174 "(unused 8)", "usb", "(unused 10)", "(unused 11)",
175 "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
176 "dma0", "dma1", "dma2", "dma3",
177 "dma4", "dma5", "dma6", "dma7",
178 "dma8", "dma9", "dma10", "dma11",
179 "dma12", "aux", "(unused 30)", "(unused 31)",
180 "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
181 "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
182 "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
183 "(unused 44)", "pwa0", "pwa1", "(unused 47)",
184 "smi", "gpio[0]", "gpio[1]", "gpio[2]",
185 "gpio[3]", "i2c", "spi", "pcm",
186 "sdhost", "uart", "(unused 58)", "(unused 59)",
187 "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
188 "Timer", "Mailbox", "Doorbell0", "Doorbell1",
189 "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
190 };
191
192 static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
193 "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
194 "mailbox0", "mailbox1", "mailbox2", "mailbox3",
195 };
196
197 #define BCM2836_INTBIT_GPUPENDING __BIT(8)
198
199 #define BCM2835_INTBIT_PENDING1 __BIT(8)
200 #define BCM2835_INTBIT_PENDING2 __BIT(9)
201 #define BCM2835_INTBIT_ARM __BITS(0,7)
202 #define BCM2835_INTBIT_GPU0 __BITS(10,14)
203 #define BCM2835_INTBIT_GPU1 __BITS(15,20)
204
205 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
206 bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
207
208 static int
209 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
210 {
211 const char * const compatible[] = {
212 "brcm,bcm2708-armctrl-ic",
213 "brcm,bcm2709-armctrl-ic",
214 "brcm,bcm2835-armctrl-ic",
215 "brcm,bcm2836-armctrl-ic",
216 "brcm,bcm2836-l1-intc",
217 NULL
218 };
219 struct fdt_attach_args * const faa = aux;
220
221 return of_match_compatible(faa->faa_phandle, compatible);
222 }
223
224 static void
225 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
226 {
227 struct bcm2835icu_softc * const sc = device_private(self);
228 struct fdt_attach_args * const faa = aux;
229 struct fdtbus_interrupt_controller_func *ifuncs;
230 const int phandle = faa->faa_phandle;
231 bus_addr_t addr;
232 bus_size_t size;
233 bus_space_handle_t ioh;
234 int error;
235
236 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
237 aprint_error(": couldn't get registers\n");
238 return;
239 }
240
241 sc->sc_dev = self;
242 sc->sc_iot = faa->faa_bst;
243
244 if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
245 aprint_error(": couldn't map device\n");
246 return;
247 }
248
249 sc->sc_ioh = ioh;
250 sc->sc_phandle = phandle;
251
252 const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
253 if (of_match_compatible(faa->faa_phandle, local_intc)) {
254 #if defined(MULTIPROCESSOR)
255 aprint_normal(": Multiprocessor");
256 #endif
257 bcml1icu_sc = sc;
258
259 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
260 BCM2836_LOCAL_CONTROL, 0);
261 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
262 BCM2836_LOCAL_PRESCALER, 0x80000000);
263
264 ifuncs = &bcm2836mpicu_fdt_funcs;
265
266 bcm2836mp_intr_init(self, curcpu());
267 arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
268 } else {
269 if (bcml1icu_sc == NULL)
270 arm_fdt_irq_set_handler(bcm2835_irq_handler);
271 bcmicu_sc = sc;
272 sc->sc_ioh = ioh;
273 sc->sc_phandle = phandle;
274 pic_add(&bcm2835_pic, BCM2835_INT_BASE);
275 ifuncs = &bcm2835icu_fdt_funcs;
276 }
277
278 error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
279 if (error != 0) {
280 aprint_error(": couldn't register with fdtbus: %d\n", error);
281 return;
282 }
283 aprint_normal("\n");
284 }
285
286 static void
287 bcm2835_irq_handler(void *frame)
288 {
289 struct cpu_info * const ci = curcpu();
290 const int oldipl = ci->ci_cpl;
291 const cpuid_t cpuid = ci->ci_cpuid;
292 const uint32_t oldipl_mask = __BIT(oldipl);
293 int ipl_mask = 0;
294
295 ci->ci_data.cpu_nintr++;
296
297 bcm2835_barrier();
298 if (cpuid == 0) {
299 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
300 }
301 #if defined(SOC_BCM2836)
302 ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
303 #endif
304
305 /*
306 * Record the pending_ipls and deliver them if we can.
307 */
308 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
309 pic_do_pending_ints(I32_bit, oldipl, frame);
310 }
311
312 static void
313 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
314 uint32_t irq_mask)
315 {
316
317 write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
318 bcm2835_barrier();
319 }
320
321 static void
322 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
323 uint32_t irq_mask)
324 {
325
326 write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
327 bcm2835_barrier();
328 }
329
330 /*
331 * Called with interrupts disabled
332 */
333 static int
334 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
335 {
336 int ipl = 0;
337 uint32_t bpending, gpu0irq, gpu1irq, armirq;
338
339 bcm2835_barrier();
340 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
341 if (bpending == 0)
342 return 0;
343
344 armirq = bpending & BCM2835_INTBIT_ARM;
345 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
346 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
347
348 if (armirq) {
349 ipl |= pic_mark_pending_sources(pic,
350 BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
351 }
352
353 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
354 uint32_t pending1;
355
356 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
357 ipl |= pic_mark_pending_sources(pic,
358 BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
359 }
360 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
361 uint32_t pending2;
362
363 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
364 ipl |= pic_mark_pending_sources(pic,
365 BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
366 }
367
368 return ipl;
369 }
370
371 static void
372 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
373 {
374
375 /* Nothing really*/
376 KASSERT(is->is_irq < BCM2835_NIRQ);
377 KASSERT(is->is_type == IST_LEVEL);
378 }
379
380 static void
381 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
382 {
383
384 strlcpy(buf, bcm2835_sources[irq], len);
385 }
386
387 static int
388 bcm2835_icu_fdt_decode_irq(u_int *specifier)
389 {
390 u_int base;
391
392 if (!specifier)
393 return -1;
394
395 /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
396 /* 2nd cell is the irq relative to that bank */
397
398 const u_int bank = be32toh(specifier[0]);
399 switch (bank) {
400 case 0:
401 base = BCM2835_INT_BASICBASE;
402 break;
403 case 1:
404 base = BCM2835_INT_GPU0BASE;
405 break;
406 case 2:
407 base = BCM2835_INT_GPU1BASE;
408 break;
409 default:
410 return -1;
411 }
412 const u_int off = be32toh(specifier[1]);
413
414 return base + off;
415 }
416
417 static void *
418 bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
419 int (*func)(void *), void *arg)
420 {
421 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
422 int irq;
423
424 irq = bcm2835_icu_fdt_decode_irq(specifier);
425 if (irq == -1)
426 return NULL;
427
428 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
429 }
430
431 static void
432 bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
433 {
434 intr_disestablish(ih);
435 }
436
437 static bool
438 bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
439 {
440 int irq;
441
442 irq = bcm2835_icu_fdt_decode_irq(specifier);
443 if (irq == -1)
444 return false;
445
446 snprintf(buf, buflen, "icu irq %d", irq);
447
448 return true;
449 }
450
451 #define BCM2836MP_TIMER_IRQS __BITS(3,0)
452 #define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
453
454 #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
455
456 static void
457 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
458 uint32_t irq_mask)
459 {
460 struct cpu_info * const ci = curcpu();
461 const cpuid_t cpuid = ci->ci_cpuid;
462 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
463 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
464
465 KASSERT(pic == &bcm2836mp_pic[cpuid]);
466 KASSERT(irqbase == 0);
467
468 if (irq_mask & BCM2836MP_TIMER_IRQS) {
469 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
470 uint32_t val = bus_space_read_4(iot, ioh,
471 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
472 val |= mask;
473 bus_space_write_4(iot, ioh,
474 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
475 val);
476 bus_space_barrier(iot, ioh,
477 BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
478 BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
479 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
480 }
481 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
482 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
483 uint32_t val = bus_space_read_4(iot, ioh,
484 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
485 val |= mask;
486 bus_space_write_4(iot, ioh,
487 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
488 val);
489 bus_space_barrier(iot, ioh,
490 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
491 BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
492 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
493 }
494
495 return;
496 }
497
498 static void
499 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
500 uint32_t irq_mask)
501 {
502 struct cpu_info * const ci = curcpu();
503 const cpuid_t cpuid = ci->ci_cpuid;
504 const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
505 const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
506
507 KASSERT(pic == &bcm2836mp_pic[cpuid]);
508 KASSERT(irqbase == 0);
509
510 if (irq_mask & BCM2836MP_TIMER_IRQS) {
511 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
512 uint32_t val = bus_space_read_4(iot, ioh,
513 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
514 val &= ~mask;
515 bus_space_write_4(iot, ioh,
516 BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
517 val);
518 }
519 if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
520 uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
521 uint32_t val = bus_space_read_4(iot, ioh,
522 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
523 val &= ~mask;
524 bus_space_write_4(iot, ioh,
525 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
526 val);
527 }
528
529 bcm2835_barrier();
530 return;
531 }
532
533 static int
534 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
535 {
536 struct cpu_info * const ci = curcpu();
537 const cpuid_t cpuid = ci->ci_cpuid;
538 uint32_t lpending;
539 int ipl = 0;
540
541 KASSERT(pic == &bcm2836mp_pic[cpuid]);
542
543 bcm2835_barrier();
544
545 lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
546 BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
547
548 lpending &= ~BCM2836_INTBIT_GPUPENDING;
549 if (lpending & BCM2836MP_ALL_IRQS) {
550 ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
551 lpending & BCM2836MP_ALL_IRQS);
552 }
553
554 return ipl;
555 }
556
557 static void
558 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
559 {
560 /* Nothing really*/
561 KASSERT(is->is_irq >= 0);
562 KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
563 }
564
565 static void
566 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
567 {
568
569 irq %= BCM2836_NIRQPERCPU;
570 strlcpy(buf, bcm2836mp_sources[irq], len);
571 }
572
573
574 #if defined(MULTIPROCESSOR)
575 static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
576 {
577
578 /* Enable IRQ and not FIQ */
579 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
580 BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_cpuid), 1);
581 }
582
583 static void
584 bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
585 {
586 KASSERT(pic != NULL);
587 KASSERT(pic != &bcm2835_pic);
588 KASSERT(pic->pic_cpus != NULL);
589
590 const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
591
592 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
593 BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
594 }
595
596 int
597 bcm2836mp_ipi_handler(void *priv)
598 {
599 const struct cpu_info *ci = curcpu();
600 const cpuid_t cpuid = ci->ci_cpuid;
601 uint32_t ipimask, bit;
602
603 ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
604 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
605 bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
606 BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
607
608 while ((bit = ffs(ipimask)) > 0) {
609 const u_int ipi = bit - 1;
610 switch (ipi) {
611 case IPI_AST:
612 pic_ipi_ast(priv);
613 break;
614 case IPI_NOP:
615 pic_ipi_nop(priv);
616 break;
617 #ifdef __HAVE_PREEMPTION
618 case IPI_KPREEMPT:
619 pic_ipi_kpreempt(priv);
620 break;
621 #endif
622 case IPI_XCALL:
623 pic_ipi_xcall(priv);
624 break;
625 case IPI_GENERIC:
626 pic_ipi_generic(priv);
627 break;
628 case IPI_SHOOTDOWN:
629 pic_ipi_shootdown(priv);
630 break;
631 #ifdef DDB
632 case IPI_DDB:
633 pic_ipi_ddb(priv);
634 break;
635 #endif
636 }
637 ipimask &= ~__BIT(ipi);
638 }
639
640 return 1;
641 }
642 #endif
643
644 static void
645 bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
646 {
647 const cpuid_t cpuid = ci->ci_cpuid;
648 struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
649
650 #if defined(MULTIPROCESSOR)
651 pic->pic_cpus = ci->ci_kcpuset;
652 #endif
653 pic_add(pic, BCM2836_INT_BASECPUN(cpuid));
654
655 #if defined(MULTIPROCESSOR)
656 intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
657 IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
658 #endif
659 /* clock interrupt will attach with gtmr */
660 if (cpuid == 0)
661 return;
662 #if defined(SOC_BCM2836)
663 intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
664 IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
665
666 #endif
667 }
668
669 static int
670 bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
671 {
672 if (!specifier)
673 return -1;
674 return be32toh(specifier[0]) + BCM2836_INT_LOCALBASE;
675 }
676
677 static void *
678 bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
679 int (*func)(void *), void *arg)
680 {
681 int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
682 int irq;
683
684 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
685 if (irq == -1)
686 return NULL;
687
688 return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
689 }
690
691 static void
692 bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
693 {
694 intr_disestablish(ih);
695 }
696
697 static bool
698 bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
699 size_t buflen)
700 {
701 int irq;
702
703 irq = bcm2836mp_icu_fdt_decode_irq(specifier);
704 if (irq == -1)
705 return false;
706
707 snprintf(buf, buflen, "local_intc irq %d", irq);
708
709 return true;
710 }
711