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: stable/10/sys/x86/x86/intr_machdep.c 307244 2016-10-14 02:03:53Z sephe $
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>
49307244Ssephe#include <sys/sx.h>
50121982Sjhb#include <sys/syslog.h>
51121982Sjhb#include <sys/systm.h>
52122572Sjhb#include <machine/clock.h>
53121982Sjhb#include <machine/intr_machdep.h>
54167273Sjhb#include <machine/smp.h>
55121982Sjhb#ifdef DDB
56121982Sjhb#include <ddb/ddb.h>
57121982Sjhb#endif
58121982Sjhb
59232744Sjhb#ifndef DEV_ATPIC
60232744Sjhb#include <machine/segments.h>
61232744Sjhb#include <machine/frame.h>
62232744Sjhb#include <dev/ic/i8259.h>
63232744Sjhb#include <x86/isa/icu.h>
64233031Snyan#ifdef PC98
65233031Snyan#include <pc98/cbus/cbus.h>
66233031Snyan#else
67232744Sjhb#include <x86/isa/isa.h>
68232744Sjhb#endif
69233031Snyan#endif
70232744Sjhb
71121982Sjhb#define	MAX_STRAY_LOG	5
72121982Sjhb
73151658Sjhbtypedef void (*mask_fn)(void *);
74121982Sjhb
75121982Sjhbstatic int intrcnt_index;
76121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS];
77307244Ssephestatic struct sx intrsrc_lock;
78307244Ssephestatic struct mtx intrpic_lock;
79169391Sjhbstatic struct mtx intrcnt_lock;
80246247Savgstatic TAILQ_HEAD(pics_head, pic) pics;
81121982Sjhb
82156124Sjhb#ifdef SMP
83156124Sjhbstatic int assign_cpu;
84156124Sjhb#endif
85156124Sjhb
86224187Sattiliou_long intrcnt[INTRCNT_COUNT];
87224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)];
88224187Sattiliosize_t sintrcnt = sizeof(intrcnt);
89224187Sattiliosize_t sintrnames = sizeof(intrnames);
90224187Sattilio
91177181Sjhbstatic int	intr_assign_cpu(void *arg, u_char cpu);
92177325Sjhbstatic void	intr_disable_src(void *arg);
93121982Sjhbstatic void	intr_init(void *__dummy);
94163219Sjhbstatic int	intr_pic_registered(struct pic *pic);
95121982Sjhbstatic void	intrcnt_setname(const char *name, int index);
96121982Sjhbstatic void	intrcnt_updatename(struct intsrc *is);
97121982Sjhbstatic void	intrcnt_register(struct intsrc *is);
98121982Sjhb
99163219Sjhbstatic int
100163219Sjhbintr_pic_registered(struct pic *pic)
101163219Sjhb{
102163219Sjhb	struct pic *p;
103163219Sjhb
104246247Savg	TAILQ_FOREACH(p, &pics, pics) {
105163219Sjhb		if (p == pic)
106163219Sjhb			return (1);
107163219Sjhb	}
108163219Sjhb	return (0);
109163219Sjhb}
110163219Sjhb
111121982Sjhb/*
112163219Sjhb * Register a new interrupt controller (PIC).  This is to support suspend
113163219Sjhb * and resume where we suspend/resume controllers rather than individual
114163219Sjhb * sources.  This also allows controllers with no active sources (such as
115163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume.
116163219Sjhb */
117163219Sjhbint
118163219Sjhbintr_register_pic(struct pic *pic)
119163219Sjhb{
120163219Sjhb	int error;
121163219Sjhb
122307244Ssephe	mtx_lock(&intrpic_lock);
123163219Sjhb	if (intr_pic_registered(pic))
124163219Sjhb		error = EBUSY;
125163219Sjhb	else {
126246247Savg		TAILQ_INSERT_TAIL(&pics, pic, pics);
127163219Sjhb		error = 0;
128163219Sjhb	}
129307244Ssephe	mtx_unlock(&intrpic_lock);
130163219Sjhb	return (error);
131163219Sjhb}
132163219Sjhb
133163219Sjhb/*
134121982Sjhb * Register a new interrupt source with the global interrupt system.
135121982Sjhb * The global interrupts need to be disabled when this function is
136121982Sjhb * called.
137121982Sjhb */
138121982Sjhbint
139121982Sjhbintr_register_source(struct intsrc *isrc)
140121982Sjhb{
141121982Sjhb	int error, vector;
142121982Sjhb
143163219Sjhb	KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC"));
144121982Sjhb	vector = isrc->is_pic->pic_vector(isrc);
145121982Sjhb	if (interrupt_sources[vector] != NULL)
146121982Sjhb		return (EEXIST);
147178092Sjeff	error = intr_event_create(&isrc->is_event, isrc, 0, vector,
148177325Sjhb	    intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source,
149177325Sjhb	    (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:",
150177181Sjhb	    vector);
151121982Sjhb	if (error)
152121982Sjhb		return (error);
153307244Ssephe	sx_xlock(&intrsrc_lock);
154121982Sjhb	if (interrupt_sources[vector] != NULL) {
155307244Ssephe		sx_xunlock(&intrsrc_lock);
156151658Sjhb		intr_event_destroy(isrc->is_event);
157121982Sjhb		return (EEXIST);
158121982Sjhb	}
159121982Sjhb	intrcnt_register(isrc);
160121982Sjhb	interrupt_sources[vector] = isrc;
161169391Sjhb	isrc->is_handlers = 0;
162307244Ssephe	sx_xunlock(&intrsrc_lock);
163121982Sjhb	return (0);
164121982Sjhb}
165121982Sjhb
166121982Sjhbstruct intsrc *
167121982Sjhbintr_lookup_source(int vector)
168121982Sjhb{
169121982Sjhb
170121982Sjhb	return (interrupt_sources[vector]);
171121982Sjhb}
172121982Sjhb
173121982Sjhbint
174166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter,
175166901Spiso    driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
176121982Sjhb{
177121982Sjhb	struct intsrc *isrc;
178121982Sjhb	int error;
179121982Sjhb
180121982Sjhb	isrc = intr_lookup_source(vector);
181121982Sjhb	if (isrc == NULL)
182121982Sjhb		return (EINVAL);
183166901Spiso	error = intr_event_add_handler(isrc->is_event, name, filter, handler,
184169320Spiso	    arg, intr_priority(flags), flags, cookiep);
185121982Sjhb	if (error == 0) {
186307244Ssephe		sx_xlock(&intrsrc_lock);
187121982Sjhb		intrcnt_updatename(isrc);
188169391Sjhb		isrc->is_handlers++;
189169391Sjhb		if (isrc->is_handlers == 1) {
190156124Sjhb			isrc->is_pic->pic_enable_intr(isrc);
191169391Sjhb			isrc->is_pic->pic_enable_source(isrc);
192169391Sjhb		}
193307244Ssephe		sx_xunlock(&intrsrc_lock);
194121982Sjhb	}
195121982Sjhb	return (error);
196121982Sjhb}
197121982Sjhb
198121982Sjhbint
199121982Sjhbintr_remove_handler(void *cookie)
200121982Sjhb{
201165125Sjhb	struct intsrc *isrc;
202307213Sroyger	int error;
203121982Sjhb
204165125Sjhb	isrc = intr_handler_source(cookie);
205151658Sjhb	error = intr_event_remove_handler(cookie);
206169391Sjhb	if (error == 0) {
207307244Ssephe		sx_xlock(&intrsrc_lock);
208169391Sjhb		isrc->is_handlers--;
209169391Sjhb		if (isrc->is_handlers == 0) {
210169391Sjhb			isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
211169391Sjhb			isrc->is_pic->pic_disable_intr(isrc);
212169391Sjhb		}
213165125Sjhb		intrcnt_updatename(isrc);
214307244Ssephe		sx_xunlock(&intrsrc_lock);
215169391Sjhb	}
216121982Sjhb	return (error);
217121982Sjhb}
218121982Sjhb
219128931Sjhbint
220128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol)
221128931Sjhb{
222128931Sjhb	struct intsrc *isrc;
223128931Sjhb
224128931Sjhb	isrc = intr_lookup_source(vector);
225128931Sjhb	if (isrc == NULL)
226128931Sjhb		return (EINVAL);
227128931Sjhb	return (isrc->is_pic->pic_config_intr(isrc, trig, pol));
228128931Sjhb}
229128931Sjhb
230177325Sjhbstatic void
231177325Sjhbintr_disable_src(void *arg)
232177325Sjhb{
233177325Sjhb	struct intsrc *isrc;
234177325Sjhb
235177325Sjhb	isrc = arg;
236177325Sjhb	isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
237177325Sjhb}
238177325Sjhb
239121982Sjhbvoid
240153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
241121982Sjhb{
242177940Sjhb	struct intr_event *ie;
243169320Spiso	int vector;
244169320Spiso
245169320Spiso	/*
246169320Spiso	 * We count software interrupts when we process them.  The
247169320Spiso	 * code here follows previous practice, but there's an
248169320Spiso	 * argument for counting hardware interrupts when they're
249169320Spiso	 * processed too.
250169320Spiso	 */
251169320Spiso	(*isrc->is_count)++;
252170291Sattilio	PCPU_INC(cnt.v_intr);
253169320Spiso
254169320Spiso	ie = isrc->is_event;
255169320Spiso
256169320Spiso	/*
257169320Spiso	 * XXX: We assume that IRQ 0 is only used for the ISA timer
258169320Spiso	 * device (clk).
259169320Spiso	 */
260169320Spiso	vector = isrc->is_pic->pic_vector(isrc);
261169320Spiso	if (vector == 0)
262169320Spiso		clkintr_pending = 1;
263169320Spiso
264169320Spiso	/*
265169320Spiso	 * For stray interrupts, mask and EOI the source, bump the
266169320Spiso	 * stray count, and log the condition.
267169320Spiso	 */
268177940Sjhb	if (intr_event_handle(ie, frame) != 0) {
269133017Sscottl		isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
270137165Sscottl		(*isrc->is_straycount)++;
271121982Sjhb		if (*isrc->is_straycount < MAX_STRAY_LOG)
272121982Sjhb			log(LOG_ERR, "stray irq%d\n", vector);
273121982Sjhb		else if (*isrc->is_straycount == MAX_STRAY_LOG)
274121982Sjhb			log(LOG_CRIT,
275121982Sjhb			    "too many stray irq %d's: not logging anymore\n",
276121982Sjhb			    vector);
277121982Sjhb	}
278121982Sjhb}
279121982Sjhb
280121982Sjhbvoid
281255726Sgibbsintr_resume(bool suspend_cancelled)
282121982Sjhb{
283163219Sjhb	struct pic *pic;
284121982Sjhb
285232744Sjhb#ifndef DEV_ATPIC
286232744Sjhb	atpic_reset();
287232744Sjhb#endif
288307244Ssephe	mtx_lock(&intrpic_lock);
289246247Savg	TAILQ_FOREACH(pic, &pics, pics) {
290163219Sjhb		if (pic->pic_resume != NULL)
291255726Sgibbs			pic->pic_resume(pic, suspend_cancelled);
292163219Sjhb	}
293307244Ssephe	mtx_unlock(&intrpic_lock);
294121982Sjhb}
295121982Sjhb
296121982Sjhbvoid
297121982Sjhbintr_suspend(void)
298121982Sjhb{
299163219Sjhb	struct pic *pic;
300121982Sjhb
301307244Ssephe	mtx_lock(&intrpic_lock);
302246247Savg	TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) {
303163219Sjhb		if (pic->pic_suspend != NULL)
304163219Sjhb			pic->pic_suspend(pic);
305163219Sjhb	}
306307244Ssephe	mtx_unlock(&intrpic_lock);
307121982Sjhb}
308121982Sjhb
309177181Sjhbstatic int
310177181Sjhbintr_assign_cpu(void *arg, u_char cpu)
311177181Sjhb{
312177181Sjhb#ifdef SMP
313195249Sjhb	struct intsrc *isrc;
314195249Sjhb	int error;
315177181Sjhb
316177181Sjhb	/*
317177181Sjhb	 * Don't do anything during early boot.  We will pick up the
318177181Sjhb	 * assignment once the APs are started.
319177181Sjhb	 */
320177181Sjhb	if (assign_cpu && cpu != NOCPU) {
321177181Sjhb		isrc = arg;
322307244Ssephe		sx_xlock(&intrsrc_lock);
323195249Sjhb		error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]);
324307244Ssephe		sx_xunlock(&intrsrc_lock);
325195249Sjhb	} else
326195249Sjhb		error = 0;
327195249Sjhb	return (error);
328177181Sjhb#else
329177181Sjhb	return (EOPNOTSUPP);
330177181Sjhb#endif
331177181Sjhb}
332177181Sjhb
333121982Sjhbstatic void
334121982Sjhbintrcnt_setname(const char *name, int index)
335121982Sjhb{
336121982Sjhb
337121982Sjhb	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
338121982Sjhb	    MAXCOMLEN, name);
339121982Sjhb}
340121982Sjhb
341121982Sjhbstatic void
342121982Sjhbintrcnt_updatename(struct intsrc *is)
343121982Sjhb{
344121982Sjhb
345151658Sjhb	intrcnt_setname(is->is_event->ie_fullname, is->is_index);
346121982Sjhb}
347121982Sjhb
348121982Sjhbstatic void
349121982Sjhbintrcnt_register(struct intsrc *is)
350121982Sjhb{
351121982Sjhb	char straystr[MAXCOMLEN + 1];
352121982Sjhb
353151658Sjhb	KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__));
354169391Sjhb	mtx_lock_spin(&intrcnt_lock);
355121982Sjhb	is->is_index = intrcnt_index;
356121982Sjhb	intrcnt_index += 2;
357209649Smav	snprintf(straystr, MAXCOMLEN + 1, "stray irq%d",
358209649Smav	    is->is_pic->pic_vector(is));
359121982Sjhb	intrcnt_updatename(is);
360121982Sjhb	is->is_count = &intrcnt[is->is_index];
361121982Sjhb	intrcnt_setname(straystr, is->is_index + 1);
362121982Sjhb	is->is_straycount = &intrcnt[is->is_index + 1];
363169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
364121982Sjhb}
365121982Sjhb
366139242Sjhbvoid
367139242Sjhbintrcnt_add(const char *name, u_long **countp)
368139242Sjhb{
369139242Sjhb
370169391Sjhb	mtx_lock_spin(&intrcnt_lock);
371139242Sjhb	*countp = &intrcnt[intrcnt_index];
372139242Sjhb	intrcnt_setname(name, intrcnt_index);
373139242Sjhb	intrcnt_index++;
374169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
375139242Sjhb}
376139242Sjhb
377121982Sjhbstatic void
378121982Sjhbintr_init(void *dummy __unused)
379121982Sjhb{
380121982Sjhb
381121982Sjhb	intrcnt_setname("???", 0);
382121982Sjhb	intrcnt_index = 1;
383246247Savg	TAILQ_INIT(&pics);
384307244Ssephe	mtx_init(&intrpic_lock, "intrpic", NULL, MTX_DEF);
385307244Ssephe	sx_init(&intrsrc_lock, "intrsrc");
386169391Sjhb	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
387121982Sjhb}
388177253SrwatsonSYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
389121982Sjhb
390232744Sjhb#ifndef DEV_ATPIC
391232744Sjhb/* Initialize the two 8259A's to a known-good shutdown state. */
392232744Sjhbvoid
393232744Sjhbatpic_reset(void)
394232744Sjhb{
395232744Sjhb
396232744Sjhb	outb(IO_ICU1, ICW1_RESET | ICW1_IC4);
397232744Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS);
398233031Snyan	outb(IO_ICU1 + ICU_IMR_OFFSET, IRQ_MASK(ICU_SLAVEID));
399233031Snyan	outb(IO_ICU1 + ICU_IMR_OFFSET, MASTER_MODE);
400232744Sjhb	outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff);
401232744Sjhb	outb(IO_ICU1, OCW3_SEL | OCW3_RR);
402232744Sjhb
403232744Sjhb	outb(IO_ICU2, ICW1_RESET | ICW1_IC4);
404232744Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8);
405233031Snyan	outb(IO_ICU2 + ICU_IMR_OFFSET, ICU_SLAVEID);
406233031Snyan	outb(IO_ICU2 + ICU_IMR_OFFSET, SLAVE_MODE);
407232744Sjhb	outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff);
408232744Sjhb	outb(IO_ICU2, OCW3_SEL | OCW3_RR);
409232744Sjhb}
410232744Sjhb#endif
411232744Sjhb
412198170Skib/* Add a description to an active interrupt handler. */
413198170Skibint
414198170Skibintr_describe(u_int vector, void *ih, const char *descr)
415198170Skib{
416198170Skib	struct intsrc *isrc;
417198170Skib	int error;
418198170Skib
419198170Skib	isrc = intr_lookup_source(vector);
420198170Skib	if (isrc == NULL)
421198170Skib		return (EINVAL);
422198170Skib	error = intr_event_describe_handler(isrc->is_event, ih, descr);
423198170Skib	if (error)
424198170Skib		return (error);
425198170Skib	intrcnt_updatename(isrc);
426198170Skib	return (0);
427198170Skib}
428198170Skib
429121982Sjhb#ifdef DDB
430121982Sjhb/*
431121982Sjhb * Dump data about interrupt handlers
432121982Sjhb */
433121982SjhbDB_SHOW_COMMAND(irqs, db_show_irqs)
434121982Sjhb{
435121982Sjhb	struct intsrc **isrc;
436160312Sjhb	int i, verbose;
437121982Sjhb
438121982Sjhb	if (strcmp(modif, "v") == 0)
439121982Sjhb		verbose = 1;
440121982Sjhb	else
441121982Sjhb		verbose = 0;
442121982Sjhb	isrc = interrupt_sources;
443160312Sjhb	for (i = 0; i < NUM_IO_INTS && !db_pager_quit; i++, isrc++)
444121982Sjhb		if (*isrc != NULL)
445151658Sjhb			db_dump_intr_event((*isrc)->is_event, verbose);
446121982Sjhb}
447121982Sjhb#endif
448156124Sjhb
449156124Sjhb#ifdef SMP
450156124Sjhb/*
451156124Sjhb * Support for balancing interrupt sources across CPUs.  For now we just
452156124Sjhb * allocate CPUs round-robin.
453156124Sjhb */
454156124Sjhb
455241371Sattiliostatic cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
456177160Sjhbstatic int current_cpu;
457156124Sjhb
458194985Sjhb/*
459194985Sjhb * Return the CPU that the next interrupt source should use.  For now
460194985Sjhb * this just returns the next local APIC according to round-robin.
461194985Sjhb */
462194985Sjhbu_int
463194985Sjhbintr_next_cpu(void)
464156124Sjhb{
465194985Sjhb	u_int apic_id;
466156124Sjhb
467194985Sjhb	/* Leave all interrupts on the BSP during boot. */
468194985Sjhb	if (!assign_cpu)
469214448Sjhb		return (PCPU_GET(apic_id));
470194985Sjhb
471195249Sjhb	mtx_lock_spin(&icu_lock);
472194985Sjhb	apic_id = cpu_apic_ids[current_cpu];
473167273Sjhb	do {
474167273Sjhb		current_cpu++;
475177160Sjhb		if (current_cpu > mp_maxid)
476167273Sjhb			current_cpu = 0;
477222813Sattilio	} while (!CPU_ISSET(current_cpu, &intr_cpus));
478195249Sjhb	mtx_unlock_spin(&icu_lock);
479194985Sjhb	return (apic_id);
480156124Sjhb}
481156124Sjhb
482177181Sjhb/* Attempt to bind the specified IRQ to the specified CPU. */
483177181Sjhbint
484177181Sjhbintr_bind(u_int vector, u_char cpu)
485177181Sjhb{
486177181Sjhb	struct intsrc *isrc;
487177181Sjhb
488177181Sjhb	isrc = intr_lookup_source(vector);
489177181Sjhb	if (isrc == NULL)
490177181Sjhb		return (EINVAL);
491177181Sjhb	return (intr_event_bind(isrc->is_event, cpu));
492177181Sjhb}
493177181Sjhb
494156124Sjhb/*
495167273Sjhb * Add a CPU to our mask of valid CPUs that can be destinations of
496167273Sjhb * interrupts.
497156124Sjhb */
498156124Sjhbvoid
499167273Sjhbintr_add_cpu(u_int cpu)
500156124Sjhb{
501156124Sjhb
502167273Sjhb	if (cpu >= MAXCPU)
503167273Sjhb		panic("%s: Invalid CPU ID", __func__);
504156124Sjhb	if (bootverbose)
505167273Sjhb		printf("INTR: Adding local APIC %d as a target\n",
506167273Sjhb		    cpu_apic_ids[cpu]);
507167273Sjhb
508222813Sattilio	CPU_SET(cpu, &intr_cpus);
509156124Sjhb}
510156124Sjhb
511156124Sjhb/*
512156124Sjhb * Distribute all the interrupt sources among the available CPUs once the
513156124Sjhb * AP's have been launched.
514156124Sjhb */
515156124Sjhbstatic void
516156124Sjhbintr_shuffle_irqs(void *arg __unused)
517156124Sjhb{
518156124Sjhb	struct intsrc *isrc;
519156124Sjhb	int i;
520156124Sjhb
521183133Skmacy#ifdef XEN
522183133Skmacy	/*
523183133Skmacy	 * Doesn't work yet
524183133Skmacy	 */
525183133Skmacy	return;
526195249Sjhb#endif
527195249Sjhb
528156124Sjhb	/* Don't bother on UP. */
529177160Sjhb	if (mp_ncpus == 1)
530156124Sjhb		return;
531156124Sjhb
532164358Sjhb	/* Round-robin assign a CPU to each enabled source. */
533307244Ssephe	sx_xlock(&intrsrc_lock);
534156124Sjhb	assign_cpu = 1;
535156124Sjhb	for (i = 0; i < NUM_IO_INTS; i++) {
536156124Sjhb		isrc = interrupt_sources[i];
537177181Sjhb		if (isrc != NULL && isrc->is_handlers > 0) {
538177181Sjhb			/*
539177181Sjhb			 * If this event is already bound to a CPU,
540177181Sjhb			 * then assign the source to that CPU instead
541195249Sjhb			 * of picking one via round-robin.  Note that
542195249Sjhb			 * this is careful to only advance the
543195249Sjhb			 * round-robin if the CPU assignment succeeds.
544177181Sjhb			 */
545177181Sjhb			if (isrc->is_event->ie_cpu != NOCPU)
546195249Sjhb				(void)isrc->is_pic->pic_assign_cpu(isrc,
547209155Smav				    cpu_apic_ids[isrc->is_event->ie_cpu]);
548195249Sjhb			else if (isrc->is_pic->pic_assign_cpu(isrc,
549195249Sjhb				cpu_apic_ids[current_cpu]) == 0)
550195249Sjhb				(void)intr_next_cpu();
551195249Sjhb
552177181Sjhb		}
553156124Sjhb	}
554307244Ssephe	sx_xunlock(&intrsrc_lock);
555156124Sjhb}
556177253SrwatsonSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
557177253Srwatson    NULL);
558195002Sjhb#else
559195002Sjhb/*
560195002Sjhb * Always route interrupts to the current processor in the UP case.
561195002Sjhb */
562195002Sjhbu_int
563195002Sjhbintr_next_cpu(void)
564195002Sjhb{
565195002Sjhb
566195002Sjhb	return (PCPU_GET(apic_id));
567195002Sjhb}
568156124Sjhb#endif
569