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