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 * 3. Neither the name of the author nor the names of any co-contributors
14121982Sjhb *    may be used to endorse or promote products derived from this software
15121982Sjhb *    without specific prior written permission.
16121982Sjhb *
17121982Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18121982Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19121982Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20121982Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21121982Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22121982Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23121982Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24121982Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25121982Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26121982Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27121982Sjhb * SUCH DAMAGE.
28121982Sjhb *
29121982Sjhb * $FreeBSD$
30121982Sjhb */
31121982Sjhb
32121982Sjhb/*
33232747Sjhb * Machine dependent interrupt code for x86.  For x86, we have to
34121982Sjhb * deal with different PICs.  Thus, we use the passed in vector to lookup
35121982Sjhb * an interrupt source associated with that vector.  The interrupt source
36121982Sjhb * describes which PIC the source belongs to and includes methods to handle
37121982Sjhb * that source.
38121982Sjhb */
39121982Sjhb
40232744Sjhb#include "opt_atpic.h"
41121982Sjhb#include "opt_ddb.h"
42121982Sjhb
43121982Sjhb#include <sys/param.h>
44121982Sjhb#include <sys/bus.h>
45121982Sjhb#include <sys/interrupt.h>
46121982Sjhb#include <sys/ktr.h>
47121982Sjhb#include <sys/kernel.h>
48169391Sjhb#include <sys/lock.h>
49121982Sjhb#include <sys/mutex.h>
50121982Sjhb#include <sys/proc.h>
51177160Sjhb#include <sys/smp.h>
52121982Sjhb#include <sys/syslog.h>
53121982Sjhb#include <sys/systm.h>
54122572Sjhb#include <machine/clock.h>
55121982Sjhb#include <machine/intr_machdep.h>
56167273Sjhb#include <machine/smp.h>
57121982Sjhb#ifdef DDB
58121982Sjhb#include <ddb/ddb.h>
59121982Sjhb#endif
60121982Sjhb
61232744Sjhb#ifndef DEV_ATPIC
62232744Sjhb#include <machine/segments.h>
63232744Sjhb#include <machine/frame.h>
64232744Sjhb#include <dev/ic/i8259.h>
65232744Sjhb#include <x86/isa/icu.h>
66233031Snyan#ifdef PC98
67233031Snyan#include <pc98/cbus/cbus.h>
68233031Snyan#else
69232744Sjhb#include <x86/isa/isa.h>
70232744Sjhb#endif
71233031Snyan#endif
72232744Sjhb
73121982Sjhb#define	MAX_STRAY_LOG	5
74121982Sjhb
75151658Sjhbtypedef void (*mask_fn)(void *);
76121982Sjhb
77121982Sjhbstatic int intrcnt_index;
78121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS];
79194985Sjhbstatic struct mtx intr_table_lock;
80169391Sjhbstatic struct mtx intrcnt_lock;
81246247Savgstatic TAILQ_HEAD(pics_head, pic) pics;
82121982Sjhb
83156124Sjhb#ifdef SMP
84156124Sjhbstatic int assign_cpu;
85156124Sjhb#endif
86156124Sjhb
87224187Sattiliou_long intrcnt[INTRCNT_COUNT];
88224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)];
89224187Sattiliosize_t sintrcnt = sizeof(intrcnt);
90224187Sattiliosize_t sintrnames = sizeof(intrnames);
91224187Sattilio
92177181Sjhbstatic int	intr_assign_cpu(void *arg, u_char cpu);
93177325Sjhbstatic void	intr_disable_src(void *arg);
94121982Sjhbstatic void	intr_init(void *__dummy);
95163219Sjhbstatic int	intr_pic_registered(struct pic *pic);
96121982Sjhbstatic void	intrcnt_setname(const char *name, int index);
97121982Sjhbstatic void	intrcnt_updatename(struct intsrc *is);
98121982Sjhbstatic void	intrcnt_register(struct intsrc *is);
99121982Sjhb
100163219Sjhbstatic int
101163219Sjhbintr_pic_registered(struct pic *pic)
102163219Sjhb{
103163219Sjhb	struct pic *p;
104163219Sjhb
105246247Savg	TAILQ_FOREACH(p, &pics, pics) {
106163219Sjhb		if (p == pic)
107163219Sjhb			return (1);
108163219Sjhb	}
109163219Sjhb	return (0);
110163219Sjhb}
111163219Sjhb
112121982Sjhb/*
113163219Sjhb * Register a new interrupt controller (PIC).  This is to support suspend
114163219Sjhb * and resume where we suspend/resume controllers rather than individual
115163219Sjhb * sources.  This also allows controllers with no active sources (such as
116163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume.
117163219Sjhb */
118163219Sjhbint
119163219Sjhbintr_register_pic(struct pic *pic)
120163219Sjhb{
121163219Sjhb	int error;
122163219Sjhb
123194985Sjhb	mtx_lock(&intr_table_lock);
124163219Sjhb	if (intr_pic_registered(pic))
125163219Sjhb		error = EBUSY;
126163219Sjhb	else {
127246247Savg		TAILQ_INSERT_TAIL(&pics, pic, pics);
128163219Sjhb		error = 0;
129163219Sjhb	}
130194985Sjhb	mtx_unlock(&intr_table_lock);
131163219Sjhb	return (error);
132163219Sjhb}
133163219Sjhb
134163219Sjhb/*
135121982Sjhb * Register a new interrupt source with the global interrupt system.
136121982Sjhb * The global interrupts need to be disabled when this function is
137121982Sjhb * called.
138121982Sjhb */
139121982Sjhbint
140121982Sjhbintr_register_source(struct intsrc *isrc)
141121982Sjhb{
142121982Sjhb	int error, vector;
143121982Sjhb
144163219Sjhb	KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC"));
145121982Sjhb	vector = isrc->is_pic->pic_vector(isrc);
146121982Sjhb	if (interrupt_sources[vector] != NULL)
147121982Sjhb		return (EEXIST);
148178092Sjeff	error = intr_event_create(&isrc->is_event, isrc, 0, vector,
149177325Sjhb	    intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source,
150177325Sjhb	    (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:",
151177181Sjhb	    vector);
152121982Sjhb	if (error)
153121982Sjhb		return (error);
154194985Sjhb	mtx_lock(&intr_table_lock);
155121982Sjhb	if (interrupt_sources[vector] != NULL) {
156194985Sjhb		mtx_unlock(&intr_table_lock);
157151658Sjhb		intr_event_destroy(isrc->is_event);
158121982Sjhb		return (EEXIST);
159121982Sjhb	}
160121982Sjhb	intrcnt_register(isrc);
161121982Sjhb	interrupt_sources[vector] = isrc;
162169391Sjhb	isrc->is_handlers = 0;
163194985Sjhb	mtx_unlock(&intr_table_lock);
164121982Sjhb	return (0);
165121982Sjhb}
166121982Sjhb
167121982Sjhbstruct intsrc *
168121982Sjhbintr_lookup_source(int vector)
169121982Sjhb{
170121982Sjhb
171121982Sjhb	return (interrupt_sources[vector]);
172121982Sjhb}
173121982Sjhb
174121982Sjhbint
175166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter,
176166901Spiso    driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
177121982Sjhb{
178121982Sjhb	struct intsrc *isrc;
179121982Sjhb	int error;
180121982Sjhb
181121982Sjhb	isrc = intr_lookup_source(vector);
182121982Sjhb	if (isrc == NULL)
183121982Sjhb		return (EINVAL);
184166901Spiso	error = intr_event_add_handler(isrc->is_event, name, filter, handler,
185169320Spiso	    arg, intr_priority(flags), flags, cookiep);
186121982Sjhb	if (error == 0) {
187194985Sjhb		mtx_lock(&intr_table_lock);
188121982Sjhb		intrcnt_updatename(isrc);
189169391Sjhb		isrc->is_handlers++;
190169391Sjhb		if (isrc->is_handlers == 1) {
191156124Sjhb			isrc->is_pic->pic_enable_intr(isrc);
192169391Sjhb			isrc->is_pic->pic_enable_source(isrc);
193169391Sjhb		}
194194985Sjhb		mtx_unlock(&intr_table_lock);
195121982Sjhb	}
196121982Sjhb	return (error);
197121982Sjhb}
198121982Sjhb
199121982Sjhbint
200121982Sjhbintr_remove_handler(void *cookie)
201121982Sjhb{
202165125Sjhb	struct intsrc *isrc;
203121982Sjhb	int error;
204121982Sjhb
205165125Sjhb	isrc = intr_handler_source(cookie);
206151658Sjhb	error = intr_event_remove_handler(cookie);
207169391Sjhb	if (error == 0) {
208194985Sjhb		mtx_lock(&intr_table_lock);
209169391Sjhb		isrc->is_handlers--;
210169391Sjhb		if (isrc->is_handlers == 0) {
211169391Sjhb			isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI);
212169391Sjhb			isrc->is_pic->pic_disable_intr(isrc);
213169391Sjhb		}
214165125Sjhb		intrcnt_updatename(isrc);
215194985Sjhb		mtx_unlock(&intr_table_lock);
216169391Sjhb	}
217121982Sjhb	return (error);
218121982Sjhb}
219121982Sjhb
220128931Sjhbint
221128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol)
222128931Sjhb{
223128931Sjhb	struct intsrc *isrc;
224128931Sjhb
225128931Sjhb	isrc = intr_lookup_source(vector);
226128931Sjhb	if (isrc == NULL)
227128931Sjhb		return (EINVAL);
228128931Sjhb	return (isrc->is_pic->pic_config_intr(isrc, trig, pol));
229128931Sjhb}
230128931Sjhb
231177325Sjhbstatic void
232177325Sjhbintr_disable_src(void *arg)
233177325Sjhb{
234177325Sjhb	struct intsrc *isrc;
235177325Sjhb
236177325Sjhb	isrc = arg;
237177325Sjhb	isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
238177325Sjhb}
239177325Sjhb
240121982Sjhbvoid
241153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
242121982Sjhb{
243177940Sjhb	struct intr_event *ie;
244169320Spiso	int vector;
245169320Spiso
246169320Spiso	/*
247169320Spiso	 * We count software interrupts when we process them.  The
248169320Spiso	 * code here follows previous practice, but there's an
249169320Spiso	 * argument for counting hardware interrupts when they're
250169320Spiso	 * processed too.
251169320Spiso	 */
252169320Spiso	(*isrc->is_count)++;
253170291Sattilio	PCPU_INC(cnt.v_intr);
254169320Spiso
255169320Spiso	ie = isrc->is_event;
256169320Spiso
257169320Spiso	/*
258169320Spiso	 * XXX: We assume that IRQ 0 is only used for the ISA timer
259169320Spiso	 * device (clk).
260169320Spiso	 */
261169320Spiso	vector = isrc->is_pic->pic_vector(isrc);
262169320Spiso	if (vector == 0)
263169320Spiso		clkintr_pending = 1;
264169320Spiso
265169320Spiso	/*
266169320Spiso	 * For stray interrupts, mask and EOI the source, bump the
267169320Spiso	 * stray count, and log the condition.
268169320Spiso	 */
269177940Sjhb	if (intr_event_handle(ie, frame) != 0) {
270133017Sscottl		isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
271137165Sscottl		(*isrc->is_straycount)++;
272121982Sjhb		if (*isrc->is_straycount < MAX_STRAY_LOG)
273121982Sjhb			log(LOG_ERR, "stray irq%d\n", vector);
274121982Sjhb		else if (*isrc->is_straycount == MAX_STRAY_LOG)
275121982Sjhb			log(LOG_CRIT,
276121982Sjhb			    "too many stray irq %d's: not logging anymore\n",
277121982Sjhb			    vector);
278121982Sjhb	}
279121982Sjhb}
280121982Sjhb
281121982Sjhbvoid
282255726Sgibbsintr_resume(bool suspend_cancelled)
283121982Sjhb{
284163219Sjhb	struct pic *pic;
285121982Sjhb
286232744Sjhb#ifndef DEV_ATPIC
287232744Sjhb	atpic_reset();
288232744Sjhb#endif
289194985Sjhb	mtx_lock(&intr_table_lock);
290246247Savg	TAILQ_FOREACH(pic, &pics, pics) {
291163219Sjhb		if (pic->pic_resume != NULL)
292255726Sgibbs			pic->pic_resume(pic, suspend_cancelled);
293163219Sjhb	}
294194985Sjhb	mtx_unlock(&intr_table_lock);
295121982Sjhb}
296121982Sjhb
297121982Sjhbvoid
298121982Sjhbintr_suspend(void)
299121982Sjhb{
300163219Sjhb	struct pic *pic;
301121982Sjhb
302194985Sjhb	mtx_lock(&intr_table_lock);
303246247Savg	TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) {
304163219Sjhb		if (pic->pic_suspend != NULL)
305163219Sjhb			pic->pic_suspend(pic);
306163219Sjhb	}
307194985Sjhb	mtx_unlock(&intr_table_lock);
308121982Sjhb}
309121982Sjhb
310177181Sjhbstatic int
311177181Sjhbintr_assign_cpu(void *arg, u_char cpu)
312177181Sjhb{
313177181Sjhb#ifdef SMP
314195249Sjhb	struct intsrc *isrc;
315195249Sjhb	int error;
316177181Sjhb
317177181Sjhb	/*
318177181Sjhb	 * Don't do anything during early boot.  We will pick up the
319177181Sjhb	 * assignment once the APs are started.
320177181Sjhb	 */
321177181Sjhb	if (assign_cpu && cpu != NOCPU) {
322177181Sjhb		isrc = arg;
323194985Sjhb		mtx_lock(&intr_table_lock);
324195249Sjhb		error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]);
325194985Sjhb		mtx_unlock(&intr_table_lock);
326195249Sjhb	} else
327195249Sjhb		error = 0;
328195249Sjhb	return (error);
329177181Sjhb#else
330177181Sjhb	return (EOPNOTSUPP);
331177181Sjhb#endif
332177181Sjhb}
333177181Sjhb
334121982Sjhbstatic void
335121982Sjhbintrcnt_setname(const char *name, int index)
336121982Sjhb{
337121982Sjhb
338121982Sjhb	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
339121982Sjhb	    MAXCOMLEN, name);
340121982Sjhb}
341121982Sjhb
342121982Sjhbstatic void
343121982Sjhbintrcnt_updatename(struct intsrc *is)
344121982Sjhb{
345121982Sjhb
346151658Sjhb	intrcnt_setname(is->is_event->ie_fullname, is->is_index);
347121982Sjhb}
348121982Sjhb
349121982Sjhbstatic void
350121982Sjhbintrcnt_register(struct intsrc *is)
351121982Sjhb{
352121982Sjhb	char straystr[MAXCOMLEN + 1];
353121982Sjhb
354151658Sjhb	KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__));
355169391Sjhb	mtx_lock_spin(&intrcnt_lock);
356121982Sjhb	is->is_index = intrcnt_index;
357121982Sjhb	intrcnt_index += 2;
358209649Smav	snprintf(straystr, MAXCOMLEN + 1, "stray irq%d",
359209649Smav	    is->is_pic->pic_vector(is));
360121982Sjhb	intrcnt_updatename(is);
361121982Sjhb	is->is_count = &intrcnt[is->is_index];
362121982Sjhb	intrcnt_setname(straystr, is->is_index + 1);
363121982Sjhb	is->is_straycount = &intrcnt[is->is_index + 1];
364169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
365121982Sjhb}
366121982Sjhb
367139242Sjhbvoid
368139242Sjhbintrcnt_add(const char *name, u_long **countp)
369139242Sjhb{
370139242Sjhb
371169391Sjhb	mtx_lock_spin(&intrcnt_lock);
372139242Sjhb	*countp = &intrcnt[intrcnt_index];
373139242Sjhb	intrcnt_setname(name, intrcnt_index);
374139242Sjhb	intrcnt_index++;
375169391Sjhb	mtx_unlock_spin(&intrcnt_lock);
376139242Sjhb}
377139242Sjhb
378121982Sjhbstatic void
379121982Sjhbintr_init(void *dummy __unused)
380121982Sjhb{
381121982Sjhb
382121982Sjhb	intrcnt_setname("???", 0);
383121982Sjhb	intrcnt_index = 1;
384246247Savg	TAILQ_INIT(&pics);
385195249Sjhb	mtx_init(&intr_table_lock, "intr sources", NULL, MTX_DEF);
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. */
533194985Sjhb	mtx_lock(&intr_table_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	}
554194985Sjhb	mtx_unlock(&intr_table_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