1 /* $NetBSD: gic.c,v 1.5 2013/12/17 13:12:45 joerg Exp $ */ 2 /*- 3 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Matt Thomas of 3am Software Foundry. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #define _INTR_PRIVATE 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.5 2013/12/17 13:12:45 joerg Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/device.h> 39 #include <sys/evcnt.h> 40 #include <sys/intr.h> 41 #include <sys/proc.h> 42 #include <sys/xcall.h> /* for xc_ipi_handler */ 43 44 #include <arm/armreg.h> 45 #include <arm/cpufunc.h> 46 #include <arm/atomic.h> 47 48 #include <arm/cortex/gic_reg.h> 49 #include <arm/cortex/mpcore_var.h> 50 51 #define ARMGIC_SGI_IPIBASE (16 - NIPI) 52 53 static int armgic_match(device_t, cfdata_t, void *); 54 static void armgic_attach(device_t, device_t, void *); 55 56 static void armgic_set_priority(struct pic_softc *, int); 57 static void armgic_unblock_irqs(struct pic_softc *, size_t, uint32_t); 58 static void armgic_block_irqs(struct pic_softc *, size_t, uint32_t); 59 static void armgic_establish_irq(struct pic_softc *, struct intrsource *); 60 #if 0 61 static void armgic_source_name(struct pic_softc *, int, char *, size_t); 62 #endif 63 64 #ifdef MULTIPROCESSOR 65 static void armgic_cpu_init(struct pic_softc *, struct cpu_info *); 66 static void armgic_ipi_send(struct pic_softc *, const kcpuset_t *, u_long); 67 #endif 68 69 static const struct pic_ops armgic_picops = { 70 .pic_unblock_irqs = armgic_unblock_irqs, 71 .pic_block_irqs = armgic_block_irqs, 72 .pic_establish_irq = armgic_establish_irq, 73 #if 0 74 .pic_source_name = armgic_source_name, 75 #endif 76 .pic_set_priority = armgic_set_priority, 77 #ifdef MULTIPROCESSOR 78 .pic_cpu_init = armgic_cpu_init, 79 .pic_ipi_send = armgic_ipi_send, 80 #endif 81 }; 82 83 #define PICTOSOFTC(pic) ((struct armgic_softc *)(pic)) 84 85 static struct armgic_softc { 86 struct pic_softc sc_pic; 87 device_t sc_dev; 88 bus_space_tag_t sc_memt; 89 bus_space_handle_t sc_gicch; 90 bus_space_handle_t sc_gicdh; 91 size_t sc_gic_lines; 92 uint32_t sc_gic_type; 93 uint32_t sc_gic_valid_lines[1024/32]; 94 uint32_t sc_enabled_local; 95 } armgic_softc = { 96 .sc_pic = { 97 .pic_ops = &armgic_picops, 98 .pic_name = "armgic", 99 }, 100 }; 101 102 static struct intrsource armgic_dummy_source; 103 104 __CTASSERT(NIPL == 8); 105 106 /* 107 * GIC register are always in little-endian. 108 */ 109 static inline uint32_t 110 gicc_read(struct armgic_softc *sc, bus_size_t o) 111 { 112 uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_gicch, o); 113 return le32toh(v); 114 } 115 116 static inline void 117 gicc_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) 118 { 119 v = htole32(v); 120 bus_space_write_4(sc->sc_memt, sc->sc_gicch, o, v); 121 } 122 123 static inline uint32_t 124 gicd_read(struct armgic_softc *sc, bus_size_t o) 125 { 126 uint32_t v = bus_space_read_4(sc->sc_memt, sc->sc_gicdh, o); 127 return le32toh(v); 128 } 129 130 static inline void 131 gicd_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) 132 { 133 v = htole32(v); 134 bus_space_write_4(sc->sc_memt, sc->sc_gicdh, o, v); 135 } 136 137 /* 138 * In the GIC prioritization scheme, lower numbers have higher priority. 139 */ 140 static inline uint32_t 141 armgic_ipl_to_priority(int ipl) 142 { 143 return (IPL_HIGH - ipl) * GICC_PMR_PRIORITIES / NIPL; 144 } 145 146 #if 0 147 static inline int 148 armgic_priority_to_ipl(uint32_t priority) 149 { 150 return IPL_HIGH - priority * NIPL / GICC_PMR_PRIORITIES; 151 } 152 #endif 153 154 static void 155 armgic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 156 { 157 struct armgic_softc * const sc = PICTOSOFTC(pic); 158 const size_t group = irq_base / 32; 159 160 if (group == 0) 161 sc->sc_enabled_local |= irq_mask; 162 163 gicd_write(sc, GICD_ISENABLERn(group), irq_mask); 164 } 165 166 static void 167 armgic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) 168 { 169 struct armgic_softc * const sc = PICTOSOFTC(pic); 170 const size_t group = irq_base / 32; 171 172 if (group == 0) 173 sc->sc_enabled_local &= ~irq_mask; 174 175 gicd_write(sc, GICD_ICENABLERn(group), irq_mask); 176 } 177 178 static uint32_t armgic_last_priority; 179 180 static void 181 armgic_set_priority(struct pic_softc *pic, int ipl) 182 { 183 struct armgic_softc * const sc = PICTOSOFTC(pic); 184 185 const uint32_t priority = armgic_ipl_to_priority(ipl); 186 gicc_write(sc, GICC_PMR, priority); 187 armgic_last_priority = priority; 188 } 189 190 #ifdef __HAVE_PIC_FAST_SOFTINTS 191 void 192 softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep_p) 193 { 194 lwp_t **lp = &l->l_cpu->ci_softlwps[level]; 195 KASSERT(*lp == NULL || *lp == l); 196 *lp = l; 197 /* 198 * Really easy. Just tell it to trigger the local CPU. 199 */ 200 *machdep_p = GICD_SGIR_TargetListFilter_Me 201 | __SHIFTIN(level, GICD_SGIR_SGIINTID); 202 } 203 204 void 205 softint_trigger(uintptr_t machdep) 206 { 207 208 gicd_write(&armgic_softc, GICD_SGIR, machdep); 209 } 210 #endif 211 212 void 213 armgic_irq_handler(void *tf) 214 { 215 struct cpu_info * const ci = curcpu(); 216 struct armgic_softc * const sc = &armgic_softc; 217 const int old_ipl = ci->ci_cpl; 218 #ifdef DIAGNOSTIC 219 const int old_mtx_count = ci->ci_mtx_count; 220 const int old_l_biglocks = ci->ci_curlwp->l_biglocks; 221 #endif 222 #ifdef DEBUG 223 size_t n = 0; 224 #endif 225 226 ci->ci_data.cpu_nintr++; 227 228 KASSERTMSG(old_ipl != IPL_HIGH, "old_ipl %d pmr %#x hppir %#x", 229 old_ipl, gicc_read(sc, GICC_PMR), gicc_read(sc, GICC_HPPIR)); 230 #if 0 231 printf("%s(enter): %s: pmr=%u hppir=%u\n", 232 __func__, ci->ci_data.cpu_name, 233 gicc_read(sc, GICC_PMR), 234 gicc_read(sc, GICC_HPPIR)); 235 #elif 0 236 printf("(%u:%d", ci->ci_index, old_ipl); 237 #endif 238 239 for (;;) { 240 uint32_t iar = gicc_read(sc, GICC_IAR); 241 uint32_t irq = __SHIFTOUT(iar, GICC_IAR_IRQ); 242 //printf(".%u", irq); 243 if (irq == GICC_IAR_IRQ_SPURIOUS) { 244 iar = gicc_read(sc, GICC_IAR); 245 irq = __SHIFTOUT(iar, GICC_IAR_IRQ); 246 if (irq == GICC_IAR_IRQ_SPURIOUS) 247 break; 248 //printf(".%u", irq); 249 } 250 251 //const uint32_t cpuid = __SHIFTOUT(iar, GICC_IAR_CPUID_MASK); 252 struct intrsource * const is = sc->sc_pic.pic_sources[irq]; 253 KASSERT(is != &armgic_dummy_source); 254 255 /* 256 * GIC has asserted IPL for us so we can just update ci_cpl. 257 * 258 * But it's not that simple. We may have already bumped ci_cpl 259 * due to a high priority interrupt and now we are about to 260 * dispatch one lower than the previous. It's possible for 261 * that previous interrupt to have deferred some interrupts 262 * so we need deal with those when lowering to the current 263 * interrupt's ipl. 264 * 265 * However, if are just raising ipl, we can just update ci_cpl. 266 */ 267 #if 0 268 const int ipl = armgic_priority_to_ipl(gicc_read(sc, GICC_RPR)); 269 KASSERTMSG(panicstr != NULL || ipl == is->is_ipl, 270 "%s: irq %d: running ipl %d != source ipl %u", 271 ci->ci_data.cpu_name, irq, ipl, is->is_ipl); 272 #else 273 const int ipl = is->is_ipl; 274 #endif 275 if (__predict_false(ipl < ci->ci_cpl)) { 276 //printf("<"); 277 pic_do_pending_ints(I32_bit, ipl, tf); 278 KASSERT(ci->ci_cpl == ipl); 279 } else { 280 KASSERTMSG(ipl > ci->ci_cpl, "ipl %d cpl %d hw-ipl %#x", 281 ipl, ci->ci_cpl, 282 gicc_read(sc, GICC_PMR)); 283 //printf(">"); 284 gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ipl)); 285 ci->ci_cpl = ipl; 286 } 287 //printf("$"); 288 cpsie(I32_bit); 289 pic_dispatch(is, tf); 290 cpsid(I32_bit); 291 gicc_write(sc, GICC_EOIR, iar); 292 #ifdef DEBUG 293 n++; 294 KDASSERTMSG(n < 5, "%s: processed too many (%zu)", 295 ci->ci_data.cpu_name, n); 296 #endif 297 } 298 299 // printf("%s(%p): exit (%zu dispatched)\n", __func__, tf, n); 300 /* 301 * Now handle any pending ints. 302 */ 303 //printf("!"); 304 KASSERT(old_ipl != IPL_HIGH); 305 pic_do_pending_ints(I32_bit, old_ipl, tf); 306 KASSERTMSG(ci->ci_cpl == old_ipl, "ci_cpl %d old_ipl %d", ci->ci_cpl, old_ipl); 307 KASSERT(old_mtx_count == ci->ci_mtx_count); 308 KASSERT(old_l_biglocks == ci->ci_curlwp->l_biglocks); 309 #if 0 310 printf("%s(exit): %s(%d): pmr=%u hppir=%u\n", 311 __func__, ci->ci_data.cpu_name, ci->ci_cpl, 312 gicc_read(sc, GICC_PMR), 313 gicc_read(sc, GICC_HPPIR)); 314 #elif 0 315 printf("->%#x)", ((struct trapframe *)tf)->tf_pc); 316 #endif 317 } 318 319 void 320 armgic_establish_irq(struct pic_softc *pic, struct intrsource *is) 321 { 322 struct armgic_softc * const sc = PICTOSOFTC(pic); 323 const size_t group = is->is_irq / 32; 324 const u_int irq = is->is_irq & 31; 325 const u_int byte_shift = 8 * (irq & 3); 326 const u_int twopair_shift = 2 * (irq & 15); 327 328 KASSERTMSG(sc->sc_gic_valid_lines[group] & __BIT(irq), 329 "irq %u: not valid (group[%zu]=0x%08x [0x%08x])", 330 is->is_irq, group, sc->sc_gic_valid_lines[group], 331 (uint32_t)__BIT(irq)); 332 333 KASSERTMSG(is->is_type == IST_LEVEL || is->is_type == IST_EDGE, 334 "irq %u: type %u unsupported", is->is_irq, is->is_type); 335 336 const bus_size_t targets_reg = GICD_ITARGETSRn(is->is_irq / 4); 337 const bus_size_t cfg_reg = GICD_ICFGRn(is->is_irq / 16); 338 uint32_t targets = gicd_read(sc, targets_reg); 339 uint32_t cfg = gicd_read(sc, cfg_reg); 340 341 if (group > 0) { 342 /* 343 * There are 4 irqs per TARGETS register. For now bind 344 * to the primary cpu. 345 */ 346 targets &= ~(0xff << byte_shift); 347 targets |= 1 << byte_shift; 348 gicd_write(sc, targets_reg, targets); 349 350 /* 351 * There are 16 irqs per CFG register. 10=EDGE 00=LEVEL 352 */ 353 uint32_t new_cfg = cfg; 354 uint32_t old_cfg = (cfg >> twopair_shift) & 3; 355 if (is->is_type == IST_LEVEL && (old_cfg & 2) != 0) { 356 new_cfg &= ~(3 << twopair_shift); 357 } else if (is->is_type == IST_EDGE && (old_cfg & 2) == 0) { 358 new_cfg |= 2 << twopair_shift; 359 } 360 if (new_cfg != cfg) { 361 gicd_write(sc, cfg_reg, cfg); 362 #if 0 363 printf("%s: irq %u: cfg changed from %#x to %#x\n", 364 pic->pic_name, is->is_irq, cfg, new_cfg); 365 #endif 366 } 367 } 368 369 /* 370 * There are 4 irqs per PRIORITY register. Map the IPL 371 * to GIC priority. 372 */ 373 const bus_size_t priority_reg = GICD_IPRIORITYRn(is->is_irq / 4); 374 uint32_t priority = gicd_read(sc, priority_reg); 375 priority &= ~(0xff << byte_shift); 376 priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; 377 gicd_write(sc, priority_reg, priority); 378 379 #if 0 380 printf("%s: irq %u: target %#x cfg %u priority %#x (%u)\n", 381 pic->pic_name, is->is_irq, (targets >> byte_shift) & 0xff, 382 (cfg >> twopair_shift) & 3, (priority >> byte_shift) & 0xff, 383 is->is_ipl); 384 #endif 385 } 386 387 #ifdef MULTIPROCESSOR 388 static void 389 armgic_cpu_init_priorities(struct armgic_softc *sc) 390 { 391 uint32_t enabled = sc->sc_enabled_local; 392 for (size_t i = 0; i < 32; i += 4, enabled >>= 4) { 393 /* 394 * If there are no enabled interrupts for the priority register, 395 * don't bother changing it. 396 */ 397 if ((enabled & 0x0f) == 0) 398 continue; 399 /* 400 * Since priorities are in 3210 order, it' 401 */ 402 const bus_size_t priority_reg = GICD_IPRIORITYRn(i / 4); 403 uint32_t priority = gicd_read(sc, priority_reg); 404 uint32_t byte_mask = 0xff; 405 size_t byte_shift = 0; 406 for (size_t j = 0; j < 4; j++, byte_mask <<= 8, byte_shift += 8) { 407 struct intrsource * const is = sc->sc_pic.pic_sources[i+j]; 408 if (is == NULL || is == &armgic_dummy_source) 409 continue; 410 priority &= ~byte_mask; 411 priority |= armgic_ipl_to_priority(is->is_ipl) << byte_shift; 412 } 413 gicd_write(sc, priority_reg, priority); 414 } 415 } 416 417 void 418 armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci) 419 { 420 struct armgic_softc * const sc = PICTOSOFTC(pic); 421 if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) { 422 armgic_cpu_init_priorities(sc); 423 } 424 KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); 425 gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ci->ci_cpl)); // set PMR 426 gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable interrupt 427 if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) 428 gicd_write(sc, GICD_ISENABLERn(0), sc->sc_enabled_local); 429 cpsie(I32_bit); // allow IRQ exceptions 430 } 431 432 void 433 armgic_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi) 434 { 435 struct armgic_softc * const sc = PICTOSOFTC(pic); 436 437 if (ipi == IPI_NOP) { 438 __asm __volatile("sev"); 439 return; 440 } 441 442 uint32_t targets; 443 kcpuset_export_u32(kcp, &targets, sizeof(targets)); 444 uint32_t sgir = __SHIFTOUT(ARMGIC_SGI_IPIBASE + ipi, GICD_SGIR_SGIINTID); 445 sgir |= __SHIFTOUT(targets, GICD_SGIR_TargetList); 446 447 printf("%s: %s: %#x", __func__, curcpu()->ci_data.cpu_name, sgir); 448 gicd_write(sc, GICD_SGIR, sgir); 449 printf("\n"); 450 } 451 #endif 452 453 int 454 armgic_match(device_t parent, cfdata_t cf, void *aux) 455 { 456 struct mpcore_attach_args * const mpcaa = aux; 457 458 if (strcmp(cf->cf_name, mpcaa->mpcaa_name) != 0) 459 return 0; 460 if (!CPU_ID_CORTEX_P(cputype) || CPU_ID_CORTEX_A8_P(cputype)) 461 return 0; 462 463 return 1; 464 } 465 466 void 467 armgic_attach(device_t parent, device_t self, void *aux) 468 { 469 struct armgic_softc * const sc = &armgic_softc; 470 struct mpcore_attach_args * const mpcaa = aux; 471 472 sc->sc_dev = self; 473 self->dv_private = sc; 474 475 sc->sc_memt = mpcaa->mpcaa_memt; /* provided for us */ 476 bus_space_subregion(sc->sc_memt, mpcaa->mpcaa_memh, mpcaa->mpcaa_off1, 477 4096, &sc->sc_gicdh); 478 bus_space_subregion(sc->sc_memt, mpcaa->mpcaa_memh, mpcaa->mpcaa_off2, 479 4096, &sc->sc_gicch); 480 481 sc->sc_gic_type = gicd_read(sc, GICD_TYPER); 482 sc->sc_pic.pic_maxsources = GICD_TYPER_LINES(sc->sc_gic_type); 483 484 gicc_write(sc, GICC_CTRL, 0); /* disable all interrupts */ 485 gicd_write(sc, GICD_CTRL, 0); /* disable all interrupts */ 486 487 gicc_write(sc, GICC_PMR, 0xff); 488 uint32_t pmr = gicc_read(sc, GICC_PMR); 489 u_int priorities = 1 << popcount32(pmr); 490 491 /* 492 * Let's find out how many real sources we have. 493 */ 494 for (size_t i = 0, group = 0; 495 i < sc->sc_pic.pic_maxsources; 496 i += 32, group++) { 497 /* 498 * To figure what sources are real, one enables all interrupts 499 * and then reads back the enable mask so which ones really 500 * got enabled. 501 */ 502 gicd_write(sc, GICD_ISENABLERn(group), 0xffffffff); 503 uint32_t valid = gicd_read(sc, GICD_ISENABLERn(group)); 504 505 /* 506 * Now disable (clear enable) them again. 507 */ 508 gicd_write(sc, GICD_ICENABLERn(group), valid); 509 510 /* 511 * Count how many are valid. 512 */ 513 sc->sc_gic_lines += popcount32(valid); 514 sc->sc_gic_valid_lines[group] = valid; 515 } 516 517 pic_add(&sc->sc_pic, 0); 518 519 /* 520 * Force the GICD to IPL_HIGH and then enable interrupts. 521 */ 522 struct cpu_info * const ci = curcpu(); 523 KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); 524 armgic_set_priority(&sc->sc_pic, ci->ci_cpl); // set PMR 525 gicd_write(sc, GICD_CTRL, GICD_CTRL_Enable); // enable Distributer 526 gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable CPU interrupts 527 cpsie(I32_bit); // allow interrupt exceptions 528 529 /* 530 * For each line that isn't valid, we set the intrsource for it to 531 * point at a dummy source so that pic_intr_establish will fail for it. 532 */ 533 for (size_t i = 0, group = 0; 534 i < sc->sc_pic.pic_maxsources; 535 i += 32, group++) { 536 uint32_t invalid = ~sc->sc_gic_valid_lines[group]; 537 for (size_t j = 0; invalid && j < 32; j++, invalid >>= 1) { 538 if (invalid & 1) { 539 sc->sc_pic.pic_sources[i + j] = 540 &armgic_dummy_source; 541 } 542 } 543 } 544 #ifdef __HAVE_PIC_FAST_SOFTINTS 545 intr_establish(SOFTINT_BIO, IPL_SOFTBIO, IST_EDGE, 546 pic_handle_softint, (void *)SOFTINT_BIO); 547 intr_establish(SOFTINT_CLOCK, IPL_SOFTCLOCK, IST_EDGE, 548 pic_handle_softint, (void *)SOFTINT_CLOCK); 549 intr_establish(SOFTINT_NET, IPL_SOFTNET, IST_EDGE, 550 pic_handle_softint, (void *)SOFTINT_NET); 551 intr_establish(SOFTINT_SERIAL, IPL_SOFTSERIAL, IST_EDGE, 552 pic_handle_softint, (void *)SOFTINT_SERIAL); 553 #endif 554 #ifdef MULTIPROCESSOR 555 intr_establish(ARMGIC_SGI_IPIBASE + IPI_AST, IPL_VM, IST_EDGE, 556 pic_ipi_nop, (void *)-1); 557 intr_establish(ARMGIC_SGI_IPIBASE + IPI_XCALL, IPL_VM, IST_EDGE, 558 pic_ipi_xcall, (void *)-1); 559 #if 0 /* Not needed */ 560 intr_establish(ARMGIC_SGI_IPIBASE + IPI_NOP, IPL_VM, IST_EDGE, 561 pic_ipi_nop, (void *)-1); 562 #endif 563 #ifdef __HAVE_PREEMPTION 564 intr_establish(ARMGIC_SGI_IPIBASE + IPI_KPREEMPT, IPL_VM, IST_EDGE, 565 pic_ipi_nop, (void *)-1); 566 #endif 567 armgic_cpu_init(&sc->sc_pic, curcpu()); 568 #endif 569 570 aprint_normal(": Generic Interrupt Controller, " 571 "%zu sources (%zu valid)\n", 572 sc->sc_pic.pic_maxsources, sc->sc_gic_lines); 573 574 const u_int ppis = popcount32(sc->sc_gic_valid_lines[0] >> 16); 575 const u_int sgis = popcount32(sc->sc_gic_valid_lines[0] & 0xffff); 576 aprint_normal_dev(sc->sc_dev, "%u Priorities, %zu SPIs, %u PPIs, %u SGIs\n", 577 priorities, sc->sc_gic_lines - ppis - sgis, ppis, sgis); 578 } 579 580 CFATTACH_DECL_NEW(armgic, 0, 581 armgic_match, armgic_attach, NULL, NULL); 582