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