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 * $FreeBSD$ 27 * 28 */ 29 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/rtprio.h> 34 #include <sys/systm.h> 35 #include <sys/interrupt.h> 36 #include <sys/kernel.h> 37 #include <sys/kthread.h> 38 #include <sys/ktr.h> 39 #include <sys/lock.h> 40 #include <sys/malloc.h> 41 #include <sys/mutex.h> 42 #include <sys/proc.h> 43 #include <sys/random.h> 44 #include <sys/resourcevar.h> 45 #include <sys/unistd.h> 46 #include <sys/vmmeter.h> 47 #include <machine/atomic.h> 48 #include <machine/cpu.h> 49 #include <machine/md_var.h> 50 #include <machine/stdarg.h> 51 52 #include <net/netisr.h> /* prototype for legacy_setsoftnet */ 53 54 struct int_entropy { 55 struct proc *proc; 56 int vector; 57 }; 58 59 void *net_ih; 60 void *vm_ih; 61 void *softclock_ih; 62 struct ithd *clk_ithd; 63 struct ithd *tty_ithd; 64 65 static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 66 67 static void ithread_update(struct ithd *); 68 static void ithread_loop(void *); 69 static void start_softintr(void *); 70 static void swi_net(void *); 71 72 u_char 73 ithread_priority(enum intr_type flags) 74 { 75 u_char pri; 76 77 flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 78 INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK); 79 switch (flags) { 80 case INTR_TYPE_TTY: 81 pri = PI_TTYLOW; 82 break; 83 case INTR_TYPE_BIO: 84 /* 85 * XXX We need to refine this. BSD/OS distinguishes 86 * between tape and disk priorities. 87 */ 88 pri = PI_DISK; 89 break; 90 case INTR_TYPE_NET: 91 pri = PI_NET; 92 break; 93 case INTR_TYPE_CAM: 94 pri = PI_DISK; /* XXX or PI_CAM? */ 95 break; 96 case INTR_TYPE_CLK: 97 pri = PI_REALTIME; 98 break; 99 case INTR_TYPE_MISC: 100 pri = PI_DULL; /* don't care */ 101 break; 102 default: 103 /* We didn't specify an interrupt level. */ 104 panic("ithread_priority: no interrupt type in flags"); 105 } 106 107 return pri; 108 } 109 110 /* 111 * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 112 */ 113 static void 114 ithread_update(struct ithd *ithd) 115 { 116 struct intrhand *ih; 117 struct proc *p; 118 int entropy; 119 120 mtx_assert(&ithd->it_lock, MA_OWNED); 121 p = ithd->it_proc; 122 if (p == NULL) 123 return; 124 125 strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name)); 126 ih = TAILQ_FIRST(&ithd->it_handlers); 127 if (ih == NULL) { 128 p->p_pri.pri_level = PRI_MAX_ITHD; 129 ithd->it_flags &= ~IT_ENTROPY; 130 return; 131 } 132 133 entropy = 0; 134 p->p_pri.pri_level = ih->ih_pri; 135 p->p_pri.pri_native = ih->ih_pri; 136 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 137 if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 138 sizeof(p->p_comm)) { 139 strcat(p->p_comm, " "); 140 strcat(p->p_comm, ih->ih_name); 141 } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 142 if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 143 p->p_comm[sizeof(p->p_comm) - 2] = '*'; 144 else 145 p->p_comm[sizeof(p->p_comm) - 2] = '+'; 146 } else 147 strcat(p->p_comm, "+"); 148 if (ih->ih_flags & IH_ENTROPY) 149 entropy++; 150 } 151 152 if (entropy) 153 ithd->it_flags |= IT_ENTROPY; 154 else 155 ithd->it_flags &= ~IT_ENTROPY; 156 157 CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm); 158 } 159 160 int 161 ithread_create(struct ithd **ithread, int vector, int flags, 162 void (*disable)(int), void (*enable)(int), const char *fmt, ...) 163 { 164 struct ithd *ithd; 165 struct proc *p; 166 int error; 167 va_list ap; 168 169 /* The only valid flag during creation is IT_SOFT. */ 170 if ((flags & ~IT_SOFT) != 0) 171 return (EINVAL); 172 173 ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 174 ithd->it_vector = vector; 175 ithd->it_disable = disable; 176 ithd->it_enable = enable; 177 ithd->it_flags = flags; 178 TAILQ_INIT(&ithd->it_handlers); 179 mtx_init(&ithd->it_lock, "ithread", MTX_DEF); 180 mtx_lock(&ithd->it_lock); 181 182 va_start(ap, fmt); 183 vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 184 va_end(ap); 185 186 error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 187 "%s", ithd->it_name); 188 if (error) { 189 mtx_destroy(&ithd->it_lock); 190 free(ithd, M_ITHREAD); 191 return (error); 192 } 193 p->p_pri.pri_class = PRI_ITHD; 194 p->p_pri.pri_level = PRI_MAX_ITHD; 195 p->p_stat = SWAIT; 196 ithd->it_proc = p; 197 p->p_ithd = ithd; 198 if (ithread != NULL) 199 *ithread = ithd; 200 mtx_unlock(&ithd->it_lock); 201 202 CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name); 203 return (0); 204 } 205 206 int 207 ithread_destroy(struct ithd *ithread) 208 { 209 210 if (ithread == NULL) 211 return (EINVAL); 212 213 mtx_lock(&ithread->it_lock); 214 if (!TAILQ_EMPTY(&ithread->it_handlers)) { 215 mtx_unlock(&ithread->it_lock); 216 return (EINVAL); 217 } 218 ithread->it_flags |= IT_DEAD; 219 mtx_lock_spin(&sched_lock); 220 if (ithread->it_proc->p_stat == SWAIT) { 221 ithread->it_proc->p_stat = SRUN; 222 setrunqueue(ithread->it_proc); 223 } 224 mtx_unlock_spin(&sched_lock); 225 mtx_unlock(&ithread->it_lock); 226 CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name); 227 return (0); 228 } 229 230 int 231 ithread_add_handler(struct ithd* ithread, const char *name, 232 driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 233 void **cookiep) 234 { 235 struct intrhand *ih, *temp_ih; 236 237 if (ithread == NULL || name == NULL || handler == NULL) 238 return (EINVAL); 239 if ((flags & INTR_FAST) !=0) 240 flags |= INTR_EXCL; 241 242 ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 243 ih->ih_handler = handler; 244 ih->ih_argument = arg; 245 ih->ih_name = name; 246 ih->ih_ithread = ithread; 247 ih->ih_pri = pri; 248 if (flags & INTR_FAST) 249 ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 250 else if (flags & INTR_EXCL) 251 ih->ih_flags = IH_EXCLUSIVE; 252 if (flags & INTR_MPSAFE) 253 ih->ih_flags |= IH_MPSAFE; 254 if (flags & INTR_ENTROPY) 255 ih->ih_flags |= IH_ENTROPY; 256 257 mtx_lock(&ithread->it_lock); 258 if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 259 goto fail; 260 if (!TAILQ_EMPTY(&ithread->it_handlers) && 261 (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 262 goto fail; 263 264 TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 265 if (temp_ih->ih_pri > ih->ih_pri) 266 break; 267 if (temp_ih == NULL) 268 TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 269 else 270 TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 271 ithread_update(ithread); 272 mtx_unlock(&ithread->it_lock); 273 274 if (cookiep != NULL) 275 *cookiep = ih; 276 CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name, 277 ithread->it_name); 278 return (0); 279 280 fail: 281 mtx_unlock(&ithread->it_lock); 282 free(ih, M_ITHREAD); 283 return (EINVAL); 284 } 285 286 int 287 ithread_remove_handler(void *cookie) 288 { 289 struct intrhand *handler = (struct intrhand *)cookie; 290 struct ithd *ithread; 291 #ifdef INVARIANTS 292 struct intrhand *ih; 293 #endif 294 295 if (handler == NULL) 296 return (EINVAL); 297 ithread = handler->ih_ithread; 298 KASSERT(ithread != NULL, 299 ("interrupt handler \"%s\" has a NULL interrupt thread", 300 handler->ih_name)); 301 CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name, 302 ithread->it_name); 303 mtx_lock(&ithread->it_lock); 304 #ifdef INVARIANTS 305 TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 306 if (ih == handler) 307 goto ok; 308 mtx_unlock(&ithread->it_lock); 309 panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 310 ih->ih_name, ithread->it_name); 311 ok: 312 #endif 313 /* 314 * If the interrupt thread is already running, then just mark this 315 * handler as being dead and let the ithread do the actual removal. 316 */ 317 mtx_lock_spin(&sched_lock); 318 if (ithread->it_proc->p_stat != SWAIT) { 319 handler->ih_flags |= IH_DEAD; 320 321 /* 322 * Ensure that the thread will process the handler list 323 * again and remove this handler if it has already passed 324 * it on the list. 325 */ 326 ithread->it_need = 1; 327 } else 328 TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 329 mtx_unlock_spin(&sched_lock); 330 if ((handler->ih_flags & IH_DEAD) != 0) 331 msleep(handler, &ithread->it_lock, PUSER, "itrmh", 0); 332 ithread_update(ithread); 333 mtx_unlock(&ithread->it_lock); 334 free(handler, M_ITHREAD); 335 return (0); 336 } 337 338 int 339 ithread_schedule(struct ithd *ithread, int do_switch) 340 { 341 struct int_entropy entropy; 342 struct proc *p; 343 critical_t savecrit; 344 345 /* 346 * If no ithread or no handlers, then we have a stray interrupt. 347 */ 348 if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 349 return (EINVAL); 350 351 /* 352 * If any of the handlers for this ithread claim to be good 353 * sources of entropy, then gather some. 354 */ 355 if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 356 entropy.vector = ithread->it_vector; 357 entropy.proc = CURPROC; 358 random_harvest(&entropy, sizeof(entropy), 2, 0, 359 RANDOM_INTERRUPT); 360 } 361 362 p = ithread->it_proc; 363 KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name)); 364 CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm, 365 ithread->it_need); 366 367 /* 368 * Set it_need to tell the thread to keep running if it is already 369 * running. Then, grab sched_lock and see if we actually need to 370 * put this thread on the runqueue. If so and the do_switch flag is 371 * true, then switch to the ithread immediately. Otherwise, use 372 * need_resched() to guarantee that this ithread will run before any 373 * userland processes. 374 */ 375 ithread->it_need = 1; 376 mtx_lock_spin(&sched_lock); 377 if (p->p_stat == SWAIT) { 378 CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid); 379 p->p_stat = SRUN; 380 setrunqueue(p); 381 if (do_switch && curproc->p_stat == SRUN) { 382 savecrit = sched_lock.mtx_savecrit; 383 mtx_intr_enable(&sched_lock); 384 if (curproc != PCPU_GET(idleproc)) 385 setrunqueue(curproc); 386 curproc->p_stats->p_ru.ru_nvcsw++; 387 mi_switch(); 388 sched_lock.mtx_savecrit = savecrit; 389 } else 390 need_resched(curproc); 391 } else { 392 CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d", 393 p->p_pid, ithread->it_need, p->p_stat); 394 } 395 mtx_unlock_spin(&sched_lock); 396 397 return (0); 398 } 399 400 int 401 swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 402 void *arg, int pri, enum intr_type flags, void **cookiep) 403 { 404 struct ithd *ithd; 405 int error; 406 407 if (flags & (INTR_FAST | INTR_ENTROPY)) 408 return (EINVAL); 409 410 ithd = (ithdp != NULL) ? *ithdp : NULL; 411 412 if (ithd != NULL) { 413 if ((ithd->it_flags & IT_SOFT) == 0) 414 return(EINVAL); 415 } else { 416 error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 417 "swi%d:", pri); 418 if (error) 419 return (error); 420 421 if (ithdp != NULL) 422 *ithdp = ithd; 423 } 424 return (ithread_add_handler(ithd, name, handler, arg, 425 (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 426 } 427 428 429 /* 430 * Schedule a heavyweight software interrupt process. 431 */ 432 void 433 swi_sched(void *cookie, int flags) 434 { 435 struct intrhand *ih = (struct intrhand *)cookie; 436 struct ithd *it = ih->ih_ithread; 437 int error; 438 439 atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 440 441 CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 442 it->it_proc->p_pid, it->it_proc->p_comm, it->it_need); 443 444 /* 445 * Set ih_need for this handler so that if the ithread is already 446 * running it will execute this handler on the next pass. Otherwise, 447 * it will execute it the next time it runs. 448 */ 449 atomic_store_rel_int(&ih->ih_need, 1); 450 if (!(flags & SWI_DELAY)) { 451 error = ithread_schedule(it, !cold && flags & SWI_SWITCH); 452 KASSERT(error == 0, ("stray software interrupt")); 453 } 454 } 455 456 /* 457 * This is the main code for interrupt threads. 458 */ 459 void 460 ithread_loop(void *arg) 461 { 462 struct ithd *ithd; /* our thread context */ 463 struct intrhand *ih; /* and our interrupt handler chain */ 464 struct proc *p; 465 466 p = curproc; 467 ithd = (struct ithd *)arg; /* point to myself */ 468 KASSERT(ithd->it_proc == p && p->p_ithd == ithd, 469 (__func__ ": ithread and proc linkage out of sync")); 470 471 /* 472 * As long as we have interrupts outstanding, go through the 473 * list of handlers, giving each one a go at it. 474 */ 475 for (;;) { 476 /* 477 * If we are an orphaned thread, then just die. 478 */ 479 if (ithd->it_flags & IT_DEAD) { 480 CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting", 481 p->p_pid, p->p_comm); 482 p->p_ithd = NULL; 483 mtx_destroy(&ithd->it_lock); 484 mtx_lock(&Giant); 485 free(ithd, M_ITHREAD); 486 kthread_exit(0); 487 } 488 489 CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d", 490 p->p_pid, p->p_comm, ithd->it_need); 491 while (ithd->it_need) { 492 /* 493 * Service interrupts. If another interrupt 494 * arrives while we are running, they will set 495 * it_need to denote that we should make 496 * another pass. 497 */ 498 atomic_store_rel_int(&ithd->it_need, 0); 499 restart: 500 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 501 if (ithd->it_flags & IT_SOFT && !ih->ih_need) 502 continue; 503 atomic_store_rel_int(&ih->ih_need, 0); 504 CTR5(KTR_INTR, 505 __func__ ": pid %d ih=%p: %p(%p) flg=%x", 506 p->p_pid, (void *)ih, 507 (void *)ih->ih_handler, ih->ih_argument, 508 ih->ih_flags); 509 510 if ((ih->ih_flags & IH_DEAD) != 0) { 511 mtx_lock(&ithd->it_lock); 512 TAILQ_REMOVE(&ithd->it_handlers, ih, 513 ih_next); 514 wakeup(ih); 515 mtx_unlock(&ithd->it_lock); 516 goto restart; 517 } 518 if ((ih->ih_flags & IH_MPSAFE) == 0) 519 mtx_lock(&Giant); 520 ih->ih_handler(ih->ih_argument); 521 if ((ih->ih_flags & IH_MPSAFE) == 0) 522 mtx_unlock(&Giant); 523 } 524 } 525 526 /* 527 * Processed all our interrupts. Now get the sched 528 * lock. This may take a while and it_need may get 529 * set again, so we have to check it again. 530 */ 531 mtx_assert(&Giant, MA_NOTOWNED); 532 mtx_lock_spin(&sched_lock); 533 if (!ithd->it_need) { 534 /* 535 * Should we call this earlier in the loop above? 536 */ 537 if (ithd->it_enable != NULL) 538 ithd->it_enable(ithd->it_vector); 539 p->p_stat = SWAIT; /* we're idle */ 540 CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid); 541 mi_switch(); 542 CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid); 543 } 544 mtx_unlock_spin(&sched_lock); 545 } 546 } 547 548 /* 549 * Start standard software interrupt threads 550 */ 551 static void 552 start_softintr(void *dummy) 553 { 554 555 if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) || 556 swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 557 INTR_MPSAFE, &softclock_ih) || 558 swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 559 panic("died while creating standard software ithreads"); 560 561 PROC_LOCK(clk_ithd->it_proc); 562 clk_ithd->it_proc->p_flag |= P_NOLOAD; 563 PROC_UNLOCK(clk_ithd->it_proc); 564 } 565 SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 566 567 void 568 legacy_setsoftnet(void) 569 { 570 swi_sched(net_ih, SWI_NOSWITCH); 571 } 572 573 /* 574 * XXX: This should really be in the network code somewhere and installed 575 * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 576 */ 577 void (*netisrs[32]) __P((void)); 578 u_int netisr; 579 580 int 581 register_netisr(num, handler) 582 int num; 583 netisr_t *handler; 584 { 585 586 if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 587 printf("register_netisr: bad isr number: %d\n", num); 588 return (EINVAL); 589 } 590 netisrs[num] = handler; 591 return (0); 592 } 593 594 int 595 unregister_netisr(num) 596 int num; 597 { 598 599 if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 600 printf("unregister_netisr: bad isr number: %d\n", num); 601 return (EINVAL); 602 } 603 netisrs[num] = NULL; 604 return (0); 605 } 606 607 static void 608 swi_net(void *dummy) 609 { 610 u_int bits; 611 int i; 612 613 bits = atomic_readandclear_int(&netisr); 614 while ((i = ffs(bits)) != 0) { 615 i--; 616 if (netisrs[i] != NULL) 617 netisrs[i](); 618 else 619 printf("swi_net: unregistered isr number: %d.\n", i); 620 bits &= ~(1 << i); 621 } 622 } 623