1121982Sjhb/*-
2121982Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3121982Sjhb * All rights reserved.
4121982Sjhb *
5121982Sjhb * Redistribution and use in source and binary forms, with or without
6121982Sjhb * modification, are permitted provided that the following conditions
7121982Sjhb * are met:
8121982Sjhb * 1. Redistributions of source code must retain the above copyright
9121982Sjhb *    notice, this list of conditions and the following disclaimer.
10121982Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11121982Sjhb *    notice, this list of conditions and the following disclaimer in the
12121982Sjhb *    documentation and/or other materials provided with the distribution.
13121982Sjhb *
14121982Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15121982Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16121982Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17121982Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18121982Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19121982Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20121982Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21121982Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22121982Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121982Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121982Sjhb * SUCH DAMAGE.
25121982Sjhb *
26121982Sjhb * $FreeBSD$
27121982Sjhb */
28121982Sjhb
29121982Sjhb/*
30232747Sjhb * Machine dependent interrupt code for x86.  For x86, we have to
31121982Sjhb * deal with different PICs.  Thus, we use the passed in vector to lookup
32121982Sjhb * an interrupt source associated with that vector.  The interrupt source
33121982Sjhb * describes which PIC the source belongs to and includes methods to handle
34121982Sjhb * that source.
35121982Sjhb */
36121982Sjhb
37232744Sjhb#include "opt_atpic.h"
38121982Sjhb#include "opt_ddb.h"
39121982Sjhb
40121982Sjhb#include <sys/param.h>
41121982Sjhb#include <sys/bus.h>
42121982Sjhb#include <sys/interrupt.h>
43121982Sjhb#include <sys/ktr.h>
44121982Sjhb#include <sys/kernel.h>
45169391Sjhb#include <sys/lock.h>
46121982Sjhb#include <sys/mutex.h>
47121982Sjhb#include <sys/proc.h>
48177160Sjhb#include <sys/smp.h>
49121982Sjhb#include <sys/syslog.h>
50121982Sjhb#include <sys/systm.h>
51122572Sjhb#include <machine/clock.h>
52121982Sjhb#include <machine/intr_machdep.h>
53167273Sjhb#include <machine/smp.h>
54121982Sjhb#ifdef DDB
55121982Sjhb#include <ddb/ddb.h>
56121982Sjhb#endif
57121982Sjhb
58232744Sjhb#ifndef DEV_ATPIC
59232744Sjhb#include <machine/segments.h>
60232744Sjhb#include <machine/frame.h>
61232744Sjhb#include <dev/ic/i8259.h>
62232744Sjhb#include <x86/isa/icu.h>
63234144Sjhb#ifdef PC98
64234144Sjhb#include <pc98/cbus/cbus.h>
65234144Sjhb#else
66232744Sjhb#include <x86/isa/isa.h>
67232744Sjhb#endif
68234144Sjhb#endif
69232744Sjhb
70121982Sjhb#define	MAX_STRAY_LOG	5
71121982Sjhb
72151658Sjhbtypedef void (*mask_fn)(void *);
73121982Sjhb
74121982Sjhbstatic int intrcnt_index;
75121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS];
76194985Sjhbstatic struct mtx intr_table_lock;
77169391Sjhbstatic struct mtx intrcnt_lock;
78247877Savgstatic TAILQ_HEAD(pics_head, pic) pics;
79121982Sjhb
80156124Sjhb#ifdef SMP
81156124Sjhbstatic int assign_cpu;
82156124Sjhb#endif
83156124Sjhb
84224187Sattiliou_long intrcnt[INTRCNT_COUNT];
85224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)];
86224187Sattiliosize_t sintrcnt = sizeof(intrcnt);
87224187Sattiliosize_t sintrnames = sizeof(intrnames);
88224187Sattilio
89177181Sjhbstatic int	intr_assign_cpu(void *arg, u_char cpu);
90177325Sjhbstatic void	intr_disable_src(void *arg);
91121982Sjhbstatic void	intr_init(void *__dummy);
92163219Sjhbstatic int	intr_pic_registered(struct pic *pic);
93121982Sjhbstatic void	intrcnt_setname(const char *name, int index);
94121982Sjhbstatic void	intrcnt_updatename(struct intsrc *is);
95121982Sjhbstatic void	intrcnt_register(struct intsrc *is);
96121982Sjhb
97163219Sjhbstatic int
98163219Sjhbintr_pic_registered(struct pic *pic)
99163219Sjhb{
100163219Sjhb	struct pic *p;
101163219Sjhb
102247877Savg	TAILQ_FOREACH(p, &pics, pics) {
103163219Sjhb		if (p == pic)
104163219Sjhb			return (1);
105163219Sjhb	}
106163219Sjhb	return (0);
107163219Sjhb}
108163219Sjhb
109121982Sjhb/*
110163219Sjhb * Register a new interrupt controller (PIC).  This is to support suspend
111163219Sjhb * and resume where we suspend/resume controllers rather than individual
112163219Sjhb * sources.  This also allows controllers with no active sources (such as
113163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume.
114163219Sjhb */
115163219Sjhbint
116163219Sjhbintr_register_pic(struct pic *pic)
117163219Sjhb{
118163219Sjhb	int error;
119163219Sjhb
120194985Sjhb	mtx_lock(&intr_table_lock);
121163219Sjhb	if (intr_pic_registered(pic))
122163219Sjhb		error = EBUSY;
123163219Sjhb	else {
124247877Savg		TAILQ_INSERT_TAIL(&pics, pic, pics);
125163219Sjhb		error = 0;
126163219Sjhb	}
127194985Sjhb	mtx_unlock(&intr_table_lock);
128163219Sjhb	return (error);
129163219Sjhb}
130163219Sjhb
131163219Sjhb/*
132121982Sjhb * Register a new interrupt source with the global interrupt system.
133121982Sjhb * The global interrupts need to be disabled when this function is
134121982Sjhb * called.
135121982Sjhb */
136121982Sjhbint
137121982Sjhbintr_register_source(struct intsrc *isrc)
138121982Sjhb{
139121982Sjhb	int error, vector;
140121982Sjhb
141163219Sjhb	KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC"));
142121982Sjhb	vector = isrc->is_pic->pic_vector(isrc);
143121982Sjhb	if (interrupt_sources[vector] != NULL)
144121982Sjhb		return (EEXIST);
145178092Sjeff	error = intr_event_create(&isrc->is_event, isrc, 0, vector,
146177325Sjhb	    intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source,
147177325Sjhb	    (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:",
148177181Sjhb	    vector);
149121982Sjhb	if (error)
150121982Sjhb		return (error);
151194985Sjhb	mtx_lock(&intr_table_lock);
152121982Sjhb	if (interrupt_sources[vector] != NULL) {
153194985Sjhb		mtx_unlock(&intr_table_lock);
154151658Sjhb		intr_event_destroy(isrc->is_event);
155121982Sjhb		return (EEXIST);
156121982Sjhb	}
157121982Sjhb	intrcnt_register(isrc);
158121982Sjhb	interrupt_sources[vector] = isrc;
159169391Sjhb	isrc->is_handlers = 0;
160194985Sjhb	mtx_unlock(&intr_table_lock);
161121982Sjhb	return (0);
162121982Sjhb}
163121982Sjhb
164121982Sjhbstruct intsrc *
165121982Sjhbintr_lookup_source(int vector)
166121982Sjhb{
167121982Sjhb
168121982Sjhb	return (interrupt_sources[vector]);
169121982Sjhb}
170121982Sjhb
171121982Sjhbint
172166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter,
173166901Spiso    driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
174121982Sjhb{
175121982Sjhb	struct intsrc *isrc;
176121982Sjhb	int error;
177121982Sjhb
178121982Sjhb	isrc = intr_lookup_source(vector);
179121982Sjhb	if (isrc == NULL)
180121982Sjhb		return (EINVAL);
181166901Spiso	error = intr_event_add_handler(isrc->is_event, name, filter, handler,
182169320Spiso	    arg, intr_priority(flags), flags, cookiep);
183121982Sjhb	if (error == 0) {
184194985Sjhb		mtx_lock(&intr_table_lock);
185121982Sjhb		intrcnt_updatename(isrc);
186169391Sjhb		isrc->is_handlers++;
187169391Sjhb		if (isrc->is_handlers == 1) {
188156124Sjhb			isrc->is_pic->pic_enable_intr(isrc);
189169391Sjhb			isrc->is_pic->pic_enable_source(isrc);
190169391Sjhb		}
191194985Sjhb		mtx_unlock(&intr_table_lock);
192121982Sjhb	}
193121982Sjhb	return (error);
194121982Sjhb}
195121982Sjhb
196121982Sjhbint
197121982Sjhbintr_remove_handler(void *cookie)
198121982Sjhb{
199165125Sjhb	struct intsrc *isrc;
200121982Sjhb	int error;
201121982Sjhb
202165125Sjhb	isrc = intr_handler_source(cookie);
203151658Sjhb	error = intr_event_remove_handler(cookie);
204169391Sjhb	if (error == 0) {
205194985Sjhb		mtx_lock(&intr_table_lock);
206169391Sjhb		isrc->is_handlers--;
207169391Sjhb		if (isrc->is_handlers == 0) {
208169391Sjhb			isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
209169391Sjhb			isrc->is_pic->pic_disable_intr(isrc);
210169391Sjhb		}
211165125Sjhb		intrcnt_updatename(isrc);
212194985Sjhb		mtx_unlock(&intr_table_lock);
213169391Sjhb	}
214121982Sjhb	return (error);
215121982Sjhb}
216121982Sjhb
217128931Sjhbint
218128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol)
219128931Sjhb{
220128931Sjhb	struct intsrc *isrc;
221128931Sjhb
222128931Sjhb	isrc = intr_lookup_source(vector);
223128931Sjhb	if (isrc == NULL)
224128931Sjhb		return (EINVAL);
225128931Sjhb	return (isrc->is_pic->pic_config_intr(isrc, trig, pol));
226128931Sjhb}
227128931Sjhb
228177325Sjhbstatic void
229177325Sjhbintr_disable_src(void *arg)
230177325Sjhb{
231177325Sjhb	struct intsrc *isrc;
232177325Sjhb
233177325Sjhb	isrc = arg;
234177325Sjhb	isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
235177325Sjhb}
236177325Sjhb
237121982Sjhbvoid
238153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
239121982Sjhb{
240177940Sjhb	struct intr_event *ie;
241169320Spiso	int vector;
242169320Spiso
243169320Spiso	/*
244169320Spiso	 * We count software interrupts when we process them.  The
245169320Spiso	 * code here follows previous practice, but there's an
246169320Spiso	 * argument for counting hardware interrupts when they're
247169320Spiso	 * processed too.
248169320Spiso	 */
249169320Spiso	(*isrc->is_count)++;
250170291Sattilio	PCPU_INC(cnt.v_intr);
251169320Spiso
252169320Spiso	ie = isrc->is_event;
253169320Spiso
254169320Spiso	/*
255169320Spiso	 * XXX: We assume that IRQ 0 is only used for the ISA timer
256169320Spiso	 * device (clk).
257169320Spiso	 */
258169320Spiso	vector = isrc->is_pic->pic_vector(isrc);
259169320Spiso	if (vector == 0)
260169320Spiso		clkintr_pending = 1;
261169320Spiso
262169320Spiso	/*
263169320Spiso	 * For stray interrupts, mask and EOI the source, bump the
264169320Spiso	 * stray count, and log the condition.
265169320Spiso	 */
266177940Sjhb	if (intr_event_handle(ie, frame) != 0) {
267133017Sscottl		isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
268137165Sscottl		(*isrc->is_straycount)++;
269121982Sjhb		if (*isrc->is_straycount < MAX_STRAY_LOG)
270121982Sjhb			log(LOG_ERR, "stray irq%d\n", vector);
271121982Sjhb		else if (*isrc->is_straycount == MAX_STRAY_LOG)
272121982Sjhb			log(LOG_CRIT,
273121982Sjhb			    "too many stray irq %d's: not logging anymore\n",
274121982Sjhb			    vector);
275121982Sjhb	}
276121982Sjhb}
277121982Sjhb
278121982Sjhbvoid
279121982Sjhbintr_resume(void)
280121982Sjhb{
281163219Sjhb	struct pic *pic;
282121982Sjhb
283232744Sjhb#ifndef DEV_ATPIC
284232744Sjhb	atpic_reset();
285232744Sjhb#endif
286194985Sjhb	mtx_lock(&intr_table_lock);
287247877Savg	TAILQ_FOREACH(pic, &pics, pics) {
288163219Sjhb		if (pic->pic_resume != NULL)
289163219Sjhb			pic->pic_resume(pic);
290163219Sjhb	}
291194985Sjhb	mtx_unlock(&intr_table_lock);
292121982Sjhb}
293121982Sjhb
294121982Sjhbvoid
295121982Sjhbintr_suspend(void)
296121982Sjhb{
297163219Sjhb	struct pic *pic;
298121982Sjhb
299194985Sjhb	mtx_lock(&intr_table_lock);
300247877Savg	TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) {
301163219Sjhb		if (pic->pic_suspend != NULL)
302163219Sjhb			pic->pic_suspend(pic);
303163219Sjhb	}
304194985Sjhb	mtx_unlock(&intr_table_lock);
305121982Sjhb}
306121982Sjhb
307177181Sjhbstatic int
308177181Sjhbintr_assign_cpu(void *arg, u_char cpu)
309177181Sjhb{
310177181Sjhb#ifdef SMP
311195249Sjhb	struct intsrc *isrc;
312195249Sjhb	int error;
313177181Sjhb
314177181Sjhb	/*
315177181Sjhb	 * Don't do anything during early boot.  We will pick up the
316177181Sjhb	 * assignment once the APs are started.
317177181Sjhb	 */
318177181Sjhb	if (assign_cpu && cpu != NOCPU) {
319177181Sjhb		isrc = arg;
320194985Sjhb		mtx_lock(&intr_table_lock);
321195249Sjhb		error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]);
322194985Sjhb		mtx_unlock(&intr_table_lock);
323195249Sjhb	} else
324195249Sjhb		error = 0;
325195249Sjhb	return (error);
326177181Sjhb#else
327177181Sjhb	return (EOPNOTSUPP);
328177181Sjhb#endif
329177181Sjhb}
330177181Sjhb
331121982Sjhbstatic void
332121982Sjhbintrcnt_setname(const char *name, int index)
333121982Sjhb{
334121982Sjhb
335121982Sjhb	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
336121982Sjhb	    MAXCOMLEN, name);
337121982Sjhb}
338121982Sjhb
339121982Sjhbstatic void
340121982Sjhbintrcnt_updatename(struct intsrc *is)
341121982Sjhb{
342121982Sjhb
343151658Sjhb	intrcnt_setname(is->is_event->ie_fullname, is->is_index);
344121982Sjhb}
345121982Sjhb
346121982Sjhbstatic void
347121982Sjhbintrcnt_register(struct intsrc *is)
348121982Sjhb{
349121982Sjhb	char straystr[MAXCOMLEN + 1];
350121982Sjhb
351151658Sjhb	KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__));
352169391Sjhb	mtx_lock_spin(&intrcnt_lock);
353121982Sjhb	is->is_index = intrcnt_index;
354121982Sjhb	intrcnt_index += 2;
355209649Smav	snprintf(straystr, MAXCOMLEN + 1, "stray irq%d",
356209649Smav	    is->is_pic->pic_vector(is));
357121982Sjhb	intrcnt_updatename(is);
358121982Sjhb	is->is_count = &intrcnt[is->is_index];
359121982Sjhb	intrcnt_setname(straystr, is->is_index + 1);
360121982Sjhb	is->is_straycount = &intrcnt[is->is_index + 1];
361169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
362121982Sjhb}
363121982Sjhb
364139242Sjhbvoid
365139242Sjhbintrcnt_add(const char *name, u_long **countp)
366139242Sjhb{
367139242Sjhb
368169391Sjhb	mtx_lock_spin(&intrcnt_lock);
369139242Sjhb	*countp = &intrcnt[intrcnt_index];
370139242Sjhb	intrcnt_setname(name, intrcnt_index);
371139242Sjhb	intrcnt_index++;
372169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
373139242Sjhb}
374139242Sjhb
375121982Sjhbstatic void
376121982Sjhbintr_init(void *dummy __unused)
377121982Sjhb{
378121982Sjhb
379121982Sjhb	intrcnt_setname("???", 0);
380121982Sjhb	intrcnt_index = 1;
381247877Savg	TAILQ_INIT(&pics);
382195249Sjhb	mtx_init(&intr_table_lock, "intr sources", NULL, MTX_DEF);
383169391Sjhb	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
384121982Sjhb}
385177253SrwatsonSYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
386121982Sjhb
387232744Sjhb#ifndef DEV_ATPIC
388232744Sjhb/* Initialize the two 8259A's to a known-good shutdown state. */
389232744Sjhbvoid
390232744Sjhbatpic_reset(void)
391232744Sjhb{
392232744Sjhb
393232744Sjhb	outb(IO_ICU1, ICW1_RESET | ICW1_IC4);
394232744Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS);
395234144Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, IRQ_MASK(ICU_SLAVEID));
396234144Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, MASTER_MODE);
397232744Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff);
398232744Sjhb	outb(IO_ICU1, OCW3_SEL | OCW3_RR);
399232744Sjhb
400232744Sjhb	outb(IO_ICU2, ICW1_RESET | ICW1_IC4);
401232744Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8);
402234144Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, ICU_SLAVEID);
403234144Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, SLAVE_MODE);
404232744Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff);
405232744Sjhb	outb(IO_ICU2, OCW3_SEL | OCW3_RR);
406232744Sjhb}
407232744Sjhb#endif
408232744Sjhb
409198170Skib/* Add a description to an active interrupt handler. */
410198170Skibint
411198170Skibintr_describe(u_int vector, void *ih, const char *descr)
412198170Skib{
413198170Skib	struct intsrc *isrc;
414198170Skib	int error;
415198170Skib
416198170Skib	isrc = intr_lookup_source(vector);
417198170Skib	if (isrc == NULL)
418198170Skib		return (EINVAL);
419198170Skib	error = intr_event_describe_handler(isrc->is_event, ih, descr);
420198170Skib	if (error)
421198170Skib		return (error);
422198170Skib	intrcnt_updatename(isrc);
423198170Skib	return (0);
424198170Skib}
425198170Skib
426121982Sjhb#ifdef DDB
427121982Sjhb/*
428121982Sjhb * Dump data about interrupt handlers
429121982Sjhb */
430121982SjhbDB_SHOW_COMMAND(irqs, db_show_irqs)
431121982Sjhb{
432121982Sjhb	struct intsrc **isrc;
433160312Sjhb	int i, verbose;
434121982Sjhb
435121982Sjhb	if (strcmp(modif, "v") == 0)
436121982Sjhb		verbose = 1;
437121982Sjhb	else
438121982Sjhb		verbose = 0;
439121982Sjhb	isrc = interrupt_sources;
440160312Sjhb	for (i = 0; i < NUM_IO_INTS && !db_pager_quit; i++, isrc++)
441121982Sjhb		if (*isrc != NULL)
442151658Sjhb			db_dump_intr_event((*isrc)->is_event, verbose);
443121982Sjhb}
444121982Sjhb#endif
445156124Sjhb
446156124Sjhb#ifdef SMP
447156124Sjhb/*
448156124Sjhb * Support for balancing interrupt sources across CPUs.  For now we just
449156124Sjhb * allocate CPUs round-robin.
450156124Sjhb */
451156124Sjhb
452222813Sattiliostatic cpuset_t intr_cpus;
453177160Sjhbstatic int current_cpu;
454156124Sjhb
455194985Sjhb/*
456194985Sjhb * Return the CPU that the next interrupt source should use.  For now
457194985Sjhb * this just returns the next local APIC according to round-robin.
458194985Sjhb */
459194985Sjhbu_int
460194985Sjhbintr_next_cpu(void)
461156124Sjhb{
462194985Sjhb	u_int apic_id;
463156124Sjhb
464194985Sjhb	/* Leave all interrupts on the BSP during boot. */
465194985Sjhb	if (!assign_cpu)
466214448Sjhb		return (PCPU_GET(apic_id));
467194985Sjhb
468195249Sjhb	mtx_lock_spin(&icu_lock);
469194985Sjhb	apic_id = cpu_apic_ids[current_cpu];
470167273Sjhb	do {
471167273Sjhb		current_cpu++;
472177160Sjhb		if (current_cpu > mp_maxid)
473167273Sjhb			current_cpu = 0;
474222813Sattilio	} while (!CPU_ISSET(current_cpu, &intr_cpus));
475195249Sjhb	mtx_unlock_spin(&icu_lock);
476194985Sjhb	return (apic_id);
477156124Sjhb}
478156124Sjhb
479177181Sjhb/* Attempt to bind the specified IRQ to the specified CPU. */
480177181Sjhbint
481177181Sjhbintr_bind(u_int vector, u_char cpu)
482177181Sjhb{
483177181Sjhb	struct intsrc *isrc;
484177181Sjhb
485177181Sjhb	isrc = intr_lookup_source(vector);
486177181Sjhb	if (isrc == NULL)
487177181Sjhb		return (EINVAL);
488177181Sjhb	return (intr_event_bind(isrc->is_event, cpu));
489177181Sjhb}
490177181Sjhb
491156124Sjhb/*
492167273Sjhb * Add a CPU to our mask of valid CPUs that can be destinations of
493167273Sjhb * interrupts.
494156124Sjhb */
495156124Sjhbvoid
496167273Sjhbintr_add_cpu(u_int cpu)
497156124Sjhb{
498156124Sjhb
499167273Sjhb	if (cpu >= MAXCPU)
500167273Sjhb		panic("%s: Invalid CPU ID", __func__);
501156124Sjhb	if (bootverbose)
502167273Sjhb		printf("INTR: Adding local APIC %d as a target\n",
503167273Sjhb		    cpu_apic_ids[cpu]);
504167273Sjhb
505222813Sattilio	CPU_SET(cpu, &intr_cpus);
506156124Sjhb}
507156124Sjhb
508156124Sjhb/*
509156124Sjhb * Distribute all the interrupt sources among the available CPUs once the
510156124Sjhb * AP's have been launched.
511156124Sjhb */
512156124Sjhbstatic void
513156124Sjhbintr_shuffle_irqs(void *arg __unused)
514156124Sjhb{
515156124Sjhb	struct intsrc *isrc;
516156124Sjhb	int i;
517156124Sjhb
518183133Skmacy#ifdef XEN
519183133Skmacy	/*
520183133Skmacy	 * Doesn't work yet
521183133Skmacy	 */
522183133Skmacy	return;
523195249Sjhb#endif
524195249Sjhb
525156124Sjhb	/* Don't bother on UP. */
526177160Sjhb	if (mp_ncpus == 1)
527156124Sjhb		return;
528156124Sjhb
529164358Sjhb	/* Round-robin assign a CPU to each enabled source. */
530194985Sjhb	mtx_lock(&intr_table_lock);
531156124Sjhb	assign_cpu = 1;
532156124Sjhb	for (i = 0; i < NUM_IO_INTS; i++) {
533156124Sjhb		isrc = interrupt_sources[i];
534177181Sjhb		if (isrc != NULL && isrc->is_handlers > 0) {
535177181Sjhb			/*
536177181Sjhb			 * If this event is already bound to a CPU,
537177181Sjhb			 * then assign the source to that CPU instead
538195249Sjhb			 * of picking one via round-robin.  Note that
539195249Sjhb			 * this is careful to only advance the
540195249Sjhb			 * round-robin if the CPU assignment succeeds.
541177181Sjhb			 */
542177181Sjhb			if (isrc->is_event->ie_cpu != NOCPU)
543195249Sjhb				(void)isrc->is_pic->pic_assign_cpu(isrc,
544209155Smav				    cpu_apic_ids[isrc->is_event->ie_cpu]);
545195249Sjhb			else if (isrc->is_pic->pic_assign_cpu(isrc,
546195249Sjhb				cpu_apic_ids[current_cpu]) == 0)
547195249Sjhb				(void)intr_next_cpu();
548195249Sjhb
549177181Sjhb		}
550156124Sjhb	}
551194985Sjhb	mtx_unlock(&intr_table_lock);
552156124Sjhb}
553177253SrwatsonSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
554177253Srwatson    NULL);
555195002Sjhb#else
556195002Sjhb/*
557195002Sjhb * Always route interrupts to the current processor in the UP case.
558195002Sjhb */
559195002Sjhbu_int
560195002Sjhbintr_next_cpu(void)
561195002Sjhb{
562195002Sjhb
563195002Sjhb	return (PCPU_GET(apic_id));
564195002Sjhb}
565235260Sattilio
566235260Sattilio/* Use an empty stub for compatibility. */
567235260Sattiliovoid
568235260Sattiliointr_add_cpu(u_int cpu __unused)
569235260Sattilio{
570235260Sattilio
571235260Sattilio}
572156124Sjhb#endif
573