1 /* $NetBSD: intr.c,v 1.18 2011/09/27 01:02:36 jym Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.18 2011/09/27 01:02:36 jym Exp $"); 31 32 #include "opt_interrupt.h" 33 #include "opt_multiprocessor.h" 34 #include "opt_pic.h" 35 36 #define __INTR_PRIVATE 37 38 #include <sys/param.h> 39 #include <sys/cpu.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 43 #include <powerpc/psl.h> 44 #include <powerpc/pic/picvar.h> 45 46 #if defined(PIC_I8259) || defined (PIC_PREPIVR) 47 #include <machine/isa_machdep.h> 48 #endif 49 50 #ifdef MULTIPROCESSOR 51 #include <powerpc/pic/ipivar.h> 52 #endif 53 54 #ifdef __HAVE_FAST_SOFTINTS 55 #include <powerpc/softint.h> 56 #endif 57 58 #define MAX_PICS 8 /* 8 PICs ought to be enough for everyone */ 59 60 #define PIC_VIRQ_LEGAL_P(x) ((u_int)(x) < NVIRQ) 61 62 struct pic_ops *pics[MAX_PICS]; 63 int num_pics = 0; 64 int max_base = 0; 65 uint8_t virq_map[NIRQ]; 66 imask_t virq_mask = HWIRQ_MASK; 67 imask_t imask[NIPL]; 68 int primary_pic = 0; 69 70 static int fakeintr(void *); 71 static int mapirq(int); 72 static void intr_calculatemasks(void); 73 static struct pic_ops *find_pic_by_hwirq(int); 74 75 static struct intr_source intrsources[NVIRQ]; 76 77 void 78 pic_init(void) 79 { 80 /* everything is in bss, no reason to zero it. */ 81 } 82 83 int 84 pic_add(struct pic_ops *pic) 85 { 86 87 if (num_pics >= MAX_PICS) 88 return -1; 89 90 pics[num_pics] = pic; 91 pic->pic_intrbase = max_base; 92 max_base += pic->pic_numintrs; 93 num_pics++; 94 95 return pic->pic_intrbase; 96 } 97 98 void 99 pic_finish_setup(void) 100 { 101 for (size_t i = 0; i < num_pics; i++) { 102 struct pic_ops * const pic = pics[i]; 103 if (pic->pic_finish_setup != NULL) 104 pic->pic_finish_setup(pic); 105 } 106 } 107 108 static struct pic_ops * 109 find_pic_by_hwirq(int hwirq) 110 { 111 for (u_int base = 0; base < num_pics; base++) { 112 struct pic_ops * const pic = pics[base]; 113 if (pic->pic_intrbase <= hwirq 114 && hwirq < pic->pic_intrbase + pic->pic_numintrs) { 115 return pic; 116 } 117 } 118 return NULL; 119 } 120 121 static int 122 fakeintr(void *arg) 123 { 124 125 return 0; 126 } 127 128 /* 129 * Register an interrupt handler. 130 */ 131 void * 132 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *), 133 void *ih_arg) 134 { 135 struct intrhand **p, *q, *ih; 136 struct pic_ops *pic; 137 static struct intrhand fakehand; 138 int maxipl = ipl; 139 140 if (maxipl == IPL_NONE) 141 maxipl = IPL_HIGH; 142 143 if (hwirq >= max_base) { 144 panic("%s: bogus IRQ %d, max is %d", __func__, hwirq, 145 max_base - 1); 146 } 147 148 pic = find_pic_by_hwirq(hwirq); 149 if (pic == NULL) { 150 151 panic("%s: cannot find a pic for IRQ %d", __func__, hwirq); 152 } 153 154 const int virq = mapirq(hwirq); 155 156 /* no point in sleeping unless someone can free memory. */ 157 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 158 if (ih == NULL) 159 panic("intr_establish: can't malloc handler info"); 160 161 if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE) 162 panic("intr_establish: bogus irq (%d) or type (%d)", 163 hwirq, type); 164 165 struct intr_source * const is = &intrsources[virq]; 166 167 switch (is->is_type) { 168 case IST_NONE: 169 is->is_type = type; 170 break; 171 case IST_EDGE: 172 case IST_LEVEL: 173 if (type == is->is_type) 174 break; 175 /* FALLTHROUGH */ 176 case IST_PULSE: 177 if (type != IST_NONE) 178 panic("intr_establish: can't share %s with %s", 179 intr_typename(is->is_type), 180 intr_typename(type)); 181 break; 182 } 183 if (is->is_hand == NULL) { 184 snprintf(is->is_source, sizeof(is->is_source), "irq %d", 185 is->is_hwirq); 186 evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL, 187 pic->pic_name, is->is_source); 188 } 189 190 /* 191 * Figure out where to put the handler. 192 * This is O(N^2), but we want to preserve the order, and N is 193 * generally small. 194 */ 195 for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) { 196 maxipl = max(maxipl, q->ih_ipl); 197 } 198 199 /* 200 * Actually install a fake handler momentarily, since we might be doing 201 * this with interrupts enabled and don't want the real routine called 202 * until masking is set up. 203 */ 204 fakehand.ih_ipl = ipl; 205 fakehand.ih_fun = fakeintr; 206 *p = &fakehand; 207 208 /* 209 * Poke the real handler in now. 210 */ 211 ih->ih_fun = ih_fun; 212 ih->ih_arg = ih_arg; 213 ih->ih_next = NULL; 214 ih->ih_ipl = ipl; 215 ih->ih_virq = virq; 216 *p = ih; 217 218 if (pic->pic_establish_irq != NULL) 219 pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase, 220 is->is_type, maxipl); 221 222 /* 223 * Remember the highest IPL used by this handler. 224 */ 225 is->is_ipl = maxipl; 226 227 /* 228 * now that the handler is established we're actually ready to 229 * calculate the masks 230 */ 231 intr_calculatemasks(); 232 233 234 return ih; 235 } 236 237 void 238 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri) 239 { 240 } 241 242 /* 243 * Deregister an interrupt handler. 244 */ 245 void 246 intr_disestablish(void *arg) 247 { 248 struct intrhand * const ih = arg; 249 const int virq = ih->ih_virq; 250 struct intr_source * const is = &intrsources[virq]; 251 struct intrhand **p, **q; 252 int maxipl = IPL_NONE; 253 254 if (!PIC_VIRQ_LEGAL_P(virq)) 255 panic("intr_disestablish: bogus virq %d", virq); 256 257 /* 258 * Remove the handler from the chain. 259 * This is O(n^2), too. 260 */ 261 for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) { 262 struct intrhand * const tmp_ih = *p; 263 if (tmp_ih == ih) { 264 q = p; 265 } else { 266 maxipl = max(maxipl, tmp_ih->ih_ipl); 267 } 268 } 269 if (q) 270 *q = ih->ih_next; 271 else 272 panic("intr_disestablish: handler not registered"); 273 free((void *)ih, M_DEVBUF); 274 275 /* 276 * Reset the IPL for this source now that we've removed a handler. 277 */ 278 is->is_ipl = maxipl; 279 280 intr_calculatemasks(); 281 282 if (is->is_hand == NULL) { 283 is->is_type = IST_NONE; 284 evcnt_detach(&is->is_ev); 285 /* 286 * Make the virutal IRQ available again. 287 */ 288 virq_map[virq] = 0; 289 virq_mask |= PIC_VIRQ_TO_MASK(virq); 290 } 291 } 292 293 /* 294 * Map max_base irqs into 32 (bits). 295 */ 296 static int 297 mapirq(int hwirq) 298 { 299 struct pic_ops *pic; 300 301 if (hwirq >= max_base) 302 panic("invalid irq %d", hwirq); 303 304 if ((pic = find_pic_by_hwirq(hwirq)) == NULL) 305 panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq); 306 307 if (virq_map[hwirq]) 308 return virq_map[hwirq]; 309 310 if (virq_mask == 0) 311 panic("virq overflow"); 312 313 const int virq = PIC_VIRQ_MS_PENDING(virq_mask); 314 struct intr_source * const is = intrsources + virq; 315 316 virq_mask &= ~PIC_VIRQ_TO_MASK(virq); 317 318 is->is_hwirq = hwirq; 319 is->is_pic = pic; 320 virq_map[hwirq] = virq; 321 #ifdef PIC_DEBUG 322 printf("mapping hwirq %d to virq %d\n", hwirq, virq); 323 #endif 324 return virq; 325 } 326 327 static const char * const intr_typenames[] = { 328 [IST_NONE] = "none", 329 [IST_PULSE] = "pulsed", 330 [IST_EDGE] = "edge-triggered", 331 [IST_LEVEL] = "level-triggered", 332 }; 333 334 const char * 335 intr_typename(int type) 336 { 337 KASSERT((unsigned int) type < __arraycount(intr_typenames)); 338 KASSERT(intr_typenames[type] != NULL); 339 return intr_typenames[type]; 340 } 341 342 /* 343 * Recalculate the interrupt masks from scratch. 344 * We could code special registry and deregistry versions of this function that 345 * would be faster, but the code would be nastier, and we don't expect this to 346 * happen very much anyway. 347 */ 348 static void 349 intr_calculatemasks(void) 350 { 351 imask_t newmask[NIPL] = { [IPL_NONE...IPL_HIGH] = 0 }; 352 struct intr_source *is; 353 int irq; 354 355 for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) { 356 newmask[ipl] = 0; 357 } 358 359 /* First, figure out which ipl each IRQ uses. */ 360 for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) { 361 newmask[is->is_ipl] |= PIC_VIRQ_TO_MASK(irq); 362 } 363 364 /* 365 * IPL_NONE is used for hardware interrupts that are never blocked, 366 * and do not block anything else. 367 */ 368 newmask[IPL_NONE] = 0; 369 370 /* 371 * strict hierarchy - all IPLs block everything blocked by any lower 372 * IPL 373 */ 374 for (u_int ipl = 1; ipl < NIPL; ipl++) { 375 newmask[ipl] |= newmask[ipl - 1]; 376 } 377 378 #ifdef DEBUG_IPL 379 for (u_int ipl = 0; ipl < NIPL; ipl++) { 380 printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]); 381 } 382 #endif 383 384 /* 385 * Disable all interrupts. 386 */ 387 for (u_int base = 0; base < num_pics; base++) { 388 struct pic_ops * const pic = pics[base]; 389 for (u_int i = 0; i < pic->pic_numintrs; i++) { 390 pic->pic_disable_irq(pic, i); 391 } 392 } 393 394 /* 395 * Now that all interrupts are disabled, update the ipl masks. 396 */ 397 for (u_int ipl = 0; ipl < NIPL; ipl++) { 398 imask[ipl] = newmask[ipl]; 399 } 400 401 /* 402 * Lastly, enable IRQs actually in use. 403 */ 404 for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) { 405 if (is->is_hand) 406 pic_enable_irq(is->is_hwirq); 407 } 408 } 409 410 void 411 pic_enable_irq(int hwirq) 412 { 413 struct pic_ops * const pic = find_pic_by_hwirq(hwirq); 414 if (pic == NULL) 415 panic("%s: bogus IRQ %d", __func__, hwirq); 416 const int type = intrsources[virq_map[hwirq]].is_type; 417 (*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type); 418 } 419 420 void 421 pic_mark_pending(int hwirq) 422 { 423 struct cpu_info * const ci = curcpu(); 424 425 const int virq = virq_map[hwirq]; 426 if (virq == 0) 427 printf("IRQ %d maps to 0\n", hwirq); 428 429 const register_t msr = mfmsr(); 430 mtmsr(msr & ~PSL_EE); 431 ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq); 432 mtmsr(msr); 433 } 434 435 static void 436 intr_deliver(struct intr_source *is, int virq) 437 { 438 bool locked = false; 439 for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) { 440 KASSERTMSG(ih->ih_fun != NULL, 441 "%s: irq %d, hwirq %d, is %p ih %p: " 442 "NULL interrupt handler!\n", __func__, 443 virq, is->is_hwirq, is, ih); 444 if (ih->ih_ipl == IPL_VM) { 445 if (!locked) { 446 KERNEL_LOCK(1, NULL); 447 locked = true; 448 } 449 } else if (locked) { 450 KERNEL_UNLOCK_ONE(NULL); 451 locked = false; 452 } 453 (*ih->ih_fun)(ih->ih_arg); 454 } 455 if (locked) { 456 KERNEL_UNLOCK_ONE(NULL); 457 } 458 is->is_ev.ev_count++; 459 } 460 461 void 462 pic_do_pending_int(void) 463 { 464 struct cpu_info * const ci = curcpu(); 465 imask_t vpend; 466 467 if (ci->ci_iactive) 468 return; 469 470 ci->ci_iactive = 1; 471 472 const register_t emsr = mfmsr(); 473 const register_t dmsr = emsr & ~PSL_EE; 474 475 KASSERT(emsr & PSL_EE); 476 mtmsr(dmsr); 477 478 const int pcpl = ci->ci_cpl; 479 #ifdef __HAVE_FAST_SOFTINTS 480 again: 481 #endif 482 483 /* Do now unmasked pendings */ 484 while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) { 485 ci->ci_idepth++; 486 KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0); 487 488 /* Get most significant pending bit */ 489 const int virq = PIC_VIRQ_MS_PENDING(vpend); 490 ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq); 491 492 struct intr_source * const is = &intrsources[virq]; 493 struct pic_ops * const pic = is->is_pic; 494 495 splraise(is->is_ipl); 496 mtmsr(emsr); 497 intr_deliver(is, virq); 498 mtmsr(dmsr); 499 ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ 500 501 pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase, 502 is->is_type); 503 ci->ci_idepth--; 504 } 505 506 #ifdef __HAVE_FAST_SOFTINTS 507 const u_int softints = (ci->ci_data.cpu_softints << pcpl) & IPL_SOFTMASK; 508 509 if (__predict_false(softints != 0)) { 510 ci->ci_cpl = IPL_HIGH; 511 mtmsr(emsr); 512 powerpc_softint(ci, pcpl, 513 (vaddr_t)__builtin_return_address(0)); 514 mtmsr(dmsr); 515 ci->ci_cpl = pcpl; 516 if (__predict_false(ci->ci_ipending & ~imask[pcpl])) 517 goto again; 518 } 519 #endif 520 521 ci->ci_iactive = 0; 522 mtmsr(emsr); 523 } 524 525 int 526 pic_handle_intr(void *cookie) 527 { 528 struct pic_ops *pic = cookie; 529 struct cpu_info *ci = curcpu(); 530 int picirq; 531 532 picirq = pic->pic_get_irq(pic, PIC_GET_IRQ); 533 if (picirq == 255) 534 return 0; 535 536 const register_t msr = mfmsr(); 537 const int pcpl = ci->ci_cpl; 538 539 do { 540 #ifdef MULTIPROCESSOR 541 /* THIS IS WRONG XXX */ 542 if (picirq == ipiops.ppc_ipi_vector) { 543 ci->ci_cpl = IPL_HIGH; 544 ipi_intr(NULL); 545 ci->ci_cpl = pcpl; 546 pic->pic_ack_irq(pic, picirq); 547 continue; 548 } 549 #endif 550 551 const int virq = virq_map[picirq + pic->pic_intrbase]; 552 KASSERT(virq != 0); 553 KASSERT(picirq < pic->pic_numintrs); 554 imask_t v_imen = PIC_VIRQ_TO_MASK(virq); 555 struct intr_source * const is = &intrsources[virq]; 556 557 if ((imask[pcpl] & v_imen) != 0) { 558 ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */ 559 pic->pic_disable_irq(pic, picirq); 560 } else { 561 /* this interrupt is no longer pending */ 562 ci->ci_ipending &= ~v_imen; 563 ci->ci_idepth++; 564 565 splraise(is->is_ipl); 566 mtmsr(msr | PSL_EE); 567 intr_deliver(is, virq); 568 mtmsr(msr); 569 ci->ci_cpl = pcpl; 570 571 ci->ci_data.cpu_nintr++; 572 ci->ci_idepth--; 573 } 574 pic->pic_ack_irq(pic, picirq); 575 } while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255); 576 577 mtmsr(msr | PSL_EE); 578 splx(pcpl); /* Process pendings. */ 579 mtmsr(msr); 580 581 return 0; 582 } 583 584 void 585 pic_ext_intr(void) 586 { 587 588 KASSERT(pics[primary_pic] != NULL); 589 pic_handle_intr(pics[primary_pic]); 590 591 return; 592 593 } 594 595 int 596 splraise(int ncpl) 597 { 598 struct cpu_info *ci = curcpu(); 599 int ocpl; 600 601 if (ncpl == ci->ci_cpl) return ncpl; 602 __asm volatile("sync; eieio"); /* don't reorder.... */ 603 ocpl = ci->ci_cpl; 604 KASSERT(ncpl < NIPL); 605 ci->ci_cpl = max(ncpl, ocpl); 606 __asm volatile("sync; eieio"); /* reorder protect */ 607 __insn_barrier(); 608 return ocpl; 609 } 610 611 static inline bool 612 have_pending_intr_p(struct cpu_info *ci, int ncpl) 613 { 614 if (ci->ci_ipending & ~imask[ncpl]) 615 return true; 616 #ifdef __HAVE_FAST_SOFTINTS 617 if ((ci->ci_data.cpu_softints << ncpl) & IPL_SOFTMASK) 618 return true; 619 #endif 620 return false; 621 } 622 623 void 624 splx(int ncpl) 625 { 626 struct cpu_info *ci = curcpu(); 627 628 __insn_barrier(); 629 __asm volatile("sync; eieio"); /* reorder protect */ 630 ci->ci_cpl = ncpl; 631 if (have_pending_intr_p(ci, ncpl)) 632 pic_do_pending_int(); 633 634 __asm volatile("sync; eieio"); /* reorder protect */ 635 } 636 637 int 638 spllower(int ncpl) 639 { 640 struct cpu_info *ci = curcpu(); 641 int ocpl; 642 643 __insn_barrier(); 644 __asm volatile("sync; eieio"); /* reorder protect */ 645 ocpl = ci->ci_cpl; 646 ci->ci_cpl = ncpl; 647 if (have_pending_intr_p(ci, ncpl)) 648 pic_do_pending_int(); 649 __asm volatile("sync; eieio"); /* reorder protect */ 650 return ocpl; 651 } 652 653 void 654 genppc_cpu_configure(void) 655 { 656 aprint_normal("biomask %x netmask %x ttymask %x\n", 657 (u_int)imask[IPL_BIO] & 0x1fffffff, 658 (u_int)imask[IPL_NET] & 0x1fffffff, 659 (u_int)imask[IPL_TTY] & 0x1fffffff); 660 661 spl0(); 662 } 663 664 #if defined(PIC_PREPIVR) || defined(PIC_I8259) 665 /* 666 * isa_intr_alloc needs to be done here, because it needs direct access to 667 * the various interrupt handler structures. 668 */ 669 670 int 671 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic, 672 int mask, int type, int *irq_p) 673 { 674 int irq, vi; 675 int maybe_irq = -1; 676 int shared_depth = 0; 677 struct intr_source *is; 678 679 if (pic == NULL) 680 return 1; 681 682 for (irq = 0; (mask != 0 && irq < pic->pic_numintrs); 683 mask >>= 1, irq++) { 684 if ((mask & 1) == 0) 685 continue; 686 vi = virq_map[irq + pic->pic_intrbase]; 687 if (!vi) { 688 *irq_p = irq; 689 return 0; 690 } 691 is = &intrsources[vi]; 692 if (is->is_type == IST_NONE) { 693 *irq_p = irq; 694 return 0; 695 } 696 /* Level interrupts can be shared */ 697 if (type == IST_LEVEL && is->is_type == IST_LEVEL) { 698 struct intrhand *ih = is->is_hand; 699 int depth; 700 701 if (maybe_irq == -1) { 702 maybe_irq = irq; 703 continue; 704 } 705 for (depth = 0; ih != NULL; ih = ih->ih_next) 706 depth++; 707 if (depth < shared_depth) { 708 maybe_irq = irq; 709 shared_depth = depth; 710 } 711 } 712 } 713 if (maybe_irq != -1) { 714 *irq_p = maybe_irq; 715 return 0; 716 } 717 return 1; 718 } 719 #endif 720