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