1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_ddb.h" 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/conf.h> 35 #include <sys/rtprio.h> 36 #include <sys/systm.h> 37 #include <sys/interrupt.h> 38 #include <sys/kernel.h> 39 #include <sys/kthread.h> 40 #include <sys/ktr.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mutex.h> 44 #include <sys/proc.h> 45 #include <sys/random.h> 46 #include <sys/resourcevar.h> 47 #include <sys/sysctl.h> 48 #include <sys/unistd.h> 49 #include <sys/vmmeter.h> 50 #include <machine/atomic.h> 51 #include <machine/cpu.h> 52 #include <machine/md_var.h> 53 #include <machine/stdarg.h> 54 #ifdef DDB 55 #include <ddb/ddb.h> 56 #include <ddb/db_sym.h> 57 #endif 58 59 struct int_entropy { 60 struct proc *proc; 61 uintptr_t vector; 62 }; 63 64 struct ithd *clk_ithd; 65 struct ithd *tty_ithd; 66 void *softclock_ih; 67 void *vm_ih; 68 69 static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 70 71 static int intr_storm_threshold = 500; 72 TUNABLE_INT("hw.intr_storm_threshold", &intr_storm_threshold); 73 SYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold, CTLFLAG_RW, 74 &intr_storm_threshold, 0, 75 "Number of consecutive interrupts before storm protection is enabled"); 76 77 static void ithread_loop(void *); 78 static void ithread_update(struct ithd *); 79 static void start_softintr(void *); 80 81 u_char 82 ithread_priority(enum intr_type flags) 83 { 84 u_char pri; 85 86 flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 87 INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV); 88 switch (flags) { 89 case INTR_TYPE_TTY: 90 pri = PI_TTYLOW; 91 break; 92 case INTR_TYPE_BIO: 93 /* 94 * XXX We need to refine this. BSD/OS distinguishes 95 * between tape and disk priorities. 96 */ 97 pri = PI_DISK; 98 break; 99 case INTR_TYPE_NET: 100 pri = PI_NET; 101 break; 102 case INTR_TYPE_CAM: 103 pri = PI_DISK; /* XXX or PI_CAM? */ 104 break; 105 case INTR_TYPE_AV: /* Audio/video */ 106 pri = PI_AV; 107 break; 108 case INTR_TYPE_CLK: 109 pri = PI_REALTIME; 110 break; 111 case INTR_TYPE_MISC: 112 pri = PI_DULL; /* don't care */ 113 break; 114 default: 115 /* We didn't specify an interrupt level. */ 116 panic("ithread_priority: no interrupt type in flags"); 117 } 118 119 return pri; 120 } 121 122 /* 123 * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 124 */ 125 static void 126 ithread_update(struct ithd *ithd) 127 { 128 struct intrhand *ih; 129 struct thread *td; 130 struct proc *p; 131 int entropy; 132 133 mtx_assert(&ithd->it_lock, MA_OWNED); 134 td = ithd->it_td; 135 if (td == NULL) 136 return; 137 p = td->td_proc; 138 139 strlcpy(p->p_comm, ithd->it_name, sizeof(p->p_comm)); 140 141 ih = TAILQ_FIRST(&ithd->it_handlers); 142 if (ih == NULL) { 143 mtx_lock_spin(&sched_lock); 144 td->td_priority = PRI_MAX_ITHD; 145 td->td_base_pri = PRI_MAX_ITHD; 146 mtx_unlock_spin(&sched_lock); 147 ithd->it_flags &= ~IT_ENTROPY; 148 return; 149 } 150 entropy = 0; 151 mtx_lock_spin(&sched_lock); 152 td->td_priority = ih->ih_pri; 153 td->td_base_pri = ih->ih_pri; 154 mtx_unlock_spin(&sched_lock); 155 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 156 if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 157 sizeof(p->p_comm)) { 158 strcat(p->p_comm, " "); 159 strcat(p->p_comm, ih->ih_name); 160 } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 161 if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 162 p->p_comm[sizeof(p->p_comm) - 2] = '*'; 163 else 164 p->p_comm[sizeof(p->p_comm) - 2] = '+'; 165 } else 166 strcat(p->p_comm, "+"); 167 if (ih->ih_flags & IH_ENTROPY) 168 entropy++; 169 } 170 if (entropy) 171 ithd->it_flags |= IT_ENTROPY; 172 else 173 ithd->it_flags &= ~IT_ENTROPY; 174 CTR2(KTR_INTR, "%s: updated %s", __func__, p->p_comm); 175 } 176 177 int 178 ithread_create(struct ithd **ithread, uintptr_t vector, int flags, 179 void (*disable)(uintptr_t), void (*enable)(uintptr_t), const char *fmt, ...) 180 { 181 struct ithd *ithd; 182 struct thread *td; 183 struct proc *p; 184 int error; 185 va_list ap; 186 187 /* The only valid flag during creation is IT_SOFT. */ 188 if ((flags & ~IT_SOFT) != 0) 189 return (EINVAL); 190 191 ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 192 ithd->it_vector = vector; 193 ithd->it_disable = disable; 194 ithd->it_enable = enable; 195 ithd->it_flags = flags; 196 TAILQ_INIT(&ithd->it_handlers); 197 mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF); 198 199 va_start(ap, fmt); 200 vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 201 va_end(ap); 202 203 error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 204 0, "%s", ithd->it_name); 205 if (error) { 206 mtx_destroy(&ithd->it_lock); 207 free(ithd, M_ITHREAD); 208 return (error); 209 } 210 td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ 211 mtx_lock_spin(&sched_lock); 212 td->td_ksegrp->kg_pri_class = PRI_ITHD; 213 td->td_priority = PRI_MAX_ITHD; 214 TD_SET_IWAIT(td); 215 mtx_unlock_spin(&sched_lock); 216 ithd->it_td = td; 217 td->td_ithd = ithd; 218 if (ithread != NULL) 219 *ithread = ithd; 220 CTR2(KTR_INTR, "%s: created %s", __func__, ithd->it_name); 221 return (0); 222 } 223 224 int 225 ithread_destroy(struct ithd *ithread) 226 { 227 228 struct thread *td; 229 if (ithread == NULL) 230 return (EINVAL); 231 232 td = ithread->it_td; 233 mtx_lock(&ithread->it_lock); 234 if (!TAILQ_EMPTY(&ithread->it_handlers)) { 235 mtx_unlock(&ithread->it_lock); 236 return (EINVAL); 237 } 238 ithread->it_flags |= IT_DEAD; 239 mtx_lock_spin(&sched_lock); 240 if (TD_AWAITING_INTR(td)) { 241 TD_CLR_IWAIT(td); 242 setrunqueue(td); 243 } 244 mtx_unlock_spin(&sched_lock); 245 mtx_unlock(&ithread->it_lock); 246 CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_name); 247 return (0); 248 } 249 250 int 251 ithread_add_handler(struct ithd* ithread, const char *name, 252 driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 253 void **cookiep) 254 { 255 struct intrhand *ih, *temp_ih; 256 257 if (ithread == NULL || name == NULL || handler == NULL) 258 return (EINVAL); 259 260 ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 261 ih->ih_handler = handler; 262 ih->ih_argument = arg; 263 ih->ih_name = name; 264 ih->ih_ithread = ithread; 265 ih->ih_pri = pri; 266 if (flags & INTR_FAST) 267 ih->ih_flags = IH_FAST; 268 else if (flags & INTR_EXCL) 269 ih->ih_flags = IH_EXCLUSIVE; 270 if (flags & INTR_MPSAFE) 271 ih->ih_flags |= IH_MPSAFE; 272 if (flags & INTR_ENTROPY) 273 ih->ih_flags |= IH_ENTROPY; 274 275 mtx_lock(&ithread->it_lock); 276 if ((flags & INTR_EXCL) != 0 && !TAILQ_EMPTY(&ithread->it_handlers)) 277 goto fail; 278 if (!TAILQ_EMPTY(&ithread->it_handlers)) { 279 temp_ih = TAILQ_FIRST(&ithread->it_handlers); 280 if (temp_ih->ih_flags & IH_EXCLUSIVE) 281 goto fail; 282 if ((ih->ih_flags & IH_FAST) && !(temp_ih->ih_flags & IH_FAST)) 283 goto fail; 284 if (!(ih->ih_flags & IH_FAST) && (temp_ih->ih_flags & IH_FAST)) 285 goto fail; 286 } 287 288 TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 289 if (temp_ih->ih_pri > ih->ih_pri) 290 break; 291 if (temp_ih == NULL) 292 TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 293 else 294 TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 295 ithread_update(ithread); 296 mtx_unlock(&ithread->it_lock); 297 298 if (cookiep != NULL) 299 *cookiep = ih; 300 CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name, 301 ithread->it_name); 302 return (0); 303 304 fail: 305 mtx_unlock(&ithread->it_lock); 306 free(ih, M_ITHREAD); 307 return (EINVAL); 308 } 309 310 int 311 ithread_remove_handler(void *cookie) 312 { 313 struct intrhand *handler = (struct intrhand *)cookie; 314 struct ithd *ithread; 315 #ifdef INVARIANTS 316 struct intrhand *ih; 317 #endif 318 319 if (handler == NULL) 320 return (EINVAL); 321 ithread = handler->ih_ithread; 322 KASSERT(ithread != NULL, 323 ("interrupt handler \"%s\" has a NULL interrupt thread", 324 handler->ih_name)); 325 CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name, 326 ithread->it_name); 327 mtx_lock(&ithread->it_lock); 328 #ifdef INVARIANTS 329 TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 330 if (ih == handler) 331 goto ok; 332 mtx_unlock(&ithread->it_lock); 333 panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 334 ih->ih_name, ithread->it_name); 335 ok: 336 #endif 337 /* 338 * If the interrupt thread is already running, then just mark this 339 * handler as being dead and let the ithread do the actual removal. 340 * 341 * During a cold boot while cold is set, msleep() does not sleep, 342 * so we have to remove the handler here rather than letting the 343 * thread do it. 344 */ 345 mtx_lock_spin(&sched_lock); 346 if (!TD_AWAITING_INTR(ithread->it_td) && !cold) { 347 handler->ih_flags |= IH_DEAD; 348 349 /* 350 * Ensure that the thread will process the handler list 351 * again and remove this handler if it has already passed 352 * it on the list. 353 */ 354 ithread->it_need = 1; 355 } else 356 TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 357 mtx_unlock_spin(&sched_lock); 358 if ((handler->ih_flags & IH_DEAD) != 0) 359 msleep(handler, &ithread->it_lock, PUSER, "itrmh", 0); 360 ithread_update(ithread); 361 mtx_unlock(&ithread->it_lock); 362 free(handler, M_ITHREAD); 363 return (0); 364 } 365 366 int 367 ithread_schedule(struct ithd *ithread, int do_switch) 368 { 369 struct int_entropy entropy; 370 struct thread *td; 371 struct thread *ctd; 372 struct proc *p; 373 374 /* 375 * If no ithread or no handlers, then we have a stray interrupt. 376 */ 377 if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 378 return (EINVAL); 379 380 ctd = curthread; 381 /* 382 * If any of the handlers for this ithread claim to be good 383 * sources of entropy, then gather some. 384 */ 385 if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 386 entropy.vector = ithread->it_vector; 387 entropy.proc = ctd->td_proc; 388 random_harvest(&entropy, sizeof(entropy), 2, 0, 389 RANDOM_INTERRUPT); 390 } 391 392 td = ithread->it_td; 393 p = td->td_proc; 394 KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name)); 395 CTR4(KTR_INTR, "%s: pid %d: (%s) need = %d", 396 __func__, p->p_pid, p->p_comm, ithread->it_need); 397 398 /* 399 * Set it_need to tell the thread to keep running if it is already 400 * running. Then, grab sched_lock and see if we actually need to 401 * put this thread on the runqueue. If so and the do_switch flag is 402 * true and it is safe to switch, then switch to the ithread 403 * immediately. Otherwise, set the needresched flag to guarantee 404 * that this ithread will run before any userland processes. 405 */ 406 ithread->it_need = 1; 407 mtx_lock_spin(&sched_lock); 408 if (TD_AWAITING_INTR(td)) { 409 CTR2(KTR_INTR, "%s: setrunqueue %d", __func__, p->p_pid); 410 TD_CLR_IWAIT(td); 411 setrunqueue(td); 412 if (do_switch && 413 (ctd->td_critnest == 1) ) { 414 KASSERT((TD_IS_RUNNING(ctd)), 415 ("ithread_schedule: Bad state for curthread.")); 416 if (ctd->td_flags & TDF_IDLETD) 417 ctd->td_state = TDS_CAN_RUN; /* XXXKSE */ 418 mi_switch(SW_INVOL); 419 } else { 420 curthread->td_flags |= TDF_NEEDRESCHED; 421 } 422 } else { 423 CTR4(KTR_INTR, "%s: pid %d: it_need %d, state %d", 424 __func__, p->p_pid, ithread->it_need, td->td_state); 425 } 426 mtx_unlock_spin(&sched_lock); 427 428 return (0); 429 } 430 431 int 432 swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 433 void *arg, int pri, enum intr_type flags, void **cookiep) 434 { 435 struct ithd *ithd; 436 int error; 437 438 if (flags & (INTR_FAST | INTR_ENTROPY)) 439 return (EINVAL); 440 441 ithd = (ithdp != NULL) ? *ithdp : NULL; 442 443 if (ithd != NULL) { 444 if ((ithd->it_flags & IT_SOFT) == 0) 445 return(EINVAL); 446 } else { 447 error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 448 "swi%d:", pri); 449 if (error) 450 return (error); 451 452 if (ithdp != NULL) 453 *ithdp = ithd; 454 } 455 return (ithread_add_handler(ithd, name, handler, arg, 456 (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 457 } 458 459 460 /* 461 * Schedule a heavyweight software interrupt process. 462 */ 463 void 464 swi_sched(void *cookie, int flags) 465 { 466 struct intrhand *ih = (struct intrhand *)cookie; 467 struct ithd *it = ih->ih_ithread; 468 int error; 469 470 atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 471 472 CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 473 it->it_td->td_proc->p_pid, it->it_td->td_proc->p_comm, it->it_need); 474 475 /* 476 * Set ih_need for this handler so that if the ithread is already 477 * running it will execute this handler on the next pass. Otherwise, 478 * it will execute it the next time it runs. 479 */ 480 atomic_store_rel_int(&ih->ih_need, 1); 481 if (!(flags & SWI_DELAY)) { 482 error = ithread_schedule(it, !cold && !dumping); 483 KASSERT(error == 0, ("stray software interrupt")); 484 } 485 } 486 487 /* 488 * This is the main code for interrupt threads. 489 */ 490 static void 491 ithread_loop(void *arg) 492 { 493 struct ithd *ithd; /* our thread context */ 494 struct intrhand *ih; /* and our interrupt handler chain */ 495 struct thread *td; 496 struct proc *p; 497 int count, warned; 498 499 td = curthread; 500 p = td->td_proc; 501 ithd = (struct ithd *)arg; /* point to myself */ 502 KASSERT(ithd->it_td == td && td->td_ithd == ithd, 503 ("%s: ithread and proc linkage out of sync", __func__)); 504 count = 0; 505 warned = 0; 506 507 /* 508 * As long as we have interrupts outstanding, go through the 509 * list of handlers, giving each one a go at it. 510 */ 511 for (;;) { 512 /* 513 * If we are an orphaned thread, then just die. 514 */ 515 if (ithd->it_flags & IT_DEAD) { 516 CTR3(KTR_INTR, "%s: pid %d: (%s) exiting", __func__, 517 p->p_pid, p->p_comm); 518 td->td_ithd = NULL; 519 mtx_destroy(&ithd->it_lock); 520 free(ithd, M_ITHREAD); 521 kthread_exit(0); 522 } 523 524 CTR4(KTR_INTR, "%s: pid %d: (%s) need=%d", __func__, 525 p->p_pid, p->p_comm, ithd->it_need); 526 while (ithd->it_need) { 527 /* 528 * Service interrupts. If another interrupt 529 * arrives while we are running, they will set 530 * it_need to denote that we should make 531 * another pass. 532 */ 533 atomic_store_rel_int(&ithd->it_need, 0); 534 535 /* 536 * If we detect an interrupt storm, pause with 537 * the source masked for 1/10th of a second. 538 */ 539 if (intr_storm_threshold != 0 && count >= 540 intr_storm_threshold) { 541 if (!warned) { 542 printf( 543 "Interrupt storm detected on \"%s\"; throttling interrupt source\n", 544 p->p_comm); 545 warned = 1; 546 } 547 tsleep(&count, td->td_priority, "istorm", 548 hz / 10); 549 count = 0; 550 } else 551 count++; 552 553 restart: 554 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 555 if (ithd->it_flags & IT_SOFT && !ih->ih_need) 556 continue; 557 atomic_store_rel_int(&ih->ih_need, 0); 558 CTR6(KTR_INTR, 559 "%s: pid %d ih=%p: %p(%p) flg=%x", __func__, 560 p->p_pid, (void *)ih, 561 (void *)ih->ih_handler, ih->ih_argument, 562 ih->ih_flags); 563 564 if ((ih->ih_flags & IH_DEAD) != 0) { 565 mtx_lock(&ithd->it_lock); 566 TAILQ_REMOVE(&ithd->it_handlers, ih, 567 ih_next); 568 wakeup(ih); 569 mtx_unlock(&ithd->it_lock); 570 goto restart; 571 } 572 if ((ih->ih_flags & IH_MPSAFE) == 0) 573 mtx_lock(&Giant); 574 ih->ih_handler(ih->ih_argument); 575 if ((ih->ih_flags & IH_MPSAFE) == 0) 576 mtx_unlock(&Giant); 577 } 578 if (ithd->it_enable != NULL) 579 ithd->it_enable(ithd->it_vector); 580 } 581 WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread"); 582 mtx_assert(&Giant, MA_NOTOWNED); 583 584 /* 585 * Processed all our interrupts. Now get the sched 586 * lock. This may take a while and it_need may get 587 * set again, so we have to check it again. 588 */ 589 mtx_lock_spin(&sched_lock); 590 if (!ithd->it_need) { 591 TD_SET_IWAIT(td); 592 count = 0; 593 CTR2(KTR_INTR, "%s: pid %d: done", __func__, p->p_pid); 594 mi_switch(SW_VOL); 595 CTR2(KTR_INTR, "%s: pid %d: resumed", __func__, p->p_pid); 596 } 597 mtx_unlock_spin(&sched_lock); 598 } 599 } 600 601 #ifdef DDB 602 /* 603 * Dump details about an interrupt handler 604 */ 605 static void 606 db_dump_intrhand(struct intrhand *ih) 607 { 608 int comma; 609 610 db_printf("\t%-10s ", ih->ih_name); 611 switch (ih->ih_pri) { 612 case PI_REALTIME: 613 db_printf("CLK "); 614 break; 615 case PI_AV: 616 db_printf("AV "); 617 break; 618 case PI_TTYHIGH: 619 case PI_TTYLOW: 620 db_printf("TTY "); 621 break; 622 case PI_TAPE: 623 db_printf("TAPE"); 624 break; 625 case PI_NET: 626 db_printf("NET "); 627 break; 628 case PI_DISK: 629 case PI_DISKLOW: 630 db_printf("DISK"); 631 break; 632 case PI_DULL: 633 db_printf("DULL"); 634 break; 635 default: 636 if (ih->ih_pri >= PI_SOFT) 637 db_printf("SWI "); 638 else 639 db_printf("%4u", ih->ih_pri); 640 break; 641 } 642 db_printf(" "); 643 db_printsym((uintptr_t)ih->ih_handler, DB_STGY_PROC); 644 db_printf("(%p)", ih->ih_argument); 645 if (ih->ih_need || 646 (ih->ih_flags & (IH_FAST | IH_EXCLUSIVE | IH_ENTROPY | IH_DEAD | 647 IH_MPSAFE)) != 0) { 648 db_printf(" {"); 649 comma = 0; 650 if (ih->ih_flags & IH_FAST) { 651 db_printf("FAST"); 652 comma = 1; 653 } 654 if (ih->ih_flags & IH_EXCLUSIVE) { 655 if (comma) 656 db_printf(", "); 657 db_printf("EXCL"); 658 comma = 1; 659 } 660 if (ih->ih_flags & IH_ENTROPY) { 661 if (comma) 662 db_printf(", "); 663 db_printf("ENTROPY"); 664 comma = 1; 665 } 666 if (ih->ih_flags & IH_DEAD) { 667 if (comma) 668 db_printf(", "); 669 db_printf("DEAD"); 670 comma = 1; 671 } 672 if (ih->ih_flags & IH_MPSAFE) { 673 if (comma) 674 db_printf(", "); 675 db_printf("MPSAFE"); 676 comma = 1; 677 } 678 if (ih->ih_need) { 679 if (comma) 680 db_printf(", "); 681 db_printf("NEED"); 682 } 683 db_printf("}"); 684 } 685 db_printf("\n"); 686 } 687 688 /* 689 * Dump details about an ithread 690 */ 691 void 692 db_dump_ithread(struct ithd *ithd, int handlers) 693 { 694 struct proc *p; 695 struct intrhand *ih; 696 int comma; 697 698 if (ithd->it_td != NULL) { 699 p = ithd->it_td->td_proc; 700 db_printf("%s (pid %d)", p->p_comm, p->p_pid); 701 } else 702 db_printf("%s: (no thread)", ithd->it_name); 703 if ((ithd->it_flags & (IT_SOFT | IT_ENTROPY | IT_DEAD)) != 0 || 704 ithd->it_need) { 705 db_printf(" {"); 706 comma = 0; 707 if (ithd->it_flags & IT_SOFT) { 708 db_printf("SOFT"); 709 comma = 1; 710 } 711 if (ithd->it_flags & IT_ENTROPY) { 712 if (comma) 713 db_printf(", "); 714 db_printf("ENTROPY"); 715 comma = 1; 716 } 717 if (ithd->it_flags & IT_DEAD) { 718 if (comma) 719 db_printf(", "); 720 db_printf("DEAD"); 721 comma = 1; 722 } 723 if (ithd->it_need) { 724 if (comma) 725 db_printf(", "); 726 db_printf("NEED"); 727 } 728 db_printf("}"); 729 } 730 db_printf("\n"); 731 732 if (handlers) 733 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) 734 db_dump_intrhand(ih); 735 } 736 #endif /* DDB */ 737 738 /* 739 * Start standard software interrupt threads 740 */ 741 static void 742 start_softintr(void *dummy) 743 { 744 struct proc *p; 745 746 if (swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 747 INTR_MPSAFE, &softclock_ih) || 748 swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih)) 749 panic("died while creating standard software ithreads"); 750 751 p = clk_ithd->it_td->td_proc; 752 PROC_LOCK(p); 753 p->p_flag |= P_NOLOAD; 754 PROC_UNLOCK(p); 755 } 756 SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 757 758 /* 759 * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. 760 * The data for this machine dependent, and the declarations are in machine 761 * dependent code. The layout of intrnames and intrcnt however is machine 762 * independent. 763 * 764 * We do not know the length of intrcnt and intrnames at compile time, so 765 * calculate things at run time. 766 */ 767 static int 768 sysctl_intrnames(SYSCTL_HANDLER_ARGS) 769 { 770 return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames, 771 req)); 772 } 773 774 SYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD, 775 NULL, 0, sysctl_intrnames, "", "Interrupt Names"); 776 777 static int 778 sysctl_intrcnt(SYSCTL_HANDLER_ARGS) 779 { 780 return (sysctl_handle_opaque(oidp, intrcnt, 781 (char *)eintrcnt - (char *)intrcnt, req)); 782 } 783 784 SYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD, 785 NULL, 0, sysctl_intrcnt, "", "Interrupt Counts"); 786 787 #ifdef DDB 788 /* 789 * DDB command to dump the interrupt statistics. 790 */ 791 DB_SHOW_COMMAND(intrcnt, db_show_intrcnt) 792 { 793 u_long *i; 794 char *cp; 795 int quit; 796 797 cp = intrnames; 798 db_setup_paging(db_simple_pager, &quit, DB_LINES_PER_PAGE); 799 for (i = intrcnt, quit = 0; i != eintrcnt && !quit; i++) { 800 if (*cp == '\0') 801 break; 802 if (*i != 0) 803 db_printf("%s\t%lu\n", cp, *i); 804 cp += strlen(cp) + 1; 805 } 806 } 807 #endif 808