1 /* $NetBSD: intr.c,v 1.61 2002/12/06 16:04:12 pk Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)intr.c 8.3 (Berkeley) 11/11/93 45 */ 46 47 #include "opt_multiprocessor.h" 48 #include "opt_sparc_arch.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <dev/cons.h> 58 59 #include <net/netisr.h> 60 61 #include <machine/cpu.h> 62 #include <machine/ctlreg.h> 63 #include <machine/instr.h> 64 #include <machine/intr.h> 65 #include <machine/trap.h> 66 #include <machine/promlib.h> 67 68 #include <sparc/sparc/asm.h> 69 #include <sparc/sparc/cpuvar.h> 70 71 #if defined(MULTIPROCESSOR) && defined(DDB) 72 #include <machine/db_machdep.h> 73 #endif 74 75 void *softnet_cookie; 76 77 void strayintr __P((struct clockframe *)); 78 #ifdef DIAGNOSTIC 79 void bogusintr __P((struct clockframe *)); 80 #endif 81 void softnet __P((void *)); 82 83 /* 84 * Stray interrupt handler. Clear it if possible. 85 * If not, and if we get 10 interrupts in 10 seconds, panic. 86 * XXXSMP: We are holding the kernel lock at entry & exit. 87 */ 88 void 89 strayintr(fp) 90 struct clockframe *fp; 91 { 92 static int straytime, nstray; 93 char bits[64]; 94 int timesince; 95 96 printf("stray interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n", 97 fp->ipl, fp->pc, fp->npc, bitmask_snprintf(fp->psr, 98 PSR_BITS, bits, sizeof(bits))); 99 100 timesince = time.tv_sec - straytime; 101 if (timesince <= 10) { 102 if (++nstray > 10) 103 panic("crazy interrupts"); 104 } else { 105 straytime = time.tv_sec; 106 nstray = 1; 107 } 108 } 109 110 111 #ifdef DIAGNOSTIC 112 /* 113 * Bogus interrupt for which neither hard nor soft interrupt bit in 114 * the IPR was set. 115 */ 116 void 117 bogusintr(fp) 118 struct clockframe *fp; 119 { 120 char bits[64]; 121 122 printf("bogus interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n", 123 fp->ipl, fp->pc, fp->npc, bitmask_snprintf(fp->psr, 124 PSR_BITS, bits, sizeof(bits))); 125 } 126 #endif /* DIAGNOSTIC */ 127 128 129 /* 130 * Process software network interrupts. 131 */ 132 void 133 softnet(fp) 134 void *fp; 135 { 136 int n, s; 137 138 s = splhigh(); 139 n = netisr; 140 netisr = 0; 141 splx(s); 142 143 if (n == 0) 144 return; 145 146 #define DONETISR(bit, fn) do { \ 147 if (n & (1 << bit)) \ 148 fn(); \ 149 } while (0) 150 151 #include <net/netisr_dispatch.h> 152 153 #undef DONETISR 154 } 155 156 #if defined(SUN4M) 157 void nmi_hard __P((void)); 158 void nmi_soft __P((struct trapframe *)); 159 160 int (*memerr_handler) __P((void)); 161 int (*sbuserr_handler) __P((void)); 162 int (*vmeerr_handler) __P((void)); 163 int (*moduleerr_handler) __P((void)); 164 165 #if defined(MULTIPROCESSOR) 166 volatile int nmi_hard_wait = 0; 167 struct simplelock nmihard_lock = SIMPLELOCK_INITIALIZER; 168 #endif 169 170 void 171 nmi_hard() 172 { 173 /* 174 * A level 15 hard interrupt. 175 */ 176 int fatal = 0; 177 u_int32_t si; 178 char bits[64]; 179 u_int afsr, afva; 180 181 afsr = afva = 0; 182 if ((*cpuinfo.get_asyncflt)(&afsr, &afva) == 0) { 183 printf("Async registers (mid %d): afsr=%s; afva=0x%x%x\n", 184 cpuinfo.mid, 185 bitmask_snprintf(afsr, AFSR_BITS, bits, sizeof(bits)), 186 (afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva); 187 } 188 189 #if defined(MULTIPROCESSOR) 190 /* 191 * Increase nmi_hard_wait. If we aren't the master, loop while this 192 * variable is non-zero. If we are the master, loop while this 193 * variable is less than the number of cpus. 194 */ 195 simple_lock(&nmihard_lock); 196 nmi_hard_wait++; 197 simple_unlock(&nmihard_lock); 198 199 if (cpuinfo.master == 0) { 200 while (nmi_hard_wait) 201 ; 202 return; 203 } else { 204 int n = 0; 205 206 while (nmi_hard_wait < ncpu) 207 if (n++ > 100000) 208 panic("nmi_hard: SMP botch."); 209 } 210 #endif 211 212 /* 213 * Examine pending system interrupts. 214 */ 215 si = *((u_int32_t *)ICR_SI_PEND); 216 printf("cpu%d: NMI: system interrupts: %s\n", cpu_number(), 217 bitmask_snprintf(si, SINTR_BITS, bits, sizeof(bits))); 218 219 if ((si & SINTR_M) != 0) { 220 /* ECC memory error */ 221 if (memerr_handler != NULL) 222 fatal |= (*memerr_handler)(); 223 } 224 if ((si & SINTR_I) != 0) { 225 /* MBus/SBus async error */ 226 if (sbuserr_handler != NULL) 227 fatal |= (*sbuserr_handler)(); 228 } 229 if ((si & SINTR_V) != 0) { 230 /* VME async error */ 231 if (vmeerr_handler != NULL) 232 fatal |= (*vmeerr_handler)(); 233 } 234 if ((si & SINTR_ME) != 0) { 235 /* Module async error */ 236 if (moduleerr_handler != NULL) 237 fatal |= (*moduleerr_handler)(); 238 } 239 240 #if defined(MULTIPROCESSOR) 241 /* 242 * Tell everyone else we've finished dealing with the hard NMI. 243 */ 244 simple_lock(&nmihard_lock); 245 nmi_hard_wait = 0; 246 simple_unlock(&nmihard_lock); 247 #endif 248 249 if (fatal) 250 panic("nmi"); 251 } 252 253 void 254 nmi_soft(tf) 255 struct trapframe *tf; 256 { 257 258 #ifdef MULTIPROCESSOR 259 switch (cpuinfo.msg.tag) { 260 case XPMSG_SAVEFPU: 261 savefpstate(cpuinfo.fpproc->p_md.md_fpstate); 262 cpuinfo.fpproc->p_md.md_fpumid = -1; 263 cpuinfo.fpproc = NULL; 264 break; 265 case XPMSG_PAUSECPU: 266 { 267 #if defined(DDB) 268 db_regs_t regs; 269 270 regs.db_tf = *tf; 271 regs.db_fr = *(struct frame *)tf->tf_out[6]; 272 cpuinfo.ci_ddb_regs = ®s; 273 #endif 274 cpuinfo.flags |= CPUFLG_PAUSED|CPUFLG_GOTMSG; 275 while (cpuinfo.flags & CPUFLG_PAUSED) 276 cpuinfo.cache_flush((caddr_t)&cpuinfo.flags, 277 sizeof(cpuinfo.flags)); 278 #if defined(DDB) 279 cpuinfo.ci_ddb_regs = 0; 280 #endif 281 return; 282 } 283 case XPMSG_FUNC: 284 { 285 struct xpmsg_func *p = &cpuinfo.msg.u.xpmsg_func; 286 287 p->retval = (*p->func)(p->arg0, p->arg1, p->arg2, p->arg3); 288 break; 289 } 290 case XPMSG_VCACHE_FLUSH_PAGE: 291 { 292 struct xpmsg_flush_page *p = &cpuinfo.msg.u.xpmsg_flush_page; 293 int ctx = getcontext(); 294 295 setcontext(p->ctx); 296 cpuinfo.sp_vcache_flush_page(p->va); 297 setcontext(ctx); 298 break; 299 } 300 case XPMSG_VCACHE_FLUSH_SEGMENT: 301 { 302 struct xpmsg_flush_segment *p = &cpuinfo.msg.u.xpmsg_flush_segment; 303 int ctx = getcontext(); 304 305 setcontext(p->ctx); 306 cpuinfo.sp_vcache_flush_segment(p->vr, p->vs); 307 setcontext(ctx); 308 break; 309 } 310 case XPMSG_VCACHE_FLUSH_REGION: 311 { 312 struct xpmsg_flush_region *p = &cpuinfo.msg.u.xpmsg_flush_region; 313 int ctx = getcontext(); 314 315 setcontext(p->ctx); 316 cpuinfo.sp_vcache_flush_region(p->vr); 317 setcontext(ctx); 318 break; 319 } 320 case XPMSG_VCACHE_FLUSH_CONTEXT: 321 { 322 struct xpmsg_flush_context *p = &cpuinfo.msg.u.xpmsg_flush_context; 323 int ctx = getcontext(); 324 325 setcontext(p->ctx); 326 cpuinfo.sp_vcache_flush_context(); 327 setcontext(ctx); 328 break; 329 } 330 case XPMSG_VCACHE_FLUSH_RANGE: 331 { 332 struct xpmsg_flush_range *p = &cpuinfo.msg.u.xpmsg_flush_range; 333 int ctx = getcontext(); 334 335 setcontext(p->ctx); 336 cpuinfo.sp_cache_flush(p->va, p->size); 337 setcontext(ctx); 338 break; 339 } 340 case XPMSG_DEMAP_TLB_PAGE: 341 { 342 struct xpmsg_flush_page *p = &cpuinfo.msg.u.xpmsg_flush_page; 343 int ctx = getcontext(); 344 345 setcontext(p->ctx); 346 tlb_flush_page_real(p->va); 347 setcontext(ctx); 348 break; 349 } 350 case XPMSG_DEMAP_TLB_SEGMENT: 351 { 352 struct xpmsg_flush_segment *p = &cpuinfo.msg.u.xpmsg_flush_segment; 353 int ctx = getcontext(); 354 355 setcontext(p->ctx); 356 tlb_flush_segment_real(p->vr, p->vs); 357 setcontext(ctx); 358 break; 359 } 360 case XPMSG_DEMAP_TLB_REGION: 361 { 362 struct xpmsg_flush_region *p = &cpuinfo.msg.u.xpmsg_flush_region; 363 int ctx = getcontext(); 364 365 setcontext(p->ctx); 366 tlb_flush_region_real(p->vr); 367 setcontext(ctx); 368 break; 369 } 370 case XPMSG_DEMAP_TLB_CONTEXT: 371 { 372 struct xpmsg_flush_context *p = &cpuinfo.msg.u.xpmsg_flush_context; 373 int ctx = getcontext(); 374 375 setcontext(p->ctx); 376 tlb_flush_context_real(); 377 setcontext(ctx); 378 break; 379 } 380 case XPMSG_DEMAP_TLB_ALL: 381 tlb_flush_all_real(); 382 break; 383 } 384 cpuinfo.flags |= CPUFLG_GOTMSG; 385 #endif 386 } 387 #endif 388 389 /* 390 * Level 15 interrupts are special, and not vectored here. 391 * Only `prewired' interrupts appear here; boot-time configured devices 392 * are attached via intr_establish() below. 393 */ 394 struct intrhand *intrhand[15] = { 395 NULL, /* 0 = error */ 396 NULL, /* 1 = software level 1 + Sbus */ 397 NULL, /* 2 = Sbus level 2 (4m: Sbus L1) */ 398 NULL, /* 3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/ 399 NULL, /* 4 = software level 4 (tty softint) (scsi) */ 400 NULL, /* 5 = Ethernet + Sbus level 4 (4m: Sbus L3) */ 401 NULL, /* 6 = software level 6 (not used) (4m: enet)*/ 402 NULL, /* 7 = video + Sbus level 5 */ 403 NULL, /* 8 = Sbus level 6 */ 404 NULL, /* 9 = Sbus level 7 */ 405 NULL, /* 10 = counter 0 = clock */ 406 NULL, /* 11 = floppy */ 407 NULL, /* 12 = zs hardware interrupt */ 408 NULL, /* 13 = audio chip */ 409 NULL, /* 14 = counter 1 = profiling timer */ 410 }; 411 412 static int fastvec; /* marks fast vectors (see below) */ 413 #ifdef DIAGNOSTIC 414 extern int sparc_interrupt4m[]; 415 extern int sparc_interrupt44c[]; 416 #endif 417 418 /* 419 * Attach an interrupt handler to the vector chain for the given level. 420 * This is not possible if it has been taken away as a fast vector. 421 */ 422 void 423 intr_establish(level, classipl, ih) 424 int level; 425 int classipl; 426 struct intrhand *ih; 427 { 428 struct intrhand **p, *q; 429 #ifdef DIAGNOSTIC 430 struct trapvec *tv; 431 int displ; 432 #endif 433 int s; 434 435 s = splhigh(); 436 if (fastvec & (1 << level)) 437 panic("intr_establish: level %d interrupt tied to fast vector", 438 level); 439 #ifdef DIAGNOSTIC 440 /* double check for legal hardware interrupt */ 441 if ((level != 1 && level != 4 && level != 6) || CPU_ISSUN4M) { 442 tv = &trapbase[T_L1INT - 1 + level]; 443 displ = (CPU_ISSUN4M) 444 ? &sparc_interrupt4m[0] - &tv->tv_instr[1] 445 : &sparc_interrupt44c[0] - &tv->tv_instr[1]; 446 447 /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */ 448 if (tv->tv_instr[0] != I_MOVi(I_L3, level) || 449 tv->tv_instr[1] != I_BA(0, displ) || 450 tv->tv_instr[2] != I_RDPSR(I_L0)) 451 panic("intr_establish(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x", 452 level, ih, 453 tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2], 454 I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0)); 455 } 456 #endif 457 458 if (classipl == 0) 459 classipl = level; 460 461 /* A requested IPL cannot exceed its device class level */ 462 if (classipl < level) 463 panic("intr_establish: class lvl (%d) < pil (%d)\n", 464 classipl, level); 465 466 /* pre-shift to PIL field in %psr */ 467 ih->ih_classipl = (classipl << 8) & PSR_PIL; 468 469 /* 470 * This is O(N^2) for long chains, but chains are never long 471 * and we do want to preserve order. 472 */ 473 for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next) 474 continue; 475 *p = ih; 476 ih->ih_next = NULL; 477 splx(s); 478 } 479 480 void 481 intr_disestablish(level, ih) 482 int level; 483 struct intrhand *ih; 484 { 485 struct intrhand **p, *q; 486 487 for (p = &intrhand[level]; (q = *p) != ih; p = &q->ih_next) 488 continue; 489 if (q == NULL) 490 panic("intr_disestablish: level %d intrhand %p fun %p arg %p", 491 level, ih, ih->ih_fun, ih->ih_arg); 492 493 *p = q->ih_next; 494 q->ih_next = NULL; 495 } 496 497 /* 498 * Like intr_establish, but wires a fast trap vector. Only one such fast 499 * trap is legal for any interrupt, and it must be a hardware interrupt. 500 */ 501 void 502 intr_fasttrap(level, vec) 503 int level; 504 void (*vec) __P((void)); 505 { 506 struct trapvec *tv; 507 u_long hi22, lo10; 508 #ifdef DIAGNOSTIC 509 int displ; /* suspenders, belt, and buttons too */ 510 #endif 511 int s; 512 513 tv = &trapbase[T_L1INT - 1 + level]; 514 hi22 = ((u_long)vec) >> 10; 515 lo10 = ((u_long)vec) & 0x3ff; 516 s = splhigh(); 517 if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL) 518 panic("intr_fasttrap: already handling level %d interrupts", 519 level); 520 #ifdef DIAGNOSTIC 521 displ = (CPU_ISSUN4M) 522 ? &sparc_interrupt4m[0] - &tv->tv_instr[1] 523 : &sparc_interrupt44c[0] - &tv->tv_instr[1]; 524 525 /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */ 526 if (tv->tv_instr[0] != I_MOVi(I_L3, level) || 527 tv->tv_instr[1] != I_BA(0, displ) || 528 tv->tv_instr[2] != I_RDPSR(I_L0)) 529 panic("intr_fasttrap(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x", 530 level, vec, 531 tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2], 532 I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0)); 533 #endif 534 /* kernel text is write protected -- let us in for a moment */ 535 pmap_changeprot(pmap_kernel(), (vaddr_t)tv, 536 VM_PROT_READ|VM_PROT_WRITE, 1); 537 cpuinfo.cache_flush_all(); 538 tv->tv_instr[0] = I_SETHI(I_L3, hi22); /* sethi %hi(vec),%l3 */ 539 tv->tv_instr[1] = I_JMPLri(I_G0, I_L3, lo10);/* jmpl %l3+%lo(vec),%g0 */ 540 tv->tv_instr[2] = I_RDPSR(I_L0); /* mov %psr, %l0 */ 541 pmap_changeprot(pmap_kernel(), (vaddr_t)tv, VM_PROT_READ, 1); 542 cpuinfo.cache_flush_all(); 543 fastvec |= 1 << level; 544 splx(s); 545 } 546 547 /* 548 * softintr_init(): initialise the MI softintr system. 549 */ 550 void 551 softintr_init() 552 { 553 554 softnet_cookie = softintr_establish(IPL_SOFTNET, softnet, NULL); 555 } 556 557 /* 558 * softintr_establish(): MI interface. establish a func(arg) as a 559 * software interrupt. 560 */ 561 void * 562 softintr_establish(level, fun, arg) 563 int level; 564 void (*fun) __P((void *)); 565 void *arg; 566 { 567 struct intrhand *ih; 568 569 ih = malloc(sizeof(*ih), M_DEVBUF, 0); 570 bzero(ih, sizeof(*ih)); 571 ih->ih_fun = (int (*) __P((void *)))fun; 572 ih->ih_arg = arg; 573 ih->ih_next = 0; 574 intr_establish(1, level, ih); 575 return (void *)ih; 576 } 577 578 /* 579 * softintr_disestablish(): MI interface. disestablish the specified 580 * software interrupt. 581 */ 582 void 583 softintr_disestablish(cookie) 584 void *cookie; 585 { 586 587 intr_disestablish(1, cookie); 588 free(cookie, M_DEVBUF); 589 } 590 591 #ifdef MULTIPROCESSOR 592 /* 593 * Called by interrupt stubs, etc., to lock/unlock the kernel. 594 */ 595 void 596 intr_lock_kernel() 597 { 598 599 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); 600 } 601 602 void 603 intr_unlock_kernel() 604 { 605 606 KERNEL_UNLOCK(); 607 } 608 #endif 609