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