1 /*- 2 * Copyright (c) 2003 John Baldwin <jhb@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, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 /* 30 * Machine dependent interrupt code for x86. For x86, we have to 31 * deal with different PICs. Thus, we use the passed in vector to lookup 32 * an interrupt source associated with that vector. The interrupt source 33 * describes which PIC the source belongs to and includes methods to handle 34 * that source. 35 */ 36 37 #include "opt_atpic.h" 38 #include "opt_ddb.h" 39 40 #include <sys/param.h> 41 #include <sys/bus.h> 42 #include <sys/interrupt.h> 43 #include <sys/ktr.h> 44 #include <sys/kernel.h> 45 #include <sys/lock.h> 46 #include <sys/mutex.h> 47 #include <sys/proc.h> 48 #include <sys/queue.h> 49 #include <sys/sbuf.h> 50 #include <sys/smp.h> 51 #include <sys/sx.h> 52 #include <sys/sysctl.h> 53 #include <sys/syslog.h> 54 #include <sys/systm.h> 55 #include <sys/taskqueue.h> 56 #include <sys/vmmeter.h> 57 #include <machine/clock.h> 58 #include <machine/intr_machdep.h> 59 #include <machine/smp.h> 60 #ifdef DDB 61 #include <ddb/ddb.h> 62 #endif 63 64 #ifndef DEV_ATPIC 65 #include <machine/segments.h> 66 #include <machine/frame.h> 67 #include <dev/ic/i8259.h> 68 #include <x86/isa/icu.h> 69 #include <isa/isareg.h> 70 #endif 71 72 #define MAX_STRAY_LOG 5 73 74 typedef void (*mask_fn)(void *); 75 76 static int intrcnt_index; 77 static struct intsrc *interrupt_sources[NUM_IO_INTS]; 78 #ifdef SMP 79 static struct intsrc *interrupt_sorted[NUM_IO_INTS]; 80 CTASSERT(sizeof(interrupt_sources) == sizeof(interrupt_sorted)); 81 static int intrbalance; 82 SYSCTL_INT(_hw, OID_AUTO, intrbalance, CTLFLAG_RW, &intrbalance, 0, 83 "Interrupt auto-balance interval (seconds). Zero disables."); 84 static struct timeout_task intrbalance_task; 85 #endif 86 static struct sx intrsrc_lock; 87 static struct mtx intrpic_lock; 88 static struct mtx intrcnt_lock; 89 static TAILQ_HEAD(pics_head, pic) pics; 90 91 #if defined(SMP) && !defined(EARLY_AP_STARTUP) 92 static int assign_cpu; 93 #endif 94 95 u_long intrcnt[INTRCNT_COUNT]; 96 char intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)]; 97 size_t sintrcnt = sizeof(intrcnt); 98 size_t sintrnames = sizeof(intrnames); 99 100 static int intr_assign_cpu(void *arg, int cpu); 101 static void intr_disable_src(void *arg); 102 static void intr_init(void *__dummy); 103 static int intr_pic_registered(struct pic *pic); 104 static void intrcnt_setname(const char *name, int index); 105 static void intrcnt_updatename(struct intsrc *is); 106 static void intrcnt_register(struct intsrc *is); 107 108 static int 109 intr_pic_registered(struct pic *pic) 110 { 111 struct pic *p; 112 113 TAILQ_FOREACH(p, &pics, pics) { 114 if (p == pic) 115 return (1); 116 } 117 return (0); 118 } 119 120 /* 121 * Register a new interrupt controller (PIC). This is to support suspend 122 * and resume where we suspend/resume controllers rather than individual 123 * sources. This also allows controllers with no active sources (such as 124 * 8259As in a system using the APICs) to participate in suspend and resume. 125 */ 126 int 127 intr_register_pic(struct pic *pic) 128 { 129 int error; 130 131 mtx_lock(&intrpic_lock); 132 if (intr_pic_registered(pic)) 133 error = EBUSY; 134 else { 135 TAILQ_INSERT_TAIL(&pics, pic, pics); 136 error = 0; 137 } 138 mtx_unlock(&intrpic_lock); 139 return (error); 140 } 141 142 /* 143 * Register a new interrupt source with the global interrupt system. 144 * The global interrupts need to be disabled when this function is 145 * called. 146 */ 147 int 148 intr_register_source(struct intsrc *isrc) 149 { 150 int error, vector; 151 152 KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC")); 153 vector = isrc->is_pic->pic_vector(isrc); 154 if (interrupt_sources[vector] != NULL) 155 return (EEXIST); 156 error = intr_event_create(&isrc->is_event, isrc, 0, vector, 157 intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source, 158 (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:", 159 vector); 160 if (error) 161 return (error); 162 sx_xlock(&intrsrc_lock); 163 if (interrupt_sources[vector] != NULL) { 164 sx_xunlock(&intrsrc_lock); 165 intr_event_destroy(isrc->is_event); 166 return (EEXIST); 167 } 168 intrcnt_register(isrc); 169 interrupt_sources[vector] = isrc; 170 isrc->is_handlers = 0; 171 sx_xunlock(&intrsrc_lock); 172 return (0); 173 } 174 175 struct intsrc * 176 intr_lookup_source(int vector) 177 { 178 179 return (interrupt_sources[vector]); 180 } 181 182 int 183 intr_add_handler(const char *name, int vector, driver_filter_t filter, 184 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 185 { 186 struct intsrc *isrc; 187 int error; 188 189 isrc = intr_lookup_source(vector); 190 if (isrc == NULL) 191 return (EINVAL); 192 error = intr_event_add_handler(isrc->is_event, name, filter, handler, 193 arg, intr_priority(flags), flags, cookiep); 194 if (error == 0) { 195 sx_xlock(&intrsrc_lock); 196 intrcnt_updatename(isrc); 197 isrc->is_handlers++; 198 if (isrc->is_handlers == 1) { 199 isrc->is_pic->pic_enable_intr(isrc); 200 isrc->is_pic->pic_enable_source(isrc); 201 } 202 sx_xunlock(&intrsrc_lock); 203 } 204 return (error); 205 } 206 207 int 208 intr_remove_handler(void *cookie) 209 { 210 struct intsrc *isrc; 211 int error; 212 213 isrc = intr_handler_source(cookie); 214 error = intr_event_remove_handler(cookie); 215 if (error == 0) { 216 sx_xlock(&intrsrc_lock); 217 isrc->is_handlers--; 218 if (isrc->is_handlers == 0) { 219 isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); 220 isrc->is_pic->pic_disable_intr(isrc); 221 } 222 intrcnt_updatename(isrc); 223 sx_xunlock(&intrsrc_lock); 224 } 225 return (error); 226 } 227 228 int 229 intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) 230 { 231 struct intsrc *isrc; 232 233 isrc = intr_lookup_source(vector); 234 if (isrc == NULL) 235 return (EINVAL); 236 return (isrc->is_pic->pic_config_intr(isrc, trig, pol)); 237 } 238 239 static void 240 intr_disable_src(void *arg) 241 { 242 struct intsrc *isrc; 243 244 isrc = arg; 245 isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 246 } 247 248 void 249 intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame) 250 { 251 struct intr_event *ie; 252 int vector; 253 254 /* 255 * We count software interrupts when we process them. The 256 * code here follows previous practice, but there's an 257 * argument for counting hardware interrupts when they're 258 * processed too. 259 */ 260 (*isrc->is_count)++; 261 VM_CNT_INC(v_intr); 262 263 ie = isrc->is_event; 264 265 /* 266 * XXX: We assume that IRQ 0 is only used for the ISA timer 267 * device (clk). 268 */ 269 vector = isrc->is_pic->pic_vector(isrc); 270 if (vector == 0) 271 clkintr_pending = 1; 272 273 /* 274 * For stray interrupts, mask and EOI the source, bump the 275 * stray count, and log the condition. 276 */ 277 if (intr_event_handle(ie, frame) != 0) { 278 isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 279 (*isrc->is_straycount)++; 280 if (*isrc->is_straycount < MAX_STRAY_LOG) 281 log(LOG_ERR, "stray irq%d\n", vector); 282 else if (*isrc->is_straycount == MAX_STRAY_LOG) 283 log(LOG_CRIT, 284 "too many stray irq %d's: not logging anymore\n", 285 vector); 286 } 287 } 288 289 void 290 intr_resume(bool suspend_cancelled) 291 { 292 struct pic *pic; 293 294 #ifndef DEV_ATPIC 295 atpic_reset(); 296 #endif 297 mtx_lock(&intrpic_lock); 298 TAILQ_FOREACH(pic, &pics, pics) { 299 if (pic->pic_resume != NULL) 300 pic->pic_resume(pic, suspend_cancelled); 301 } 302 mtx_unlock(&intrpic_lock); 303 } 304 305 void 306 intr_suspend(void) 307 { 308 struct pic *pic; 309 310 mtx_lock(&intrpic_lock); 311 TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) { 312 if (pic->pic_suspend != NULL) 313 pic->pic_suspend(pic); 314 } 315 mtx_unlock(&intrpic_lock); 316 } 317 318 static int 319 intr_assign_cpu(void *arg, int cpu) 320 { 321 #ifdef SMP 322 struct intsrc *isrc; 323 int error; 324 325 #ifdef EARLY_AP_STARTUP 326 MPASS(mp_ncpus == 1 || smp_started); 327 328 /* Nothing to do if there is only a single CPU. */ 329 if (mp_ncpus > 1 && cpu != NOCPU) { 330 #else 331 /* 332 * Don't do anything during early boot. We will pick up the 333 * assignment once the APs are started. 334 */ 335 if (assign_cpu && cpu != NOCPU) { 336 #endif 337 isrc = arg; 338 sx_xlock(&intrsrc_lock); 339 error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]); 340 if (error == 0) 341 isrc->is_cpu = cpu; 342 sx_xunlock(&intrsrc_lock); 343 } else 344 error = 0; 345 return (error); 346 #else 347 return (EOPNOTSUPP); 348 #endif 349 } 350 351 static void 352 intrcnt_setname(const char *name, int index) 353 { 354 355 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 356 MAXCOMLEN, name); 357 } 358 359 static void 360 intrcnt_updatename(struct intsrc *is) 361 { 362 363 intrcnt_setname(is->is_event->ie_fullname, is->is_index); 364 } 365 366 static void 367 intrcnt_register(struct intsrc *is) 368 { 369 char straystr[MAXCOMLEN + 1]; 370 371 KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); 372 mtx_lock_spin(&intrcnt_lock); 373 is->is_index = intrcnt_index; 374 intrcnt_index += 2; 375 snprintf(straystr, MAXCOMLEN + 1, "stray irq%d", 376 is->is_pic->pic_vector(is)); 377 intrcnt_updatename(is); 378 is->is_count = &intrcnt[is->is_index]; 379 intrcnt_setname(straystr, is->is_index + 1); 380 is->is_straycount = &intrcnt[is->is_index + 1]; 381 mtx_unlock_spin(&intrcnt_lock); 382 } 383 384 void 385 intrcnt_add(const char *name, u_long **countp) 386 { 387 388 mtx_lock_spin(&intrcnt_lock); 389 *countp = &intrcnt[intrcnt_index]; 390 intrcnt_setname(name, intrcnt_index); 391 intrcnt_index++; 392 mtx_unlock_spin(&intrcnt_lock); 393 } 394 395 static void 396 intr_init(void *dummy __unused) 397 { 398 399 intrcnt_setname("???", 0); 400 intrcnt_index = 1; 401 TAILQ_INIT(&pics); 402 mtx_init(&intrpic_lock, "intrpic", NULL, MTX_DEF); 403 sx_init(&intrsrc_lock, "intrsrc"); 404 mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN); 405 } 406 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); 407 408 static void 409 intr_init_final(void *dummy __unused) 410 { 411 412 /* 413 * Enable interrupts on the BSP after all of the interrupt 414 * controllers are initialized. Device interrupts are still 415 * disabled in the interrupt controllers until interrupt 416 * handlers are registered. Interrupts are enabled on each AP 417 * after their first context switch. 418 */ 419 enable_intr(); 420 } 421 SYSINIT(intr_init_final, SI_SUB_INTR, SI_ORDER_ANY, intr_init_final, NULL); 422 423 #ifndef DEV_ATPIC 424 /* Initialize the two 8259A's to a known-good shutdown state. */ 425 void 426 atpic_reset(void) 427 { 428 429 outb(IO_ICU1, ICW1_RESET | ICW1_IC4); 430 outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS); 431 outb(IO_ICU1 + ICU_IMR_OFFSET, IRQ_MASK(ICU_SLAVEID)); 432 outb(IO_ICU1 + ICU_IMR_OFFSET, MASTER_MODE); 433 outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff); 434 outb(IO_ICU1, OCW3_SEL | OCW3_RR); 435 436 outb(IO_ICU2, ICW1_RESET | ICW1_IC4); 437 outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8); 438 outb(IO_ICU2 + ICU_IMR_OFFSET, ICU_SLAVEID); 439 outb(IO_ICU2 + ICU_IMR_OFFSET, SLAVE_MODE); 440 outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff); 441 outb(IO_ICU2, OCW3_SEL | OCW3_RR); 442 } 443 #endif 444 445 /* Add a description to an active interrupt handler. */ 446 int 447 intr_describe(u_int vector, void *ih, const char *descr) 448 { 449 struct intsrc *isrc; 450 int error; 451 452 isrc = intr_lookup_source(vector); 453 if (isrc == NULL) 454 return (EINVAL); 455 error = intr_event_describe_handler(isrc->is_event, ih, descr); 456 if (error) 457 return (error); 458 intrcnt_updatename(isrc); 459 return (0); 460 } 461 462 void 463 intr_reprogram(void) 464 { 465 struct intsrc *is; 466 int v; 467 468 sx_xlock(&intrsrc_lock); 469 for (v = 0; v < NUM_IO_INTS; v++) { 470 is = interrupt_sources[v]; 471 if (is == NULL) 472 continue; 473 if (is->is_pic->pic_reprogram_pin != NULL) 474 is->is_pic->pic_reprogram_pin(is); 475 } 476 sx_xunlock(&intrsrc_lock); 477 } 478 479 #ifdef DDB 480 /* 481 * Dump data about interrupt handlers 482 */ 483 DB_SHOW_COMMAND(irqs, db_show_irqs) 484 { 485 struct intsrc **isrc; 486 int i, verbose; 487 488 if (strcmp(modif, "v") == 0) 489 verbose = 1; 490 else 491 verbose = 0; 492 isrc = interrupt_sources; 493 for (i = 0; i < NUM_IO_INTS && !db_pager_quit; i++, isrc++) 494 if (*isrc != NULL) 495 db_dump_intr_event((*isrc)->is_event, verbose); 496 } 497 #endif 498 499 #ifdef SMP 500 /* 501 * Support for balancing interrupt sources across CPUs. For now we just 502 * allocate CPUs round-robin. 503 */ 504 505 cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1); 506 static int current_cpu; 507 508 /* 509 * Return the CPU that the next interrupt source should use. For now 510 * this just returns the next local APIC according to round-robin. 511 */ 512 u_int 513 intr_next_cpu(void) 514 { 515 u_int apic_id; 516 517 #ifdef EARLY_AP_STARTUP 518 MPASS(mp_ncpus == 1 || smp_started); 519 if (mp_ncpus == 1) 520 return (PCPU_GET(apic_id)); 521 #else 522 /* Leave all interrupts on the BSP during boot. */ 523 if (!assign_cpu) 524 return (PCPU_GET(apic_id)); 525 #endif 526 527 mtx_lock_spin(&icu_lock); 528 apic_id = cpu_apic_ids[current_cpu]; 529 do { 530 current_cpu++; 531 if (current_cpu > mp_maxid) 532 current_cpu = 0; 533 } while (!CPU_ISSET(current_cpu, &intr_cpus)); 534 mtx_unlock_spin(&icu_lock); 535 return (apic_id); 536 } 537 538 /* Attempt to bind the specified IRQ to the specified CPU. */ 539 int 540 intr_bind(u_int vector, u_char cpu) 541 { 542 struct intsrc *isrc; 543 544 isrc = intr_lookup_source(vector); 545 if (isrc == NULL) 546 return (EINVAL); 547 return (intr_event_bind(isrc->is_event, cpu)); 548 } 549 550 /* 551 * Add a CPU to our mask of valid CPUs that can be destinations of 552 * interrupts. 553 */ 554 void 555 intr_add_cpu(u_int cpu) 556 { 557 558 if (cpu >= MAXCPU) 559 panic("%s: Invalid CPU ID", __func__); 560 if (bootverbose) 561 printf("INTR: Adding local APIC %d as a target\n", 562 cpu_apic_ids[cpu]); 563 564 CPU_SET(cpu, &intr_cpus); 565 } 566 567 #ifndef EARLY_AP_STARTUP 568 /* 569 * Distribute all the interrupt sources among the available CPUs once the 570 * AP's have been launched. 571 */ 572 static void 573 intr_shuffle_irqs(void *arg __unused) 574 { 575 struct intsrc *isrc; 576 u_int cpu; 577 int i; 578 579 /* Don't bother on UP. */ 580 if (mp_ncpus == 1) 581 return; 582 583 /* Round-robin assign a CPU to each enabled source. */ 584 sx_xlock(&intrsrc_lock); 585 assign_cpu = 1; 586 for (i = 0; i < NUM_IO_INTS; i++) { 587 isrc = interrupt_sources[i]; 588 if (isrc != NULL && isrc->is_handlers > 0) { 589 /* 590 * If this event is already bound to a CPU, 591 * then assign the source to that CPU instead 592 * of picking one via round-robin. Note that 593 * this is careful to only advance the 594 * round-robin if the CPU assignment succeeds. 595 */ 596 cpu = isrc->is_event->ie_cpu; 597 if (cpu == NOCPU) 598 cpu = current_cpu; 599 if (isrc->is_pic->pic_assign_cpu(isrc, 600 cpu_apic_ids[cpu]) == 0) { 601 isrc->is_cpu = cpu; 602 if (isrc->is_event->ie_cpu == NOCPU) 603 intr_next_cpu(); 604 } 605 } 606 } 607 sx_xunlock(&intrsrc_lock); 608 } 609 SYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs, 610 NULL); 611 #endif 612 613 /* 614 * TODO: Export this information in a non-MD fashion, integrate with vmstat -i. 615 */ 616 static int 617 sysctl_hw_intrs(SYSCTL_HANDLER_ARGS) 618 { 619 struct sbuf sbuf; 620 struct intsrc *isrc; 621 int error; 622 int i; 623 624 error = sysctl_wire_old_buffer(req, 0); 625 if (error != 0) 626 return (error); 627 628 sbuf_new_for_sysctl(&sbuf, NULL, 128, req); 629 sx_slock(&intrsrc_lock); 630 for (i = 0; i < NUM_IO_INTS; i++) { 631 isrc = interrupt_sources[i]; 632 if (isrc == NULL) 633 continue; 634 sbuf_printf(&sbuf, "%s:%d @%d: %ld\n", 635 isrc->is_event->ie_fullname, 636 isrc->is_index, 637 isrc->is_cpu, 638 *isrc->is_count); 639 } 640 641 sx_sunlock(&intrsrc_lock); 642 error = sbuf_finish(&sbuf); 643 sbuf_delete(&sbuf); 644 return (error); 645 } 646 SYSCTL_PROC(_hw, OID_AUTO, intrs, CTLTYPE_STRING | CTLFLAG_RW, 647 0, 0, sysctl_hw_intrs, "A", "interrupt:number @cpu: count"); 648 649 /* 650 * Compare two, possibly NULL, entries in the interrupt source array 651 * by load. 652 */ 653 static int 654 intrcmp(const void *one, const void *two) 655 { 656 const struct intsrc *i1, *i2; 657 658 i1 = *(const struct intsrc * const *)one; 659 i2 = *(const struct intsrc * const *)two; 660 if (i1 != NULL && i2 != NULL) 661 return (*i1->is_count - *i2->is_count); 662 if (i1 != NULL) 663 return (1); 664 if (i2 != NULL) 665 return (-1); 666 return (0); 667 } 668 669 /* 670 * Balance IRQs across available CPUs according to load. 671 */ 672 static void 673 intr_balance(void *dummy __unused, int pending __unused) 674 { 675 struct intsrc *isrc; 676 int interval; 677 u_int cpu; 678 int i; 679 680 interval = intrbalance; 681 if (interval == 0) 682 goto out; 683 684 /* 685 * Sort interrupts according to count. 686 */ 687 sx_xlock(&intrsrc_lock); 688 memcpy(interrupt_sorted, interrupt_sources, sizeof(interrupt_sorted)); 689 qsort(interrupt_sorted, NUM_IO_INTS, sizeof(interrupt_sorted[0]), 690 intrcmp); 691 692 /* 693 * Restart the scan from the same location to avoid moving in the 694 * common case. 695 */ 696 current_cpu = 0; 697 698 /* 699 * Assign round-robin from most loaded to least. 700 */ 701 for (i = NUM_IO_INTS - 1; i >= 0; i--) { 702 isrc = interrupt_sorted[i]; 703 if (isrc == NULL || isrc->is_event->ie_cpu != NOCPU) 704 continue; 705 cpu = current_cpu; 706 intr_next_cpu(); 707 if (isrc->is_cpu != cpu && 708 isrc->is_pic->pic_assign_cpu(isrc, 709 cpu_apic_ids[cpu]) == 0) 710 isrc->is_cpu = cpu; 711 } 712 sx_xunlock(&intrsrc_lock); 713 out: 714 taskqueue_enqueue_timeout(taskqueue_thread, &intrbalance_task, 715 interval ? hz * interval : hz * 60); 716 717 } 718 719 static void 720 intr_balance_init(void *dummy __unused) 721 { 722 723 TIMEOUT_TASK_INIT(taskqueue_thread, &intrbalance_task, 0, intr_balance, 724 NULL); 725 taskqueue_enqueue_timeout(taskqueue_thread, &intrbalance_task, hz); 726 } 727 SYSINIT(intr_balance_init, SI_SUB_SMP, SI_ORDER_ANY, intr_balance_init, NULL); 728 729 #else 730 /* 731 * Always route interrupts to the current processor in the UP case. 732 */ 733 u_int 734 intr_next_cpu(void) 735 { 736 737 return (PCPU_GET(apic_id)); 738 } 739 #endif 740