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