1 /* $OpenBSD: openpic.c,v 1.65 2011/08/29 20:21:44 drahn Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org> 5 * Copyright (c) 1995 Per Fogelstrom 6 * Copyright (c) 1993, 1994 Charles M. Hannum. 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * William Jolitz and Don Ahn. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)isa.c 7.2 (Berkeley) 5/12/91 38 */ 39 40 #include <sys/param.h> 41 #include <sys/device.h> 42 #include <sys/ioctl.h> 43 #include <sys/mbuf.h> 44 #include <sys/socket.h> 45 #include <sys/systm.h> 46 47 #include <uvm/uvm.h> 48 #include <ddb/db_var.h> 49 50 #include <machine/atomic.h> 51 #include <machine/autoconf.h> 52 #include <machine/intr.h> 53 #include <machine/psl.h> 54 #include <machine/pio.h> 55 #include <machine/powerpc.h> 56 #include <macppc/dev/openpicreg.h> 57 #include <dev/ofw/openfirm.h> 58 59 #define ICU_LEN 128 60 int openpic_numirq = ICU_LEN; 61 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) 62 63 int openpic_pri_share[IPL_NUM]; 64 65 struct intrq openpic_handler[ICU_LEN]; 66 67 void openpic_calc_mask(void); 68 69 ppc_splraise_t openpic_splraise; 70 ppc_spllower_t openpic_spllower; 71 ppc_splx_t openpic_splx; 72 73 /* IRQ vector used for inter-processor interrupts. */ 74 #define IPI_VECTOR_NOP 64 75 #define IPI_VECTOR_DDB 65 76 #ifdef MULTIPROCESSOR 77 static struct evcount ipi_ddb[PPC_MAXPROCS]; 78 static struct evcount ipi_nop[PPC_MAXPROCS]; 79 static int ipi_nopirq = IPI_VECTOR_NOP; 80 static int ipi_ddbirq = IPI_VECTOR_DDB; 81 #endif 82 struct evcount openpic_spurious; 83 int openpic_spurious_irq = 255; 84 85 void openpic_enable_irq(int, int); 86 void openpic_disable_irq(int); 87 void openpic_init(void); 88 void openpic_set_priority(int, int); 89 void openpic_ipi_ddb(void); 90 void *openpic_intr_establish(void *, int, int, int, int (*)(void *), 91 void *, const char *); 92 93 typedef void (void_f) (void); 94 extern void_f *pending_int_f; 95 96 vaddr_t openpic_base; 97 void openpic_intr_disestablish( void *lcp, void *arg); 98 void openpic_collect_preconf_intr(void); 99 int openpic_big_endian; 100 #ifdef MULTIPROCESSOR 101 intr_send_ipi_t openpic_send_ipi; 102 #endif 103 104 u_int openpic_read(int reg); 105 void openpic_write(int reg, u_int val); 106 107 struct openpic_softc { 108 struct device sc_dev; 109 }; 110 111 int openpic_match(struct device *parent, void *cf, void *aux); 112 void openpic_attach(struct device *, struct device *, void *); 113 void openpic_do_pending_int(int pcpl); 114 void openpic_do_pending_int_dis(int pcpl, int s); 115 void openpic_collect_preconf_intr(void); 116 void openpic_ext_intr(void); 117 118 struct cfattach openpic_ca = { 119 sizeof(struct openpic_softc), 120 openpic_match, 121 openpic_attach 122 }; 123 124 struct cfdriver openpic_cd = { 125 NULL, "openpic", DV_DULL 126 }; 127 128 u_int 129 openpic_read(int reg) 130 { 131 char *addr = (void *)(openpic_base + reg); 132 133 asm volatile("eieio"::: "memory"); 134 if (openpic_big_endian) 135 return in32(addr); 136 else 137 return in32rb(addr); 138 } 139 140 void 141 openpic_write(int reg, u_int val) 142 { 143 char *addr = (void *)(openpic_base + reg); 144 145 if (openpic_big_endian) 146 out32(addr, val); 147 else 148 out32rb(addr, val); 149 asm volatile("eieio"::: "memory"); 150 } 151 152 static inline int 153 openpic_read_irq(int cpu) 154 { 155 return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK; 156 } 157 158 static inline void 159 openpic_eoi(int cpu) 160 { 161 openpic_write(OPENPIC_EOI(cpu), 0); 162 } 163 164 int 165 openpic_match(struct device *parent, void *cf, void *aux) 166 { 167 char type[40]; 168 int pirq; 169 struct confargs *ca = aux; 170 171 bzero (type, sizeof(type)); 172 173 if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq)) 174 == sizeof(pirq)) 175 return 0; /* XXX */ 176 177 if (strcmp(ca->ca_name, "interrupt-controller") != 0 && 178 strcmp(ca->ca_name, "mpic") != 0) 179 return 0; 180 181 OF_getprop(ca->ca_node, "device_type", type, sizeof(type)); 182 if (strcmp(type, "open-pic") != 0) 183 return 0; 184 185 if (ca->ca_nreg < 8) 186 return 0; 187 188 return 1; 189 } 190 191 void 192 openpic_attach(struct device *parent, struct device *self, void *aux) 193 { 194 struct cpu_info *ci = curcpu(); 195 struct confargs *ca = aux; 196 u_int32_t reg; 197 198 reg = 0; 199 if (OF_getprop(ca->ca_node, "big-endian", ®, sizeof reg) == 0) 200 openpic_big_endian = 1; 201 202 openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr + 203 ca->ca_reg[0], 0x40000); 204 205 /* openpic may support more than 128 interupts but driver doesn't */ 206 openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1; 207 208 printf(": version 0x%x feature %x %s", 209 openpic_read(OPENPIC_VENDOR_ID), 210 openpic_read(OPENPIC_FEATURE), 211 openpic_big_endian ? "BE" : "LE" ); 212 213 openpic_init(); 214 215 intr_establish_func = openpic_intr_establish; 216 intr_disestablish_func = openpic_intr_disestablish; 217 mac_intr_establish_func = openpic_intr_establish; 218 mac_intr_disestablish_func = openpic_intr_disestablish; 219 #ifdef MULTIPROCESSOR 220 intr_send_ipi_func = openpic_send_ipi; 221 #endif 222 223 ppc_smask_init(); 224 225 openpic_collect_preconf_intr(); 226 227 evcount_attach(&openpic_spurious, "spurious", &openpic_spurious_irq); 228 229 ppc_intr_func.raise = openpic_splraise; 230 ppc_intr_func.lower = openpic_spllower; 231 ppc_intr_func.x = openpic_splx; 232 233 openpic_set_priority(0, ci->ci_cpl); 234 235 ppc_intr_enable(1); 236 237 printf("\n"); 238 } 239 240 static inline void 241 openpic_setipl(int newcpl) 242 { 243 struct cpu_info *ci = curcpu(); 244 int s; 245 /* XXX - try do to this without the disable */ 246 s = ppc_intr_disable(); 247 ci->ci_cpl = newcpl; 248 openpic_set_priority(ci->ci_cpuid, newcpl); 249 ppc_intr_enable(s); 250 } 251 252 int 253 openpic_splraise(int newcpl) 254 { 255 struct cpu_info *ci = curcpu(); 256 newcpl = openpic_pri_share[newcpl]; 257 int ocpl = ci->ci_cpl; 258 if (ocpl > newcpl) 259 newcpl = ocpl; 260 261 openpic_setipl(newcpl); 262 263 return ocpl; 264 } 265 266 int 267 openpic_spllower(int newcpl) 268 { 269 struct cpu_info *ci = curcpu(); 270 int ocpl = ci->ci_cpl; 271 272 openpic_splx(newcpl); 273 274 return ocpl; 275 } 276 277 void 278 openpic_splx(int newcpl) 279 { 280 openpic_do_pending_int(newcpl); 281 } 282 283 void 284 openpic_collect_preconf_intr() 285 { 286 int i; 287 for (i = 0; i < ppc_configed_intr_cnt; i++) { 288 #ifdef DEBUG 289 printf("\n\t%s irq %d level %d fun %x arg %x", 290 ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq, 291 ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun, 292 ppc_configed_intr[i].ih_arg); 293 #endif 294 openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq, 295 IST_LEVEL, ppc_configed_intr[i].ih_level, 296 ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg, 297 ppc_configed_intr[i].ih_what); 298 } 299 } 300 301 /* 302 * Register an interrupt handler. 303 */ 304 void * 305 openpic_intr_establish(void *lcv, int irq, int type, int level, 306 int (*ih_fun)(void *), void *ih_arg, const char *name) 307 { 308 struct intrhand *ih; 309 struct intrq *iq; 310 int s; 311 312 /* no point in sleeping unless someone can free memory. */ 313 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 314 if (ih == NULL) 315 panic("intr_establish: can't malloc handler info"); 316 iq = &openpic_handler[irq]; 317 318 if (!LEGAL_IRQ(irq) || type == IST_NONE) 319 panic("intr_establish: bogus irq or type"); 320 321 switch (iq->iq_ist) { 322 case IST_NONE: 323 iq->iq_ist = type; 324 break; 325 case IST_EDGE: 326 intr_shared_edge = 1; 327 /* FALLTHROUGH */ 328 case IST_LEVEL: 329 if (type == iq->iq_ist) 330 break; 331 case IST_PULSE: 332 if (type != IST_NONE) 333 panic("intr_establish: can't share %s with %s", 334 ppc_intr_typename(iq->iq_ist), 335 ppc_intr_typename(type)); 336 break; 337 } 338 339 ih->ih_fun = ih_fun; 340 ih->ih_arg = ih_arg; 341 ih->ih_level = level; 342 ih->ih_irq = irq; 343 344 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 345 346 /* 347 * Append handler to end of list 348 */ 349 s = ppc_intr_disable(); 350 351 TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); 352 openpic_calc_mask(); 353 354 ppc_intr_enable(s); 355 356 return (ih); 357 } 358 359 /* 360 * Deregister an interrupt handler. 361 */ 362 void 363 openpic_intr_disestablish(void *lcp, void *arg) 364 { 365 struct intrhand *ih = arg; 366 int irq = ih->ih_irq; 367 struct intrq *iq = &openpic_handler[irq]; 368 int s; 369 370 if (!LEGAL_IRQ(irq)) 371 panic("intr_disestablish: bogus irq"); 372 373 /* 374 * Remove the handler from the chain. 375 */ 376 s = ppc_intr_disable(); 377 378 TAILQ_REMOVE(&iq->iq_list, ih, ih_list); 379 openpic_calc_mask(); 380 381 ppc_intr_enable(s); 382 383 evcount_detach(&ih->ih_count); 384 free((void *)ih, M_DEVBUF); 385 386 if (TAILQ_EMPTY(&iq->iq_list)) 387 iq->iq_ist = IST_NONE; 388 } 389 390 /* 391 * Recalculate the interrupt masks from scratch. 392 * We could code special registry and deregistry versions of this function that 393 * would be faster, but the code would be nastier, and we don't expect this to 394 * happen very much anyway. 395 */ 396 397 void 398 openpic_calc_mask() 399 { 400 struct cpu_info *ci = curcpu(); 401 int irq; 402 struct intrhand *ih; 403 int i; 404 405 /* disable all openpic interrupts */ 406 openpic_set_priority(ci->ci_cpuid, 15); 407 408 for (i = IPL_NONE; i < IPL_NUM; i++) { 409 openpic_pri_share[i] = i; 410 } 411 412 for (irq = 0; irq < openpic_numirq; irq++) { 413 int maxipl = IPL_NONE; 414 int minipl = IPL_HIGH; 415 struct intrq *iq = &openpic_handler[irq]; 416 417 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { 418 if (ih->ih_level > maxipl) 419 maxipl = ih->ih_level; 420 if (ih->ih_level < minipl) 421 minipl = ih->ih_level; 422 } 423 424 if (maxipl == IPL_NONE) { 425 minipl = IPL_NONE; /* Interrupt not enabled */ 426 427 openpic_disable_irq(irq); 428 } else { 429 for (i = minipl; i <= maxipl; i++) { 430 openpic_pri_share[i] = maxipl; 431 } 432 openpic_enable_irq(irq, maxipl); 433 } 434 435 iq->iq_ipl = maxipl; 436 } 437 438 /* restore interrupts */ 439 openpic_set_priority(ci->ci_cpuid, ci->ci_cpl); 440 } 441 442 void 443 openpic_do_pending_int(int pcpl) 444 { 445 int s; 446 s = ppc_intr_disable(); 447 openpic_do_pending_int_dis(pcpl, s); 448 ppc_intr_enable(s); 449 450 } 451 452 /* 453 * This function expect interrupts disabled on entry and exit, 454 * the s argument indicates if interrupts may be enabled during 455 * the processing of off level interrupts, s 'should' always be 1. 456 */ 457 void 458 openpic_do_pending_int_dis(int pcpl, int s) 459 { 460 struct cpu_info *ci = curcpu(); 461 462 if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { 463 /* soft interrupts are being processed, just set ipl/return */ 464 openpic_setipl(pcpl); 465 return; 466 } 467 468 atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 469 470 do { 471 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && 472 (pcpl < IPL_SOFTCLOCK)) { 473 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); 474 softintr_dispatch(SI_SOFTCLOCK); 475 } 476 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && 477 (pcpl < IPL_SOFTNET)) { 478 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); 479 softintr_dispatch(SI_SOFTNET); 480 } 481 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && 482 (pcpl < IPL_SOFTTTY)) { 483 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); 484 softintr_dispatch(SI_SOFTTTY); 485 } 486 } while (ci->ci_ipending & ppc_smask[pcpl]); 487 openpic_setipl(pcpl); /* Don't use splx... we are here already! */ 488 489 atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 490 } 491 492 void 493 openpic_enable_irq(int irq, int pri) 494 { 495 u_int x; 496 struct intrq *iq = &openpic_handler[irq]; 497 498 x = irq; 499 if (iq->iq_ist == IST_LEVEL) 500 x |= OPENPIC_SENSE_LEVEL; 501 else 502 x |= OPENPIC_SENSE_EDGE; 503 x |= OPENPIC_POLARITY_NEGATIVE; 504 x |= pri << OPENPIC_PRIORITY_SHIFT; 505 openpic_write(OPENPIC_SRC_VECTOR(irq), x); 506 } 507 508 void 509 openpic_disable_irq(int irq) 510 { 511 u_int x; 512 513 x = openpic_read(OPENPIC_SRC_VECTOR(irq)); 514 x |= OPENPIC_IMASK; 515 openpic_write(OPENPIC_SRC_VECTOR(irq), x); 516 } 517 518 void 519 openpic_set_priority(int cpu, int pri) 520 { 521 openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri); 522 } 523 524 #ifdef MULTIPROCESSOR 525 void 526 openpic_send_ipi(struct cpu_info *ci, int id) 527 { 528 switch (id) { 529 case PPC_IPI_NOP: 530 id = 0; 531 break; 532 case PPC_IPI_DDB: 533 id = 1; 534 break; 535 default: 536 panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id); 537 } 538 539 openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid); 540 } 541 542 #endif 543 544 int openpic_irqnest[PPC_MAXPROCS]; 545 int openpic_irqloop[PPC_MAXPROCS]; 546 void 547 openpic_ext_intr() 548 { 549 struct cpu_info *ci = curcpu(); 550 int irq, pcpl, ret; 551 int maxipl = IPL_NONE; 552 struct intrhand *ih; 553 struct intrq *iq; 554 int spurious; 555 556 pcpl = ci->ci_cpl; 557 558 openpic_irqloop[ci->ci_cpuid] = 0; 559 irq = openpic_read_irq(ci->ci_cpuid); 560 openpic_irqnest[ci->ci_cpuid]++; 561 562 while (irq != 255) { 563 openpic_irqloop[ci->ci_cpuid]++; 564 if (openpic_irqloop[ci->ci_cpuid] > 20 || 565 openpic_irqnest[ci->ci_cpuid] > 3) { 566 printf("irqloop %d irqnest %d\n", 567 openpic_irqloop[ci->ci_cpuid], 568 openpic_irqnest[ci->ci_cpuid]); 569 } 570 #ifdef MULTIPROCESSOR 571 if (irq == IPI_VECTOR_NOP) { 572 ipi_nop[ci->ci_cpuid].ec_count++; 573 openpic_eoi(ci->ci_cpuid); 574 irq = openpic_read_irq(ci->ci_cpuid); 575 continue; 576 } 577 if (irq == IPI_VECTOR_DDB) { 578 ipi_ddb[ci->ci_cpuid].ec_count++; 579 openpic_eoi(ci->ci_cpuid); 580 openpic_ipi_ddb(); 581 irq = openpic_read_irq(ci->ci_cpuid); 582 continue; 583 } 584 #endif 585 iq = &openpic_handler[irq]; 586 587 if (iq->iq_ipl <= ci->ci_cpl) 588 printf("invalid interrupt %d lvl %d at %d hw %d\n", 589 irq, iq->iq_ipl, ci->ci_cpl, 590 openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid))); 591 if (iq->iq_ipl > maxipl) 592 maxipl = iq->iq_ipl; 593 splraise(iq->iq_ipl); 594 openpic_eoi(ci->ci_cpuid); 595 596 spurious = 1; 597 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { 598 ppc_intr_enable(1); 599 KERNEL_LOCK(); 600 ret = (*ih->ih_fun)(ih->ih_arg); 601 if (ret) { 602 ih->ih_count.ec_count++; 603 spurious = 0; 604 } 605 KERNEL_UNLOCK(); 606 607 (void)ppc_intr_disable(); 608 if (intr_shared_edge == 00 && ret == 1) 609 break; 610 } 611 if (spurious) { 612 openpic_spurious.ec_count++; 613 #ifdef OPENPIC_NOISY 614 printf("spurious intr %d\n", irq); 615 #endif 616 } 617 618 uvmexp.intrs++; 619 openpic_setipl(pcpl); 620 621 irq = openpic_read_irq(ci->ci_cpuid); 622 } 623 624 if (openpic_irqnest[ci->ci_cpuid] == 1) { 625 openpic_irqloop[ci->ci_cpuid] = 0; 626 /* raise IPL back to max until do_pending will lower it back */ 627 openpic_setipl(maxipl); 628 /* 629 * we must not process pending soft interrupts when nested, can 630 * cause excessive recursion. 631 * 632 * The loop here is because an interrupt could case a pending 633 * soft interrupt between the finishing of the 634 * openpic_do_pending_int, but before ppc_intr_disable 635 */ 636 do { 637 openpic_irqloop[ci->ci_cpuid]++; 638 if (openpic_irqloop[ci->ci_cpuid] > 5) { 639 printf("ext_intr: do_pending loop %d\n", 640 openpic_irqloop[ci->ci_cpuid]); 641 } 642 if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { 643 openpic_setipl(pcpl); 644 /* 645 * some may be pending but someone else is 646 * processing them 647 */ 648 break; 649 } else { 650 openpic_do_pending_int_dis(pcpl, 1); 651 } 652 } while (ci->ci_ipending & ppc_smask[pcpl]); 653 } 654 openpic_irqnest[ci->ci_cpuid]--; 655 } 656 657 void 658 openpic_init() 659 { 660 struct cpu_info *ci = curcpu(); 661 struct intrq *iq; 662 int irq; 663 u_int x; 664 int i; 665 666 openpic_set_priority(ci->ci_cpuid, 15); 667 668 /* disable all interrupts */ 669 for (irq = 0; irq < openpic_numirq; irq++) 670 openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); 671 672 for (i = 0; i < openpic_numirq; i++) { 673 iq = &openpic_handler[i]; 674 TAILQ_INIT(&iq->iq_list); 675 } 676 677 /* we don't need 8259 pass through mode */ 678 x = openpic_read(OPENPIC_CONFIG); 679 x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; 680 openpic_write(OPENPIC_CONFIG, x); 681 682 /* initialize all vectors to something sane */ 683 for (irq = 0; irq < ICU_LEN; irq++) { 684 x = irq; 685 x |= OPENPIC_IMASK; 686 x |= OPENPIC_POLARITY_NEGATIVE; 687 x |= OPENPIC_SENSE_LEVEL; 688 x |= 8 << OPENPIC_PRIORITY_SHIFT; 689 openpic_write(OPENPIC_SRC_VECTOR(irq), x); 690 } 691 692 /* send all interrupts to cpu 0 */ 693 for (irq = 0; irq < openpic_numirq; irq++) 694 openpic_write(OPENPIC_IDEST(irq), 1 << 0); 695 696 /* clear all pending interrunts */ 697 for (irq = 0; irq < ICU_LEN; irq++) { 698 openpic_read_irq(ci->ci_cpuid); 699 openpic_eoi(ci->ci_cpuid); 700 } 701 702 #ifdef MULTIPROCESSOR 703 /* Set up inter-processor interrupts. */ 704 /* IPI0 - NOP */ 705 x = IPI_VECTOR_NOP; 706 x |= 15 << OPENPIC_PRIORITY_SHIFT; 707 openpic_write(OPENPIC_IPI_VECTOR(0), x); 708 /* IPI1 - DDB */ 709 x = IPI_VECTOR_DDB; 710 x |= 15 << OPENPIC_PRIORITY_SHIFT; 711 openpic_write(OPENPIC_IPI_VECTOR(1), x); 712 713 /* XXX - ncpus */ 714 evcount_attach(&ipi_nop[0], "ipi_nop0", &ipi_nopirq); 715 evcount_attach(&ipi_nop[1], "ipi_nop1", &ipi_nopirq); 716 evcount_attach(&ipi_ddb[0], "ipi_ddb0", &ipi_ddbirq); 717 evcount_attach(&ipi_ddb[1], "ipi_ddb1", &ipi_ddbirq); 718 #endif 719 720 /* clear all pending interrunts */ 721 for (irq = 0; irq < ICU_LEN; irq++) { 722 openpic_read_irq(0); 723 openpic_eoi(0); 724 } 725 726 #if 0 727 openpic_write(OPENPIC_SPURIOUS_VECTOR, 255); 728 #endif 729 730 install_extint(openpic_ext_intr); 731 732 openpic_set_priority(ci->ci_cpuid, 0); 733 } 734 735 void 736 openpic_ipi_ddb() 737 { 738 #ifdef OPENPIC_NOISY 739 printf("ipi_ddb() called\n"); 740 #endif 741 Debugger(); 742 } 743