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